summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/.cvsignore12
-rw-r--r--[-rwxr-xr-x]sql/CMakeLists.txt350
-rw-r--r--sql/Makefile.am193
-rwxr-xr-xsql/add_errmsg4
-rw-r--r--sql/authors.h7
-rw-r--r--sql/client_settings.h14
-rw-r--r--sql/contributors.h5
-rw-r--r--sql/datadict.cc184
-rw-r--r--sql/datadict.h42
-rw-r--r--sql/debug_sync.cc214
-rw-r--r--sql/derror.cc96
-rw-r--r--sql/derror.h25
-rw-r--r--sql/des_key_file.cc16
-rw-r--r--sql/des_key_file.h40
-rw-r--r--sql/discover.cc31
-rw-r--r--sql/discover.h24
-rw-r--r--sql/event_data_objects.cc96
-rw-r--r--sql/event_data_objects.h13
-rw-r--r--sql/event_db_repository.cc172
-rw-r--r--sql/event_db_repository.h7
-rw-r--r--sql/event_parse_data.cc4
-rw-r--r--sql/event_parse_data.h6
-rw-r--r--sql/event_queue.cc70
-rw-r--r--sql/event_queue.h15
-rw-r--r--[-rwxr-xr-x]sql/event_scheduler.cc125
-rw-r--r--sql/event_scheduler.h8
-rw-r--r--sql/events.cc376
-rw-r--r--sql/events.h71
-rw-r--r--[-rwxr-xr-x]sql/examples/CMakeLists.txt8
-rw-r--r--sql/field.cc1361
-rw-r--r--sql/field.h342
-rw-r--r--sql/field_conv.cc5
-rw-r--r--sql/filesort.cc68
-rw-r--r--sql/filesort.h36
-rw-r--r--sql/frm_crypt.cc3
-rw-r--r--sql/frm_crypt.h23
-rw-r--r--sql/gen_lex_hash.cc85
-rw-r--r--sql/gstream.cc4
-rw-r--r--sql/gstream.h14
-rw-r--r--sql/ha_ndbcluster.cc1165
-rw-r--r--sql/ha_ndbcluster.h38
-rw-r--r--sql/ha_ndbcluster_binlog.cc632
-rw-r--r--sql/ha_ndbcluster_binlog.h32
-rw-r--r--sql/ha_ndbcluster_cond.cc232
-rw-r--r--sql/ha_ndbcluster_cond.h12
-rw-r--r--sql/ha_ndbcluster_tables.h5
-rw-r--r--sql/ha_partition.cc767
-rw-r--r--sql/ha_partition.h81
-rw-r--r--sql/handler.cc549
-rw-r--r--sql/handler.h272
-rw-r--r--sql/hash_filo.cc2
-rw-r--r--sql/hash_filo.h32
-rw-r--r--sql/hostname.cc618
-rw-r--r--sql/hostname.h30
-rw-r--r--sql/init.cc11
-rw-r--r--sql/init.h24
-rw-r--r--sql/item.cc632
-rw-r--r--sql/item.h354
-rw-r--r--sql/item_buff.cc9
-rw-r--r--sql/item_cmpfunc.cc142
-rw-r--r--sql/item_cmpfunc.h67
-rw-r--r--sql/item_create.cc216
-rw-r--r--sql/item_create.h6
-rw-r--r--sql/item_func.cc856
-rw-r--r--sql/item_func.h141
-rw-r--r--sql/item_geofunc.cc18
-rw-r--r--sql/item_geofunc.h21
-rw-r--r--sql/item_row.cc9
-rw-r--r--sql/item_row.h5
-rw-r--r--sql/item_strfunc.cc704
-rw-r--r--sql/item_strfunc.h152
-rw-r--r--sql/item_subselect.cc23
-rw-r--r--sql/item_subselect.h25
-rw-r--r--sql/item_sum.cc1298
-rw-r--r--sql/item_sum.h567
-rw-r--r--sql/item_timefunc.cc253
-rw-r--r--sql/item_timefunc.h124
-rw-r--r--sql/item_xmlfunc.cc12
-rw-r--r--sql/item_xmlfunc.h4
-rw-r--r--sql/key.cc36
-rw-r--r--sql/key.h39
-rw-r--r--sql/keycaches.cc163
-rw-r--r--sql/keycaches.h45
-rw-r--r--sql/lex.h38
-rw-r--r--sql/lock.cc1228
-rw-r--r--sql/lock.h28
-rw-r--r--sql/log.cc2101
-rw-r--r--sql/log.h200
-rw-r--r--sql/log_event.cc825
-rw-r--r--sql/log_event.h335
-rw-r--r--sql/log_event_old.cc261
-rw-r--r--sql/main.cc25
-rw-r--r--sql/mdl.cc2628
-rw-r--r--sql/mdl.h856
-rw-r--r--sql/message.h7
-rw-r--r--sql/mf_iocache.cc3
-rw-r--r--sql/my_decimal.cc64
-rw-r--r--sql/my_decimal.h20
-rw-r--r--sql/my_lock.c78
-rw-r--r--sql/mysql_priv.h2519
-rw-r--r--sql/mysql_priv.h.pp10977
-rw-r--r--sql/mysqld.cc5202
-rw-r--r--sql/mysqld.h508
-rw-r--r--sql/mysqld_suffix.h4
-rw-r--r--sql/net_serv.cc71
-rw-r--r--sql/nt_servc.cc24
-rw-r--r--sql/nt_servc.h5
-rw-r--r--sql/opt_range.cc738
-rw-r--r--sql/opt_range.h51
-rw-r--r--sql/opt_sum.cc13
-rw-r--r--sql/parse_file.cc36
-rw-r--r--sql/parse_file.h8
-rw-r--r--sql/partition_element.h49
-rw-r--r--sql/partition_info.cc1355
-rw-r--r--sql/partition_info.h97
-rw-r--r--sql/password.c13
-rw-r--r--sql/procedure.cc2
-rw-r--r--sql/procedure.h15
-rw-r--r--sql/protocol.cc520
-rw-r--r--sql/protocol.h49
-rw-r--r--sql/records.cc81
-rw-r--r--sql/records.h79
-rw-r--r--sql/repl_failsafe.cc567
-rw-r--r--sql/repl_failsafe.h18
-rw-r--r--sql/replication.h552
-rw-r--r--sql/rpl_filter.cc21
-rw-r--r--sql/rpl_filter.h6
-rw-r--r--sql/rpl_handler.cc558
-rw-r--r--sql/rpl_handler.h213
-rw-r--r--sql/rpl_injector.cc24
-rw-r--r--sql/rpl_injector.h4
-rw-r--r--sql/rpl_mi.cc272
-rw-r--r--sql/rpl_mi.h27
-rw-r--r--sql/rpl_record.cc104
-rw-r--r--sql/rpl_record.h5
-rw-r--r--sql/rpl_record_old.cc4
-rw-r--r--sql/rpl_record_old.h2
-rw-r--r--sql/rpl_reporting.cc32
-rw-r--r--sql/rpl_reporting.h29
-rw-r--r--sql/rpl_rli.cc176
-rw-r--r--sql/rpl_rli.h73
-rw-r--r--sql/rpl_tblmap.cc20
-rw-r--r--sql/rpl_tblmap.h11
-rw-r--r--sql/rpl_utility.cc904
-rw-r--r--sql/rpl_utility.h197
-rw-r--r--sql/scheduler.cc174
-rw-r--r--sql/scheduler.h71
-rw-r--r--sql/set_var.cc4193
-rw-r--r--sql/set_var.h1493
-rw-r--r--sql/sha2.cc68
-rw-r--r--sql/share/.cvsignore2
-rw-r--r--sql/share/CMakeLists.txt54
-rw-r--r--sql/share/Makefile.am62
-rw-r--r--sql/share/errmsg-utf8.txt6396
-rw-r--r--sql/share/errmsg.txt6215
-rw-r--r--sql/slave.cc1396
-rw-r--r--sql/slave.h38
-rw-r--r--sql/sp.cc1024
-rw-r--r--sql/sp.h148
-rw-r--r--sql/sp_cache.cc111
-rw-r--r--sql/sp_cache.h7
-rw-r--r--sql/sp_head.cc794
-rw-r--r--sql/sp_head.h103
-rw-r--r--sql/sp_pcontext.cc50
-rw-r--r--sql/sp_pcontext.h13
-rw-r--r--sql/sp_rcontext.cc275
-rw-r--r--sql/sp_rcontext.h99
-rw-r--r--sql/spatial.cc51
-rw-r--r--sql/spatial.h6
-rw-r--r--sql/sql_acl.cc4078
-rw-r--r--sql/sql_acl.h217
-rw-r--r--sql/sql_admin.cc1033
-rw-r--r--sql/sql_admin.h132
-rw-r--r--sql/sql_alter.cc109
-rw-r--r--sql/sql_alter.h66
-rw-r--r--sql/sql_analyse.cc2
-rw-r--r--sql/sql_analyse.h9
-rw-r--r--sql/sql_array.h4
-rw-r--r--sql/sql_audit.cc494
-rw-r--r--sql/sql_audit.h130
-rw-r--r--sql/sql_base.cc7175
-rw-r--r--sql/sql_base.h597
-rw-r--r--sql/sql_binlog.cc26
-rw-r--r--sql/sql_binlog.h23
-rw-r--r--sql/sql_bitmap.h15
-rw-r--r--sql/sql_builtin.cc.in19
-rw-r--r--sql/sql_cache.cc508
-rw-r--r--sql/sql_cache.h119
-rw-r--r--sql/sql_callback.h43
-rw-r--r--sql/sql_class.cc1820
-rw-r--r--sql/sql_class.h1487
-rw-r--r--sql/sql_client.cc3
-rw-r--r--sql/sql_connect.cc628
-rw-r--r--sql/sql_connect.h50
-rw-r--r--sql/sql_const.h248
-rw-r--r--sql/sql_crypt.cc4
-rw-r--r--sql/sql_crypt.h8
-rw-r--r--sql/sql_cursor.cc419
-rw-r--r--sql/sql_cursor.h20
-rw-r--r--sql/sql_db.cc791
-rw-r--r--sql/sql_db.h50
-rw-r--r--sql/sql_delete.cc335
-rw-r--r--sql/sql_delete.h32
-rw-r--r--sql/sql_derived.cc18
-rw-r--r--sql/sql_derived.h29
-rw-r--r--sql/sql_do.cc12
-rw-r--r--sql/sql_do.h26
-rw-r--r--sql/sql_error.cc773
-rw-r--r--sql/sql_error.h522
-rw-r--r--sql/sql_handler.cc565
-rw-r--r--sql/sql_handler.h36
-rw-r--r--sql/sql_help.cc43
-rw-r--r--sql/sql_help.h28
-rw-r--r--sql/sql_hset.h97
-rw-r--r--sql/sql_insert.cc1491
-rw-r--r--sql/sql_insert.h49
-rw-r--r--sql/sql_lex.cc381
-rw-r--r--sql/sql_lex.h889
-rw-r--r--sql/sql_list.cc3
-rw-r--r--sql/sql_list.h54
-rw-r--r--sql/sql_load.cc634
-rw-r--r--sql/sql_load.h34
-rw-r--r--sql/sql_locale.cc892
-rw-r--r--sql/sql_locale.h78
-rw-r--r--sql/sql_manager.cc37
-rw-r--r--sql/sql_manager.h23
-rw-r--r--sql/sql_map.cc140
-rw-r--r--sql/sql_map.h62
-rw-r--r--sql/sql_olap.cc187
-rw-r--r--sql/sql_parse.cc3884
-rw-r--r--sql/sql_parse.h200
-rw-r--r--sql/sql_partition.cc3030
-rw-r--r--sql/sql_partition.h133
-rw-r--r--sql/sql_partition_admin.cc193
-rw-r--r--sql/sql_partition_admin.h236
-rw-r--r--sql/sql_plist.h260
-rw-r--r--sql/sql_plugin.cc1269
-rw-r--r--sql/sql_plugin.h60
-rw-r--r--sql/sql_plugin_services.h58
-rw-r--r--sql/sql_prepare.cc1060
-rw-r--r--sql/sql_prepare.h367
-rw-r--r--sql/sql_priv.h286
-rw-r--r--sql/sql_profile.cc68
-rw-r--r--sql/sql_profile.h23
-rw-r--r--sql/sql_reload.cc440
-rw-r--r--sql/sql_reload.h26
-rw-r--r--sql/sql_rename.cc55
-rw-r--r--sql/sql_rename.h27
-rw-r--r--sql/sql_repl.cc744
-rw-r--r--sql/sql_repl.h5
-rw-r--r--sql/sql_select.cc1461
-rw-r--r--sql/sql_select.h86
-rw-r--r--sql/sql_servers.cc156
-rw-r--r--sql/sql_servers.h10
-rw-r--r--sql/sql_show.cc2171
-rw-r--r--sql/sql_show.h96
-rw-r--r--sql/sql_signal.cc506
-rw-r--r--sql/sql_signal.h152
-rw-r--r--sql/sql_sort.h17
-rw-r--r--sql/sql_string.cc231
-rw-r--r--sql/sql_string.h31
-rw-r--r--sql/sql_table.cc3241
-rw-r--r--sql/sql_table.h217
-rw-r--r--sql/sql_tablespace.cc10
-rw-r--r--sql/sql_tablespace.h24
-rw-r--r--sql/sql_test.cc137
-rw-r--r--sql/sql_test.h37
-rw-r--r--sql/sql_time.cc (renamed from sql/time.cc)85
-rw-r--r--sql/sql_time.h101
-rw-r--r--sql/sql_trigger.cc254
-rw-r--r--sql/sql_trigger.h47
-rw-r--r--sql/sql_truncate.cc516
-rw-r--r--sql/sql_truncate.h64
-rw-r--r--sql/sql_udf.cc158
-rw-r--r--sql/sql_udf.h4
-rw-r--r--sql/sql_union.cc18
-rw-r--r--sql/sql_union.h31
-rw-r--r--sql/sql_update.cc320
-rw-r--r--sql/sql_update.h44
-rw-r--r--sql/sql_view.cc267
-rw-r--r--sql/sql_view.h18
-rw-r--r--sql/sql_yacc.yy2337
-rw-r--r--sql/strfunc.cc271
-rw-r--r--sql/strfunc.h51
-rw-r--r--sql/structs.h53
-rw-r--r--sql/sys_vars.cc3121
-rw-r--r--sql/sys_vars.h1689
-rw-r--r--sql/sys_vars_shared.h86
-rw-r--r--sql/table.cc914
-rw-r--r--sql/table.h656
-rw-r--r--sql/thr_malloc.cc16
-rw-r--r--sql/thr_malloc.h35
-rw-r--r--sql/transaction.cc744
-rw-r--r--sql/transaction.h46
-rw-r--r--sql/tzfile.h5
-rw-r--r--sql/tztime.cc118
-rw-r--r--sql/tztime.h13
-rw-r--r--sql/udf_example.c22
-rw-r--r--sql/uniques.cc15
-rw-r--r--sql/unireg.cc271
-rw-r--r--sql/unireg.h106
301 files changed, 74817 insertions, 58850 deletions
diff --git a/sql/.cvsignore b/sql/.cvsignore
deleted file mode 100644
index 3e2f44f5a10..00000000000
--- a/sql/.cvsignore
+++ /dev/null
@@ -1,12 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-deadlock_test.c
-gen_lex_hash
-lex_hash.h
-mysqlbinlog
-mysqlbinlog
-mysqld
-sql_yacc.cc
-sql_yacc.h
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 1f4c4034e8c..1bec2d7b082 100755..100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2006 MySQL AB
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -11,50 +11,47 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake")
-
-SET(CMAKE_CXX_FLAGS_DEBUG
- "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR /Zi")
-SET(CMAKE_C_FLAGS_DEBUG
- "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR /Zi")
-SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /MAP /MAPINFO:EXPORTS")
-
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
- ${CMAKE_SOURCE_DIR}/extra/yassl/include
- ${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/regex
- ${CMAKE_SOURCE_DIR}/zlib
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+INCLUDE_DIRECTORIES(
+${CMAKE_SOURCE_DIR}/include
+${CMAKE_SOURCE_DIR}/sql
+${CMAKE_SOURCE_DIR}/regex
+${ZLIB_INCLUDE_DIR}
+${SSL_INCLUDE_DIRS}
+${CMAKE_BINARY_DIR}/sql
+)
+
+SET(GEN_SOURCES
+${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.h
+${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc
+${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
+${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h
)
-SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/sql/sql_yacc.h
- ${CMAKE_SOURCE_DIR}/sql/sql_yacc.cc
- ${CMAKE_SOURCE_DIR}/include/mysql_version.h
- ${CMAKE_SOURCE_DIR}/sql/sql_builtin.cc
- ${CMAKE_SOURCE_DIR}/sql/lex_hash.h
- ${PROJECT_SOURCE_DIR}/include/mysqld_error.h
- ${PROJECT_SOURCE_DIR}/include/mysqld_ername.h
- ${PROJECT_SOURCE_DIR}/include/sql_state.h
- PROPERTIES GENERATED 1)
+SET_SOURCE_FILES_PROPERTIES(${GEN_SOURCES} PROPERTIES GENERATED 1)
-ADD_DEFINITIONS(-DMYSQL_SERVER -D_CONSOLE -DHAVE_DLOPEN -DHAVE_EVENT_SCHEDULER)
+ADD_DEFINITIONS(-DMYSQL_SERVER -DHAVE_EVENT_SCHEDULER)
+IF(SSL_DEFINES)
+ ADD_DEFINITIONS(${SSL_DEFINES})
+ENDIF()
SET (SQL_SOURCE
- ../sql-common/client.c derror.cc des_key_file.cc
+ ../sql-common/client.c derror.cc des_key_file.cc
discover.cc ../libmysql/errmsg.c field.cc field_conv.cc
- filesort.cc gstream.cc
- ha_partition.cc
- handler.cc hash_filo.cc hash_filo.h
+ filesort.cc gstream.cc sha2.cc
+ handler.cc hash_filo.h sql_plugin_services.h
hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc
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
+ key.cc log.cc lock.cc
log_event.cc rpl_record.cc rpl_reporting.cc
log_event_old.cc rpl_record_old.cc
message.h mf_iocache.cc my_decimal.cc ../sql-common/my_time.c
- mysqld.cc net_serv.cc
- nt_servc.cc nt_servc.h opt_range.cc opt_range.h opt_sum.cc
+ mysqld.cc net_serv.cc keycaches.cc
+ ../sql-common/client_plugin.c
+ opt_range.cc opt_range.h opt_sum.cc
../sql-common/pack.c parse_file.cc password.c procedure.cc
protocol.cc records.cc repl_failsafe.cc rpl_filter.cc set_var.cc
slave.cc sp.cc sp_cache.cc sp_head.cc sp_pcontext.cc
@@ -62,94 +59,235 @@ SET (SQL_SOURCE
sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h
sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc sql_do.cc
sql_error.cc sql_handler.cc sql_help.cc sql_insert.cc sql_lex.cc
- sql_list.cc sql_load.cc sql_manager.cc sql_map.cc sql_parse.cc
+ sql_list.cc sql_load.cc sql_manager.cc sql_parse.cc
sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc
debug_sync.cc debug_sync.h
sql_repl.cc sql_select.cc sql_show.cc sql_state.c sql_string.cc
sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
- time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc
+ sql_time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc
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
- rpl_rli.cc rpl_mi.cc sql_servers.cc
- sql_connect.cc scheduler.cc
- sql_profile.cc event_parse_data.cc
- ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
- ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
- ${PROJECT_SOURCE_DIR}/include/mysqld_error.h
- ${PROJECT_SOURCE_DIR}/include/mysqld_ername.h
- ${PROJECT_SOURCE_DIR}/include/sql_state.h
- ${PROJECT_SOURCE_DIR}/include/mysql_version.h
- ${PROJECT_SOURCE_DIR}/sql/sql_builtin.cc
- ${PROJECT_SOURCE_DIR}/sql/lex_hash.h)
-ADD_LIBRARY(sql ${SQL_SOURCE})
-
-IF (NOT EXISTS cmake_dummy.cc)
- FILE (WRITE cmake_dummy.cc "")
-ENDIF (NOT EXISTS cmake_dummy.cc)
-ADD_EXECUTABLE(mysqld cmake_dummy.cc message.rc)
-
-SET_TARGET_PROPERTIES(mysqld PROPERTIES OUTPUT_NAME mysqld${MYSQLD_EXE_SUFFIX})
-SET_TARGET_PROPERTIES(mysqld PROPERTIES ENABLE_EXPORTS TRUE)
-
-SET (MYSQLD_CORE_LIBS mysys zlib dbug strings yassl taocrypt vio regex sql)
-TARGET_LINK_LIBRARIES(mysqld ${MYSQLD_CORE_LIBS} ${MYSQLD_STATIC_ENGINE_LIBS})
-TARGET_LINK_LIBRARIES(mysqld ws2_32.lib)
-
-
-IF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS)
- # Set module definition file. Also use non-incremental linker,
- # incremental appears to crash from time to time,if used with /DEF option
- SET_TARGET_PROPERTIES(mysqld PROPERTIES LINK_FLAGS "/DEF:mysqld.def /INCREMENTAL:NO")
-
- FOREACH (CORELIB ${MYSQLD_CORE_LIBS})
- GET_TARGET_PROPERTY(LOC ${CORELIB} LOCATION)
- FILE(TO_NATIVE_PATH ${LOC} LOC)
- SET (LIB_LOCATIONS ${LIB_LOCATIONS} ${LOC})
- ENDFOREACH (CORELIB ${MYSQLD_CORE_LIBS})
+ 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
+ sql_signal.cc rpl_handler.cc mdl.cc sql_admin.cc
+ transaction.cc sys_vars.cc sql_truncate.cc datadict.cc
+ sql_reload.cc
+ ${GEN_SOURCES}
+ ${MYSYS_LIBWRAP_SOURCE})
+
+MYSQL_ADD_PLUGIN(partition ha_partition.cc STORAGE_ENGINE DEFAULT STATIC_ONLY
+RECOMPILE_FOR_EMBEDDED)
+
+ADD_LIBRARY(sql STATIC ${SQL_SOURCE})
+ADD_DEPENDENCIES(sql GenServerSource)
+DTRACE_INSTRUMENT(sql)
+TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS}
+ mysys dbug strings vio regex
+ ${LIBWRAP} ${LIBCRYPT} ${LIBDL}
+ ${SSL_LIBRARIES})
+
- ADD_CUSTOM_COMMAND(TARGET mysqld PRE_LINK
- COMMAND cscript ARGS //nologo ${PROJECT_SOURCE_DIR}/win/create_def_file.js
- ${PLATFORM} ${LIB_LOCATIONS} > mysqld.def
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/sql)
-ENDIF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS)
-ADD_DEPENDENCIES(sql GenError)
+IF(WIN32)
+ SET(MYSQLD_SOURCE main.cc nt_servc.cc nt_servc.h message.rc)
+ELSE()
+ SET(MYSQLD_SOURCE main.cc ${DTRACE_PROBES_ALL})
+ENDIF()
-# Sql Parser custom command
-ADD_CUSTOM_COMMAND(
- OUTPUT ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
- ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
- COMMAND bison ARGS -y -p MYSQL --defines=sql_yacc.h
- --output=sql_yacc.cc sql_yacc.yy
- DEPENDS ${PROJECT_SOURCE_DIR}/sql/sql_yacc.yy)
+MYSQL_ADD_EXECUTABLE(mysqld ${MYSQLD_SOURCE} DESTINATION ${INSTALL_SBINDIR} COMPONENT Server)
+
+IF(NOT WITHOUT_DYNAMIC_PLUGINS)
+ SET_TARGET_PROPERTIES(mysqld PROPERTIES ENABLE_EXPORTS TRUE)
+ GET_TARGET_PROPERTY(mysqld_link_flags mysqld LINK_FLAGS)
+ IF(NOT mysqld_link_flags)
+ SET(mysqld_link_flags)
+ ENDIF()
+ IF (MINGW OR CYGWIN)
+ SET_TARGET_PROPERTIES(mysqld PROPERTIES LINK_FLAGS "${mysqld_link_flags} -Wl,--export-all-symbols")
+ ENDIF()
+ IF(MSVC)
+ # Set module definition file. Also use non-incremental linker,
+ # incremental appears to crash from time to time,if used with /DEF option
+ SET_TARGET_PROPERTIES(mysqld PROPERTIES LINK_FLAGS "${mysqld_link_flags} /DEF:mysqld.def /INCREMENTAL:NO")
+
+ FOREACH (CORELIB sql mysys dbug strings)
+ GET_TARGET_PROPERTY(LOC ${CORELIB} LOCATION)
+ FILE(TO_NATIVE_PATH ${LOC} LOC)
+ SET (LIB_LOCATIONS ${LIB_LOCATIONS} ${LOC})
+ ENDFOREACH (CORELIB ${MYSQLD_CORE_LIBS})
+ SET(_PLATFORM x86)
+ IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ SET(_PLATFORM x64)
+ ENDIF()
+ ADD_CUSTOM_COMMAND(TARGET mysqld PRE_LINK
+ COMMAND echo ${_PLATFORM} && cscript ARGS //nologo ${PROJECT_SOURCE_DIR}/win/create_def_file.js
+ ${_PLATFORM} ${LIB_LOCATIONS} > mysqld.def
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ ADD_DEPENDENCIES(sql GenError)
+ ENDIF()
+ENDIF()
+SET_TARGET_PROPERTIES(mysqld PROPERTIES ENABLE_EXPORTS TRUE)
+TARGET_LINK_LIBRARIES(mysqld sql)
+
+# Provide plugins with minimal set of libraries
+SET(INTERFACE_LIBS ${LIBRT})
+IF(INTERFACE_LIBS)
+ SET_TARGET_PROPERTIES(mysqld PROPERTIES LINK_INTERFACE_LIBRARIES
+ "${INTERFACE_LIBS}")
+ENDIF()
+
+# On Solaris, some extra effort is required in order to get dtrace probes
+# from static libraries
+DTRACE_INSTRUMENT_STATIC_LIBS(mysqld
+ "sql;mysys;${MYSQLD_STATIC_PLUGIN_LIBS}")
+
+
+SET(WITH_MYSQLD_LDFLAGS "" CACHE STRING "Additional linker flags for mysqld")
+MARK_AS_ADVANCED(WITH_MYSQLD_LDFLAGS)
+IF(WITH_MYSQLD_LDFLAGS)
+ GET_TARGET_PROPERTY(mysqld LINK_FLAGS MYSQLD_LINK_FLAGS)
+ IF(NOT MYSQLD_LINK_FLAGS)
+ SET(MYSQLD_LINK_FLAGS)
+ ENDIF()
+ SET_TARGET_PROPERTIES(mysqld PROPERTIES LINK_FLAGS
+ "${MYSQLD_LINK_FLAGS} ${WITH_MYSQLD_LDFLAGS}")
+ENDIF()
+INSTALL_DEBUG_TARGET(mysqld
+ DESTINATION ${INSTALL_SBINDIR}
+ PDB_DESTINATION ${INSTALL_SBINDIR}/debug
+ RENAME mysqld-debug)
+
+# Handle out-of-source build from source package with possibly broken
+# bison. Copy bison output to from source to build directory, if not already
+# there
+IF (NOT ${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
+ IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/sql_yacc.cc)
+ IF(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc)
+ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/sql_yacc.cc
+ ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc COPYONLY)
+ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/sql_yacc.h
+ ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.h COPYONLY)
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+
+INCLUDE(${CMAKE_SOURCE_DIR}/cmake/bison.cmake)
+RUN_BISON(
+ ${CMAKE_CURRENT_SOURCE_DIR}/sql_yacc.yy
+ ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc
+ ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.h
+)
# Gen_lex_hash
ADD_EXECUTABLE(gen_lex_hash gen_lex_hash.cc)
-TARGET_LINK_LIBRARIES(gen_lex_hash debug dbug mysqlclient wsock32)
-GET_TARGET_PROPERTY(GEN_LEX_HASH_EXE gen_lex_hash LOCATION)
+
ADD_CUSTOM_COMMAND(
- OUTPUT ${PROJECT_SOURCE_DIR}/sql/lex_hash.h
- COMMAND ${GEN_LEX_HASH_EXE} ARGS > lex_hash.h
- DEPENDS ${GEN_LEX_HASH_EXE})
-
-ADD_CUSTOM_TARGET(
- GenServerSource ALL
- DEPENDS ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
- ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
- ${PROJECT_SOURCE_DIR}/sql/message.h
- ${PROJECT_SOURCE_DIR}/sql/message.rc
- ${PROJECT_SOURCE_DIR}/sql/lex_hash.h)
-
-ADD_DEPENDENCIES(mysqld GenServerSource)
-
-# Remove the auto-generated files as part of 'Clean Solution'
-SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
- "lex_hash.h;sql_yacc.h;sql_yacc.cc;mysqld.def")
-
-ADD_LIBRARY(udf_example MODULE udf_example.c udf_example.def)
-ADD_DEPENDENCIES(udf_example strings GenError)
-TARGET_LINK_LIBRARIES(udf_example strings wsock32)
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h
+ COMMAND gen_lex_hash > lex_hash.h
+ DEPENDS gen_lex_hash
+)
+
+MYSQL_ADD_EXECUTABLE(mysql_tzinfo_to_sql tztime.cc)
+SET_TARGET_PROPERTIES(mysql_tzinfo_to_sql PROPERTIES COMPILE_FLAGS "-DTZINFO2SQL")
+TARGET_LINK_LIBRARIES(mysql_tzinfo_to_sql mysys)
+
+ADD_CUSTOM_TARGET(
+ GenServerSource
+ DEPENDS ${GEN_SOURCES}
+)
+
+#Need this only for embedded
+SET_TARGET_PROPERTIES(GenServerSource PROPERTIES EXCLUDE_FROM_ALL TRUE)
+
+IF(WIN32 OR HAVE_DLOPEN AND NOT DISABLE_SHARED)
+ ADD_LIBRARY(udf_example MODULE udf_example.c)
+ SET_TARGET_PROPERTIES(udf_example PROPERTIES PREFIX "")
+ # udf_example depends on strings
+ IF(WIN32)
+ IF(MSVC)
+ SET_TARGET_PROPERTIES(udf_example PROPERTIES LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/udf_example.def")
+ ENDIF()
+ TARGET_LINK_LIBRARIES(udf_example strings)
+ ELSE()
+ # udf_example is using safemutex exported by mysqld
+ TARGET_LINK_LIBRARIES(udf_example mysqld)
+ ENDIF()
+ENDIF()
+
+FOREACH(tool glibtoolize libtoolize aclocal autoconf autoheader automake gtar
+ tar bzr)
+ STRING(TOUPPER ${tool} TOOL)
+ FIND_PROGRAM(${TOOL}_EXECUTABLE ${tool} DOC "path to the executable")
+ MARK_AS_ADVANCED(${TOOL}_EXECUTABLE)
+ENDFOREACH()
+
+CONFIGURE_FILE(
+ ${CMAKE_SOURCE_DIR}/cmake/make_dist.cmake.in ${CMAKE_BINARY_DIR}/make_dist.cmake @ONLY)
+
+ADD_CUSTOM_TARGET(dist
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/make_dist.cmake
+ DEPENDS ${CMAKE_BINARY_DIR}/sql/sql_yacc.cc ${CMAKE_BINARY_DIR}/sql/sql_yacc.h
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+)
+
+ADD_CUSTOM_TARGET(distclean
+ COMMAND ${CMAKE_COMMAND} -E echo WARNING: distclean target is not functional
+ COMMAND ${CMAKE_COMMAND} -E echo Use 'bzr clean-tree' with --unknown and/or
+ --ignored parameter instead
+ VERBATIM
+ )
+
+IF(INSTALL_LAYOUT STREQUAL "STANDALONE")
+
+# We need to create empty directories (data/test) the installation.
+# This does not work with current CPack due to http://www.cmake.org/Bug/view.php?id=8767
+# Avoid completely empty directories and install dummy file instead.
+SET(DUMMY_FILE ${CMAKE_CURRENT_BINARY_DIR}/.empty )
+FILE(WRITE ${DUMMY_FILE} "")
+INSTALL(FILES ${DUMMY_FILE} DESTINATION data/test COMPONENT DataFiles)
+
+# Install initial database on windows
+IF(NOT CMAKE_CROSSCOMPILING)
+ GET_TARGET_PROPERTY(MYSQLD_EXECUTABLE mysqld LOCATION)
+ENDIF()
+IF(WIN32 AND MYSQLD_EXECUTABLE)
+ CONFIGURE_FILE(
+ ${CMAKE_SOURCE_DIR}/cmake/create_initial_db.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/create_initial_db.cmake
+ @ONLY
+ )
+
+ IF(MSVC_IDE OR CMAKE_GENERATOR MATCHES "Xcode")
+ SET (CONFIG_PARAM -DCONFIG=${CMAKE_CFG_INTDIR})
+ ENDIF()
+ MAKE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR}/data)
+ ADD_CUSTOM_COMMAND(
+ OUTPUT initdb.dep
+ COMMAND ${CMAKE_COMMAND}
+ ${CONFIG_PARAM} -P ${CMAKE_CURRENT_BINARY_DIR}/create_initial_db.cmake
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/initdb.dep
+ DEPENDS mysqld
+ )
+ ADD_CUSTOM_TARGET(initial_database
+ ALL
+ DEPENDS initdb.dep
+ )
+ INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data DESTINATION .
+ COMPONENT DataFiles PATTERN "initdb.dep" EXCLUDE PATTERN "bootstrap.sql" EXCLUDE)
+ELSE()
+ # Not windows or cross compiling, just install an empty directory
+ INSTALL(FILES ${DUMMY_FILE} DESTINATION data/mysql COMPONENT DataFiles)
+ENDIF()
+ENDIF()
+
+ADD_CUSTOM_TARGET(show-dist-name
+ COMMAND ${CMAKE_COMMAND} -E echo "${CPACK_PACKAGE_FILE_NAME}"
+)
+
diff --git a/sql/Makefile.am b/sql/Makefile.am
deleted file mode 100644
index 40a3565cb91..00000000000
--- a/sql/Makefile.am
+++ /dev/null
@@ -1,193 +0,0 @@
-# Copyright (C) 2000-2006 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-#called from the top level Makefile
-
-MYSQLDATAdir = $(localstatedir)
-MYSQLSHAREdir = $(pkgdatadir)
-MYSQLBASEdir= $(prefix)
-MYSQLLIBdir= $(pkglibdir)
-pkgplugindir = $(pkglibdir)/plugin
-INCLUDES = @ZLIB_INCLUDES@ \
- -I$(top_builddir)/include -I$(top_srcdir)/include \
- -I$(top_srcdir)/regex -I$(srcdir) $(openssl_includes)
-WRAPLIBS= @WRAPLIBS@
-SUBDIRS = share
-libexec_PROGRAMS = mysqld
-EXTRA_PROGRAMS = gen_lex_hash
-bin_PROGRAMS = mysql_tzinfo_to_sql
-
-noinst_LTLIBRARIES= libndb.la \
- udf_example.la
-
-SUPPORTING_LIBS = $(top_builddir)/vio/libvio.a \
- $(top_builddir)/mysys/libmysys.a \
- $(top_builddir)/dbug/libdbug.a \
- $(top_builddir)/regex/libregex.a \
- $(top_builddir)/strings/libmystrings.a
-mysqld_DEPENDENCIES= @mysql_plugin_libs@ $(SUPPORTING_LIBS) libndb.la
-LDADD = $(SUPPORTING_LIBS) @ZLIB_LIBS@ @NDB_SCI_LIBS@
-mysqld_LDADD = libndb.la \
- @MYSQLD_EXTRA_LDFLAGS@ \
- @mysql_plugin_libs@ \
- $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ \
- $(yassl_libs) $(openssl_libs) @MYSQLD_EXTRA_LIBS@
-
-noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
- item_strfunc.h item_timefunc.h \
- item_xmlfunc.h \
- item_create.h item_subselect.h item_row.h \
- mysql_priv.h item_geofunc.h sql_bitmap.h \
- procedure.h sql_class.h sql_lex.h sql_list.h \
- sql_map.h sql_string.h unireg.h \
- sql_error.h field.h handler.h mysqld_suffix.h \
- sql_profile.h \
- ha_ndbcluster.h ha_ndbcluster_cond.h \
- ha_ndbcluster_binlog.h ha_ndbcluster_tables.h \
- ha_partition.h rpl_constants.h \
- debug_sync.h \
- opt_range.h protocol.h rpl_tblmap.h rpl_utility.h \
- rpl_reporting.h \
- log.h sql_show.h rpl_rli.h rpl_mi.h \
- sql_select.h structs.h table.h sql_udf.h hash_filo.h \
- lex.h lex_symbol.h sql_acl.h sql_crypt.h \
- sql_repl.h slave.h rpl_filter.h rpl_injector.h \
- log_event.h rpl_record.h \
- log_event_old.h rpl_record_old.h \
- sql_sort.h sql_cache.h set_var.h \
- spatial.h gstream.h client_settings.h tzfile.h \
- tztime.h my_decimal.h\
- sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
- parse_file.h sql_view.h sql_trigger.h \
- sql_array.h sql_cursor.h events.h scheduler.h \
- event_db_repository.h event_queue.h \
- sql_plugin.h authors.h event_parse_data.h \
- event_data_objects.h event_scheduler.h \
- sql_partition.h partition_info.h partition_element.h \
- contributors.h sql_servers.h
-
-mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
- item.cc item_sum.cc item_buff.cc item_func.cc \
- item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
- thr_malloc.cc item_create.cc item_subselect.cc \
- item_row.cc item_geofunc.cc item_xmlfunc.cc \
- field.cc strfunc.cc key.cc sql_class.cc sql_list.cc \
- net_serv.cc protocol.cc sql_state.c \
- lock.cc my_lock.c \
- sql_string.cc sql_manager.cc sql_map.cc \
- mysqld.cc password.c hash_filo.cc hostname.cc \
- sql_connect.cc scheduler.cc sql_parse.cc \
- set_var.cc sql_yacc.yy \
- sql_base.cc table.cc sql_select.cc sql_insert.cc \
- sql_profile.cc \
- sql_prepare.cc sql_error.cc sql_locale.cc \
- sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
- procedure.cc sql_test.cc \
- log.cc init.cc derror.cc sql_acl.cc \
- unireg.cc des_key_file.cc \
- log_event.cc rpl_record.cc \
- log_event_old.cc rpl_record_old.cc \
- discover.cc time.cc opt_range.cc opt_sum.cc \
- records.cc filesort.cc handler.cc \
- ha_partition.cc \
- debug_sync.cc \
- sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
- sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
- sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
- slave.cc sql_repl.cc rpl_filter.cc rpl_tblmap.cc \
- rpl_utility.cc rpl_injector.cc rpl_rli.cc rpl_mi.cc \
- rpl_reporting.cc \
- sql_union.cc sql_derived.cc \
- sql_client.cc \
- repl_failsafe.h repl_failsafe.cc \
- sql_olap.cc sql_view.cc \
- gstream.cc spatial.cc sql_help.cc sql_cursor.cc \
- tztime.cc my_decimal.cc\
- sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
- sp_cache.cc parse_file.cc sql_trigger.cc \
- event_scheduler.cc event_data_objects.cc \
- event_queue.cc event_db_repository.cc events.cc \
- sql_plugin.cc sql_binlog.cc \
- sql_builtin.cc sql_tablespace.cc partition_info.cc \
- sql_servers.cc event_parse_data.cc
-
-nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c
-
-libndb_la_CPPFLAGS= @ndbcluster_includes@
-libndb_la_SOURCES= ha_ndbcluster.cc \
- ha_ndbcluster_binlog.cc \
- ha_ndbcluster_cond.cc
-
-gen_lex_hash_SOURCES = gen_lex_hash.cc
-gen_lex_hash_LDFLAGS = @NOINST_LDFLAGS@
-
-mysql_tzinfo_to_sql_SOURCES = tztime.cc
-mysql_tzinfo_to_sql_CXXFLAGS= -DTZINFO2SQL
-
-DEFS = -DMYSQL_SERVER \
- -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
- -DMYSQL_DATADIR="\"$(MYSQLDATAdir)\"" \
- -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
- -DPLUGINDIR="\"$(pkgplugindir)\"" \
- -DHAVE_EVENT_SCHEDULER \
- @DEFS@
-
-BUILT_MAINT_SRC = sql_yacc.cc sql_yacc.h
-BUILT_SOURCES = $(BUILT_MAINT_SRC) lex_hash.h link_sources
-EXTRA_DIST = udf_example.c udf_example.def $(BUILT_MAINT_SRC) \
- nt_servc.cc nt_servc.h \
- message.mc message.h message.rc MSG00001.bin \
- CMakeLists.txt
-
-CLEANFILES = lex_hash.h sql_yacc.output link_sources
-DISTCLEANFILES = $(EXTRA_PROGRAMS)
-MAINTAINERCLEANFILES = $(BUILT_MAINT_SRC)
-AM_YFLAGS = -d --verbose
-
-# These are listed in 'nodist_mysqld_SOURCES'
-link_sources:
- rm -f mini_client_errors.c
- @LN_CP_F@ $(top_srcdir)/libmysql/errmsg.c mini_client_errors.c
- rm -f pack.c
- @LN_CP_F@ $(top_srcdir)/sql-common/pack.c pack.c
- rm -f client.c
- @LN_CP_F@ $(top_srcdir)/sql-common/client.c client.c
- rm -f my_time.c
- @LN_CP_F@ $(top_srcdir)/sql-common/my_time.c my_time.c
- rm -f my_user.c
- @LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c
- echo timestamp > link_sources
-
-# This generates lex_hash.h
-# NOTE Built sources should depend on their sources not the tool
-# this avoid the rebuild of the built files in a source dist
-lex_hash.h: gen_lex_hash.cc lex.h
- $(MAKE) $(AM_MAKEFLAGS) gen_lex_hash$(EXEEXT)
- ./gen_lex_hash$(EXEEXT) > $@-t
- $(MV) $@-t $@
-
-# For testing of udf_example.so
-udf_example_la_SOURCES= udf_example.c
-udf_example_la_LDFLAGS= -module -rpath $(pkglibdir)
-
-# We might have some stuff not built in this build, but that we want to install
-install-exec-hook:
- $(mkinstalldirs) $(DESTDIR)$(libexecdir) $(DESTDIR)$(pkglibdir)
- test ! -x mysqld-debug$(EXEEXT) || $(INSTALL_PROGRAM) mysqld-debug$(EXEEXT) $(DESTDIR)$(libexecdir)
- test ! -f mysqld-debug.sym.gz || $(INSTALL_DATA) mysqld-debug.sym.gz $(DESTDIR)$(pkglibdir)
- test ! -f mysqld.sym.gz || $(INSTALL_DATA) mysqld.sym.gz $(DESTDIR)$(pkglibdir)
-
-# Don't update the files from bitkeeper
-%::SCCS/s.%
diff --git a/sql/add_errmsg b/sql/add_errmsg
index cf54ede5dce..86226926d38 100755
--- a/sql/add_errmsg
+++ b/sql/add_errmsg
@@ -8,8 +8,8 @@ then
fi
FILE=/tmp/add.$$
-tail -$1 share/english/errmsg.txt > $FILE
-for i in `ls share/*/errmsg.txt | grep -v english`
+tail -$1 share/english/errmsg-utf8.txt > $FILE
+for i in `ls share/*/errmsg-utf8.txt | grep -v english`
do
cat $FILE >> $i
done
diff --git a/sql/authors.h b/sql/authors.h
index 925c942fa24..db0ab00fb86 100644
--- a/sql/authors.h
+++ b/sql/authors.h
@@ -1,3 +1,6 @@
+#ifndef AUTHORS_INCLUDED
+#define AUTHORS_INCLUDED
+
/* Copyright (C) 2005-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -36,6 +39,7 @@ struct show_table_authors_st {
struct show_table_authors_st show_table_authors[]= {
{ "Brian (Krow) Aker", "Seattle, WA, USA",
"Architecture, archive, federated, bunch of little stuff :)" },
+ { "Marc Alff", "Denver, CO, USA", "Signal, Resignal, Performance schema" },
{ "Venu Anuganti", "", "Client/server protocol (4.1)" },
{ "David Axmark", "Uppsala, Sweden",
"Small stuff long time ago, Monty ripped it out!" },
@@ -89,6 +93,7 @@ struct show_table_authors_st show_table_authors[]= {
{ "Arjen Lentz", "Brisbane, Australia",
"Documentation (2001-2004), Dutch error messages, LOG2()" },
{ "Marc Liyanage", "", "Created Mac OS X packages" },
+ { "Kelly Long", "Denver, CO, USA", "Pool Of Threads" },
{ "Zarko Mocnik", "", "Sorting for Slovenian language" },
{ "Per-Erik Martin", "Uppsala, Sweden", "Stored Procedures (5.0)" },
{ "Alexis Mikhailov", "", "User-defined functions" },
@@ -151,3 +156,5 @@ struct show_table_authors_st show_table_authors[]= {
"SHA1(), AES_ENCRYPT(), AES_DECRYPT(), bug fixing" },
{NULL, NULL, NULL}
};
+
+#endif /* AUTHORS_INCLUDED */
diff --git a/sql/client_settings.h b/sql/client_settings.h
index 4f06c15a29e..ff35cff2440 100644
--- a/sql/client_settings.h
+++ b/sql/client_settings.h
@@ -14,7 +14,14 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#ifndef CLIENT_SETTINGS_INCLUDED
+#define CLIENT_SETTINGS_INCLUDED
+#else
+#error You have already included an client_settings.h and it should not be included twice
+#endif /* CLIENT_SETTINGS_INCLUDED */
+
#include <thr_alarm.h>
+#include <sql_common.h>
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \
CLIENT_SECURE_CONNECTION | CLIENT_TRANSACTIONS | \
@@ -24,14 +31,11 @@
#define set_sigpipe(mysql)
#define reset_sigpipe(mysql)
#define read_user_name(A) {}
-#define mysql_rpl_query_type(A,B) MYSQL_RPL_ADMIN
-#define mysql_master_send_query(A, B, C) 1
-#define mysql_slave_send_query(A, B, C) 1
-#define mysql_rpl_probe(mysql) 0
#undef HAVE_SMEM
#undef _CUSTOMCONFIG_
-#define mysql_server_init(a,b,c) 0
+#define mysql_server_init(a,b,c) mysql_client_plugin_init()
+#define mysql_server_end() mysql_client_plugin_deinit()
#ifdef HAVE_REPLICATION
C_MODE_START
diff --git a/sql/contributors.h b/sql/contributors.h
index 87001e29d88..6cf8bb88e3b 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -1,3 +1,6 @@
+#ifndef CONTRIBUTORS_INCLUDED
+#define CONTRIBUTORS_INCLUDED
+
/* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -37,3 +40,5 @@ struct show_table_contributors_st show_table_contributors[]= {
{"Mark Shuttleworth", "London, UK.", "EFF contribution for UC2006 Auction"},
{NULL, NULL, NULL}
};
+
+#endif /* CONTRIBUTORS_INCLUDED */
diff --git a/sql/datadict.cc b/sql/datadict.cc
new file mode 100644
index 00000000000..e3f679cc7ec
--- /dev/null
+++ b/sql/datadict.cc
@@ -0,0 +1,184 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 */
+
+#include "datadict.h"
+#include "sql_priv.h"
+#include "sql_class.h"
+#include "sql_table.h"
+
+
+/**
+ Check type of .frm if we are not going to parse it.
+
+ @param[in] thd The current session.
+ @param[in] path path to FRM file.
+ @param[out] dbt db_type of the table if FRMTYPE_TABLE, otherwise undefined.
+
+ @retval FRMTYPE_ERROR error
+ @retval FRMTYPE_TABLE table
+ @retval FRMTYPE_VIEW view
+*/
+
+frm_type_enum dd_frm_type(THD *thd, char *path, enum legacy_db_type *dbt)
+{
+ File file;
+ uchar header[10]; //"TYPE=VIEW\n" it is 10 characters
+ size_t error;
+ DBUG_ENTER("dd_frm_type");
+
+ *dbt= DB_TYPE_UNKNOWN;
+
+ if ((file= mysql_file_open(key_file_frm, path, O_RDONLY | O_SHARE, MYF(0))) < 0)
+ DBUG_RETURN(FRMTYPE_ERROR);
+ error= mysql_file_read(file, (uchar*) header, sizeof(header), MYF(MY_NABP));
+ mysql_file_close(file, MYF(MY_WME));
+
+ if (error)
+ DBUG_RETURN(FRMTYPE_ERROR);
+ if (!strncmp((char*) header, "TYPE=VIEW\n", sizeof(header)))
+ DBUG_RETURN(FRMTYPE_VIEW);
+
+ /*
+ This is just a check for DB_TYPE. We'll return default unknown type
+ if the following test is true (arg #3). This should not have effect
+ on return value from this function (default FRMTYPE_TABLE)
+ */
+ if (header[0] != (uchar) 254 || header[1] != 1 ||
+ (header[2] != FRM_VER && header[2] != FRM_VER+1 &&
+ (header[2] < FRM_VER+3 || header[2] > FRM_VER+4)))
+ DBUG_RETURN(FRMTYPE_TABLE);
+
+ *dbt= (enum legacy_db_type) (uint) *(header + 3);
+
+ /* Probably a table. */
+ DBUG_RETURN(FRMTYPE_TABLE);
+}
+
+
+/**
+ Given a table name, check type of .frm and legacy table type.
+
+ @param[in] thd The current session.
+ @param[in] db Table schema.
+ @param[in] table_name Table database.
+ @param[out] table_type handlerton of the table if FRMTYPE_TABLE,
+ otherwise undefined.
+
+ @return FALSE if FRMTYPE_TABLE and storage engine found. TRUE otherwise.
+*/
+
+bool dd_frm_storage_engine(THD *thd, const char *db, const char *table_name,
+ handlerton **table_type)
+{
+ char path[FN_REFLEN + 1];
+ enum legacy_db_type db_type;
+ LEX_STRING db_name = {(char *) db, strlen(db)};
+
+ /* There should be at least some lock on the table. */
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db,
+ table_name, MDL_SHARED));
+
+ if (check_db_name(&db_name))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
+ return TRUE;
+ }
+
+ if (check_table_name(table_name, strlen(table_name), FALSE))
+ {
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name);
+ return TRUE;
+ }
+
+ (void) build_table_filename(path, sizeof(path) - 1, db,
+ table_name, reg_ext, 0);
+
+ dd_frm_type(thd, path, &db_type);
+
+ /* Type is unknown if the object is not found or is not a table. */
+ if (db_type == DB_TYPE_UNKNOWN ||
+ !(*table_type= ha_resolve_by_legacy_type(thd, db_type)))
+ {
+ my_error(ER_NO_SUCH_TABLE, MYF(0), db, table_name);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Given a table name, check if the storage engine for the
+ table referred by this name supports an option 'flag'.
+ Return an error if the table does not exist or is not a
+ base table.
+
+ @pre Any metadata lock on the table.
+
+ @param[in] thd The current session.
+ @param[in] db Table schema.
+ @param[in] table_name Table database.
+ @param[in] flag The option to check.
+ @param[out] yes_no The result. Undefined if error.
+*/
+
+bool dd_check_storage_engine_flag(THD *thd,
+ const char *db, const char *table_name,
+ uint32 flag, bool *yes_no)
+{
+ handlerton *table_type;
+
+ if (dd_frm_storage_engine(thd, db, table_name, &table_type))
+ return TRUE;
+
+ *yes_no= ha_check_storage_engine_flag(table_type, flag);
+
+ return FALSE;
+}
+
+
+/*
+ Regenerate a metadata locked table.
+
+ @param thd Thread context.
+ @param db Name of the database to which the table belongs to.
+ @param name Table name.
+
+ @retval FALSE Success.
+ @retval TRUE Error.
+*/
+
+bool dd_recreate_table(THD *thd, const char *db, const char *table_name)
+{
+ bool error= TRUE;
+ HA_CREATE_INFO create_info;
+ char path[FN_REFLEN + 1];
+ DBUG_ENTER("dd_recreate_table");
+
+ /* There should be a exclusive metadata lock on the table. */
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
+ MDL_EXCLUSIVE));
+
+ memset(&create_info, 0, sizeof(create_info));
+
+ /* Create a path to the table, but without a extension. */
+ build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
+
+ /* Attempt to reconstruct the table. */
+ error= ha_create_table(thd, path, db, table_name, &create_info, TRUE);
+
+ DBUG_RETURN(error);
+}
+
diff --git a/sql/datadict.h b/sql/datadict.h
new file mode 100644
index 00000000000..65e40998929
--- /dev/null
+++ b/sql/datadict.h
@@ -0,0 +1,42 @@
+#ifndef DATADICT_INCLUDED
+#define DATADICT_INCLUDED
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 */
+
+#include "handler.h"
+
+/*
+ Data dictionary API.
+*/
+
+enum frm_type_enum
+{
+ FRMTYPE_ERROR= 0,
+ FRMTYPE_TABLE,
+ FRMTYPE_VIEW
+};
+
+
+frm_type_enum dd_frm_type(THD *thd, char *path, enum legacy_db_type *dbt);
+
+bool dd_frm_storage_engine(THD *thd, const char *db, const char *table_name,
+ handlerton **table_type);
+bool dd_check_storage_engine_flag(THD *thd,
+ const char *db, const char *table_name,
+ uint32 flag,
+ bool *yes_no);
+bool dd_recreate_table(THD *thd, const char *db, const char *table_name);
+
+#endif // DATADICT_INCLUDED
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc
index 91c850c6009..4f353597d6d 100644
--- a/sql/debug_sync.cc
+++ b/sql/debug_sync.cc
@@ -221,14 +221,14 @@
There are quite a few places in MySQL, where we use a synchronization
pattern like this:
- pthread_mutex_lock(&mutex);
+ mysql_mutex_lock(&mutex);
thd->enter_cond(&condition_variable, &mutex, new_message);
#if defined(ENABLE_DEBUG_SYNC)
if (!thd->killed && !end_of_wait_condition)
DEBUG_SYNC(thd, "sync_point_name");
#endif
while (!thd->killed && !end_of_wait_condition)
- pthread_cond_wait(&condition_variable, &mutex);
+ mysql_cond_wait(&condition_variable, &mutex);
thd->exit_cond(old_message);
Here some explanations:
@@ -264,12 +264,12 @@
while (!thd->killed && !end_of_wait_condition)
{
- pthread_mutex_lock(&mutex);
+ mysql_mutex_lock(&mutex);
thd->enter_cond(&condition_variable, &mutex, new_message);
if (!thd->killed [&& !end_of_wait_condition])
{
[DEBUG_SYNC(thd, "sync_point_name");]
- pthread_cond_wait(&condition_variable, &mutex);
+ mysql_cond_wait(&condition_variable, &mutex);
}
thd->exit_cond(old_message);
}
@@ -285,7 +285,7 @@
before sleeping, we hold the mutex, which is registered in mysys_var.
The killing thread would try to acquire the mutex before signaling
the condition variable. Since the mutex is only released implicitly in
- pthread_cond_wait(), the signaling happens at the right place. We
+ mysql_cond_wait(), the signaling happens at the right place. We
have a safe synchronization.
=== Co-work with the DBUG facility ===
@@ -321,12 +321,13 @@
/*
Due to weaknesses in our include files, we need to include
- mysql_priv.h here. To have THD declared, we need to include
+ sql_priv.h here. To have THD declared, we need to include
sql_class.h. This includes log_event.h, which in turn requires
- declarations from mysql_priv.h (e.g. OPTION_AUTO_IS_NULL).
- mysql_priv.h includes almost everything, so is sufficient here.
+ declarations from sql_priv.h (e.g. OPTION_AUTO_IS_NULL).
+ sql_priv.h includes almost everything, so is sufficient here.
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_parse.h"
/*
Action to perform at a synchronization point.
@@ -373,8 +374,8 @@ struct st_debug_sync_control
struct st_debug_sync_globals
{
String ds_signal; /* signal variable */
- pthread_cond_t ds_cond; /* condition variable */
- pthread_mutex_t ds_mutex; /* mutex variable */
+ mysql_cond_t ds_cond; /* condition variable */
+ mysql_mutex_t ds_mutex; /* mutex variable */
ulonglong dsp_hits; /* statistics */
ulonglong dsp_executed; /* statistics */
ulonglong dsp_max_active; /* statistics */
@@ -386,6 +387,13 @@ static st_debug_sync_globals debug_sync_global; /* All globals in one object */
*/
extern "C" void (*debug_sync_C_callback_ptr)(const char *, size_t);
+/**
+ Callbacks from C files.
+*/
+C_MODE_START
+static void debug_sync_C_callback(const char *, size_t);
+static int debug_sync_qsort_cmp(const void *, const void *);
+C_MODE_END
/**
Callback for debug sync, to be used by C files. See thr_lock.c for example.
@@ -394,7 +402,7 @@ extern "C" void (*debug_sync_C_callback_ptr)(const char *, size_t);
We cannot place a sync point directly in C files (like those in mysys or
certain storage engines written mostly in C like MyISAM or Maria). Because
- they are C code and do not include mysql_priv.h. So they do not know the
+ they are C code and do not include sql_priv.h. So they do not know the
macro DEBUG_SYNC(thd, sync_point_name). The macro needs a 'thd' argument.
Hence it cannot be used in files outside of the sql/ directory.
@@ -421,9 +429,40 @@ extern "C" void (*debug_sync_C_callback_ptr)(const char *, size_t);
static void debug_sync_C_callback(const char *sync_point_name,
size_t name_len)
{
- if (unlikely(opt_debug_sync_timeout))
- debug_sync(current_thd, sync_point_name, name_len);
+ if (unlikely(opt_debug_sync_timeout))
+ debug_sync(current_thd, sync_point_name, name_len);
+}
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_debug_sync_globals_ds_mutex;
+
+static PSI_mutex_info all_debug_sync_mutexes[]=
+{
+ { &key_debug_sync_globals_ds_mutex, "DEBUG_SYNC::mutex", PSI_FLAG_GLOBAL}
+};
+
+static PSI_cond_key key_debug_sync_globals_ds_cond;
+
+static PSI_cond_info all_debug_sync_conds[]=
+{
+ { &key_debug_sync_globals_ds_cond, "DEBUG_SYNC::cond", PSI_FLAG_GLOBAL}
+};
+
+static void init_debug_sync_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_debug_sync_mutexes);
+ PSI_server->register_mutex(category, all_debug_sync_mutexes, count);
+
+ count= array_elements(all_debug_sync_conds);
+ PSI_server->register_cond(category, all_debug_sync_conds, count);
}
+#endif /* HAVE_PSI_INTERFACE */
/**
@@ -438,15 +477,21 @@ int debug_sync_init(void)
{
DBUG_ENTER("debug_sync_init");
+#ifdef HAVE_PSI_INTERFACE
+ init_debug_sync_psi_keys();
+#endif
+
if (opt_debug_sync_timeout)
{
int rc;
/* Initialize the global variables. */
debug_sync_global.ds_signal.length(0);
- if ((rc= pthread_cond_init(&debug_sync_global.ds_cond, NULL)) ||
- (rc= pthread_mutex_init(&debug_sync_global.ds_mutex,
- MY_MUTEX_INIT_FAST)))
+ if ((rc= mysql_cond_init(key_debug_sync_globals_ds_cond,
+ &debug_sync_global.ds_cond, NULL)) ||
+ (rc= mysql_mutex_init(key_debug_sync_globals_ds_mutex,
+ &debug_sync_global.ds_mutex,
+ MY_MUTEX_INIT_FAST)))
DBUG_RETURN(rc); /* purecov: inspected */
/* Set the call back pointer in C files. */
@@ -476,8 +521,8 @@ void debug_sync_end(void)
/* Destroy the global variables. */
debug_sync_global.ds_signal.free();
- (void) pthread_cond_destroy(&debug_sync_global.ds_cond);
- (void) pthread_mutex_destroy(&debug_sync_global.ds_mutex);
+ mysql_cond_destroy(&debug_sync_global.ds_cond);
+ mysql_mutex_destroy(&debug_sync_global.ds_mutex);
/* Print statistics. */
{
@@ -581,18 +626,18 @@ void debug_sync_end_thread(THD *thd)
action->wait_for.free();
action->sync_point.free();
}
- my_free(ds_control->ds_action, MYF(0));
+ my_free(ds_control->ds_action);
}
/* Statistics. */
- pthread_mutex_lock(&debug_sync_global.ds_mutex);
+ mysql_mutex_lock(&debug_sync_global.ds_mutex);
debug_sync_global.dsp_hits+= ds_control->dsp_hits;
debug_sync_global.dsp_executed+= ds_control->dsp_executed;
if (debug_sync_global.dsp_max_active < ds_control->dsp_max_active)
debug_sync_global.dsp_max_active= ds_control->dsp_max_active;
- pthread_mutex_unlock(&debug_sync_global.ds_mutex);
+ mysql_mutex_unlock(&debug_sync_global.ds_mutex);
- my_free(ds_control, MYF(0));
+ my_free(ds_control);
thd->debug_sync_control= NULL;
}
@@ -824,9 +869,9 @@ static void debug_sync_reset(THD *thd)
ds_control->ds_active= 0;
/* Clear the global signal. */
- pthread_mutex_lock(&debug_sync_global.ds_mutex);
+ mysql_mutex_lock(&debug_sync_global.ds_mutex);
debug_sync_global.ds_signal.length(0);
- pthread_mutex_unlock(&debug_sync_global.ds_mutex);
+ mysql_mutex_unlock(&debug_sync_global.ds_mutex);
DBUG_VOID_RETURN;
}
@@ -1524,56 +1569,6 @@ static bool debug_sync_eval_action(THD *thd, char *action_str)
DBUG_RETURN(FALSE);
}
-
-/**
- Check if the system variable 'debug_sync' can be set.
-
- @param[in] thd thread handle
- @param[in] var set variable request
-
- @return status
- @retval FALSE ok, variable can be set
- @retval TRUE error, variable cannot be set
-*/
-
-bool sys_var_debug_sync::check(THD *thd, set_var *var)
-{
- DBUG_ENTER("sys_var_debug_sync::check");
- DBUG_ASSERT(thd);
- DBUG_ASSERT(var);
-
- /*
- Variable can be set for the session only.
-
- This could be changed later. Then we need to have a global array of
- actions in addition to the thread local ones. SET GLOBAL would
- manage the global array, SET [SESSION] the local array. A sync point
- would need to look for a local and a global action. Setting and
- executing of global actions need to be protected by a mutex.
-
- The purpose of global actions could be to allow synchronizing with
- connectionless threads that cannot execute SET statements.
- */
- if (var->type == OPT_GLOBAL)
- {
- my_error(ER_LOCAL_VARIABLE, MYF(0), name);
- DBUG_RETURN(TRUE);
- }
-
- /*
- Do not check for disabled facility. Test result should not
- unnecessarily differ from enabled facility.
- */
-
- /*
- Facility requires SUPER privilege. Sync points could be inside
- global mutexes (e.g. LOCK_open). Waiting there forever would
- stall the whole server.
- */
- DBUG_RETURN(check_global_access(thd, SUPER_ACL));
-}
-
-
/**
Set the system variable 'debug_sync'.
@@ -1594,28 +1589,9 @@ bool sys_var_debug_sync::check(THD *thd, set_var *var)
terminators in the string. So we need to take a copy here.
*/
-bool sys_var_debug_sync::update(THD *thd, set_var *var)
+bool debug_sync_update(THD *thd, char *val_str)
{
- char *val_str;
- String *val_ptr;
- String val_buf;
- DBUG_ENTER("sys_var_debug_sync::update");
- DBUG_ASSERT(thd);
-
- /*
- Depending on the value type (string literal, user variable, ...)
- val_buf receives a copy of the value or not. But we always need
- a copy. So we take a copy, if it is not done by val_str().
- If val_str() puts a copy into val_buf, then it returns &val_buf,
- otherwise it returns a pointer to the string object that we need
- to copy.
- */
- val_ptr= var ? var->value->val_str(&val_buf) : &val_buf;
- if (val_ptr != &val_buf)
- {
- val_buf.copy(*val_ptr);
- }
- val_str= val_buf.c_ptr();
+ DBUG_ENTER("debug_sync_update");
DBUG_PRINT("debug_sync", ("set action: '%s'", val_str));
/*
@@ -1632,8 +1608,6 @@ bool sys_var_debug_sync::update(THD *thd, set_var *var)
Retrieve the value of the system variable 'debug_sync'.
@param[in] thd thread handle
- @param[in] type variable type, unused
- @param[in] base variable base, unused
@return string
@retval != NULL ok, string pointer
@@ -1646,20 +1620,17 @@ bool sys_var_debug_sync::update(THD *thd, set_var *var)
When "ON", the current signal is added.
*/
-uchar *sys_var_debug_sync::value_ptr(THD *thd,
- enum_var_type type __attribute__((unused)),
- LEX_STRING *base __attribute__((unused)))
+uchar *debug_sync_value_ptr(THD *thd)
{
char *value;
- DBUG_ENTER("sys_var_debug_sync::value_ptr");
- DBUG_ASSERT(thd);
+ DBUG_ENTER("debug_sync_value_ptr");
if (opt_debug_sync_timeout)
{
static char on[]= "ON - current signal: '";
// Ensure exclusive access to debug_sync_global.ds_signal
- pthread_mutex_lock(&debug_sync_global.ds_mutex);
+ mysql_mutex_lock(&debug_sync_global.ds_mutex);
size_t lgt= (sizeof(on) /* includes '\0' */ +
debug_sync_global.ds_signal.length() + 1 /* for '\'' */);
@@ -1676,12 +1647,12 @@ uchar *sys_var_debug_sync::value_ptr(THD *thd,
*(vptr++)= '\'';
*vptr= '\0'; /* We have one byte reserved for the worst case. */
}
- pthread_mutex_unlock(&debug_sync_global.ds_mutex);
+ mysql_mutex_unlock(&debug_sync_global.ds_mutex);
}
else
{
/* purecov: begin tested */
- value= strmake_root(thd->mem_root, STRING_WITH_LEN("OFF"));
+ value= const_cast<char*>("OFF");
/* purecov: end */
}
@@ -1701,9 +1672,11 @@ uchar *sys_var_debug_sync::value_ptr(THD *thd,
static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
{
- IF_DBUG(const char *dsp_name= action->sync_point.c_ptr());
- IF_DBUG(const char *sig_emit= action->signal.c_ptr());
- IF_DBUG(const char *sig_wait= action->wait_for.c_ptr());
+#ifndef DBUG_OFF
+ const char *dsp_name= action->sync_point.c_ptr();
+ const char *sig_emit= action->signal.c_ptr();
+ const char *sig_wait= action->wait_for.c_ptr();
+#endif
DBUG_ENTER("debug_sync_execute");
DBUG_ASSERT(thd);
DBUG_ASSERT(action);
@@ -1742,7 +1715,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
read access too, to create a memory barrier in order to avoid that
threads just reads an old cached version of the signal.
*/
- pthread_mutex_lock(&debug_sync_global.ds_mutex);
+ mysql_mutex_lock(&debug_sync_global.ds_mutex);
if (action->signal.length())
{
@@ -1756,15 +1729,15 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
debug_sync_emergency_disable(); /* purecov: tested */
}
/* Wake threads waiting in a sync point. */
- pthread_cond_broadcast(&debug_sync_global.ds_cond);
+ mysql_cond_broadcast(&debug_sync_global.ds_cond);
DBUG_PRINT("debug_sync_exec", ("signal '%s' at: '%s'",
sig_emit, dsp_name));
} /* end if (action->signal.length()) */
if (action->wait_for.length())
{
- pthread_mutex_t *old_mutex;
- pthread_cond_t *old_cond;
+ mysql_mutex_t *old_mutex;
+ mysql_cond_t *old_cond;
int error= 0;
struct timespec abstime;
@@ -1795,9 +1768,9 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
while (stringcmp(&debug_sync_global.ds_signal, &action->wait_for) &&
!thd->killed && opt_debug_sync_timeout)
{
- error= pthread_cond_timedwait(&debug_sync_global.ds_cond,
- &debug_sync_global.ds_mutex,
- &abstime);
+ error= mysql_cond_timedwait(&debug_sync_global.ds_cond,
+ &debug_sync_global.ds_mutex,
+ &abstime);
DBUG_EXECUTE("debug_sync", {
/* Functions as DBUG_PRINT args can change keyword and line nr. */
const char *sig_glob= debug_sync_global.ds_signal.c_ptr();
@@ -1830,18 +1803,17 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
protected mutex must always unlocked _before_ mysys_var->mutex
is locked. (See comment in THD::exit_cond().)
*/
- pthread_mutex_unlock(&debug_sync_global.ds_mutex);
- pthread_mutex_lock(&thd->mysys_var->mutex);
+ mysql_mutex_unlock(&debug_sync_global.ds_mutex);
+ mysql_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= old_mutex;
thd->mysys_var->current_cond= old_cond;
thd_proc_info(thd, old_proc_info);
- pthread_mutex_unlock(&thd->mysys_var->mutex);
-
+ mysql_mutex_unlock(&thd->mysys_var->mutex);
}
else
{
/* In case we don't wait, we just release the mutex. */
- pthread_mutex_unlock(&debug_sync_global.ds_mutex);
+ mysql_mutex_unlock(&debug_sync_global.ds_mutex);
} /* end if (action->wait_for.length()) */
} /* end if (action->execute) */
diff --git a/sql/derror.cc b/sql/derror.cc
index a8cfa00ad1d..db9cd3c0c58 100644
--- a/sql/derror.cc
+++ b/sql/derror.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2005 MySQL AB
+/* Copyright (C) 2000-2005 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -21,13 +21,26 @@
Read language depeneded messagefile
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "derror.h"
#include "mysys_err.h"
+#include "mysqld.h" // lc_messages_dir
+#include "derror.h" // read_texts
+#include "sql_class.h" // THD
-static bool read_texts(const char *file_name,const char ***point,
- uint error_messages);
static void init_myfunc_errs(void);
+
+C_MODE_START
+static const char **get_server_errmsgs()
+{
+ if (!current_thd)
+ return DEFAULT_ERRMSGS;
+ return CURRENT_THD_ERRMSGS;
+}
+C_MODE_END
+
/**
Read messages from errorfile.
@@ -54,7 +67,8 @@ bool init_errmessage(void)
errmsgs= my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST);
/* Read messages from file. */
- if (read_texts(ERRMSG_FILE, &errmsgs, ER_ERROR_LAST - ER_ERROR_FIRST + 1) &&
+ if (read_texts(ERRMSG_FILE, my_default_lc_messages->errmsgs->language,
+ &errmsgs, ER_ERROR_LAST - ER_ERROR_FIRST + 1) &&
!errmsgs)
{
if (!(errmsgs= (const char**) my_malloc((ER_ERROR_LAST-ER_ERROR_FIRST+1)*
@@ -65,13 +79,13 @@ bool init_errmessage(void)
}
/* Register messages for use with my_error(). */
- if (my_error_register(errmsgs, ER_ERROR_FIRST, ER_ERROR_LAST))
+ if (my_error_register(get_server_errmsgs, ER_ERROR_FIRST, ER_ERROR_LAST))
{
- x_free((uchar*) errmsgs);
+ my_free(errmsgs);
DBUG_RETURN(TRUE);
}
- errmesg= errmsgs; /* Init global variabel */
+ DEFAULT_ERRMSGS= errmsgs; /* Init global variable */
init_myfunc_errs(); /* Init myfunc messages */
DBUG_RETURN(FALSE);
}
@@ -81,19 +95,17 @@ bool init_errmessage(void)
Read text from packed textfile in language-directory.
If we can't read messagefile then it's panic- we can't continue.
-
- @todo
- Convert the character set to server system character set
*/
-static bool read_texts(const char *file_name,const char ***point,
- uint error_messages)
+bool read_texts(const char *file_name, const char *language,
+ const char ***point, uint error_messages)
{
register uint i;
uint count,funktpos,textcount;
size_t length;
File file;
char name[FN_REFLEN];
+ char lang_path[FN_REFLEN];
uchar *buff;
uchar head[32],*pos;
const char *errmsg;
@@ -101,33 +113,37 @@ static bool read_texts(const char *file_name,const char ***point,
LINT_INIT(buff);
funktpos=0;
- if ((file=my_open(fn_format(name,file_name,language,"",4),
- O_RDONLY | O_SHARE | O_BINARY,
- MYF(0))) < 0)
- goto err; /* purecov: inspected */
+ convert_dirname(lang_path, language, NullS);
+ (void) my_load_path(lang_path, lang_path, lc_messages_dir);
+ if ((file= mysql_file_open(key_file_ERRMSG,
+ fn_format(name, file_name, lang_path, "", 4),
+ O_RDONLY | O_SHARE | O_BINARY,
+ MYF(0))) < 0)
+ {
+ /*
+ Trying pre-5.4 sematics of the --language parameter.
+ It included the language-specific part, e.g.:
+
+ --language=/path/to/english/
+ */
+ if ((file= mysql_file_open(key_file_ERRMSG,
+ fn_format(name, file_name, lc_messages_dir, "", 4),
+ O_RDONLY | O_SHARE | O_BINARY,
+ MYF(0))) < 0)
+ goto err;
+ sql_print_error("An old style --language value with language specific part detected: %s", lc_messages_dir);
+ sql_print_error("Use --lc-messages-dir without language specific part instead.");
+ }
funktpos=1;
- if (my_read(file,(uchar*) head,32,MYF(MY_NABP))) goto err;
+ if (mysql_file_read(file, (uchar*) head, 32, MYF(MY_NABP)))
+ goto err;
if (head[0] != (uchar) 254 || head[1] != (uchar) 254 ||
head[2] != 2 || head[3] != 1)
goto err; /* purecov: inspected */
textcount=head[4];
- if (!head[30])
- {
- sql_print_error("Character set information not found in '%s'. \
-Please install the latest version of this file.",name);
- goto err1;
- }
-
- /* TODO: Convert the character set to server system character set */
- if (!get_charset(head[30],MYF(MY_WME)))
- {
- sql_print_error("Character set #%d is not supported for messagefile '%s'",
- (int)head[30],name);
- goto err1;
- }
-
+ error_message_charset_info= system_charset_info;
length=uint2korr(head+6); count=uint2korr(head+8);
if (count < error_messages)
@@ -137,11 +153,12 @@ Error message file '%s' had only %d error messages,\n\
but it should contain at least %d error messages.\n\
Check that the above file is the right version for this program!",
name,count,error_messages);
- VOID(my_close(file,MYF(MY_WME)));
+ (void) mysql_file_close(file, MYF(MY_WME));
DBUG_RETURN(1);
}
- x_free((uchar*) *point); /* Free old language */
+ /* Free old language */
+ my_free(*point);
if (!(*point= (const char**)
my_malloc((size_t) (length+count*sizeof(char*)),MYF(0))))
{
@@ -150,21 +167,21 @@ Check that the above file is the right version for this program!",
}
buff= (uchar*) (*point + count);
- if (my_read(file, buff, (size_t) count*2,MYF(MY_NABP)))
+ if (mysql_file_read(file, buff, (size_t) count*2, MYF(MY_NABP)))
goto err;
for (i=0, pos= buff ; i< count ; i++)
{
(*point)[i]= (char*) buff+uint2korr(pos);
pos+=2;
}
- if (my_read(file, buff, length, MYF(MY_NABP)))
+ if (mysql_file_read(file, buff, length, MYF(MY_NABP)))
goto err;
for (i=1 ; i < textcount ; i++)
{
point[i]= *point +uint2korr(head+10+i+i);
}
- VOID(my_close(file,MYF(0)));
+ (void) mysql_file_close(file, MYF(0));
DBUG_RETURN(0);
err:
@@ -180,9 +197,8 @@ err:
break;
}
sql_print_error(errmsg, name);
-err1:
if (file != FERR)
- VOID(my_close(file,MYF(MY_WME)));
+ (void) mysql_file_close(file, MYF(MY_WME));
DBUG_RETURN(1);
} /* read_texts */
diff --git a/sql/derror.h b/sql/derror.h
new file mode 100644
index 00000000000..cb8ae91acbc
--- /dev/null
+++ b/sql/derror.h
@@ -0,0 +1,25 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 DERROR_INCLUDED
+#define DERROR_INCLUDED
+
+#include "my_global.h" /* uint */
+
+bool init_errmessage(void);
+bool read_texts(const char *file_name, const char *language,
+ const char ***point, uint error_messages);
+
+#endif /* DERROR_INCLUDED */
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
index 317cb237360..d2bf2ebdaa7 100644
--- a/sql/des_key_file.cc
+++ b/sql/des_key_file.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2003, 2005 MySQL AB
+/* Copyright (C) 2001-2003, 2005 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -13,7 +13,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "my_global.h" // HAVE_*
+#include "sql_priv.h"
+#include "des_key_file.h" // st_des_keyschedule, st_des_keyblock
+#include "log.h" // sql_print_error
#include <m_ctype.h>
#ifdef HAVE_OPENSSL
@@ -43,8 +46,9 @@ load_des_key_file(const char *file_name)
DBUG_ENTER("load_des_key_file");
DBUG_PRINT("enter",("name: %s",file_name));
- VOID(pthread_mutex_lock(&LOCK_des_key_file));
- if ((file=my_open(file_name,O_RDONLY | O_BINARY ,MYF(MY_WME))) < 0 ||
+ mysql_mutex_lock(&LOCK_des_key_file);
+ if ((file= mysql_file_open(key_file_des_key_file, file_name,
+ O_RDONLY | O_BINARY, MYF(MY_WME))) < 0 ||
init_io_cache(&io, file, IO_SIZE*2, READ_CACHE, 0, 0, MYF(MY_WME)))
goto error;
@@ -93,10 +97,10 @@ load_des_key_file(const char *file_name)
error:
if (file >= 0)
{
- my_close(file,MYF(0));
+ mysql_file_close(file, MYF(0));
end_io_cache(&io);
}
- VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ mysql_mutex_unlock(&LOCK_des_key_file);
DBUG_RETURN(result);
}
#endif /* HAVE_OPENSSL */
diff --git a/sql/des_key_file.h b/sql/des_key_file.h
new file mode 100644
index 00000000000..d817ff93949
--- /dev/null
+++ b/sql/des_key_file.h
@@ -0,0 +1,40 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 DES_KEY_FILE_INCLUDED
+#define DES_KEY_FILE_INCLUDED
+
+#ifdef HAVE_OPENSSL
+#include <openssl/des.h>
+
+#include "violite.h" /* DES_cblock, DES_key_schedule */
+
+struct st_des_keyblock
+{
+ DES_cblock key1, key2, key3;
+};
+
+struct st_des_keyschedule
+{
+ DES_key_schedule ks1, ks2, ks3;
+};
+
+extern struct st_des_keyschedule des_keyschedule[10];
+extern uint des_default_key;
+
+bool load_des_key_file(const char *file_name);
+#endif /* HAVE_OPENSSL */
+
+#endif /* DES_KEY_FILE_INCLUDED */
diff --git a/sql/discover.cc b/sql/discover.cc
index 56dc00cc5c4..f50f7deed99 100644
--- a/sql/discover.cc
+++ b/sql/discover.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004 MySQL AB
+/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -21,7 +21,9 @@
Functions for discover of frm file from handler
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "discover.h"
#include <my_dir.h>
/**
@@ -57,15 +59,16 @@ int readfrm(const char *name, uchar **frmdata, size_t *len)
*frmdata= NULL; // In case of errors
*len= 0;
error= 1;
- if ((file=my_open(fn_format(index_file,name,"",reg_ext,
- MY_UNPACK_FILENAME|MY_APPEND_EXT),
- O_RDONLY | O_SHARE,
- MYF(0))) < 0)
+ if ((file= mysql_file_open(key_file_frm,
+ fn_format(index_file, name, "", reg_ext,
+ MY_UNPACK_FILENAME|MY_APPEND_EXT),
+ O_RDONLY | O_SHARE,
+ MYF(0))) < 0)
goto err_end;
// Get length of file
error= 2;
- if (my_fstat(file, &state, MYF(0)))
+ if (mysql_file_fstat(file, &state, MYF(0)))
goto err;
read_len= state.st_size;
@@ -82,7 +85,7 @@ int readfrm(const char *name, uchar **frmdata, size_t *len)
err:
if (file > 0)
- VOID(my_close(file,MYF(MY_WME)));
+ (void) mysql_file_close(file, MYF(MY_WME));
err_end: /* Here when no file */
DBUG_RETURN (error);
@@ -112,13 +115,15 @@ int writefrm(const char *name, const uchar *frmdata, size_t len)
DBUG_PRINT("enter",("name: '%s' len: %lu ",name, (ulong) len));
error= 0;
- if ((file=my_create(fn_format(index_file,name,"",reg_ext,
- MY_UNPACK_FILENAME|MY_APPEND_EXT),
- CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
+ if ((file= mysql_file_create(key_file_frm,
+ fn_format(index_file, name, "", reg_ext,
+ MY_UNPACK_FILENAME | MY_APPEND_EXT),
+ CREATE_MODE, O_RDWR | O_TRUNC,
+ MYF(MY_WME))) >= 0)
{
- if (my_write(file, frmdata, len,MYF(MY_WME | MY_NABP)))
+ if (mysql_file_write(file, frmdata, len, MYF(MY_WME | MY_NABP)))
error= 2;
- VOID(my_close(file,MYF(0)));
+ (void) mysql_file_close(file, MYF(0));
}
DBUG_RETURN(error);
} /* writefrm */
diff --git a/sql/discover.h b/sql/discover.h
new file mode 100644
index 00000000000..54fb78ddd2f
--- /dev/null
+++ b/sql/discover.h
@@ -0,0 +1,24 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 DISCOVER_INCLUDED
+#define DISCOVER_INCLUDED
+
+#include "my_global.h" /* uchar */
+
+int readfrm(const char *name, uchar **data, size_t *length);
+int writefrm(const char* name, const uchar* data, size_t len);
+
+#endif /* DISCOVER_INCLUDED */
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 6119a97dbf9..ef14a061677 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2006 MySQL AB
+/* Copyright (C) 2004-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -14,11 +14,23 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define MYSQL_LEX 1
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_parse.h" // parse_sql
+#include "strfunc.h" // find_string_in_array
+#include "sql_db.h" // get_default_db_collation
+#include "sql_time.h" // interval_type_to_name,
+ // date_add_interval,
+ // calc_time_diff
+#include "tztime.h" // my_tz_find, my_tz_OFFSET0, struct Time_zone
+#include "sql_acl.h" // EVENT_ACL, SUPER_ACL
+#include "sp.h" // load_charset, load_collation
#include "events.h"
#include "event_data_objects.h"
#include "event_db_repository.h"
#include "sp_head.h"
+#include "sql_show.h" // append_definer, append_identifier
/**
@addtogroup Event_Scheduler
@@ -164,7 +176,7 @@ Event_queue_element_for_exec::init(LEX_STRING db, LEX_STRING n)
return TRUE;
if (!(name.str= my_strndup(n.str, name.length= n.length, MYF(MY_WME))))
{
- my_free((uchar*) dbname.str, MYF(0));
+ my_free(dbname.str);
return TRUE;
}
return FALSE;
@@ -180,8 +192,8 @@ Event_queue_element_for_exec::init(LEX_STRING db, LEX_STRING n)
Event_queue_element_for_exec::~Event_queue_element_for_exec()
{
- my_free((uchar*) dbname.str, MYF(0));
- my_free((uchar*) name.str, MYF(0));
+ my_free(dbname.str);
+ my_free(name.str);
}
@@ -196,7 +208,7 @@ Event_basic::Event_basic()
{
DBUG_ENTER("Event_basic::Event_basic");
/* init memory root */
- init_alloc_root(&mem_root, 256, 512);
+ init_sql_alloc(&mem_root, 256, 512);
dbname.str= name.str= NULL;
dbname.length= name.length= 0;
time_zone= NULL;
@@ -278,7 +290,6 @@ Event_basic::load_time_zone(THD *thd, const LEX_STRING tz_name)
*/
Event_queue_element::Event_queue_element():
- status_changed(FALSE), last_executed_changed(FALSE),
on_completion(Event_parse_data::ON_COMPLETION_DROP),
status(Event_parse_data::ENABLED), expression(0), dropped(FALSE),
execution_count(0)
@@ -527,7 +538,6 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
TIME_NO_ZERO_DATE);
last_executed= my_tz_OFFSET0->TIME_to_gmt_sec(&time,&not_used);
}
- last_executed_changed= FALSE;
if ((ptr= get_field(&mem_root, table->field[ET_FIELD_STATUS])) == NullS)
DBUG_RETURN(TRUE);
@@ -923,7 +933,6 @@ Event_queue_element::compute_next_execution_time()
DBUG_PRINT("info",("One-time event will be dropped: %d.", dropped));
status= Event_parse_data::DISABLED;
- status_changed= TRUE;
}
goto ret;
}
@@ -943,7 +952,6 @@ Event_queue_element::compute_next_execution_time()
dropped= TRUE;
DBUG_PRINT("info", ("Dropped: %d", dropped));
status= Event_parse_data::DISABLED;
- status_changed= TRUE;
goto ret;
}
@@ -1006,7 +1014,6 @@ Event_queue_element::compute_next_execution_time()
if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
dropped= TRUE;
status= Event_parse_data::DISABLED;
- status_changed= TRUE;
}
else
{
@@ -1096,7 +1103,6 @@ Event_queue_element::compute_next_execution_time()
execute_at= 0;
execute_at_null= TRUE;
status= Event_parse_data::DISABLED;
- status_changed= TRUE;
if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
dropped= TRUE;
}
@@ -1132,50 +1138,11 @@ void
Event_queue_element::mark_last_executed(THD *thd)
{
last_executed= (my_time_t) thd->query_start();
- last_executed_changed= TRUE;
execution_count++;
}
-/*
- Saves status and last_executed_at to the disk if changed.
-
- SYNOPSIS
- Event_queue_element::update_timing_fields()
- thd - thread context
-
- RETURN VALUE
- FALSE OK
- TRUE Error while opening mysql.event for writing or during
- write on disk
-*/
-
-bool
-Event_queue_element::update_timing_fields(THD *thd)
-{
- Event_db_repository *db_repository= Events::get_db_repository();
- int ret;
-
- DBUG_ENTER("Event_queue_element::update_timing_fields");
-
- DBUG_PRINT("enter", ("name: %*s", (int) name.length, name.str));
-
- /* No need to update if nothing has changed */
- if (!(status_changed || last_executed_changed))
- DBUG_RETURN(0);
-
- ret= db_repository->update_timing_fields_for_event(thd,
- dbname, name,
- last_executed_changed,
- last_executed,
- status_changed,
- (ulonglong) status);
- last_executed_changed= status_changed= FALSE;
- DBUG_RETURN(ret);
-}
-
-
static
void
append_datetime(String *buf, Time_zone *time_zone, my_time_t secs,
@@ -1226,7 +1193,9 @@ Event_timed::get_create_event(THD *thd, String *buf)
expression))
DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
- buf->append(STRING_WITH_LEN("CREATE EVENT "));
+ buf->append(STRING_WITH_LEN("CREATE "));
+ append_definer(thd, buf, &definer_user, &definer_host);
+ buf->append(STRING_WITH_LEN("EVENT "));
append_identifier(thd, buf, name.str, name.length);
if (expression)
@@ -1388,6 +1357,8 @@ Event_job_data::execute(THD *thd, bool drop)
*/
thd->set_db(dbname.str, dbname.length);
+ lex_start(thd);
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (event_sctx.change_security_context(thd,
&definer_user, &definer_host,
@@ -1397,12 +1368,11 @@ Event_job_data::execute(THD *thd, bool drop)
"[%s].[%s.%s] execution failed, "
"failed to authenticate the user.",
definer.str, dbname.str, name.str);
- goto end_no_lex_start;
+ goto end;
}
#endif
- if (check_access(thd, EVENT_ACL, dbname.str,
- 0, 0, 0, is_schema_db(dbname.str, dbname.length)))
+ if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
{
/*
This aspect of behavior is defined in the worklog,
@@ -1414,11 +1384,11 @@ Event_job_data::execute(THD *thd, bool drop)
"[%s].[%s.%s] execution failed, "
"user no longer has EVENT privilege.",
definer.str, dbname.str, name.str);
- goto end_no_lex_start;
+ goto end;
}
if (construct_sp_sql(thd, &sp_sql))
- goto end_no_lex_start;
+ goto end;
/*
Set up global thread attributes to reflect the properties of
@@ -1438,8 +1408,6 @@ Event_job_data::execute(THD *thd, bool drop)
if (parser_state.init(thd, thd->query(), thd->query_length()))
goto end;
- lex_start(thd);
-
if (parse_sql(thd, & parser_state, creation_ctx))
{
sql_print_error("Event Scheduler: "
@@ -1471,13 +1439,6 @@ Event_job_data::execute(THD *thd, bool drop)
}
end:
- if (thd->lex->sphead) /* NULL only if a parse error */
- {
- delete thd->lex->sphead;
- thd->lex->sphead= NULL;
- }
-
-end_no_lex_start:
if (drop && !thd->is_fatal_error)
{
/*
@@ -1516,12 +1477,11 @@ end_no_lex_start:
if (save_sctx)
event_sctx.restore_security_context(thd, save_sctx);
#endif
- lex_end(thd->lex);
thd->lex->unit.cleanup();
thd->end_statement();
thd->cleanup_after_query();
/* Avoid races with SHOW PROCESSLIST */
- thd->set_query(NULL, 0);
+ thd->reset_query();
DBUG_PRINT("info", ("EXECUTED %s.%s ret: %d", dbname.str, name.str, ret));
diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h
index e32077b9c97..46740812d31 100644
--- a/sql/event_data_objects.h
+++ b/sql/event_data_objects.h
@@ -23,6 +23,12 @@
*/
#include "event_parse_data.h"
+#include "thr_lock.h" /* thr_lock_type */
+
+class Field;
+class THD;
+class Time_zone;
+struct TABLE;
class Event_queue_element_for_exec
{
@@ -76,10 +82,6 @@ protected:
class Event_queue_element : public Event_basic
{
-protected:
- bool status_changed;
- bool last_executed_changed;
-
public:
int on_completion;
int status;
@@ -111,9 +113,6 @@ public:
void
mark_last_executed(THD *thd);
-
- bool
- update_timing_fields(THD *thd);
};
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index 753e9d21b65..053558aa0c3 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -13,12 +13,21 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_base.h" // close_thread_tables
#include "event_db_repository.h"
+#include "key.h" // key_copy
+#include "sql_db.h" // get_default_db_collation
+#include "sql_time.h" // interval_type_to_name
+#include "tztime.h" // struct Time_zone
+#include "sql_acl.h" // SUPER_ACL, MYSQL_DB_FIELD_COUNT, mysql_db_table_fields
+#include "records.h" // init_read_record, end_read_record
#include "sp_head.h"
#include "event_data_objects.h"
#include "events.h"
#include "sql_show.h"
+#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
/**
@addtogroup Event_Scheduler
@@ -509,17 +518,20 @@ Event_db_repository::table_scan_all_for_i_s(THD *thd, TABLE *schema_table,
*/
bool
-Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables,
+Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *i_s_table,
const char *db)
{
- TABLE *schema_table= tables->table;
- TABLE *event_table= NULL;
+ TABLE *schema_table= i_s_table->table;
+ Open_tables_backup open_tables_backup;
+ TABLE_LIST event_table;
int ret= 0;
DBUG_ENTER("Event_db_repository::fill_schema_events");
DBUG_PRINT("info",("db=%s", db? db:"(null)"));
- if (open_event_table(thd, TL_READ, &event_table))
+ event_table.init_one_table("mysql", 5, "event", 5, "event", TL_READ);
+
+ if (open_system_tables_for_read(thd, &event_table, &open_tables_backup))
DBUG_RETURN(TRUE);
/*
@@ -532,11 +544,11 @@ Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables,
every single row's `db` with the schema which we show.
*/
if (db)
- ret= index_read_for_db_for_i_s(thd, schema_table, event_table, db);
+ ret= index_read_for_db_for_i_s(thd, schema_table, event_table.table, db);
else
- ret= table_scan_all_for_i_s(thd, schema_table, event_table);
+ ret= table_scan_all_for_i_s(thd, schema_table, event_table.table);
- close_thread_tables(thd);
+ close_system_tables(thd, &open_tables_backup);
DBUG_PRINT("info", ("Return code=%d", ret));
DBUG_RETURN(ret);
@@ -572,13 +584,10 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
TABLE_LIST tables;
DBUG_ENTER("Event_db_repository::open_event_table");
- tables.init_one_table("mysql", "event", lock_type);
+ tables.init_one_table("mysql", 5, "event", 5, "event", lock_type);
- if (simple_open_n_lock_tables(thd, &tables))
- {
- close_thread_tables(thd);
+ if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
DBUG_RETURN(TRUE);
- }
*table= tables.table;
tables.table->use_all_columns();
@@ -613,6 +622,12 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
TABLE *table= NULL;
sp_head *sp= thd->lex->sphead;
ulong saved_mode= thd->variables.sql_mode;
+ /*
+ Take a savepoint to release only the lock on mysql.event
+ table at the end but keep the global read lock and
+ possible other locks taken by the caller.
+ */
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("Event_db_repository::create_event");
@@ -690,8 +705,9 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
ret= 0;
end:
- if (table)
- close_thread_tables(thd);
+ close_thread_tables(thd);
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+
thd->variables.sql_mode= saved_mode;
DBUG_RETURN(test(ret));
}
@@ -724,6 +740,12 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
TABLE *table= NULL;
sp_head *sp= thd->lex->sphead;
ulong saved_mode= thd->variables.sql_mode;
+ /*
+ Take a savepoint to release only the lock on mysql.event
+ table at the end but keep the global read lock and
+ possible other locks taken by the caller.
+ */
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
int ret= 1;
DBUG_ENTER("Event_db_repository::update_event");
@@ -801,8 +823,9 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
ret= 0;
end:
- if (table)
- close_thread_tables(thd);
+ close_thread_tables(thd);
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+
thd->variables.sql_mode= saved_mode;
DBUG_RETURN(test(ret));
}
@@ -827,6 +850,12 @@ Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
bool drop_if_exists)
{
TABLE *table= NULL;
+ /*
+ Take a savepoint to release only the lock on mysql.event
+ table at the end but keep the global read lock and
+ possible other locks taken by the caller.
+ */
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
int ret= 1;
DBUG_ENTER("Event_db_repository::drop_event");
@@ -855,8 +884,8 @@ Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
ret= 0;
end:
- if (table)
- close_thread_tables(thd);
+ close_thread_tables(thd);
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
DBUG_RETURN(test(ret));
}
@@ -925,33 +954,13 @@ Event_db_repository::find_named_event(LEX_STRING db, LEX_STRING name,
void
Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
{
- DBUG_ENTER("Event_db_repository::drop_schema_events");
- drop_events_by_field(thd, ET_FIELD_DB, schema);
- DBUG_VOID_RETURN;
-}
-
-
-/**
- Drops all events which have a specific value of a field.
-
- @pre The thread handle has no open tables.
-
- @param[in,out] thd Thread
- @param[in,out] table mysql.event TABLE
- @param[in] field Which field of the row to use for matching
- @param[in] field_value The value that should match
-*/
-
-void
-Event_db_repository::drop_events_by_field(THD *thd,
- enum enum_events_table_field field,
- LEX_STRING field_value)
-{
int ret= 0;
TABLE *table= NULL;
READ_RECORD read_record_info;
- DBUG_ENTER("Event_db_repository::drop_events_by_field");
- DBUG_PRINT("enter", ("field=%d field_value=%s", field, field_value.str));
+ enum enum_events_table_field field= ET_FIELD_DB;
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ DBUG_ENTER("Event_db_repository::drop_schema_events");
+ DBUG_PRINT("enter", ("field=%d schema=%s", field, schema.str));
if (open_event_table(thd, TL_WRITE, &table))
DBUG_VOID_RETURN;
@@ -970,7 +979,7 @@ Event_db_repository::drop_events_by_field(THD *thd,
get_field(thd->mem_root,
table->field[ET_FIELD_NAME])));
- if (!sortcmp_lex_string(et_field_lex, field_value, system_charset_info))
+ if (!sortcmp_lex_string(et_field_lex, schema, system_charset_info))
{
DBUG_PRINT("info", ("Dropping"));
if ((ret= table->file->ha_delete_row(table->record[0])))
@@ -980,6 +989,11 @@ Event_db_repository::drop_events_by_field(THD *thd,
}
end_read_record(&read_record_info);
close_thread_tables(thd);
+ /*
+ Make sure to only release the MDL lock on mysql.event, not other
+ metadata locks DROP DATABASE might have acquired.
+ */
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
DBUG_VOID_RETURN;
}
@@ -1000,24 +1014,33 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
LEX_STRING name, Event_basic *etn)
{
bool ret;
- TABLE *table= NULL;
ulong saved_mode= thd->variables.sql_mode;
+ Open_tables_backup open_tables_backup;
+ TABLE_LIST event_table;
DBUG_ENTER("Event_db_repository::load_named_event");
DBUG_PRINT("enter",("thd: 0x%lx name: %*s", (long) thd,
(int) name.length, name.str));
+ event_table.init_one_table("mysql", 5, "event", 5, "event", TL_READ);
+
/* Reset sql_mode during data dictionary operations. */
thd->variables.sql_mode= 0;
- if (!(ret= open_event_table(thd, TL_READ, &table)))
+ /*
+ We don't use open_event_table() here to make sure that SHOW
+ CREATE EVENT works properly in transactional context, and
+ does not release transactional metadata locks when the
+ event table is closed.
+ */
+ if (!(ret= open_system_tables_for_read(thd, &event_table, &open_tables_backup)))
{
- if ((ret= find_named_event(dbname, name, table)))
+ if ((ret= find_named_event(dbname, name, event_table.table)))
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
- else if ((ret= etn->load_from_row(thd, table)))
+ else if ((ret= etn->load_from_row(thd, event_table.table)))
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
- close_thread_tables(thd);
+ close_system_tables(thd, &open_tables_backup);
}
thd->variables.sql_mode= saved_mode;
@@ -1037,15 +1060,14 @@ Event_db_repository::
update_timing_fields_for_event(THD *thd,
LEX_STRING event_db_name,
LEX_STRING event_name,
- bool update_last_executed,
my_time_t last_executed,
- bool update_status,
ulonglong status)
{
TABLE *table= NULL;
Field **fields;
int ret= 1;
bool save_binlog_row_based;
+ MYSQL_TIME time;
DBUG_ENTER("Event_db_repository::update_timing_fields_for_event");
@@ -1053,8 +1075,8 @@ update_timing_fields_for_event(THD *thd,
Turn off row binlogging of event timing updates. These are not used
for RBR of events replicated to the slave.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
DBUG_ASSERT(thd->security_ctx->master_access & SUPER_ACL);
@@ -1070,20 +1092,12 @@ update_timing_fields_for_event(THD *thd,
/* Don't update create on row update. */
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
- if (update_last_executed)
- {
- MYSQL_TIME time;
- my_tz_OFFSET0->gmt_sec_to_TIME(&time, last_executed);
+ my_tz_OFFSET0->gmt_sec_to_TIME(&time, last_executed);
+ fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
+ fields[ET_FIELD_LAST_EXECUTED]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
- fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
- fields[ET_FIELD_LAST_EXECUTED]->store_time(&time,
- MYSQL_TIMESTAMP_DATETIME);
- }
- if (update_status)
- {
- fields[ET_FIELD_STATUS]->set_notnull();
- fields[ET_FIELD_STATUS]->store(status, TRUE);
- }
+ fields[ET_FIELD_STATUS]->set_notnull();
+ fields[ET_FIELD_STATUS]->store(status, TRUE);
if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
{
@@ -1095,9 +1109,12 @@ update_timing_fields_for_event(THD *thd,
end:
if (table)
- close_thread_tables(thd);
+ close_mysql_tables(thd);
+
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(test(ret));
}
@@ -1127,11 +1144,10 @@ Event_db_repository::check_system_tables(THD *thd)
DBUG_ENTER("Event_db_repository::check_system_tables");
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
-
/* Check mysql.db */
- tables.init_one_table("mysql", "db", TL_READ);
+ tables.init_one_table("mysql", 5, "db", 2, "db", TL_READ);
- if (simple_open_n_lock_tables(thd, &tables))
+ if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{
ret= 1;
sql_print_error("Cannot open mysql.db");
@@ -1141,12 +1157,12 @@ Event_db_repository::check_system_tables(THD *thd)
if (table_intact.check(tables.table, &mysql_db_table_def))
ret= 1;
- close_thread_tables(thd);
+ close_mysql_tables(thd);
}
/* Check mysql.user */
- tables.init_one_table("mysql", "user", TL_READ);
+ tables.init_one_table("mysql", 5, "user", 4, "user", TL_READ);
- if (simple_open_n_lock_tables(thd, &tables))
+ if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{
ret= 1;
sql_print_error("Cannot open mysql.user");
@@ -1161,12 +1177,12 @@ Event_db_repository::check_system_tables(THD *thd)
event_priv_column_position);
ret= 1;
}
- close_thread_tables(thd);
+ close_mysql_tables(thd);
}
/* Check mysql.event */
- tables.init_one_table("mysql", "event", TL_READ);
+ tables.init_one_table("mysql", 5, "event", 5, "event", TL_READ);
- if (simple_open_n_lock_tables(thd, &tables))
+ if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{
ret= 1;
sql_print_error("Cannot open mysql.event");
@@ -1175,7 +1191,7 @@ Event_db_repository::check_system_tables(THD *thd)
{
if (table_intact.check(tables.table, &event_table_def))
ret= 1;
- close_thread_tables(thd);
+ close_mysql_tables(thd);
}
DBUG_RETURN(test(ret));
diff --git a/sql/event_db_repository.h b/sql/event_db_repository.h
index ef778407d1e..58484d17f06 100644
--- a/sql/event_db_repository.h
+++ b/sql/event_db_repository.h
@@ -91,7 +91,7 @@ public:
bool
load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
- bool
+ static bool
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
bool
@@ -101,17 +101,12 @@ public:
update_timing_fields_for_event(THD *thd,
LEX_STRING event_db_name,
LEX_STRING event_name,
- bool update_last_executed,
my_time_t last_executed,
- bool update_status,
ulonglong status);
public:
static bool
check_system_tables(THD *thd);
private:
- void
- drop_events_by_field(THD *thd, enum enum_events_table_field field,
- LEX_STRING field_value);
bool
index_read_for_db_for_i_s(THD *thd, TABLE *schema_table, TABLE *event_table,
const char *db);
diff --git a/sql/event_parse_data.cc b/sql/event_parse_data.cc
index 86905b38627..c36567fc8e1 100644
--- a/sql/event_parse_data.cc
+++ b/sql/event_parse_data.cc
@@ -13,9 +13,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
#include "sp_head.h"
#include "event_parse_data.h"
+#include "sql_time.h" // TIME_to_timestamp
/*
Returns a new instance
diff --git a/sql/event_parse_data.h b/sql/event_parse_data.h
index 8b42eb23937..4ca46b40d3f 100644
--- a/sql/event_parse_data.h
+++ b/sql/event_parse_data.h
@@ -16,6 +16,12 @@
#ifndef _EVENT_PARSE_DATA_H_
#define _EVENT_PARSE_DATA_H_
+#include "sql_list.h" /* Sql_alloc */
+
+class Item;
+class THD;
+class sp_name;
+
#define EVEX_GET_FIELD_FAILED -2
#define EVEX_BAD_PARAMS -5
#define EVEX_MICROSECOND_UNSUP -6
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index 04d4f858b43..bdc8fa258a8 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2006 MySQL AB
+/* Copyright (C) 2004-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -13,9 +13,16 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
#include "event_queue.h"
#include "event_data_objects.h"
+#include "event_db_repository.h"
+#include "events.h"
+#include "sql_audit.h"
+#include "tztime.h" // my_tz_find, my_tz_OFFSET0, struct Time_zone
+#include "log.h" // sql_print_error
+#include "sql_class.h" // struct THD
/**
@addtogroup Event_Scheduler
@@ -94,16 +101,16 @@ Event_queue::Event_queue()
mutex_queue_data_attempting_lock(FALSE),
waiting_on_cond(FALSE)
{
- pthread_mutex_init(&LOCK_event_queue, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&COND_queue_state, NULL);
+ mysql_mutex_init(key_LOCK_event_queue, &LOCK_event_queue, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_queue_state, &COND_queue_state, NULL);
}
Event_queue::~Event_queue()
{
deinit_queue();
- pthread_mutex_destroy(&LOCK_event_queue);
- pthread_cond_destroy(&COND_queue_state);
+ mysql_mutex_destroy(&LOCK_event_queue);
+ mysql_cond_destroy(&COND_queue_state);
}
@@ -210,7 +217,7 @@ Event_queue::create_event(THD *thd, Event_queue_element *new_element,
LOCK_QUEUE_DATA();
*created= (queue_insert_safe(&queue, (uchar *) new_element) == FALSE);
dbug_dump_queue(thd->query_start());
- pthread_cond_broadcast(&COND_queue_state);
+ mysql_cond_broadcast(&COND_queue_state);
UNLOCK_QUEUE_DATA();
DBUG_RETURN(!*created);
@@ -258,7 +265,7 @@ Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
{
DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element));
queue_insert_safe(&queue, (uchar *) new_element);
- pthread_cond_broadcast(&COND_queue_state);
+ mysql_cond_broadcast(&COND_queue_state);
}
dbug_dump_queue(thd->query_start());
@@ -343,7 +350,7 @@ Event_queue::drop_matching_events(THD *thd, LEX_STRING pattern,
i++;
}
/*
- We don't call pthread_cond_broadcast(&COND_queue_state);
+ We don't call mysql_cond_broadcast(&COND_queue_state);
If we remove the top event:
1. The queue is empty. The scheduler will wake up at some time and
realize that the queue is empty. If create_event() comes inbetween
@@ -439,7 +446,6 @@ Event_queue::recalculate_activation_times(THD *thd)
for (i= 0; i < queue.elements; i++)
{
((Event_queue_element*)queue_element(&queue, i))->compute_next_execution_time();
- ((Event_queue_element*)queue_element(&queue, i))->update_timing_fields(thd);
}
queue_fix(&queue);
/*
@@ -562,6 +568,8 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
{
bool ret= FALSE;
*event_name= NULL;
+ my_time_t UNINIT_VAR(last_executed);
+ int UNINIT_VAR(status);
DBUG_ENTER("Event_queue::get_top_for_execution_if_time");
LOCK_QUEUE_DATA();
@@ -581,6 +589,9 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
/* There are no events in the queue */
next_activation_at= 0;
+ /* Release any held audit resources before waiting */
+ mysql_audit_release(thd);
+
/* Wait on condition until signaled. Release LOCK_queue while waiting. */
cond_wait(thd, NULL, queue_empty_msg, SCHED_FUNC, __LINE__);
@@ -600,6 +611,10 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
*/
struct timespec top_time;
set_timespec(top_time, next_activation_at - thd->query_start());
+
+ /* Release any held audit resources before waiting */
+ mysql_audit_release(thd);
+
cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__);
continue;
@@ -620,8 +635,14 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
top->execution_count++;
(*event_name)->dropped= top->dropped;
+ /*
+ Save new values of last_executed timestamp and event status on stack
+ in order to be able to update event description in system table once
+ QUEUE_DATA lock is released.
+ */
+ last_executed= top->last_executed;
+ status= top->status;
- top->update_timing_fields(thd);
if (top->status == Event_parse_data::DISABLED)
{
DBUG_PRINT("info", ("removing from the queue"));
@@ -644,9 +665,16 @@ end:
ret, (long) *event_name));
if (*event_name)
+ {
DBUG_PRINT("info", ("db: %s name: %s",
(*event_name)->dbname.str, (*event_name)->name.str));
+ Event_db_repository *db_repository= Events::get_db_repository();
+ (void) db_repository->update_timing_fields_for_event(thd,
+ (*event_name)->dbname, (*event_name)->name,
+ last_executed, (ulonglong) status);
+ }
+
DBUG_RETURN(ret);
}
@@ -669,7 +697,7 @@ Event_queue::lock_data(const char *func, uint line)
mutex_last_attempted_lock_in_func= func;
mutex_last_attempted_lock_at_line= line;
mutex_queue_data_attempting_lock= TRUE;
- pthread_mutex_lock(&LOCK_event_queue);
+ mysql_mutex_lock(&LOCK_event_queue);
mutex_last_attempted_lock_in_func= "";
mutex_last_attempted_lock_at_line= 0;
mutex_queue_data_attempting_lock= FALSE;
@@ -700,19 +728,19 @@ Event_queue::unlock_data(const char *func, uint line)
mutex_last_unlocked_at_line= line;
mutex_queue_data_locked= FALSE;
mutex_last_unlocked_in_func= func;
- pthread_mutex_unlock(&LOCK_event_queue);
+ mysql_mutex_unlock(&LOCK_event_queue);
DBUG_VOID_RETURN;
}
/*
- Wrapper for pthread_cond_wait/timedwait
+ Wrapper for mysql_cond_wait/timedwait
SYNOPSIS
Event_queue::cond_wait()
thd Thread (Could be NULL during shutdown procedure)
msg Message for thd->proc_info
- abstime If not null then call pthread_cond_timedwait()
+ abstime If not null then call mysql_cond_timedwait()
func Which function is requesting cond_wait
line On which line cond_wait is requested
*/
@@ -729,11 +757,13 @@ Event_queue::cond_wait(THD *thd, struct timespec *abstime, const char* msg,
thd->enter_cond(&COND_queue_state, &LOCK_event_queue, msg);
- DBUG_PRINT("info", ("pthread_cond_%swait", abstime? "timed":""));
- if (!abstime)
- pthread_cond_wait(&COND_queue_state, &LOCK_event_queue);
- else
- pthread_cond_timedwait(&COND_queue_state, &LOCK_event_queue, abstime);
+ if (!thd->killed)
+ {
+ if (!abstime)
+ mysql_cond_wait(&COND_queue_state, &LOCK_event_queue);
+ else
+ mysql_cond_timedwait(&COND_queue_state, &LOCK_event_queue, abstime);
+ }
mutex_last_locked_in_func= func;
mutex_last_locked_at_line= line;
diff --git a/sql/event_queue.h b/sql/event_queue.h
index 2870ecb4d0b..93af03ba901 100644
--- a/sql/event_queue.h
+++ b/sql/event_queue.h
@@ -1,6 +1,6 @@
#ifndef _EVENT_QUEUE_H_
#define _EVENT_QUEUE_H_
-/* Copyright (C) 2004-2006 MySQL AB
+/* Copyright (C) 2004-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -25,6 +25,15 @@
Queue of events awaiting execution.
*/
+#ifdef HAVE_PSI_INTERFACE
+extern PSI_mutex_key key_LOCK_event_queue;
+extern PSI_cond_key key_COND_queue_state;
+#endif /* HAVE_PSI_INTERFACE */
+
+#include "queues.h" // QUEUE
+#include "sql_string.h" /* LEX_STRING */
+#include "my_time.h" /* my_time_t, interval_type */
+
class Event_basic;
class Event_queue_element;
class Event_queue_element_for_exec;
@@ -101,8 +110,8 @@ private:
dbug_dump_queue(time_t now);
/* LOCK_event_queue is the mutex which protects the access to the queue. */
- pthread_mutex_t LOCK_event_queue;
- pthread_cond_t COND_queue_state;
+ mysql_mutex_t LOCK_event_queue;
+ mysql_cond_t COND_queue_state;
/* The sorted queue with the Event_queue_element objects */
QUEUE queue;
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index 706afb3e0ad..aa4d376d86e 100755..100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2006 MySQL AB
+/* Copyright (C) 2004, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -11,14 +11,17 @@
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "event_scheduler.h"
#include "events.h"
#include "event_data_objects.h"
-#include "event_scheduler.h"
#include "event_queue.h"
#include "event_db_repository.h"
+#include "sql_connect.h" // init_new_connection_handler_thread
+#include "sql_acl.h" // SUPER_ACL
/**
@addtogroup Event_Scheduler
@@ -74,7 +77,7 @@ Event_worker_thread::print_warnings(THD *thd, Event_job_data *et)
{
MYSQL_ERROR *err;
DBUG_ENTER("evex_print_warnings");
- if (!thd->warn_list.elements)
+ if (thd->warning_info->is_empty())
DBUG_VOID_RETURN;
char msg_buf[10 * STRING_BUFFER_USUAL_SIZE];
@@ -90,17 +93,18 @@ Event_worker_thread::print_warnings(THD *thd, Event_job_data *et)
prefix.append(et->name.str, et->name.length, system_charset_info);
prefix.append("] ", 2);
- List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+ List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
while ((err= it++))
{
String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
/* set it to 0 or we start adding at the end. That's the trick ;) */
err_msg.length(0);
err_msg.append(prefix);
- err_msg.append(err->msg, strlen(err->msg), system_charset_info);
- DBUG_ASSERT(err->level < 3);
- (sql_print_message_handlers[err->level])("%*s", err_msg.length(),
- err_msg.c_ptr());
+ err_msg.append(err->get_message_text(),
+ err->get_message_octet_length(), system_charset_info);
+ DBUG_ASSERT(err->get_level() < 3);
+ (sql_print_message_handlers[err->get_level()])("%*s", err_msg.length(),
+ err_msg.c_ptr());
}
DBUG_VOID_RETURN;
}
@@ -127,14 +131,12 @@ post_init_event_thread(THD *thd)
thd->cleanup();
return TRUE;
}
- lex_start(thd);
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
threads.append(thd);
thread_count++;
- thread_running++;
- pthread_mutex_unlock(&LOCK_thread_count);
-
+ inc_thread_running();
+ mysql_mutex_unlock(&LOCK_thread_count);
return FALSE;
}
@@ -154,17 +156,17 @@ deinit_event_thread(THD *thd)
DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net);
DBUG_PRINT("exit", ("Event thread finishing"));
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thread_count--;
- thread_running--;
+ dec_thread_running();
delete thd;
- pthread_cond_broadcast(&COND_thread_count);
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
}
/*
- Performs pre- pthread_create() initialisation of THD. Do this
+ Performs pre- mysql_thread_create() initialisation of THD. Do this
in the thread that will pass THD to the child thread. In the
child thread call post_init_event_thread().
@@ -189,11 +191,11 @@ pre_init_event_thread(THD* thd)
thd->security_ctx->set_user((char*)"event_scheduler");
thd->net.read_timeout= slave_net_timeout;
thd->slave_thread= 0;
- thd->options|= OPTION_AUTO_IS_NULL;
+ thd->variables.option_bits|= OPTION_AUTO_IS_NULL;
thd->client_capabilities|= CLIENT_MULTI_RESULTS;
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
/*
Guarantees that we will see the thread in SHOW PROCESSLIST though its
@@ -201,9 +203,11 @@ pre_init_event_thread(THD* thd)
*/
thd->proc_info= "Initialized";
- thd->version= refresh_version;
thd->set_time();
+ /* Do not use user-supplied timeout value for system threads. */
+ thd->variables.lock_wait_timeout= LONG_TIMEOUT;
+
DBUG_VOID_RETURN;
}
@@ -228,10 +232,13 @@ event_scheduler_thread(void *arg)
bool res;
thd->thread_stack= (char *)&thd; // remember where our stack is
+
+ mysql_thread_set_psi_id(thd->thread_id);
+
res= post_init_event_thread(thd);
DBUG_ENTER("event_scheduler_thread");
- my_free((char*)arg, MYF(0));
+ my_free(arg);
if (!res)
scheduler->run(thd);
@@ -261,6 +268,8 @@ event_worker_thread(void *arg)
thd= event->thd;
+ mysql_thread_set_psi_id(thd->thread_id);
+
Event_worker_thread worker_thread;
worker_thread.run(thd, event);
@@ -337,16 +346,17 @@ Event_scheduler::Event_scheduler(Event_queue *queue_arg)
waiting_on_cond(FALSE),
started_events(0)
{
- pthread_mutex_init(&LOCK_scheduler_state, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&COND_state, NULL);
+ mysql_mutex_init(key_event_scheduler_LOCK_scheduler_state,
+ &LOCK_scheduler_state, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_event_scheduler_COND_state, &COND_state, NULL);
}
Event_scheduler::~Event_scheduler()
{
stop(); /* does nothing if not running */
- pthread_mutex_destroy(&LOCK_scheduler_state);
- pthread_cond_destroy(&COND_state);
+ mysql_mutex_destroy(&LOCK_scheduler_state);
+ mysql_cond_destroy(&COND_state);
}
@@ -405,8 +415,9 @@ Event_scheduler::start()
DBUG_PRINT("info", ("Setting state go RUNNING"));
state= RUNNING;
DBUG_PRINT("info", ("Forking new thread for scheduler. THD: 0x%lx", (long) new_thd));
- if (pthread_create(&th, &connection_attrib, event_scheduler_thread,
- (void*)scheduler_param_value))
+ if (mysql_thread_create(key_thread_event_scheduler,
+ &th, &connection_attrib, event_scheduler_thread,
+ (void*)scheduler_param_value))
{
DBUG_PRINT("error", ("cannot create a new thread"));
state= INITIALIZED;
@@ -416,12 +427,12 @@ Event_scheduler::start()
new_thd->proc_info= "Clearing";
DBUG_ASSERT(new_thd->net.buff != 0);
net_end(&new_thd->net);
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thread_count--;
- thread_running--;
+ dec_thread_running();
delete new_thd;
- pthread_cond_broadcast(&COND_thread_count);
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
}
end:
UNLOCK_DATA();
@@ -488,8 +499,8 @@ Event_scheduler::run(THD *thd)
deinit_event_thread(thd);
scheduler_thd= NULL;
state= INITIALIZED;
- DBUG_PRINT("info", ("Signalling back to the stopper COND_state"));
- pthread_cond_signal(&COND_state);
+ DBUG_PRINT("info", ("Broadcasting COND_state back to the stoppers"));
+ mysql_cond_broadcast(&COND_state);
UNLOCK_DATA();
DBUG_RETURN(res);
@@ -533,8 +544,9 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name)
reasonable level.
*/
/* Major failure */
- if ((res= pthread_create(&th, &connection_attrib, event_worker_thread,
- event_name)))
+ if ((res= mysql_thread_create(key_thread_event_worker,
+ &th, &connection_attrib, event_worker_thread,
+ event_name)))
goto error;
++started_events;
@@ -549,12 +561,12 @@ error:
new_thd->proc_info= "Clearing";
DBUG_ASSERT(new_thd->net.buff != 0);
net_end(&new_thd->net);
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thread_count--;
- thread_running--;
+ dec_thread_running();
delete new_thd;
- pthread_cond_broadcast(&COND_thread_count);
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
}
delete event_name;
DBUG_RETURN(TRUE);
@@ -607,7 +619,12 @@ Event_scheduler::stop()
LOCK_DATA();
DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state].str));
if (state != RUNNING)
+ {
+ /* Synchronously wait until the scheduler stops. */
+ while (state != INITIALIZED)
+ COND_STATE_WAIT(thd, NULL, "Waiting for the scheduler to stop");
goto end;
+ }
/* Guarantee we don't catch spurious signals */
do {
@@ -629,13 +646,13 @@ Event_scheduler::stop()
DBUG_PRINT("info", ("Scheduler thread has id %lu",
scheduler_thd->thread_id));
/* Lock from delete */
- pthread_mutex_lock(&scheduler_thd->LOCK_thd_data);
+ mysql_mutex_lock(&scheduler_thd->LOCK_thd_data);
/* This will wake up the thread if it waits on Queue's conditional */
sql_print_information("Event Scheduler: Killing the scheduler thread, "
"thread id %lu",
scheduler_thd->thread_id);
scheduler_thd->awake(THD::KILL_CONNECTION);
- pthread_mutex_unlock(&scheduler_thd->LOCK_thd_data);
+ mysql_mutex_unlock(&scheduler_thd->LOCK_thd_data);
/* thd could be 0x0, when shutting down */
sql_print_information("Event Scheduler: "
@@ -664,12 +681,12 @@ Event_scheduler::workers_count()
uint count= 0;
DBUG_ENTER("Event_scheduler::workers_count");
- pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
I_List_iterator<THD> it(threads);
while ((tmp=it++))
if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER)
++count;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
DBUG_PRINT("exit", ("%d", count));
DBUG_RETURN(count);
}
@@ -690,7 +707,7 @@ Event_scheduler::lock_data(const char *func, uint line)
{
DBUG_ENTER("Event_scheduler::lock_data");
DBUG_PRINT("enter", ("func=%s line=%u", func, line));
- pthread_mutex_lock(&LOCK_scheduler_state);
+ mysql_mutex_lock(&LOCK_scheduler_state);
mutex_last_locked_in_func= func;
mutex_last_locked_at_line= line;
mutex_scheduler_data_locked= TRUE;
@@ -716,18 +733,18 @@ Event_scheduler::unlock_data(const char *func, uint line)
mutex_last_unlocked_at_line= line;
mutex_scheduler_data_locked= FALSE;
mutex_last_unlocked_in_func= func;
- pthread_mutex_unlock(&LOCK_scheduler_state);
+ mysql_mutex_unlock(&LOCK_scheduler_state);
DBUG_VOID_RETURN;
}
/*
- Wrapper for pthread_cond_wait/timedwait
+ Wrapper for mysql_cond_wait/timedwait
SYNOPSIS
Event_scheduler::cond_wait()
thd Thread (Could be NULL during shutdown procedure)
- abstime If not null then call pthread_cond_timedwait()
+ abstime If not null then call mysql_cond_timedwait()
msg Message for thd->proc_info
func Which function is requesting cond_wait
line On which line cond_wait is requested
@@ -745,11 +762,11 @@ Event_scheduler::cond_wait(THD *thd, struct timespec *abstime, const char* msg,
if (thd)
thd->enter_cond(&COND_state, &LOCK_scheduler_state, msg);
- DBUG_PRINT("info", ("pthread_cond_%swait", abstime? "timed":""));
+ DBUG_PRINT("info", ("mysql_cond_%swait", abstime? "timed":""));
if (!abstime)
- pthread_cond_wait(&COND_state, &LOCK_scheduler_state);
+ mysql_cond_wait(&COND_state, &LOCK_scheduler_state);
else
- pthread_cond_timedwait(&COND_state, &LOCK_scheduler_state, abstime);
+ mysql_cond_timedwait(&COND_state, &LOCK_scheduler_state, abstime);
if (thd)
{
/*
diff --git a/sql/event_scheduler.h b/sql/event_scheduler.h
index 0be93a65d33..ecd7031f546 100644
--- a/sql/event_scheduler.h
+++ b/sql/event_scheduler.h
@@ -1,6 +1,6 @@
#ifndef _EVENT_SCHEDULER_H_
#define _EVENT_SCHEDULER_H_
-/* Copyright (C) 2004-2006 MySQL AB
+/* Copyright (C) 2004-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -34,7 +34,9 @@
class Event_queue;
class Event_job_data;
class Event_db_repository;
+class Event_queue_element_for_exec;
class Events;
+class THD;
void
pre_init_event_thread(THD* thd);
@@ -115,7 +117,7 @@ private:
cond_wait(THD *thd, struct timespec *abstime, const char* msg,
const char *func, uint line);
- pthread_mutex_t LOCK_scheduler_state;
+ mysql_mutex_t LOCK_scheduler_state;
enum enum_state
{
@@ -129,7 +131,7 @@ private:
THD *scheduler_thd;
- pthread_cond_t COND_state;
+ mysql_cond_t COND_state;
Event_queue *queue;
diff --git a/sql/events.cc b/sql/events.cc
index afae512c61d..23a0dc9eb52 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2006 MySQL AB
+/* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -11,15 +11,26 @@
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_parse.h" // check_access
+#include "sql_base.h" // close_mysql_tables
+#include "sql_show.h" // append_definer
#include "events.h"
+#include "sql_db.h" // check_db_dir_existence
+#include "sql_table.h" // write_bin_log
+#include "tztime.h" // struct Time_zone
+#include "sql_acl.h" // EVENT_ACL
+#include "records.h" // init_read_record, end_read_record
#include "event_data_objects.h"
#include "event_db_repository.h"
#include "event_queue.h"
#include "event_scheduler.h"
#include "sp_head.h" // for Stored_program_creation_ctx
+#include "set_var.h"
+#include "lock.h" // lock_object_name
/**
@addtogroup Event_Scheduler
@@ -63,44 +74,10 @@
eligible for execution.
*/
-/*
- Keep the order of the first to as in var_typelib
- sys_var_event_scheduler::value_ptr() references this array. Keep in
- mind!
-*/
-static const char *opt_event_scheduler_state_names[]=
- { "OFF", "ON", "0", "1", "DISABLED", NullS };
-
-const TYPELIB Events::opt_typelib=
-{
- array_elements(opt_event_scheduler_state_names)-1,
- "",
- opt_event_scheduler_state_names,
- NULL
-};
-
-
-/*
- The order should not be changed. We consider OFF to be equivalent of INT 0
- And ON of 1. If OFF & ON are interchanged the logic in
- sys_var_event_scheduler::update() will be broken!
-*/
-static const char *var_event_scheduler_state_names[]= { "OFF", "ON", NullS };
-
-const TYPELIB Events::var_typelib=
-{
- array_elements(var_event_scheduler_state_names)-1,
- "",
- var_event_scheduler_state_names,
- NULL
-};
-
Event_queue *Events::event_queue;
Event_scheduler *Events::scheduler;
Event_db_repository *Events::db_repository;
-enum Events::enum_opt_event_scheduler
-Events::opt_event_scheduler= Events::EVENTS_OFF;
-pthread_mutex_t Events::LOCK_event_metadata;
+ulong Events::opt_event_scheduler= Events::EVENTS_OFF;
bool Events::check_system_tables_error= FALSE;
@@ -127,69 +104,6 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
/**
- @brief Initialize the start up option of the Events scheduler.
-
- Do not initialize the scheduler subsystem yet - the initialization
- is split into steps as it has to fit into the common MySQL
- initialization framework.
- No locking as this is called only at start up.
-
- @param[in,out] argument The value of the argument. If this value
- is found in the typelib, the argument is
- updated.
-
- @retval TRUE unknown option value
- @retval FALSE success
-*/
-
-bool
-Events::set_opt_event_scheduler(char *argument)
-{
- if (argument == NULL)
- opt_event_scheduler= Events::EVENTS_ON;
- else
- {
- int type;
- /*
- type= 1 2 3 4 5
- (OFF | ON) - (0 | 1) (DISABLE )
- */
- const static enum enum_opt_event_scheduler type2state[]=
- { EVENTS_OFF, EVENTS_ON, EVENTS_OFF, EVENTS_ON, EVENTS_DISABLED };
-
- type= find_type(argument, &opt_typelib, 1);
-
- DBUG_ASSERT(type >= 0 && type <= 5); /* guaranteed by find_type */
-
- if (type == 0)
- {
- fprintf(stderr, "Unknown option to event-scheduler: %s\n", argument);
- return TRUE;
- }
- opt_event_scheduler= type2state[type-1];
- }
- return FALSE;
-}
-
-
-/**
- Return a string representation of the current scheduler mode.
-*/
-
-const char *
-Events::get_opt_event_scheduler_str()
-{
- const char *str;
-
- pthread_mutex_lock(&LOCK_event_metadata);
- str= opt_typelib.type_names[(int) opt_event_scheduler];
- pthread_mutex_unlock(&LOCK_event_metadata);
-
- return str;
-}
-
-
-/**
Push an error into the error stack if the system tables are
not up to date.
*/
@@ -394,15 +308,6 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
bool save_binlog_row_based;
DBUG_ENTER("Events::create_event");
- /*
- Let's commit the transaction first - MySQL manual specifies
- that a DDL issues an implicit commit, and it doesn't say "successful
- DDL", so that an implicit commit is a property of any successfully
- parsed DDL statement.
- */
- if (end_active_trans(thd))
- DBUG_RETURN(TRUE);
-
if (check_if_system_tables_error())
DBUG_RETURN(TRUE);
@@ -417,9 +322,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
/* At create, one of them must be set */
DBUG_ASSERT(parse_data->expression || parse_data->execute_at);
- if (check_access(thd, EVENT_ACL, parse_data->dbname.str, 0, 0, 0,
- is_schema_db(parse_data->dbname.str,
- parse_data->dbname.length)))
+ if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
if (check_db_dir_existence(parse_data->dbname.str))
@@ -434,10 +337,12 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
Turn off row binlogging of this statement and use statement-based
so that all supporting tables are updated for CREATE EVENT command.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
- pthread_mutex_lock(&LOCK_event_metadata);
+ if (lock_object_name(thd, MDL_key::EVENT,
+ parse_data->dbname.str, parse_data->name.str))
+ DBUG_RETURN(TRUE);
/* On error conditions my_error() is called so no need to handle here */
if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists)))
@@ -475,18 +380,20 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
{
sql_print_error("Event Error: An error occurred while creating query string, "
"before writing it into binary log.");
- /* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
- DBUG_RETURN(TRUE);
+ ret= TRUE;
+ }
+ else
+ {
+ /* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER
+ will be written into the binary log as the definer for the SQL thread. */
+ ret= write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
}
- /* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER
- will be written into the binary log as the definer for the SQL thread. */
- ret= write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
}
}
- pthread_mutex_unlock(&LOCK_event_metadata);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(ret);
}
@@ -521,22 +428,13 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
DBUG_ENTER("Events::update_event");
- /*
- For consistency, implicit COMMIT should be the first thing in the
- execution chain.
- */
- if (end_active_trans(thd))
- DBUG_RETURN(TRUE);
-
if (check_if_system_tables_error())
DBUG_RETURN(TRUE);
if (parse_data->check_parse_data(thd) || parse_data->do_not_create)
DBUG_RETURN(TRUE);
- if (check_access(thd, EVENT_ACL, parse_data->dbname.str, 0, 0, 0,
- is_schema_db(parse_data->dbname.str,
- parse_data->dbname.length)))
+ if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
if (new_dbname) /* It's a rename */
@@ -557,8 +455,7 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
to tell the user that a database doesn't exist if they can not
access it.
*/
- if (check_access(thd, EVENT_ACL, new_dbname->str, 0, 0, 0,
- is_schema_db(new_dbname->str, new_dbname->length)))
+ if (check_access(thd, EVENT_ACL, new_dbname->str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
/* Check that the target database exists */
@@ -573,10 +470,12 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
Turn off row binlogging of this statement and use statement-based
so that all supporting tables are updated for UPDATE EVENT command.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
- pthread_mutex_lock(&LOCK_event_metadata);
+ if (lock_object_name(thd, MDL_key::EVENT,
+ parse_data->dbname.str, parse_data->name.str))
+ DBUG_RETURN(TRUE);
/* On error conditions my_error() is called so no need to handle here */
if (!(ret= db_repository->update_event(thd, parse_data,
@@ -589,10 +488,7 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
ret= TRUE; // OOM
else if ((ret= db_repository->load_named_event(thd, dbname, name,
new_element)))
- {
- DBUG_ASSERT(ret == OP_LOAD_ERROR);
delete new_element;
- }
else
{
/*
@@ -609,9 +505,10 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
}
- pthread_mutex_unlock(&LOCK_event_metadata);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(ret);
}
@@ -648,35 +545,22 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
bool save_binlog_row_based;
DBUG_ENTER("Events::drop_event");
- /*
- In MySQL, DDL must always commit: since mysql.* tables are
- non-transactional, we must modify them outside a transaction
- to not break atomicity.
- But the second and more important reason to commit here
- regardless whether we're actually changing mysql.event table
- or not is replication: end_active_trans syncs the binary log,
- and unless we run DDL in it's own transaction it may simply
- never appear on the slave in case the outside transaction
- rolls back.
- */
- if (end_active_trans(thd))
- DBUG_RETURN(TRUE);
-
if (check_if_system_tables_error())
DBUG_RETURN(TRUE);
- if (check_access(thd, EVENT_ACL, dbname.str, 0, 0, 0,
- is_schema_db(dbname.str, dbname.length)))
+ if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
/*
Turn off row binlogging of this statement and use statement-based so
that all supporting tables are updated for DROP EVENT command.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
- pthread_mutex_lock(&LOCK_event_metadata);
+ if (lock_object_name(thd, MDL_key::EVENT,
+ dbname.str, name.str))
+ DBUG_RETURN(TRUE);
/* On error conditions my_error() is called so no need to handle here */
if (!(ret= db_repository->drop_event(thd, dbname, name, if_exists)))
{
@@ -686,9 +570,10 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
DBUG_ASSERT(thd->query() && thd->query_length());
ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
- pthread_mutex_unlock(&LOCK_event_metadata);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(ret);
}
@@ -713,15 +598,12 @@ Events::drop_schema_events(THD *thd, char *db)
DBUG_PRINT("enter", ("dropping events from %s", db));
/*
- sic: no check if the scheduler is disabled or system tables
+ Sic: no check if the scheduler is disabled or system tables
are damaged, as intended.
*/
-
- pthread_mutex_lock(&LOCK_event_metadata);
if (event_queue)
event_queue->drop_schema_events(thd, db_lex);
db_repository->drop_schema_events(thd, db_lex);
- pthread_mutex_unlock(&LOCK_event_metadata);
DBUG_VOID_RETURN;
}
@@ -749,8 +631,7 @@ send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
field_list.push_back(new Item_empty_string("Event", NAME_CHAR_LEN));
- if (sys_var_thd_sql_mode::symbolic_mode_representation(thd, et->sql_mode,
- &sql_mode))
+ if (sql_mode_string_representation(thd, et->sql_mode, &sql_mode))
DBUG_RETURN(TRUE);
field_list.push_back(new Item_empty_string("sql_mode", (uint) sql_mode.length));
@@ -772,7 +653,7 @@ send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
field_list.push_back(
new Item_empty_string("Database Collation", MY_CS_NAME_SIZE));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
@@ -815,7 +696,6 @@ send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
bool
Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
{
- Open_tables_state open_tables_backup;
Event_timed et;
bool ret;
@@ -825,8 +705,7 @@ Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
if (check_if_system_tables_error())
DBUG_RETURN(TRUE);
- if (check_access(thd, EVENT_ACL, dbname.str, 0, 0, 0,
- is_schema_db(dbname.str, dbname.length)))
+ if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
/*
@@ -839,9 +718,7 @@ Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
deadlock can occur please refer to the description of 'system table'
flag.
*/
- thd->reset_n_backup_open_tables_state(&open_tables_backup);
ret= db_repository->load_named_event(thd, dbname, name, &et);
- thd->restore_backup_open_tables_state(&open_tables_backup);
if (!ret)
ret= send_show_create_event(thd, &et, thd->protocol);
@@ -871,7 +748,6 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
{
char *db= NULL;
int ret;
- Open_tables_state open_tables_backup;
DBUG_ENTER("Events::fill_schema_events");
if (check_if_system_tables_error())
@@ -884,20 +760,13 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
{
DBUG_ASSERT(thd->lex->select_lex.db);
- if (!is_schema_db(thd->lex->select_lex.db) && // There is no events in I_S
- check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0, 0))
+ if (!is_infoschema_db(thd->lex->select_lex.db) && // There is no events in I_S
+ check_access(thd, EVENT_ACL, thd->lex->select_lex.db,
+ NULL, NULL, 0, 0))
DBUG_RETURN(1);
db= thd->lex->select_lex.db;
}
- /*
- Reset and backup of the currently open tables in this thread
- is a way to allow SELECTs from INFORMATION_SCHEMA.events under
- LOCK TABLES and in pre-locked mode. See also
- Events::show_create_event for additional comments.
- */
- thd->reset_n_backup_open_tables_state(&open_tables_backup);
ret= db_repository->fill_schema_events(thd, tables, db);
- thd->restore_backup_open_tables_state(&open_tables_backup);
DBUG_RETURN(ret);
}
@@ -940,7 +809,6 @@ Events::init(my_bool opt_noacl_or_bootstrap)
*/
thd->thread_stack= (char*) &thd;
thd->store_globals();
- lex_start(thd);
/*
We will need Event_db_repository anyway, even if the scheduler is
@@ -1046,33 +914,65 @@ Events::deinit()
DBUG_VOID_RETURN;
}
+#ifdef HAVE_PSI_INTERFACE
+PSI_mutex_key key_LOCK_event_queue,
+ key_event_scheduler_LOCK_scheduler_state;
-/**
- Inits Events mutexes
+static PSI_mutex_info all_events_mutexes[]=
+{
+ { &key_LOCK_event_queue, "LOCK_event_queue", PSI_FLAG_GLOBAL},
+ { &key_event_scheduler_LOCK_scheduler_state, "Event_scheduler::LOCK_scheduler_state", PSI_FLAG_GLOBAL}
+};
- SYNOPSIS
- Events::init_mutexes()
- thd Thread
-*/
+PSI_cond_key key_event_scheduler_COND_state, key_COND_queue_state;
-void
-Events::init_mutexes()
+static PSI_cond_info all_events_conds[]=
{
- pthread_mutex_init(&LOCK_event_metadata, MY_MUTEX_INIT_FAST);
-}
+ { &key_event_scheduler_COND_state, "Event_scheduler::COND_state", PSI_FLAG_GLOBAL},
+ { &key_COND_queue_state, "COND_queue_state", PSI_FLAG_GLOBAL},
+};
+PSI_thread_key key_thread_event_scheduler, key_thread_event_worker;
-/*
- Destroys Events mutexes
+static PSI_thread_info all_events_threads[]=
+{
+ { &key_thread_event_scheduler, "event_scheduler", PSI_FLAG_GLOBAL},
+ { &key_thread_event_worker, "event_worker", 0}
+};
+
+static void init_events_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_events_mutexes);
+ PSI_server->register_mutex(category, all_events_mutexes, count);
+
+ count= array_elements(all_events_conds);
+ PSI_server->register_cond(category, all_events_conds, count);
+
+ count= array_elements(all_events_threads);
+ PSI_server->register_thread(category, all_events_threads, count);
+}
+#endif /* HAVE_PSI_INTERFACE */
+
+/**
+ Inits Events mutexes
SYNOPSIS
- Events::destroy_mutexes()
+ Events::init_mutexes()
+ thd Thread
*/
void
-Events::destroy_mutexes()
+Events::init_mutexes()
{
- pthread_mutex_destroy(&LOCK_event_metadata);
+#ifdef HAVE_PSI_INTERFACE
+ init_events_psi_keys();
+#endif
}
@@ -1094,7 +994,11 @@ Events::dump_internal_status()
puts("LLA = Last Locked At LUA = Last Unlocked At");
puts("WOC = Waiting On Condition DL = Data Locked");
- pthread_mutex_lock(&LOCK_event_metadata);
+ /*
+ opt_event_scheduler should only be accessed while
+ holding LOCK_global_system_variables.
+ */
+ mysql_mutex_lock(&LOCK_global_system_variables);
if (opt_event_scheduler == EVENTS_DISABLED)
puts("The Event Scheduler is disabled");
else
@@ -1103,64 +1007,19 @@ Events::dump_internal_status()
event_queue->dump_internal_status();
}
- pthread_mutex_unlock(&LOCK_event_metadata);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
DBUG_VOID_RETURN;
}
-
-/**
- Starts or stops the event scheduler thread.
-
- @retval FALSE success
- @retval TRUE error
-*/
-
-bool
-Events::switch_event_scheduler_state(enum_opt_event_scheduler new_state)
+bool Events::start()
{
- bool ret= FALSE;
-
- DBUG_ENTER("Events::switch_event_scheduler_state");
-
- DBUG_ASSERT(new_state == Events::EVENTS_ON ||
- new_state == Events::EVENTS_OFF);
-
- /*
- If the scheduler was disabled because there are no/bad
- system tables, produce a more meaningful error message
- than ER_OPTION_PREVENTS_STATEMENT
- */
- if (check_if_system_tables_error())
- DBUG_RETURN(TRUE);
-
- pthread_mutex_lock(&LOCK_event_metadata);
-
- if (opt_event_scheduler == EVENTS_DISABLED)
- {
- my_error(ER_OPTION_PREVENTS_STATEMENT,
- MYF(0), "--event-scheduler=DISABLED or --skip-grant-tables");
- ret= TRUE;
- goto end;
- }
-
- if (new_state == EVENTS_ON)
- ret= scheduler->start();
- else
- ret= scheduler->stop();
-
- if (ret)
- {
- my_error(ER_EVENT_SET_VAR_ERROR, MYF(0));
- goto end;
- }
-
- opt_event_scheduler= new_state;
-
-end:
- pthread_mutex_unlock(&LOCK_event_metadata);
- DBUG_RETURN(ret);
+ return scheduler->start();
}
+bool Events::stop()
+{
+ return scheduler->stop();
+}
/**
Loads all ENABLED events from mysql.event into a prioritized
@@ -1269,8 +1128,7 @@ Events::load_events_from_db(THD *thd)
end:
end_read_record(&read_record_info);
- close_thread_tables(thd);
-
+ close_mysql_tables(thd);
DBUG_RETURN(ret);
}
diff --git a/sql/events.h b/sql/events.h
index 2bc87517748..a337b29049a 100644
--- a/sql/events.h
+++ b/sql/events.h
@@ -1,6 +1,6 @@
#ifndef _EVENT_H_
#define _EVENT_H_
-/* Copyright (C) 2004-2006 MySQL AB
+/* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -13,7 +13,7 @@
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/**
@defgroup Event_Scheduler Event Scheduler
@@ -25,23 +25,23 @@
A public interface of Events_Scheduler module.
*/
-class Event_parse_data;
+#ifdef HAVE_PSI_INTERFACE
+extern PSI_mutex_key key_event_scheduler_LOCK_scheduler_state;
+extern PSI_cond_key key_event_scheduler_COND_state;
+extern PSI_thread_key key_thread_event_scheduler, key_thread_event_worker;
+#endif /* HAVE_PSI_INTERFACE */
+
+#include "sql_string.h" /* LEX_STRING */
+#include "my_time.h" /* interval_type */
+
class Event_db_repository;
+class Event_parse_data;
class Event_queue;
class Event_scheduler;
-
-/* Return codes */
-enum enum_events_error_code
-{
- OP_OK= 0,
- OP_NOT_RUNNING,
- OP_CANT_KILL,
- OP_CANT_INIT,
- OP_DISABLED_EVENT,
- OP_LOAD_ERROR,
- OP_ALREADY_EXISTS
-};
-
+struct TABLE_LIST;
+class THD;
+typedef class Item COND;
+typedef struct charset_info_st CHARSET_INFO;
int
sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
@@ -56,7 +56,7 @@ sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
The life cycle of the Events module is the following:
At server start up:
- set_opt_event_scheduler() -> init_mutexes() -> init()
+ init_mutexes() -> init()
When the server is running:
create_event(), drop_event(), start_or_stop_event_scheduler(), etc
At shutdown:
@@ -70,23 +70,19 @@ sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
class Events
{
public:
- /* The order should match the order in opt_typelib */
- enum enum_opt_event_scheduler
- {
- EVENTS_OFF= 0,
- EVENTS_ON= 1,
- EVENTS_DISABLED= 4
- };
-
- /* Possible values of @@event_scheduler variable */
- static const TYPELIB var_typelib;
-
- static bool
- set_opt_event_scheduler(char *argument);
-
- static const char *
- get_opt_event_scheduler_str();
+ /*
+ the following block is to support --event-scheduler command line option
+ and the @@global.event_scheduler SQL variable.
+ See sys_var.cc
+ */
+ enum enum_opt_event_scheduler { EVENTS_OFF, EVENTS_ON, EVENTS_DISABLED };
+ /* Protected using LOCK_global_system_variables only. */
+ static ulong opt_event_scheduler;
+ static bool check_if_system_tables_error();
+ static bool start();
+ static bool stop();
+public:
/* A hack needed for Event_queue_element */
static Event_db_repository *
get_db_repository() { return db_repository; }
@@ -104,9 +100,6 @@ public:
destroy_mutexes();
static bool
- switch_event_scheduler_state(enum enum_opt_event_scheduler new_state);
-
- static bool
create_event(THD *thd, Event_parse_data *parse_data, bool if_exists);
static bool
@@ -134,20 +127,14 @@ public:
dump_internal_status();
private:
- static bool check_if_system_tables_error();
static bool
load_events_from_db(THD *thd);
private:
- /* Command line option names */
- static const TYPELIB opt_typelib;
- static pthread_mutex_t LOCK_event_metadata;
static Event_queue *event_queue;
static Event_scheduler *scheduler;
static Event_db_repository *db_repository;
- /* Current state of Event Scheduler */
- static enum enum_opt_event_scheduler opt_event_scheduler;
/* Set to TRUE if an error at start up */
static bool check_system_tables_error;
diff --git a/sql/examples/CMakeLists.txt b/sql/examples/CMakeLists.txt
index 1a22e9a3efd..abe4de402bf 100755..100644
--- a/sql/examples/CMakeLists.txt
+++ b/sql/examples/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2006 MySQL AB
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -11,10 +11,10 @@
#
# 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
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFE_MUTEX")
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFE_MUTEX")
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql
${CMAKE_SOURCE_DIR}/extra/yassl/include
diff --git a/sql/field.cc b/sql/field.cc
index 724f8e0af73..e5cae9ea8e3 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -25,15 +25,21 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
#include "sql_select.h"
#include "rpl_rli.h" // Pull in Relay_log_info
#include "slave.h" // Pull in rpl_master_has_bug()
+#include "strfunc.h" // find_type2, find_set
+#include "sql_time.h" // str_to_datetime_with_warn,
+ // str_to_time_with_warn,
+ // TIME_to_timestamp,
+ // make_time, make_date,
+ // make_truncated_value_warning
+#include "tztime.h" // struct Time_zone
+#include "filesort.h" // change_double_for_sort
+#include "log_event.h" // class Table_map_log_event
#include <m_ctype.h>
#include <errno.h>
-#ifdef HAVE_FCONVERT
-#include <floatingpoint.h>
-#endif
// Maximum allowed exponent value for converting string to decimal
#define MAX_EXPONENT 1024
@@ -50,7 +56,7 @@ template class List_iterator<Create_field>;
uchar Field_null::null[1]={1};
const char field_separator=',';
-#define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE 320
+#define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE FLOATING_POINT_BUFFER
#define LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE 128
#define DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE 128
#define BLOB_PACK_LENGTH_TO_MAX_LENGH(arg) \
@@ -59,6 +65,8 @@ const char field_separator=',';
#define ASSERT_COLUMN_MARKED_FOR_READ DBUG_ASSERT(!table || (!table->read_set || bitmap_is_set(table->read_set, field_index)))
#define ASSERT_COLUMN_MARKED_FOR_WRITE DBUG_ASSERT(!table || (!table->write_set || bitmap_is_set(table->write_set, field_index)))
+#define FLAGSTR(S,F) ((S) & (F) ? #F " " : "")
+
/*
Rules for merging different types of fields in UNION
@@ -997,6 +1005,25 @@ test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend)
/**
+ Function to compare two unsigned integers for their relative order.
+ Used below. In an anonymous namespace to not clash with definitions
+ in other files.
+ */
+
+CPP_UNNAMED_NS_START
+
+int compare(unsigned int a, unsigned int b)
+{
+ if (a < b)
+ return -1;
+ if (b < a)
+ return 1;
+ return 0;
+}
+
+CPP_UNNAMED_NS_END
+
+/**
Detect Item_result by given field type of UNION merge result.
@param field_type given field type
@@ -1016,6 +1043,36 @@ Item_result Field::result_merge_type(enum_field_types field_type)
Static help functions
*****************************************************************************/
+/**
+ Output a warning for erroneous conversion of strings to numerical
+ values. For use with ER_TRUNCATED_WRONG_VALUE[_FOR_FIELD]
+
+ @param thd THD object
+ @param str pointer to string that failed to be converted
+ @param length length of string
+ @param cs charset for string
+ @param typestr string describing type converted to
+ @param error error value to output
+ @param field_name (for *_FOR_FIELD) name of field
+ @param row_num (for *_FOR_FIELD) row number
+ */
+static void push_numerical_conversion_warning(THD* thd, const char* str,
+ uint length, CHARSET_INFO* cs,
+ const char* typestr, int error,
+ const char* field_name="UNKNOWN",
+ ulong row_num=0)
+{
+ char buf[max(max(DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE,
+ LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE),
+ DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE)];
+
+ String tmp(buf, sizeof(buf), cs);
+ tmp.copy(str, length, cs);
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ error, ER(error), typestr, tmp.c_ptr(),
+ field_name, row_num);
+}
+
/**
Check whether a field type can be partially indexed by a key.
@@ -1109,14 +1166,12 @@ int Field_num::check_int(CHARSET_INFO *cs, const char *str, int length,
/* Test if we get an empty string or wrong integer */
if (str == int_end || error == MY_ERRNO_EDOM)
{
- char buff[128];
- String tmp(buff, (uint32) sizeof(buff), system_charset_info);
- tmp.copy(str, length, system_charset_info);
+ ErrConvString err(str, length, cs);
push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
- "integer", tmp.c_ptr(), field_name,
- (ulong) table->in_use->row_count);
+ "integer", err.ptr(), field_name,
+ (ulong) table->in_use->warning_info->current_row_for_warning());
return 1;
}
/* Test if we have garbage at the end of the given string. */
@@ -1222,61 +1277,6 @@ int Field::warn_if_overflow(int op_result)
}
-#ifdef NOT_USED
-static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
-{
- cs= system_charset_info; // QQ move test_if_real into CHARSET_INFO struct
-
- while (length && my_isspace(cs,*str))
- { // Allow start space
- length--; str++;
- }
- if (!length)
- return 0;
- if (*str == '+' || *str == '-')
- {
- length--; str++;
- if (!length || !(my_isdigit(cs,*str) || *str == '.'))
- return 0;
- }
- while (length && my_isdigit(cs,*str))
- {
- length--; str++;
- }
- if (!length)
- return 1;
- if (*str == '.')
- {
- length--; str++;
- while (length && my_isdigit(cs,*str))
- {
- length--; str++;
- }
- }
- if (!length)
- return 1;
- if (*str == 'E' || *str == 'e')
- {
- if (length < 3 || (str[1] != '+' && str[1] != '-') ||
- !my_isdigit(cs,str[2]))
- return 0;
- length-=3;
- str+=3;
- while (length && my_isdigit(cs,*str))
- {
- length--; str++;
- }
- }
- for (; length ; length--, str++)
- { // Allow end space
- if (!my_isspace(cs,*str))
- return 0;
- }
- return 1;
-}
-#endif
-
-
/**
Interpret field value as an integer but return the result as a string.
@@ -1329,7 +1329,7 @@ void Field::hash(ulong *nr, ulong *nr2)
else
{
uint len= pack_length();
- CHARSET_INFO *cs= charset();
+ CHARSET_INFO *cs= sort_charset();
cs->coll->hash_sort(cs, ptr, len, nr, nr2);
}
}
@@ -1367,24 +1367,48 @@ bool Field::send_binary(Protocol *protocol)
/**
Check to see if field size is compatible with destination.
- This method is used in row-based replication to verify that the slave's
- field size is less than or equal to the master's field size. The
- encoded field metadata (from the master or source) is decoded and compared
- to the size of this field (the slave or destination).
+ This method is used in row-based replication to verify that the
+ slave's field size is less than or equal to the master's field
+ size. The encoded field metadata (from the master or source) is
+ decoded and compared to the size of this field (the slave or
+ destination).
+
+ @note
+
+ The comparison is made so that if the source data (from the master)
+ is less than the target data (on the slave), -1 is returned in @c
+ <code>*order_var</code>. This implies that a conversion is
+ necessary, but that it is lossy and can result in truncation of the
+ value.
+
+ If the source data is strictly greater than the target data, 1 is
+ returned in <code>*order_var</code>. This implies that the source
+ type can is contained in the target type and that a conversion is
+ necessary but is non-lossy.
+
+ If no conversion is required to fit the source type in the target
+ type, 0 is returned in <code>*order_var</code>.
@param field_metadata Encoded size in field metadata
@param mflags Flags from the table map event for the table.
+ @param order_var Pointer to variable where the order
+ between the source field and this field
+ will be returned.
- @retval 0 if this field's size is < the source field's size
- @retval 1 if this field's size is >= the source field's size
+ @return @c true if this field's size is compatible with the
+ master's field size, @c false otherwise.
*/
-int Field::compatible_field_size(uint field_metadata,
- const Relay_log_info *rli_arg __attribute__((unused)),
- uint16 mflags __attribute__((unused)))
+bool Field::compatible_field_size(uint field_metadata,
+ Relay_log_info *rli_arg __attribute__((unused)),
+ uint16 mflags __attribute__((unused)),
+ int *order_var)
{
uint const source_size= pack_length_from_metadata(field_metadata);
uint const destination_size= row_pack_length();
- return (source_size <= destination_size);
+ DBUG_PRINT("debug", ("real_type: %d, source_size: %u, destination_size: %u",
+ real_type(), source_size, destination_size));
+ *order_var = compare(source_size, destination_size);
+ return true;
}
@@ -1531,7 +1555,12 @@ void Field::make_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->org_table_name= orig_table->s->table_name.str;
+ 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);
+ else
+ field->org_table_name= orig_table->s->table_name.str;
}
else
field->org_table_name= field->db_name= "";
@@ -1735,7 +1764,7 @@ bool Field::get_date(MYSQL_TIME *ltime,uint fuzzydate)
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->ptr(), res->length(),
+ str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
return 1;
return 0;
@@ -1746,7 +1775,7 @@ bool Field::get_time(MYSQL_TIME *ltime)
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_time_with_warn(res->ptr(), res->length(), ltime))
+ str_to_time_with_warn(res->charset(), res->ptr(), res->length(), ltime))
return 1;
return 0;
}
@@ -1763,7 +1792,9 @@ int Field::store_time(MYSQL_TIME *ltime, timestamp_type type_arg)
ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[MAX_DATE_STRING_REP_LENGTH];
uint length= (uint) my_TIME_to_str(ltime, buff);
- return store(buff, length, &my_charset_bin);
+ /* Avoid conversion when field character set is ASCII compatible */
+ return store(buff, length, (charset()->state & MY_CS_NONASCII) ?
+ &my_charset_latin1 : charset());
}
@@ -1773,7 +1804,7 @@ bool Field::optimize_range(uint idx, uint part)
}
-Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field::new_field(MEM_ROOT *root, TABLE *new_table,
bool keep_type __attribute__((unused)))
{
Field *tmp;
@@ -1794,7 +1825,7 @@ Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table,
}
-Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field::new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
@@ -1811,7 +1842,7 @@ Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
/* This is used to generate a field in TABLE from TABLE_SHARE */
-Field *Field::clone(MEM_ROOT *root, struct st_table *new_table)
+Field *Field::clone(MEM_ROOT *root, TABLE *new_table)
{
Field *tmp;
if ((tmp= (Field*) memdup_root(root,(char*) this,size_of())))
@@ -2272,13 +2303,7 @@ int Field_decimal::store(double nr)
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
fyllchar = zerofill ? (char) '0' : (char) ' ';
-#ifdef HAVE_SNPRINTF
- buff[sizeof(buff)-1]=0; // Safety
- snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr);
- length= strlen(buff);
-#else
- length= sprintf(buff, "%.*f", dec, nr);
-#endif
+ length= my_fcvt(nr, dec, buff, NULL);
if (length > field_length)
{
@@ -2361,7 +2386,7 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
size_t tmp_length;
for (str=ptr ; *str == ' ' ; str++) ;
- val_ptr->set_charset(&my_charset_bin);
+ val_ptr->set_charset(&my_charset_numeric);
tmp_length= (size_t) (str-ptr);
if (field_length < tmp_length) // Error in data
val_ptr->length(0);
@@ -2491,7 +2516,7 @@ Field *Field_new_decimal::create_from_item (Item *item)
{
uint8 dec= item->decimals;
uint8 intg= item->decimal_precision() - dec;
- uint32 len= item->max_length;
+ uint32 len= item->max_char_length();
DBUG_ASSERT (item->result_type() == DECIMAL_RESULT);
@@ -2634,15 +2659,12 @@ int Field_new_decimal::store(const char *from, uint length,
&decimal_value)) &&
table->in_use->abort_on_warning)
{
- /* Because "from" is not NUL-terminated and we use %s in the ER() */
- String from_as_str;
- from_as_str.copy(from, length, &my_charset_bin);
-
- push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ErrConvString errmsg(from, length, &my_charset_bin);
+ push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
- "decimal", from_as_str.c_ptr(), field_name,
- (ulong) table->in_use->row_count);
+ "decimal", errmsg.ptr(), field_name,
+ (ulong) table->in_use->warning_info->current_row_for_warning());
DBUG_RETURN(err);
}
@@ -2657,18 +2679,15 @@ int Field_new_decimal::store(const char *from, uint length,
break;
case E_DEC_BAD_NUM:
{
- /* Because "from" is not NUL-terminated and we use %s in the ER() */
- String from_as_str;
- from_as_str.copy(from, length, &my_charset_bin);
-
- push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
- ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
- "decimal", from_as_str.c_ptr(), field_name,
- (ulong) table->in_use->row_count);
- my_decimal_set_zero(&decimal_value);
-
- break;
+ ErrConvString errmsg(from, length, &my_charset_bin);
+ push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ "decimal", errmsg.ptr(), field_name,
+ (ulong) table->in_use->warning_info->
+ current_row_for_warning());
+ my_decimal_set_zero(&decimal_value);
+ break;
}
}
@@ -2697,17 +2716,6 @@ int Field_new_decimal::store(double nr)
err= double2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, nr,
&decimal_value);
- /*
- TODO: fix following when double2my_decimal when double2decimal
- will return E_DEC_TRUNCATED always correctly
- */
- if (!err)
- {
- double nr2;
- my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &nr2);
- if (nr2 != nr)
- err= E_DEC_TRUNCATED;
- }
if (err)
{
if (check_overflow(err))
@@ -2800,6 +2808,7 @@ String *Field_new_decimal::val_str(String *val_buffer,
uint fixed_precision= zerofill ? precision : 0;
my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
fixed_precision, dec, '0', val_buffer);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -2867,34 +2876,16 @@ uint Field_new_decimal::pack_length_from_metadata(uint field_metadata)
}
-/**
- Check to see if field size is compatible with destination.
-
- This method is used in row-based replication to verify that the slave's
- field size is less than or equal to the master's field size. The
- encoded field metadata (from the master or source) is decoded and compared
- to the size of this field (the slave or destination).
-
- @param field_metadata Encoded size in field metadata
-
- @retval 0 if this field's size is < the source field's size
- @retval 1 if this field's size is >= the source field's size
-*/
-int Field_new_decimal::compatible_field_size(uint field_metadata,
- const Relay_log_info * __attribute__((unused)),
- uint16 mflags __attribute__((unused)))
+bool Field_new_decimal::compatible_field_size(uint field_metadata,
+ Relay_log_info * __attribute__((unused)),
+ uint16 mflags __attribute__((unused)),
+ int *order_var)
{
- int compatible= 0;
uint const source_precision= (field_metadata >> 8U) & 0x00ff;
uint const source_decimal= field_metadata & 0x00ff;
- uint const source_size= my_decimal_get_binary_size(source_precision,
- source_decimal);
- uint const destination_size= row_pack_length();
- compatible= (source_size <= destination_size);
- if (compatible)
- compatible= (source_precision <= precision) &&
- (source_decimal <= decimals());
- return (compatible);
+ int order= compare(source_precision, precision);
+ *order_var= order != 0 ? order : compare(source_decimal, dec);
+ return true;
}
@@ -3089,7 +3080,7 @@ String *Field_tiny::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
- CHARSET_INFO *cs= &my_charset_bin;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length;
uint mlength=max(field_length+1,5*cs->mbmaxlen);
val_buffer->alloc(mlength);
@@ -3105,6 +3096,7 @@ String *Field_tiny::val_str(String *val_buffer,
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(cs);
return val_buffer;
}
@@ -3301,7 +3293,7 @@ String *Field_short::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
- CHARSET_INFO *cs= &my_charset_bin;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length;
uint mlength=max(field_length+1,7*cs->mbmaxlen);
val_buffer->alloc(mlength);
@@ -3322,6 +3314,7 @@ String *Field_short::val_str(String *val_buffer,
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(cs);
return val_buffer;
}
@@ -3518,7 +3511,7 @@ String *Field_medium::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
- CHARSET_INFO *cs= &my_charset_bin;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length;
uint mlength=max(field_length+1,10*cs->mbmaxlen);
val_buffer->alloc(mlength);
@@ -3529,6 +3522,7 @@ String *Field_medium::val_str(String *val_buffer,
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer); /* purecov: inspected */
+ val_buffer->set_charset(cs);
return val_buffer;
}
@@ -3737,7 +3731,7 @@ String *Field_long::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
- CHARSET_INFO *cs= &my_charset_bin;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length;
uint mlength=max(field_length+1,12*cs->mbmaxlen);
val_buffer->alloc(mlength);
@@ -3757,6 +3751,7 @@ String *Field_long::val_str(String *val_buffer,
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(cs);
return val_buffer;
}
@@ -3978,7 +3973,7 @@ longlong Field_longlong::val_int(void)
String *Field_longlong::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
- CHARSET_INFO *cs= &my_charset_bin;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length;
uint mlength=max(field_length+1,22*cs->mbmaxlen);
val_buffer->alloc(mlength);
@@ -3996,6 +3991,7 @@ String *Field_longlong::val_str(String *val_buffer,
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(cs);
return val_buffer;
}
@@ -4147,7 +4143,7 @@ int Field_float::store(double nr)
}
else
#endif
- memcpy_fixed(ptr,(uchar*) &j,sizeof(j));
+ memcpy(ptr, &j, sizeof(j));
return error;
}
@@ -4170,7 +4166,7 @@ double Field_float::val_real(void)
}
else
#endif
- memcpy_fixed((uchar*) &j,ptr,sizeof(j));
+ memcpy(&j, ptr, sizeof(j));
return ((double) j);
}
@@ -4184,7 +4180,7 @@ longlong Field_float::val_int(void)
}
else
#endif
- memcpy_fixed((uchar*) &j,ptr,sizeof(j));
+ memcpy(&j, ptr, sizeof(j));
return (longlong) rint(j);
}
@@ -4193,6 +4189,7 @@ String *Field_float::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
+ DBUG_ASSERT(!zerofill || field_length <= MAX_FIELD_CHARLENGTH);
float nr;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4201,74 +4198,33 @@ String *Field_float::val_str(String *val_buffer,
}
else
#endif
- memcpy_fixed((uchar*) &nr,ptr,sizeof(nr));
+ memcpy(&nr, ptr, sizeof(nr));
+
+ uint to_length= 70;
+ if (val_buffer->alloc(to_length))
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return val_buffer;
+ }
- uint to_length=max(field_length,70);
- val_buffer->alloc(to_length);
char *to=(char*) val_buffer->ptr();
+ size_t len;
if (dec >= NOT_FIXED_DEC)
- {
- sprintf(to,"%-*.*g",(int) field_length,FLT_DIG,nr);
- to=strcend(to,' ');
- *to=0;
- }
+ len= my_gcvt(nr, MY_GCVT_ARG_FLOAT, to_length - 1, to, NULL);
else
{
-#ifdef HAVE_FCONVERT
- char buff[70],*pos=buff;
- int decpt,sign,tmp_dec=dec;
-
- VOID(sfconvert(&nr,tmp_dec,&decpt,&sign,buff));
- if (sign)
- {
- *to++='-';
- }
- if (decpt < 0)
- { /* val_buffer is < 0 */
- *to++='0';
- if (!tmp_dec)
- goto end;
- *to++='.';
- if (-decpt > tmp_dec)
- decpt= - (int) tmp_dec;
- tmp_dec=(uint) ((int) tmp_dec+decpt);
- while (decpt++ < 0)
- *to++='0';
- }
- else if (decpt == 0)
- {
- *to++= '0';
- if (!tmp_dec)
- goto end;
- *to++='.';
- }
- else
- {
- while (decpt-- > 0)
- *to++= *pos++;
- if (!tmp_dec)
- goto end;
- *to++='.';
- }
- while (tmp_dec--)
- *to++= *pos++;
-#else
-#ifdef HAVE_SNPRINTF
- to[to_length-1]=0; // Safety
- snprintf(to,to_length-1,"%.*f",dec,nr);
- to=strend(to);
-#else
- to+= sprintf(to, "%.*f", dec, nr);
-#endif
-#endif
+ /*
+ We are safe here because the buffer length is 70, and
+ fabs(float) < 10^39, dec < NOT_FIXED_DEC. So the resulting string
+ will be not longer than 69 chars + terminating '\0'.
+ */
+ len= my_fcvt(nr, dec, to, NULL);
}
-#ifdef HAVE_FCONVERT
- end:
-#endif
- val_buffer->length((uint) (to-val_buffer->ptr()));
+ val_buffer->length((uint) len);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -4285,8 +4241,8 @@ int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr)
else
#endif
{
- memcpy_fixed(&a,a_ptr,sizeof(float));
- memcpy_fixed(&b,b_ptr,sizeof(float));
+ memcpy(&a, a_ptr, sizeof(float));
+ memcpy(&b, b_ptr, sizeof(float));
}
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
@@ -4303,7 +4259,7 @@ void Field_float::sort_string(uchar *to,uint length __attribute__((unused)))
}
else
#endif
- memcpy_fixed(&nr,ptr,sizeof(float));
+ memcpy(&nr, ptr, sizeof(float));
uchar *tmp= to;
if (nr == (float) 0.0)
@@ -4314,7 +4270,7 @@ void Field_float::sort_string(uchar *to,uint length __attribute__((unused)))
else
{
#ifdef WORDS_BIGENDIAN
- memcpy_fixed(tmp,&nr,sizeof(nr));
+ memcpy(tmp, &nr, sizeof(nr));
#else
tmp[0]= ptr[3]; tmp[1]=ptr[2]; tmp[2]= ptr[1]; tmp[3]=ptr[0];
#endif
@@ -4454,8 +4410,12 @@ int Field_real::truncate(double *nr, double max_value)
max_value*= log_10[order];
max_value-= 1.0 / log_10[dec];
- double tmp= rint((res - floor(res)) * log_10[dec]) / log_10[dec];
- res= floor(res) + tmp;
+ /* Check for infinity so we don't get NaN in calculations */
+ if (!my_isinf(res))
+ {
+ double tmp= rint((res - floor(res)) * log_10[dec]) / log_10[dec];
+ res= floor(res) + tmp;
+ }
}
if (res < -max_value)
@@ -4530,10 +4490,11 @@ warn:
char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
String tmp(buf, sizeof(buf), &my_charset_latin1), *str;
str= val_str(&tmp, 0);
+ ErrConvString err(str);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER",
- str->c_ptr());
+ err.ptr());
}
return res;
}
@@ -4551,6 +4512,7 @@ String *Field_double::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
+ DBUG_ASSERT(!zerofill || field_length <= MAX_FIELD_CHARLENGTH);
double nr;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4560,74 +4522,25 @@ String *Field_double::val_str(String *val_buffer,
else
#endif
doubleget(nr,ptr);
-
uint to_length= DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE;
- val_buffer->alloc(to_length);
+ if (val_buffer->alloc(to_length))
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return val_buffer;
+ }
+
char *to=(char*) val_buffer->ptr();
+ size_t len;
if (dec >= NOT_FIXED_DEC)
- {
- sprintf(to,"%-*.*g",(int) field_length,DBL_DIG,nr);
- to=strcend(to,' ');
- }
+ len= my_gcvt(nr, MY_GCVT_ARG_DOUBLE, to_length - 1, to, NULL);
else
- {
-#ifdef HAVE_FCONVERT
- char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- char *pos= buff;
- int decpt,sign,tmp_dec=dec;
+ len= my_fcvt(nr, dec, to, NULL);
- VOID(fconvert(nr,tmp_dec,&decpt,&sign,buff));
- if (sign)
- {
- *to++='-';
- }
- if (decpt < 0)
- { /* val_buffer is < 0 */
- *to++='0';
- if (!tmp_dec)
- goto end;
- *to++='.';
- if (-decpt > tmp_dec)
- decpt= - (int) tmp_dec;
- tmp_dec=(uint) ((int) tmp_dec+decpt);
- while (decpt++ < 0)
- *to++='0';
- }
- else if (decpt == 0)
- {
- *to++= '0';
- if (!tmp_dec)
- goto end;
- *to++='.';
- }
- else
- {
- while (decpt-- > 0)
- *to++= *pos++;
- if (!tmp_dec)
- goto end;
- *to++='.';
- }
- while (tmp_dec--)
- *to++= *pos++;
-#else
-#ifdef HAVE_SNPRINTF
- to[to_length-1]=0; // Safety
- snprintf(to,to_length-1,"%.*f",dec,nr);
- to=strend(to);
-#else
- to+= sprintf(to, "%.*f", dec, nr);
-#endif
-#endif
- }
-#ifdef HAVE_FCONVERT
- end:
-#endif
-
- val_buffer->length((uint) (to-val_buffer->ptr()));
+ val_buffer->length((uint) len);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -4762,7 +4675,7 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
unireg_check_arg, field_name_arg, cs)
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
- flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
+ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG | BINARY_FLAG;
if (!share->timestamp_field && unireg_check != NONE)
{
/* This timestamp has auto-update */
@@ -4782,7 +4695,7 @@ Field_timestamp::Field_timestamp(bool maybe_null_arg,
NONE, field_name_arg, cs)
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
- flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
+ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG | BINARY_FLAG;
if (unireg_check != TIMESTAMP_DN_FIELD)
flags|= ON_UPDATE_NOW_FLAG;
}
@@ -4834,7 +4747,7 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
THD *thd= table ? table->in_use : current_thd;
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
- have_smth_to_conv= (str_to_datetime(from, len, &l_time,
+ have_smth_to_conv= (str_to_datetime(cs, from, len, &l_time,
(thd->variables.sql_mode &
MODE_NO_ZERO_DATE) |
MODE_NO_ZERO_IN_DATE, &error) >
@@ -4983,10 +4896,10 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
if (temp == 0L)
{ /* Zero time is "000000" */
- val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_bin);
+ val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_numeric);
return val_ptr;
}
- val_buffer->set_charset(&my_charset_bin); // Safety
+ val_buffer->set_charset(&my_charset_numeric); // Safety
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,(my_time_t)temp);
@@ -5030,6 +4943,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
*to++= (char) ('0'+(char) (temp2));
*to++= (char) ('0'+(char) (temp));
*to= 0;
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -5140,7 +5054,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
int error= 0;
int warning;
- if (str_to_time(from, len, &ltime, &warning))
+ if (str_to_time(cs, from, len, &ltime, &warning))
{
tmp=0L;
error= 2;
@@ -5299,6 +5213,7 @@ String *Field_time::val_str(String *val_buffer,
ltime.minute= (uint) (tmp/100 % 100);
ltime.second= (uint) (tmp % 100);
make_time((DATE_TIME_FORMAT*) 0, &ltime, val_buffer);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -5318,7 +5233,7 @@ bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
ER(ER_WARN_DATA_OUT_OF_RANGE), field_name,
- thd->row_count);
+ thd->warning_info->current_row_for_warning());
return 1;
}
return Field_time::get_time(ltime);
@@ -5483,6 +5398,7 @@ String *Field_year::val_str(String *val_buffer,
val_buffer->length(field_length);
char *to=(char*) val_buffer->ptr();
sprintf(to,field_length == 2 ? "%02d" : "%04d",(int) Field_year::val_int());
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -5510,7 +5426,7 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
int error;
THD *thd= table ? table->in_use : current_thd;
- if (str_to_datetime(from, len, &l_time, TIME_FUZZY_DATE |
+ if (str_to_datetime(cs, from, len, &l_time, TIME_FUZZY_DATE |
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES)),
@@ -5655,6 +5571,7 @@ String *Field_date::val_str(String *val_buffer,
ltime.month= (int) ((uint32) tmp/100 % 100);
ltime.day= (int) ((uint32) tmp % 100);
make_date((DATE_TIME_FORMAT *) 0, &ltime, val_buffer);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -5744,7 +5661,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
int error;
THD *thd= table ? table->in_use : current_thd;
enum enum_mysql_timestamp_type ret;
- if ((ret= str_to_datetime(from, len, &l_time,
+ if ((ret= str_to_datetime(cs, from, len, &l_time,
(TIME_FUZZY_DATE |
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
@@ -5916,6 +5833,7 @@ String *Field_newdate::val_str(String *val_buffer,
*pos--= (char) ('0'+part%10); part/=10;
*pos--= (char) ('0'+part%10); part/=10;
*pos= (char) ('0'+part);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -5978,7 +5896,7 @@ int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
enum enum_mysql_timestamp_type func_res;
THD *thd= table ? table->in_use : current_thd;
- func_res= str_to_datetime(from, len, &time_tmp,
+ func_res= str_to_datetime(cs, from, len, &time_tmp,
(TIME_FUZZY_DATE |
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
@@ -6178,6 +6096,7 @@ String *Field_datetime::val_str(String *val_buffer,
*pos--= (char) ('0'+(char) (part3%10)); part3/=10;
*pos--= (char) ('0'+(char) (part3%10)); part3/=10;
*pos=(char) ('0'+(char) part3);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -6298,21 +6217,20 @@ check_string_copy_error(Field_str *field,
{
const char *pos;
char tmp[32];
-
+ THD *thd= field->table->in_use;
+
if (!(pos= well_formed_error_pos) &&
!(pos= cannot_convert_error_pos))
return FALSE;
convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6);
- push_warning_printf(field->table->in_use,
- field->table->in_use->abort_on_warning ?
- MYSQL_ERROR::WARN_LEVEL_ERROR :
+ push_warning_printf(thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
"string", tmp, field->field_name,
- (ulong) field->table->in_use->row_count);
+ thd->warning_info->current_row_for_warning());
return TRUE;
}
@@ -6346,7 +6264,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end,
if (test_if_important_data(field_charset, pstr, end))
{
if (table->in_use->abort_on_warning)
- set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1);
else
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
return 2;
@@ -6408,85 +6326,22 @@ int Field_str::store(double nr)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- uint length;
uint local_char_length= field_length / charset()->mbmaxlen;
- double anr= fabs(nr);
- bool fractional= (anr != floor(anr));
- int neg= (nr < 0.0) ? 1 : 0;
- uint max_length;
- int exp;
- uint digits;
- uint i;
-
- /* Calculate the exponent from the 'e'-format conversion */
- if (anr < 1.0 && anr > 0)
- {
- for (exp= 0; anr < 1e-100; exp-= 100, anr*= 1e100) ;
- for (; anr < 1e-10; exp-= 10, anr*= 1e10) ;
- for (i= 1; anr < 1 / log_10[i]; exp--, i++) ;
- exp--;
- }
- else
- {
- for (exp= 0; anr > 1e100; exp+= 100, anr/= 1e100) ;
- for (; anr > 1e10; exp+= 10, anr/= 1e10) ;
- for (i= 1; anr > log_10[i]; exp++, i++) ;
- }
-
- max_length= local_char_length - neg;
+ size_t length= 0;
+ my_bool error= (local_char_length == 0);
- /*
- Since in sprintf("%g") precision means the number of significant digits,
- calculate the maximum number of significant digits if the 'f'-format
- would be used (+1 for decimal point if the number has a fractional part).
- */
- digits= max(1, (int) max_length - fractional);
- /*
- If the exponent is negative, decrease digits by the number of leading zeros
- after the decimal point that do not count as significant digits.
- */
- if (exp < 0)
- digits= max(1, (int) digits + exp);
- /*
- 'e'-format is used only if the exponent is less than -4 or greater than or
- equal to the precision. In this case we need to adjust the number of
- significant digits to take "e+NN" + decimal point into account (hence -5).
- We also have to reserve one additional character if abs(exp) >= 100.
- */
- if (exp >= (int) digits || exp < -4)
- digits= max(1, (int) (max_length - 5 - (exp >= 100 || exp <= -100)));
+ // my_gcvt() requires width > 0, and we may have a CHAR(0) column.
+ if (!error)
+ length= my_gcvt(nr, MY_GCVT_ARG_DOUBLE, local_char_length, buff, &error);
- /* Limit precision to DBL_DIG to avoid garbage past significant digits */
- set_if_smaller(digits, DBL_DIG);
-
- length= (uint) sprintf(buff, "%-.*g", digits, nr);
-
-#ifdef __WIN__
- /*
- Windows always zero-pads the exponent to 3 digits, we want to remove the
- leading 0 to match the sprintf() output on other platforms.
- */
- if ((exp >= (int) digits || exp < -4) && exp > -100 && exp < 100)
+ if (error)
{
- DBUG_ASSERT(length >= 6); /* 1e+NNN */
- uint tmp= length - 3;
- buff[tmp]= buff[tmp + 1];
- tmp++;
- buff[tmp]= buff[tmp + 1];
- length--;
+ if (table->in_use->abort_on_warning)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1);
+ else
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
}
-#endif
-
- /*
- +1 below is because "precision" in %g above means the
- max. number of significant digits, not the output width.
- Thus the width can be larger than number of significant digits by 1
- (for decimal point)
- the test for local_char_length < 5 is for extreme cases,
- like inserting 500.0 in char(1)
- */
- DBUG_ASSERT(local_char_length < 5 || length <= local_char_length+1);
- return store(buff, length, charset());
+ return store(buff, length, &my_charset_numeric);
}
@@ -6521,7 +6376,7 @@ int Field_string::store(longlong nr, bool unsigned_val)
int Field_longstr::store_decimal(const my_decimal *d)
{
char buff[DECIMAL_MAX_STR_LENGTH+1];
- String str(buff, sizeof(buff), &my_charset_bin);
+ String str(buff, sizeof(buff), &my_charset_numeric);
my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
return store(str.ptr(), str.length(), str.charset());
}
@@ -6546,13 +6401,11 @@ double Field_string::val_real(void)
!check_if_only_end_space(cs, end,
(char*) ptr + field_length))))
{
- char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- String tmp(buf, sizeof(buf), cs);
- tmp.copy((char*) ptr, field_length, cs);
+ ErrConvString err((char*) ptr, field_length, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE,
- ER(ER_TRUNCATED_WRONG_VALUE),
- "DOUBLE", tmp.c_ptr());
+ ER_TRUNCATED_WRONG_VALUE,
+ ER(ER_TRUNCATED_WRONG_VALUE), "DOUBLE",
+ err.ptr());
}
return result;
}
@@ -6572,13 +6425,11 @@ longlong Field_string::val_int(void)
!check_if_only_end_space(cs, end,
(char*) ptr + field_length))))
{
- char buf[LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE];
- String tmp(buf, sizeof(buf), cs);
- tmp.copy((char*) ptr, field_length, cs);
+ ErrConvString err((char*) ptr, field_length, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
- "INTEGER", tmp.c_ptr());
+ "INTEGER", err.ptr());
}
return result;
}
@@ -6610,14 +6461,11 @@ my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
charset(), decimal_value);
if (!table->in_use->no_errors && err)
{
- char buf[DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE];
- CHARSET_INFO *cs= charset();
- String tmp(buf, sizeof(buf), cs);
- tmp.copy((char*) ptr, field_length, cs);
+ ErrConvString errmsg((char*) ptr, field_length, charset());
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
- "DECIMAL", tmp.c_ptr());
+ "DECIMAL", errmsg.ptr());
}
return decimal_value;
@@ -6642,9 +6490,11 @@ check_field_for_37426(const void *param_arg)
}
#endif
-int Field_string::compatible_field_size(uint field_metadata,
- const Relay_log_info *rli_arg,
- uint16 mflags __attribute__((unused)))
+bool
+Field_string::compatible_field_size(uint field_metadata,
+ Relay_log_info *rli_arg,
+ uint16 mflags __attribute__((unused)),
+ int *order_var)
{
#ifdef HAVE_REPLICATION
const Check_field_param check_param = { this };
@@ -6652,7 +6502,7 @@ int Field_string::compatible_field_size(uint field_metadata,
check_field_for_37426, &check_param))
return FALSE; // Not compatible field sizes
#endif
- return Field::compatible_field_size(field_metadata, rli_arg, mflags);
+ return Field::compatible_field_size(field_metadata, rli_arg, mflags, order_var);
}
@@ -6681,9 +6531,8 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_string::sort_string(uchar *to,uint length)
{
- IF_DBUG(uint tmp=) my_strnxfrm(field_charset,
- to, length,
- ptr, field_length);
+ uint tmp __attribute__((unused))=
+ my_strnxfrm(field_charset, to, length, ptr, field_length);
DBUG_ASSERT(tmp == length);
}
@@ -6714,12 +6563,26 @@ uchar *Field_string::pack(uchar *to, const uchar *from,
{
uint length= min(field_length,max_length);
uint local_char_length= max_length/field_charset->mbmaxlen;
+ DBUG_PRINT("debug", ("Packing field '%s' - length: %u ", field_name, length));
+
if (length > local_char_length)
local_char_length= my_charpos(field_charset, from, from+length,
local_char_length);
set_if_smaller(length, local_char_length);
- while (length && from[length-1] == field_charset->pad_char)
- length--;
+
+ /*
+ TODO: change charset interface to add a new function that does
+ the following or add a flag to lengthsp to do it itself
+ (this is for not packing padding adding bytes in BINARY
+ fields).
+ */
+ if (field_charset->mbmaxlen == 1)
+ {
+ while (length && from[length-1] == field_charset->pad_char)
+ length --;
+ }
+ else
+ length= field_charset->cset->lengthsp(field_charset, (const char*) from, length);
// Length always stored little-endian
*to++= (uchar) length;
@@ -6785,7 +6648,7 @@ Field_string::unpack(uchar *to,
memcpy(to, from, length);
// Pad the string with the pad character of the fields charset
- bfill(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;
}
@@ -6832,86 +6695,6 @@ int Field_string::do_save_field_metadata(uchar *metadata_ptr)
}
-/*
- Compare two packed keys
-
- SYNOPSIS
- pack_cmp()
- a New key
- b Original key
- length Key length
- insert_or_update 1 if this is an insert or update
-
- RETURN
- < 0 a < b
- 0 a = b
- > 0 a > b
-*/
-
-int Field_string::pack_cmp(const uchar *a, const uchar *b, uint length,
- my_bool insert_or_update)
-{
- uint a_length, b_length;
- if (length > 255)
- {
- a_length= uint2korr(a);
- b_length= uint2korr(b);
- a+= 2;
- b+= 2;
- }
- else
- {
- a_length= (uint) *a++;
- b_length= (uint) *b++;
- }
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length,
- b, b_length,
- insert_or_update);
-}
-
-
-/**
- Compare a packed key against row.
-
- @param key Original key
- @param length Key length. (May be less than field length)
- @param insert_or_update 1 if this is an insert or update
-
- @return
- < 0 row < key
- @return
- 0 row = key
- @return
- > 0 row > key
-*/
-
-int Field_string::pack_cmp(const uchar *key, uint length,
- my_bool insert_or_update)
-{
- uint row_length, local_key_length;
- uchar *end;
- if (length > 255)
- {
- local_key_length= uint2korr(key);
- key+= 2;
- }
- else
- local_key_length= (uint) *key++;
-
- /* Only use 'length' of key, not field_length */
- end= ptr + length;
- while (end > ptr && end[-1] == ' ')
- end--;
- row_length= (uint) (end - ptr);
-
- return field_charset->coll->strnncollsp(field_charset,
- ptr, row_length,
- key, local_key_length,
- insert_or_update);
-}
-
-
uint Field_string::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
@@ -6939,7 +6722,7 @@ uint Field_string::get_key_image(uchar *buff, uint length, imagetype type_arg)
}
-Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field_string::new_field(MEM_ROOT *root, TABLE *new_table,
bool keep_type)
{
Field *field;
@@ -7049,22 +6832,46 @@ int Field_varstring::store(longlong nr, bool unsigned_val)
double Field_varstring::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- int not_used;
- char *end_not_used;
+ int error;
+ char *end;
+ double result;
+ CHARSET_INFO* cs= charset();
+
uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- return my_strntod(field_charset, (char*) ptr+length_bytes, length,
- &end_not_used, &not_used);
+ result= my_strntod(cs, (char*)ptr+length_bytes, length, &end, &error);
+
+ if (!table->in_use->no_errors &&
+ (error || (length != (uint)(end - (char*)ptr+length_bytes) &&
+ !check_if_only_end_space(cs, end, (char*)ptr+length_bytes+length))))
+ {
+ push_numerical_conversion_warning(current_thd, (char*)ptr+length_bytes,
+ length, cs,"DOUBLE",
+ ER_TRUNCATED_WRONG_VALUE);
+ }
+ return result;
}
longlong Field_varstring::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- int not_used;
- char *end_not_used;
+ int error;
+ char *end;
+ CHARSET_INFO *cs= charset();
+
uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- return my_strntoll(field_charset, (char*) ptr+length_bytes, length, 10,
- &end_not_used, &not_used);
+ longlong result= my_strntoll(cs, (char*) ptr+length_bytes, length, 10,
+ &end, &error);
+
+ if (!table->in_use->no_errors &&
+ (error || (length != (uint)(end - (char*)ptr+length_bytes) &&
+ !check_if_only_end_space(cs, end, (char*)ptr+length_bytes+length))))
+ {
+ push_numerical_conversion_warning(current_thd, (char*)ptr+length_bytes,
+ length, cs, "INTEGER",
+ ER_TRUNCATED_WRONG_VALUE);
+ }
+ return result;
}
String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
@@ -7080,9 +6887,17 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value)
{
ASSERT_COLUMN_MARKED_FOR_READ;
+ CHARSET_INFO *cs= charset();
uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr+length_bytes, length,
- charset(), decimal_value);
+ int error= str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr+length_bytes, length,
+ cs, decimal_value);
+
+ if (!table->in_use->no_errors && error)
+ {
+ push_numerical_conversion_warning(current_thd, (char*)ptr+length_bytes,
+ length, cs, "DECIMAL",
+ ER_TRUNCATED_WRONG_VALUE);
+ }
return decimal_value;
}
@@ -7238,90 +7053,6 @@ uchar *Field_varstring::pack(uchar *to, const uchar *from,
}
-uchar *
-Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length,
- bool low_byte_first __attribute__((unused)))
-{
- uint length= length_bytes == 1 ? (uint) *key : uint2korr(key);
- uint local_char_length= ((field_charset->mbmaxlen > 1) ?
- max_length/field_charset->mbmaxlen : max_length);
- key+= length_bytes;
- if (length > local_char_length)
- {
- local_char_length= my_charpos(field_charset, key, key+length,
- local_char_length);
- set_if_smaller(length, local_char_length);
- }
- *to++= (char) (length & 255);
- if (max_length > 255)
- *to++= (char) (length >> 8);
- if (length)
- memcpy(to, key, length);
- return to+length;
-}
-
-
-/**
- Unpack a key into a record buffer.
-
- A VARCHAR key has a maximum size of 64K-1.
- In its packed form, the length field is one or two bytes long,
- depending on 'max_length'.
-
- @param to Pointer into the record buffer.
- @param key Pointer to the packed key.
- @param max_length Key length limit from key description.
-
- @return
- Pointer to end of 'key' (To the next key part if multi-segment key)
-*/
-
-const uchar *
-Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length,
- bool low_byte_first __attribute__((unused)))
-{
- /* get length of the blob key */
- uint32 length= *key++;
- if (max_length > 255)
- length+= (*key++) << 8;
-
- /* put the length into the record buffer */
- if (length_bytes == 1)
- *ptr= (uchar) length;
- else
- int2store(ptr, length);
- memcpy(ptr + length_bytes, key, length);
- return key + length;
-}
-
-/**
- Create a packed key that will be used for storage in the index tree.
-
- @param to Store packed key segment here
- @param from Key segment (as given to index_read())
- @param max_length Max length of key
-
- @return
- end of key storage
-*/
-
-uchar *
-Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length,
- bool low_byte_first __attribute__((unused)))
-{
- /* Key length is always stored as 2 bytes */
- uint length= uint2korr(from);
- if (length > max_length)
- length= max_length;
- *to++= (char) (length & 255);
- if (max_length > 255)
- *to++= (char) (length >> 8);
- if (length)
- memcpy(to, from+HA_KEY_BLOB_LENGTH, length);
- return to+length;
-}
-
-
/**
Unpack a varstring field from row data.
@@ -7364,59 +7095,6 @@ Field_varstring::unpack(uchar *to, const uchar *from,
}
-int Field_varstring::pack_cmp(const uchar *a, const uchar *b,
- uint key_length_arg,
- my_bool insert_or_update)
-{
- uint a_length, b_length;
- if (key_length_arg > 255)
- {
- a_length=uint2korr(a); a+= 2;
- b_length=uint2korr(b); b+= 2;
- }
- else
- {
- a_length= (uint) *a++;
- b_length= (uint) *b++;
- }
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length,
- b, b_length,
- insert_or_update);
-}
-
-
-int Field_varstring::pack_cmp(const uchar *b, uint key_length_arg,
- my_bool insert_or_update)
-{
- uchar *a= ptr+ length_bytes;
- uint a_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- uint b_length;
- uint local_char_length= ((field_charset->mbmaxlen > 1) ?
- key_length_arg / field_charset->mbmaxlen :
- key_length_arg);
-
- if (key_length_arg > 255)
- {
- b_length=uint2korr(b); b+= HA_KEY_BLOB_LENGTH;
- }
- else
- b_length= (uint) *b++;
-
- if (a_length > local_char_length)
- {
- local_char_length= my_charpos(field_charset, a, a+a_length,
- local_char_length);
- set_if_smaller(a_length, local_char_length);
- }
-
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length,
- b, b_length,
- insert_or_update);
-}
-
-
uint Field_varstring::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
@@ -7484,7 +7162,7 @@ int Field_varstring::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
}
-Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field_varstring::new_field(MEM_ROOT *root, TABLE *new_table,
bool keep_type)
{
Field_varstring *res= (Field_varstring*) Field::new_field(root, new_table,
@@ -7496,7 +7174,7 @@ Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table,
Field *Field_varstring::new_key_field(MEM_ROOT *root,
- struct st_table *new_table,
+ TABLE *new_table,
uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
@@ -7560,6 +7238,7 @@ Field_blob::Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
cs),
packlength(blob_pack_length)
{
+ DBUG_ASSERT(blob_pack_length <= 4); // Only pack lengths 1-4 supported currently
flags|= BLOB_FLAG;
share->blob_fields++;
/* TODO: why do not fill table->s->blob_field array here? */
@@ -7754,7 +7433,7 @@ oom_error:
int Field_blob::store(double nr)
{
CHARSET_INFO *cs=charset();
- value.set_real(nr, 2, cs);
+ value.set_real(nr, NOT_FIXED_DEC, cs);
return Field_blob::store(value.ptr(),(uint) value.length(), cs);
}
@@ -7775,7 +7454,7 @@ double Field_blob::val_real(void)
uint32 length;
CHARSET_INFO *cs;
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ memcpy(&blob, ptr+packlength, sizeof(char*));
if (!blob)
return 0.0;
length= get_length(ptr);
@@ -7789,7 +7468,7 @@ longlong Field_blob::val_int(void)
ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *blob;
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ memcpy(&blob, ptr+packlength, sizeof(char*));
if (!blob)
return 0;
uint32 length=get_length(ptr);
@@ -7801,7 +7480,7 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
{
ASSERT_COLUMN_MARKED_FOR_READ;
char *blob;
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ memcpy(&blob, ptr+packlength, sizeof(char*));
if (!blob)
val_ptr->set("",0,charset()); // A bit safer than ->length(0)
else
@@ -7815,7 +7494,7 @@ my_decimal *Field_blob::val_decimal(my_decimal *decimal_value)
ASSERT_COLUMN_MARKED_FOR_READ;
const char *blob;
size_t length;
- memcpy_fixed(&blob, ptr+packlength, sizeof(const uchar*));
+ memcpy(&blob, ptr+packlength, sizeof(const uchar*));
if (!blob)
{
blob= "";
@@ -7843,8 +7522,8 @@ int Field_blob::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
uint max_length)
{
uchar *blob1,*blob2;
- memcpy_fixed(&blob1,a_ptr+packlength,sizeof(char*));
- memcpy_fixed(&blob2,b_ptr+packlength,sizeof(char*));
+ memcpy(&blob1, a_ptr+packlength, sizeof(char*));
+ memcpy(&blob2, b_ptr+packlength, sizeof(char*));
uint a_len= get_length(a_ptr), b_len= get_length(b_ptr);
set_if_smaller(a_len, max_length);
set_if_smaller(b_len, max_length);
@@ -7858,8 +7537,8 @@ int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
char *a,*b;
uint diff;
uint32 a_length,b_length;
- memcpy_fixed(&a,a_ptr+packlength,sizeof(char*));
- memcpy_fixed(&b,b_ptr+packlength,sizeof(char*));
+ memcpy(&a, a_ptr+packlength, sizeof(char*));
+ memcpy(&b, b_ptr+packlength, sizeof(char*));
a_length=get_length(a_ptr);
if (a_length > max_length)
a_length=max_length;
@@ -7940,7 +7619,7 @@ int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length)
{
uchar *blob1;
uint blob_length=get_length(ptr);
- memcpy_fixed(&blob1,ptr+packlength,sizeof(char*));
+ memcpy(&blob1, ptr+packlength, sizeof(char*));
CHARSET_INFO *cs= charset();
uint local_char_length= max_key_length / cs->mbmaxlen;
local_char_length= my_charpos(cs, blob1, blob1+blob_length,
@@ -7970,8 +7649,10 @@ int Field_blob::key_cmp(const uchar *a,const uchar *b)
*/
int Field_blob::do_save_field_metadata(uchar *metadata_ptr)
{
+ DBUG_ENTER("Field_blob::do_save_field_metadata");
*metadata_ptr= pack_length_no_ptr();
- return 1;
+ DBUG_PRINT("debug", ("metadata: %u (pack_length_no_ptr)", *metadata_ptr));
+ DBUG_RETURN(1);
}
@@ -8016,7 +7697,7 @@ void Field_blob::sort_string(uchar *to,uint length)
break;
}
}
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ memcpy(&blob, ptr+packlength, sizeof(char*));
blob_length=my_strnxfrm(field_charset,
to, length, blob, blob_length);
@@ -8047,12 +7728,6 @@ void Field_blob::sql_type(String &res) const
uchar *Field_blob::pack(uchar *to, const uchar *from,
uint max_length, bool low_byte_first)
{
- DBUG_ENTER("Field_blob::pack");
- DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;"
- " max_length: %u; low_byte_first: %d",
- (ulong) to, (ulong) from,
- max_length, low_byte_first));
- DBUG_DUMP("record", from, table->s->reclength);
uchar *save= ptr;
ptr= (uchar*) from;
uint32 length=get_length(); // Length of from string
@@ -8073,8 +7748,7 @@ uchar *Field_blob::pack(uchar *to, const uchar *from,
memcpy(to+packlength, from,length);
}
ptr=save; // Restore org row pointer
- DBUG_DUMP("packed", to, packlength + length);
- DBUG_RETURN(to+packlength+length);
+ return to+packlength+length;
}
@@ -8115,139 +7789,6 @@ const uchar *Field_blob::unpack(uchar *to,
DBUG_RETURN(from + master_packlength + length);
}
-/* Keys for blobs are like keys on varchars */
-
-int Field_blob::pack_cmp(const uchar *a, const uchar *b, uint key_length_arg,
- my_bool insert_or_update)
-{
- uint a_length, b_length;
- if (key_length_arg > 255)
- {
- a_length=uint2korr(a); a+=2;
- b_length=uint2korr(b); b+=2;
- }
- else
- {
- a_length= (uint) *a++;
- b_length= (uint) *b++;
- }
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length,
- b, b_length,
- insert_or_update);
-}
-
-
-int Field_blob::pack_cmp(const uchar *b, uint key_length_arg,
- my_bool insert_or_update)
-{
- uchar *a;
- uint a_length, b_length;
- memcpy_fixed(&a,ptr+packlength,sizeof(char*));
- if (!a)
- return key_length_arg > 0 ? -1 : 0;
-
- a_length= get_length(ptr);
- if (key_length_arg > 255)
- {
- b_length= uint2korr(b); b+=2;
- }
- else
- b_length= (uint) *b++;
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length,
- b, b_length,
- insert_or_update);
-}
-
-/** Create a packed key that will be used for storage from a MySQL row. */
-
-uchar *
-Field_blob::pack_key(uchar *to, const uchar *from, uint max_length,
- bool low_byte_first __attribute__((unused)))
-{
- uchar *save= ptr;
- ptr= (uchar*) from;
- uint32 length=get_length(); // Length of from string
- uint local_char_length= ((field_charset->mbmaxlen > 1) ?
- max_length/field_charset->mbmaxlen : max_length);
- if (length)
- get_ptr((uchar**) &from);
- if (length > local_char_length)
- local_char_length= my_charpos(field_charset, from, from+length,
- local_char_length);
- set_if_smaller(length, local_char_length);
- *to++= (uchar) length;
- if (max_length > 255) // 2 byte length
- *to++= (uchar) (length >> 8);
- memcpy(to, from, length);
- ptr=save; // Restore org row pointer
- return to+length;
-}
-
-
-/**
- Unpack a blob key into a record buffer.
-
- A blob key has a maximum size of 64K-1.
- In its packed form, the length field is one or two bytes long,
- depending on 'max_length'.
- Depending on the maximum length of a blob, its length field is
- put into 1 to 4 bytes. This is a property of the blob object,
- described by 'packlength'.
- Blobs are internally stored apart from the record buffer, which
- contains a pointer to the blob buffer.
-
-
- @param to Pointer into the record buffer.
- @param from Pointer to the packed key.
- @param max_length Key length limit from key description.
-
- @return
- Pointer into 'from' past the last byte copied from packed key.
-*/
-
-const uchar *
-Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length,
- bool low_byte_first __attribute__((unused)))
-{
- /* get length of the blob key */
- uint32 length= *from++;
- if (max_length > 255)
- length+= *from++ << 8;
-
- /* put the length into the record buffer */
- put_length(to, length);
-
- /* put the address of the blob buffer or NULL */
- if (length)
- memcpy_fixed(to + packlength, &from, sizeof(from));
- else
- bzero(to + packlength, sizeof(from));
-
- /* point to first byte of next field in 'from' */
- return from + length;
-}
-
-
-/** Create a packed key that will be used for storage from a MySQL key. */
-
-uchar *
-Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length,
- bool low_byte_first __attribute__((unused)))
-{
- uint length=uint2korr(from);
- if (length > max_length)
- length=max_length;
- *to++= (char) (length & 255);
- if (max_length > 255)
- *to++= (char) (length >> 8);
- if (length)
- memcpy(to, from+HA_KEY_BLOB_LENGTH, length);
- return to+length;
-}
-
-
uint Field_blob::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
@@ -8625,7 +8166,7 @@ void Field_enum::sql_type(String &res) const
}
-Field *Field_enum::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field_enum::new_field(MEM_ROOT *root, TABLE *new_table,
bool keep_type)
{
Field_enum *res= (Field_enum*) Field::new_field(root, new_table, keep_type);
@@ -8851,6 +8392,54 @@ uint Field_enum::is_equal(Create_field *new_field)
}
+uchar *Field_enum::pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first)
+{
+ DBUG_ENTER("Field_enum::pack");
+ DBUG_PRINT("debug", ("packlength: %d", packlength));
+ DBUG_DUMP("from", from, packlength);
+
+ switch (packlength)
+ {
+ case 1:
+ *to = *from;
+ DBUG_RETURN(to + 1);
+ case 2: DBUG_RETURN(pack_int16(to, from, low_byte_first));
+ case 3: DBUG_RETURN(pack_int24(to, from, low_byte_first));
+ case 4: DBUG_RETURN(pack_int32(to, from, low_byte_first));
+ case 8: DBUG_RETURN(pack_int64(to, from, low_byte_first));
+ default:
+ DBUG_ASSERT(0);
+ }
+ MY_ASSERT_UNREACHABLE();
+ DBUG_RETURN(NULL);
+}
+
+const uchar *Field_enum::unpack(uchar *to, const uchar *from,
+ uint param_data, bool low_byte_first)
+{
+ DBUG_ENTER("Field_enum::unpack");
+ DBUG_PRINT("debug", ("packlength: %d", packlength));
+ DBUG_DUMP("from", from, packlength);
+
+ switch (packlength)
+ {
+ case 1:
+ *to = *from;
+ DBUG_RETURN(from + 1);
+
+ case 2: DBUG_RETURN(unpack_int16(to, from, low_byte_first));
+ case 3: DBUG_RETURN(unpack_int24(to, from, low_byte_first));
+ case 4: DBUG_RETURN(unpack_int32(to, from, low_byte_first));
+ case 8: DBUG_RETURN(unpack_int64(to, from, low_byte_first));
+ default:
+ DBUG_ASSERT(0);
+ }
+ MY_ASSERT_UNREACHABLE();
+ DBUG_RETURN(NULL);
+}
+
+
/**
@return
returns 1 if the fields are equally defined
@@ -8923,6 +8512,9 @@ Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7),
bytes_in_rec(len_arg / 8)
{
+ DBUG_ENTER("Field_bit::Field_bit");
+ DBUG_PRINT("enter", ("ptr_arg: %p, null_ptr_arg: %p, len_arg: %u, bit_len: %u, bytes_in_rec: %u",
+ ptr_arg, null_ptr_arg, len_arg, bit_len, bytes_in_rec));
flags|= UNSIGNED_FLAG;
/*
Ensure that Field::eq() can distinguish between two different bit fields.
@@ -8930,6 +8522,7 @@ Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
*/
if (!null_ptr_arg)
null_bit= bit_ofs_arg;
+ DBUG_VOID_RETURN;
}
@@ -8978,7 +8571,7 @@ Field_bit::do_last_null_byte() const
Field *Field_bit::new_key_field(MEM_ROOT *root,
- struct st_table *new_table,
+ TABLE *new_table,
uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
@@ -9019,7 +8612,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
set_rec_bits((1 << bit_len) - 1, bit_ptr, bit_ofs, bit_len);
memset(ptr, 0xff, bytes_in_rec);
if (table->in_use->really_abort_on_warning())
- set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1);
else
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
return 1;
@@ -9114,7 +8707,7 @@ String *Field_bit::val_str(String *val_buffer,
mi_int8store(buff,bits);
val_buffer->alloc(length);
- memcpy_fixed((char*) val_buffer->ptr(), buff+8-length, length);
+ memcpy((char *) val_buffer->ptr(), buff+8-length, length);
val_buffer->length(length);
val_buffer->set_charset(&my_charset_bin);
return val_buffer;
@@ -9214,6 +8807,9 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg)
*/
int Field_bit::do_save_field_metadata(uchar *metadata_ptr)
{
+ DBUG_ENTER("Field_bit::do_save_field_metadata");
+ DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d",
+ bit_len, bytes_in_rec));
/*
Since this class and Field_bit_as_char have different ideas of
what should be stored here, we compute the values of the metadata
@@ -9221,7 +8817,7 @@ int Field_bit::do_save_field_metadata(uchar *metadata_ptr)
*/
metadata_ptr[0]= field_length % 8;
metadata_ptr[1]= field_length / 8;
- return 2;
+ DBUG_RETURN(2);
}
@@ -9246,26 +8842,19 @@ uint Field_bit::pack_length_from_metadata(uint field_metadata)
}
-/**
- Check to see if field size is compatible with destination.
-
- This method is used in row-based replication to verify that the slave's
- field size is less than or equal to the master's field size. The
- encoded field metadata (from the master or source) is decoded and compared
- to the size of this field (the slave or destination).
-
- @param field_metadata Encoded size in field metadata
-
- @retval 0 if this field's size is < the source field's size
- @retval 1 if this field's size is >= the source field's size
-*/
-int Field_bit::compatible_field_size(uint field_metadata,
- const Relay_log_info * __attribute__((unused)),
- uint16 mflags)
+bool
+Field_bit::compatible_field_size(uint field_metadata,
+ Relay_log_info * __attribute__((unused)),
+ uint16 mflags,
+ int *order_var)
{
- uint from_bit_len= 8 * (field_metadata >> 8) + (field_metadata & 0xff);
+ DBUG_ENTER("Field_bit::compatible_field_size");
+ DBUG_ASSERT((field_metadata >> 16) == 0);
+ uint from_bit_len=
+ 8 * (field_metadata >> 8) + (field_metadata & 0xff);
uint to_bit_len= max_display_length();
-
+ DBUG_PRINT("debug", ("from_bit_len: %u, to_bit_len: %u",
+ from_bit_len, to_bit_len));
/*
If the bit length exact flag is clear, we are dealing with an old
master, so we allow some less strict behaviour if replicating by
@@ -9279,7 +8868,8 @@ int Field_bit::compatible_field_size(uint field_metadata,
to_bit_len= (to_bit_len + 7) / 8;
}
- return from_bit_len <= to_bit_len;
+ *order_var= compare(from_bit_len, to_bit_len);
+ DBUG_RETURN(TRUE);
}
@@ -9345,8 +8935,15 @@ const uchar *
Field_bit::unpack(uchar *to, const uchar *from, uint param_data,
bool low_byte_first __attribute__((unused)))
{
+ DBUG_ENTER("Field_bit::unpack");
+ DBUG_PRINT("enter", ("to: %p, from: %p, param_data: 0x%x",
+ to, from, param_data));
+ DBUG_PRINT("debug", ("bit_ptr: %p, bit_len: %u, bit_ofs: %u",
+ bit_ptr, bit_len, bit_ofs));
uint const from_len= (param_data >> 8U) & 0x00ff;
uint const from_bit_len= param_data & 0x00ff;
+ DBUG_PRINT("debug", ("from_len: %u, from_bit_len: %u",
+ from_len, from_bit_len));
/*
If the parameter data is zero (i.e., undefined), or if the master
and slave have the same sizes, then use the old unpack() method.
@@ -9367,7 +8964,7 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data,
from++;
}
memcpy(to, from, bytes_in_rec);
- return from + bytes_in_rec;
+ DBUG_RETURN(from + bytes_in_rec);
}
/*
@@ -9393,7 +8990,7 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data,
bitmap_set_bit(table->write_set,field_index);
store(value, new_len, system_charset_info);
my_afree(value);
- return from + len;
+ DBUG_RETURN(from + len);
}
@@ -9441,7 +9038,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
if (bits)
*ptr&= ((1 << bits) - 1); /* set first uchar */
if (table->in_use->really_abort_on_warning())
- set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1);
else
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
return 1;
@@ -9521,8 +9118,11 @@ void Create_field::create_length_to_internal_length(void)
*/
void Create_field::init_for_tmp_table(enum_field_types sql_type_arg,
uint32 length_arg, uint32 decimals_arg,
- bool maybe_null, bool is_unsigned)
+ bool maybe_null, bool is_unsigned,
+ uint pack_length_arg)
{
+ DBUG_ENTER("Create_field::init_for_tmp_table");
+
field_name= "";
sql_type= sql_type_arg;
char_length= length= length_arg;;
@@ -9530,10 +9130,93 @@ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg,
interval= 0;
charset= &my_charset_bin;
geom_type= Field::GEOM_GEOMETRY;
- pack_flag= (FIELDFLAG_NUMBER |
- ((decimals_arg & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
- (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
- (is_unsigned ? 0 : FIELDFLAG_DECIMAL));
+
+ DBUG_PRINT("enter", ("sql_type: %d, length: %u, pack_length: %u",
+ sql_type_arg, length_arg, pack_length_arg));
+
+ /*
+ These pack flags are crafted to get it correctly through the
+ branches of make_field().
+ */
+ switch (sql_type_arg)
+ {
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_SET:
+ pack_flag= 0;
+ break;
+
+ case MYSQL_TYPE_GEOMETRY:
+ pack_flag= FIELDFLAG_GEOM;
+ break;
+
+ case MYSQL_TYPE_ENUM:
+ pack_flag= FIELDFLAG_INTERVAL;
+ break;
+
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ pack_flag= FIELDFLAG_NUMBER |
+ (decimals_arg & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT;
+ break;
+
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ pack_flag= FIELDFLAG_BLOB;
+ break;
+
+ case MYSQL_TYPE_BIT:
+ pack_flag= FIELDFLAG_NUMBER | FIELDFLAG_TREAT_BIT_AS_CHAR;
+ break;
+
+ default:
+ pack_flag= FIELDFLAG_NUMBER;
+ break;
+ }
+
+ /*
+ Set the pack flag correctly for the blob-like types. This sets the
+ packtype to something that make_field can use. If the pack type is
+ not set correctly, the packlength will be reeeeally wierd (like
+ 129 or so).
+ */
+ switch (sql_type_arg)
+ {
+ 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_GEOMETRY:
+ // If you are going to use the above types, you have to pass a
+ // pack_length as parameter. Assert that is really done.
+ DBUG_ASSERT(pack_length_arg != ~0U);
+ pack_flag|= pack_length_to_packflag(pack_length_arg);
+ break;
+ default:
+ /* Nothing */
+ break;
+ }
+
+ pack_flag|=
+ (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
+ (is_unsigned ? 0 : FIELDFLAG_DECIMAL);
+
+ DBUG_PRINT("debug", ("pack_flag: %s%s%s%s%s%s, pack_type: %d",
+ FLAGSTR(pack_flag, FIELDFLAG_BINARY),
+ FLAGSTR(pack_flag, FIELDFLAG_NUMBER),
+ FLAGSTR(pack_flag, FIELDFLAG_INTERVAL),
+ FLAGSTR(pack_flag, FIELDFLAG_GEOM),
+ FLAGSTR(pack_flag, FIELDFLAG_BLOB),
+ FLAGSTR(pack_flag, FIELDFLAG_DECIMAL),
+ f_packtype(pack_flag)));
+ DBUG_VOID_RETURN;
}
@@ -9828,8 +9511,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
break;
case MYSQL_TYPE_DATE:
/* Old date type. */
- if (protocol_version != PROTOCOL_VERSION-1)
- sql_type= MYSQL_TYPE_NEWDATE;
+ sql_type= MYSQL_TYPE_NEWDATE;
/* fall trough */
case MYSQL_TYPE_NEWDATE:
length= MAX_DATE_WIDTH;
@@ -9919,8 +9601,8 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
- charset= &my_charset_bin;
- flags|= BINCMP_FLAG;
+ charset= &my_charset_numeric;
+ flags|= BINARY_FLAG;
default: break;
}
@@ -10036,10 +9718,18 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
- field_charset= &my_charset_bin;
+ field_charset= &my_charset_numeric;
default: break;
}
+ DBUG_PRINT("debug", ("field_type: %d, field_length: %u, interval: %p, pack_flag: %s%s%s%s%s",
+ field_type, field_length, interval,
+ FLAGSTR(pack_flag, FIELDFLAG_BINARY),
+ FLAGSTR(pack_flag, FIELDFLAG_INTERVAL),
+ FLAGSTR(pack_flag, FIELDFLAG_NUMBER),
+ FLAGSTR(pack_flag, FIELDFLAG_PACK),
+ FLAGSTR(pack_flag, FIELDFLAG_BLOB)));
+
if (f_is_alpha(pack_flag))
{
if (!f_is_packed(pack_flag))
@@ -10262,6 +9952,39 @@ Create_field::Create_field(Field *old_field,Field *orig_field)
/**
+ maximum possible character length for blob.
+
+ This method is used in Item_field::set_field to calculate
+ max_length for Item.
+
+ For example:
+ CREATE TABLE t2 SELECT CONCAT(tinyblob_utf8_column) FROM t1;
+ must create a "VARCHAR(255) CHARACTER SET utf8" column.
+
+ @return
+ length
+*/
+
+uint32 Field_blob::char_length()
+{
+ switch (packlength)
+ {
+ case 1:
+ return 255;
+ case 2:
+ return 65535;
+ case 3:
+ return 16777215;
+ case 4:
+ return (uint32) 4294967295U;
+ default:
+ DBUG_ASSERT(0); // we should never go here
+ return 0;
+ }
+}
+
+
+/**
maximum possible display length for blob.
@return
@@ -10324,7 +10047,7 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
{
thd->cuted_fields+= cuted_increment;
push_warning_printf(thd, level, code, ER(code), field_name,
- thd->row_count);
+ thd->warning_info->current_row_for_warning());
return 0;
}
return level >= MYSQL_ERROR::WARN_LEVEL_WARN;
diff --git a/sql/field.h b/sql/field.h
index cbdfa686ff8..e3db95260c3 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1,3 +1,6 @@
+#ifndef FIELD_INCLUDED
+#define FIELD_INCLUDED
+
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
@@ -22,14 +25,45 @@
#pragma interface /* gcc class implementation */
#endif
-#define NOT_FIXED_DEC 31
+#include "mysqld.h" /* system_charset_info */
+#include "table.h" /* TABLE */
+#include "sql_string.h" /* String */
+#include "my_decimal.h" /* my_decimal */
+#include "sql_error.h" /* MYSQL_ERROR */
+
#define DATETIME_DEC 6
-const uint32 max_field_size= (uint32) 4294967295U;
class Send_field;
class Protocol;
class Create_field;
class Relay_log_info;
+class Field;
+
+enum enum_check_fields
+{
+ CHECK_FIELD_IGNORE,
+ CHECK_FIELD_WARN,
+ CHECK_FIELD_ERROR_FOR_NULL
+};
+
+
+enum Derivation
+{
+ DERIVATION_IGNORABLE= 6,
+ DERIVATION_NUMERIC= 5,
+ DERIVATION_COERCIBLE= 4,
+ DERIVATION_SYSCONST= 3,
+ DERIVATION_IMPLICIT= 2,
+ DERIVATION_NONE= 1,
+ DERIVATION_EXPLICIT= 0
+};
+
+#define STORAGE_TYPE_MASK 7
+#define COLUMN_FORMAT_MASK 7
+#define COLUMN_FORMAT_SHIFT 3
+
+#define my_charset_numeric my_charset_latin1
+#define MY_REPERTOIRE_NUMERIC MY_REPERTOIRE_ASCII
struct st_cache_field;
int field_conv(Field *to,Field *from);
@@ -64,8 +98,8 @@ public:
Note that you can use table->in_use as replacement for current_thd member
only inside of val_*() and store() members (e.g. you can't use it in cons)
*/
- struct st_table *table; // Pointer for table
- struct st_table *orig_table; // Pointer to original table
+ TABLE *table; // Pointer for table
+ TABLE *orig_table; // Pointer to original table
const char **table_name, *field_name;
LEX_STRING comment;
/* Field is part of the following keys */
@@ -168,22 +202,13 @@ public:
table, which is located on disk).
*/
virtual uint32 pack_length_in_rec() const { return pack_length(); }
- virtual int compatible_field_size(uint field_metadata,
- const Relay_log_info *, uint16 mflags);
+ virtual bool compatible_field_size(uint metadata, Relay_log_info *rli,
+ uint16 mflags, int *order);
virtual uint pack_length_from_metadata(uint field_metadata)
- { return field_metadata; }
- /*
- This method is used to return the size of the data in a row-based
- replication row record. The default implementation of returning 0 is
- designed to allow fields that do not use metadata to return TRUE (1)
- from compatible_field_size() which uses this function in the comparison.
- The default value for field metadata for fields that do not have
- metadata is 0. Thus, 0 == 0 means the fields are compatible in size.
-
- Note: While most classes that override this method return pack_length(),
- the classes Field_string, Field_varstring, and Field_blob return
- field_length + 1, field_length, and pack_length_no_ptr() respectfully.
- */
+ {
+ DBUG_ENTER("Field::pack_length_from_metadata");
+ DBUG_RETURN(field_metadata);
+ }
virtual uint row_pack_length() { return 0; }
virtual int save_field_metadata(uchar *first_byte)
{ return do_save_field_metadata(first_byte); }
@@ -308,12 +333,12 @@ public:
*/
virtual bool can_be_compared_as_longlong() const { return FALSE; }
virtual void free() {}
- virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table,
+ virtual Field *new_field(MEM_ROOT *root, TABLE *new_table,
bool keep_type);
- virtual Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
+ virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
- Field *clone(MEM_ROOT *mem_root, struct st_table *new_table);
+ Field *clone(MEM_ROOT *mem_root, TABLE *new_table);
inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
{
ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
@@ -414,32 +439,11 @@ public:
DBUG_RETURN(result);
}
- virtual uchar *pack_key(uchar* to, const uchar *from,
- uint max_length, bool low_byte_first)
- {
- return pack(to, from, max_length, low_byte_first);
- }
- virtual uchar *pack_key_from_key_image(uchar* to, const uchar *from,
- uint max_length, bool low_byte_first)
- {
- return pack(to, from, max_length, low_byte_first);
- }
- virtual const uchar *unpack_key(uchar* to, const uchar *from,
- uint max_length, bool low_byte_first)
- {
- return unpack(to, from, max_length, low_byte_first);
- }
virtual uint packed_col_length(const uchar *to, uint length)
{ return length;}
virtual uint max_packed_col_length(uint max_length)
{ return max_length;}
- virtual int pack_cmp(const uchar *a,const uchar *b, uint key_length_arg,
- my_bool insert_or_update)
- { return cmp(a,b); }
- virtual int pack_cmp(const uchar *b, uint key_length_arg,
- my_bool insert_or_update)
- { return cmp(ptr,b); }
uint offset(uchar *record)
{
return (uint) (ptr - record);
@@ -449,11 +453,14 @@ public:
virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
virtual bool get_time(MYSQL_TIME *ltime);
virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
+ 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 void set_charset(CHARSET_INFO *charset_arg) { }
virtual enum Derivation derivation(void) const
{ return DERIVATION_IMPLICIT; }
+ virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; }
virtual void set_derivation(enum Derivation derivation_arg) { }
bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
int cuted_increment);
@@ -491,7 +498,7 @@ public:
longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag,
int *err);
/* The max. number of characters */
- inline uint32 char_length() const
+ virtual uint32 char_length()
{
return field_length / charset()->mbmaxlen;
}
@@ -504,7 +511,6 @@ public:
}
/* Hash value */
virtual void hash(ulong *nr, ulong *nr2);
- friend bool reopen_table(THD *,struct st_table *,bool);
friend int cre_myisam(char * name, register TABLE *form, uint options,
ulonglong auto_increment_value);
friend class Copy_field;
@@ -548,6 +554,48 @@ private:
{ return 0; }
protected:
+ static void handle_int16(uchar *to, const uchar *from,
+ bool low_byte_first_from, bool low_byte_first_to)
+ {
+ int16 val;
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first_from)
+ val = sint2korr(from);
+ else
+#endif
+ shortget(val, from);
+
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first_to)
+ int2store(to, val);
+ else
+#endif
+ shortstore(to, val);
+ }
+
+ static void handle_int24(uchar *to, const uchar *from,
+ bool low_byte_first_from, bool low_byte_first_to)
+ {
+ int32 val;
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first_from)
+ val = sint3korr(from);
+ else
+#endif
+ val= (from[0] << 16) + (from[1] << 8) + from[2];
+
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first_to)
+ int2store(to, val);
+ else
+#endif
+ {
+ to[0]= 0xFF & (val >> 16);
+ to[1]= 0xFF & (val >> 8);
+ to[2]= 0xFF & val;
+ }
+ }
+
/*
Helper function to pack()/unpack() int32 values
*/
@@ -592,6 +640,32 @@ protected:
longlongstore(to, val);
}
+ uchar *pack_int16(uchar *to, const uchar *from, bool low_byte_first_to)
+ {
+ handle_int16(to, from, table->s->db_low_byte_first, low_byte_first_to);
+ return to + sizeof(int16);
+ }
+
+ const uchar *unpack_int16(uchar* to, const uchar *from,
+ bool low_byte_first_from)
+ {
+ handle_int16(to, from, low_byte_first_from, table->s->db_low_byte_first);
+ return from + sizeof(int16);
+ }
+
+ uchar *pack_int24(uchar *to, const uchar *from, bool low_byte_first_to)
+ {
+ handle_int24(to, from, table->s->db_low_byte_first, low_byte_first_to);
+ return to + 3;
+ }
+
+ const uchar *unpack_int24(uchar* to, const uchar *from,
+ bool low_byte_first_from)
+ {
+ handle_int24(to, from, low_byte_first_from, table->s->db_low_byte_first);
+ return from + 3;
+ }
+
uchar *pack_int32(uchar *to, const uchar *from, bool low_byte_first_to)
{
handle_int32(to, from, table->s->db_low_byte_first, low_byte_first_to);
@@ -635,6 +709,9 @@ public:
const char *field_name_arg,
uint8 dec_arg, bool zero_arg, bool unsigned_arg);
Item_result result_type () const { return REAL_RESULT; }
+ 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; }
void prepend_zeros(String *value);
void add_zerofill_and_unsigned(String &res) const;
friend class Create_field;
@@ -645,6 +722,13 @@ public:
int store_decimal(const my_decimal *);
my_decimal *val_decimal(my_decimal *);
uint is_equal(Create_field *new_field);
+ uint row_pack_length() { return pack_length(); }
+ uint32 pack_length_from_metadata(uint field_metadata) {
+ uint32 length= pack_length();
+ DBUG_PRINT("result", ("pack_length_from_metadata(%d): %u",
+ field_metadata, length));
+ return length;
+ }
int check_int(CHARSET_INFO *cs, const char *str, int length,
const char *int_end, int error);
bool get_int(CHARSET_INFO *cs, const char *from, uint len,
@@ -662,12 +746,27 @@ public:
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg, CHARSET_INFO *charset);
Item_result result_type () const { return STRING_RESULT; }
+ /*
+ match_collation_to_optimize_range() is to distinguish in
+ range optimizer (see opt_range.cc) between real string types:
+ CHAR, VARCHAR, TEXT
+ and the other string-alike types with result_type() == STRING_RESULT:
+ DATE, TIME, DATETIME, TIMESTAMP
+ We need it to decide whether to test if collation of the operation
+ matches collation of the field (needed only for real string types).
+ QQ: shouldn't DATE/TIME types have their own XXX_RESULT types eventually?
+ */
+ virtual bool match_collation_to_optimize_range() const=0;
uint decimals() const { return NOT_FIXED_DEC; }
int store(double nr);
int store(longlong nr, bool unsigned_val)=0;
int store_decimal(const my_decimal *);
int store(const char *to,uint length,CHARSET_INFO *cs)=0;
uint size_of() const { return sizeof(*this); }
+ uint repertoire(void) const
+ {
+ return my_charset_repertoire(field_charset);
+ }
CHARSET_INFO *charset(void) const { return field_charset; }
void set_charset(CHARSET_INFO *charset_arg) { field_charset= charset_arg; }
enum Derivation derivation(void) const { return field_derivation; }
@@ -809,8 +908,8 @@ public:
uint32 pack_length() const { return (uint32) bin_size; }
uint pack_length_from_metadata(uint field_metadata);
uint row_pack_length() { return pack_length(); }
- int compatible_field_size(uint field_metadata,
- const Relay_log_info *rli, uint16 mflags);
+ bool compatible_field_size(uint field_metadata, Relay_log_info *rli,
+ uint16 mflags, int *order_var);
uint is_equal(Create_field *new_field);
virtual const uchar *unpack(uchar* to, const uchar *from,
uint param_data, bool low_byte_first);
@@ -898,41 +997,13 @@ public:
virtual uchar *pack(uchar* to, const uchar *from,
uint max_length, bool low_byte_first)
{
- int16 val;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- val = sint2korr(from);
- else
-#endif
- shortget(val, from);
-
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first)
- int2store(to, val);
- else
-#endif
- shortstore(to, val);
- return to + sizeof(val);
+ return pack_int16(to, from, low_byte_first);
}
virtual const uchar *unpack(uchar* to, const uchar *from,
uint param_data, bool low_byte_first)
{
- int16 val;
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first)
- val = sint2korr(from);
- else
-#endif
- shortget(val, from);
-
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- int2store(to, val);
- else
-#endif
- shortstore(to, val);
- return from + sizeof(val);
+ return unpack_int16(to, from, low_byte_first);
}
};
@@ -1167,6 +1238,7 @@ public:
unireg_check_arg, field_name_arg, cs)
{}
enum_field_types type() const { return MYSQL_TYPE_NULL;}
+ bool match_collation_to_optimize_range() const { return FALSE; }
int store(const char *to, uint length, CHARSET_INFO *cs)
{ null[0]=1; return 0; }
int store(double nr) { null[0]=1; return 0; }
@@ -1196,8 +1268,13 @@ public:
Field_timestamp(bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs);
enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;}
+ bool match_collation_to_optimize_range() const { return FALSE; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
enum Item_result cmp_type () const { return INT_RESULT; }
+ 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; }
+ bool binary() const { return 1; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@@ -1290,14 +1367,19 @@ public:
CHARSET_INFO *cs)
:Field_str(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, cs)
- {}
+ { flags|= BINARY_FLAG; }
Field_date(bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs)
:Field_str((uchar*) 0, MAX_DATE_WIDTH, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
+ NONE, field_name_arg, cs) { flags|= BINARY_FLAG; }
enum_field_types type() const { return MYSQL_TYPE_DATE;}
+ bool match_collation_to_optimize_range() const { return FALSE; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
enum Item_result cmp_type () const { return INT_RESULT; }
+ 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; }
+ bool binary() const { return 1; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@@ -1334,15 +1416,20 @@ public:
CHARSET_INFO *cs)
:Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, cs)
- {}
+ { flags|= BINARY_FLAG; }
Field_newdate(bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs)
:Field_str((uchar*) 0,10, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
+ NONE, field_name_arg, cs) { flags|= BINARY_FLAG; }
enum_field_types type() const { return MYSQL_TYPE_DATE;}
enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; }
+ bool match_collation_to_optimize_range() const { return FALSE; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; }
enum Item_result cmp_type () const { return INT_RESULT; }
+ 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; }
+ bool binary() const { return 1; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@@ -1370,14 +1457,19 @@ public:
CHARSET_INFO *cs)
:Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, cs)
- {}
+ { flags|= BINARY_FLAG; }
Field_time(bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs)
:Field_str((uchar*) 0,8, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
+ NONE, field_name_arg, cs) { flags|= BINARY_FLAG; }
enum_field_types type() const { return MYSQL_TYPE_TIME;}
+ bool match_collation_to_optimize_range() const { return FALSE; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
enum Item_result cmp_type () const { return INT_RESULT; }
+ 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; }
+ bool binary() const { return 1; }
int store_time(MYSQL_TIME *ltime, timestamp_type type);
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
@@ -1405,16 +1497,21 @@ public:
CHARSET_INFO *cs)
:Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, cs)
- {}
+ { flags|= BINARY_FLAG; }
Field_datetime(bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs)
:Field_str((uchar*) 0, MAX_DATETIME_WIDTH, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
+ NONE, field_name_arg, cs) { flags|= BINARY_FLAG; }
enum_field_types type() const { return MYSQL_TYPE_DATETIME;}
+ bool match_collation_to_optimize_range() const { return FALSE; }
#ifdef HAVE_LONG_LONG
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
#endif
enum Item_result cmp_type () const { return INT_RESULT; }
+ 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; }
+ bool binary() const { return 1; }
uint decimals() const { return DATETIME_DEC; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
@@ -1475,6 +1572,7 @@ public:
orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR ?
MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING);
}
+ bool match_collation_to_optimize_range() const { return TRUE; }
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
bool zero_pack() const { return 0; }
@@ -1505,9 +1603,9 @@ public:
return row_pack_length();
return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff);
}
- int compatible_field_size(uint field_metadata,
- const Relay_log_info *rli, uint16 mflags);
- uint row_pack_length() { return (field_length + 1); }
+ bool compatible_field_size(uint field_metadata, Relay_log_info *rli,
+ uint16 mflags, int *order_var);
+ uint row_pack_length() { return field_length; }
int pack_cmp(const uchar *a,const uchar *b,uint key_length,
my_bool insert_or_update);
int pack_cmp(const uchar *b,uint key_length,my_bool insert_or_update);
@@ -1517,7 +1615,7 @@ public:
enum_field_types real_type() const { return MYSQL_TYPE_STRING; }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
- Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
+ Field *new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
virtual uint get_key_image(uchar *buff,uint length, imagetype type);
private:
int do_save_field_metadata(uchar *first_byte);
@@ -1555,6 +1653,7 @@ public:
}
enum_field_types type() const { return MYSQL_TYPE_VARCHAR; }
+ bool match_collation_to_optimize_range() const { return TRUE; }
enum ha_base_keytype key_type() const;
uint row_pack_length() { return field_length; }
bool zero_pack() const { return 0; }
@@ -1584,16 +1683,8 @@ public:
void sql_type(String &str) const;
virtual uchar *pack(uchar *to, const uchar *from,
uint max_length, bool low_byte_first);
- uchar *pack_key(uchar *to, const uchar *from, uint max_length, bool low_byte_first);
- uchar *pack_key_from_key_image(uchar* to, const uchar *from,
- uint max_length, bool low_byte_first);
virtual const uchar *unpack(uchar* to, const uchar *from,
uint param_data, bool low_byte_first);
- const uchar *unpack_key(uchar* to, const uchar *from,
- uint max_length, bool low_byte_first);
- int pack_cmp(const uchar *a, const uchar *b, uint key_length,
- my_bool insert_or_update);
- int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update);
int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0L);
int key_cmp(const uchar *,const uchar*);
int key_cmp(const uchar *str, uint length);
@@ -1604,8 +1695,8 @@ public:
enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
- Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
- Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
+ Field *new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
+ Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
uint is_equal(Create_field *new_field);
@@ -1658,6 +1749,7 @@ public:
:Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, "temp", system_charset_info),
packlength(packlength_arg) {}
enum_field_types type() const { return MYSQL_TYPE_BLOB;}
+ bool match_collation_to_optimize_range() const { return TRUE; }
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; }
int store(const char *to,uint length,CHARSET_INFO *charset);
@@ -1730,22 +1822,22 @@ public:
void put_length(uchar *pos, uint32 length);
inline void get_ptr(uchar **str)
{
- memcpy_fixed((uchar*) str,ptr+packlength,sizeof(uchar*));
+ memcpy(str, ptr+packlength, sizeof(uchar*));
}
inline void get_ptr(uchar **str, uint row_offset)
{
- memcpy_fixed((uchar*) str,ptr+packlength+row_offset,sizeof(char*));
+ memcpy(str, ptr+packlength+row_offset, sizeof(char*));
}
inline void set_ptr(uchar *length, uchar *data)
{
memcpy(ptr,length,packlength);
- memcpy_fixed(ptr+packlength,&data,sizeof(char*));
+ memcpy(ptr+packlength, &data,sizeof(char*));
}
void set_ptr_offset(my_ptrdiff_t ptr_diff, uint32 length, uchar *data)
{
uchar *ptr_ofs= ADD_TO_PTR(ptr,ptr_diff,uchar*);
store_length(ptr_ofs, packlength, length);
- memcpy_fixed(ptr_ofs+packlength,&data,sizeof(char*));
+ memcpy(ptr_ofs+packlength, &data, sizeof(char*));
}
inline void set_ptr(uint32 length, uchar *data)
{
@@ -1764,22 +1856,13 @@ public:
return 1;
}
tmp=(uchar*) value.ptr();
- memcpy_fixed(ptr+packlength,&tmp,sizeof(char*));
+ memcpy(ptr+packlength, &tmp, sizeof(char*));
return 0;
}
virtual uchar *pack(uchar *to, const uchar *from,
uint max_length, bool low_byte_first);
- uchar *pack_key(uchar *to, const uchar *from,
- uint max_length, bool low_byte_first);
- uchar *pack_key_from_key_image(uchar* to, const uchar *from,
- uint max_length, bool low_byte_first);
virtual const uchar *unpack(uchar *to, const uchar *from,
uint param_data, bool low_byte_first);
- const uchar *unpack_key(uchar* to, const uchar *from,
- uint max_length, bool low_byte_first);
- int pack_cmp(const uchar *a, const uchar *b, uint key_length,
- my_bool insert_or_update);
- int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update);
uint packed_col_length(const uchar *col_ptr, uint length);
uint max_packed_col_length(uint max_length);
void free() { value.free(); }
@@ -1789,6 +1872,7 @@ public:
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
uint32 max_display_length();
+ uint32 char_length();
uint is_equal(Create_field *new_field);
inline bool in_read_set() { return bitmap_is_set(table->read_set, field_index); }
inline bool in_write_set() { return bitmap_is_set(table->write_set, field_index); }
@@ -1815,6 +1899,7 @@ public:
{ geom_type= geom_type_arg; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; }
enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; }
+ bool match_collation_to_optimize_range() const { return FALSE; }
void sql_type(String &str) const;
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
@@ -1844,8 +1929,9 @@ public:
{
flags|=ENUM_FLAG;
}
- Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
+ Field *new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
enum_field_types type() const { return MYSQL_TYPE_STRING; }
+ bool match_collation_to_optimize_range() const { return FALSE; }
enum Item_result cmp_type () const { return INT_RESULT; }
enum Item_result cast_to_int_type () const { return INT_RESULT; }
enum ha_base_keytype key_type() const;
@@ -1871,6 +1957,12 @@ public:
bool has_charset(void) const { return TRUE; }
/* enum and set are sorted as integers */
CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
+
+ virtual uchar *pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first);
+ virtual const uchar *unpack(uchar *to, const uchar *from,
+ uint param_data, bool low_byte_first);
+
private:
int do_save_field_metadata(uchar *first_byte);
uint is_equal(Create_field *new_field);
@@ -1949,9 +2041,12 @@ public:
virtual bool str_needs_quotes() { return TRUE; }
my_decimal *val_decimal(my_decimal *);
int cmp(const uchar *a, const uchar *b)
- {
- DBUG_ASSERT(ptr == a);
- return Field_bit::key_cmp(b, bytes_in_rec+test(bit_len));
+ {
+ DBUG_ASSERT(ptr == a || ptr == b);
+ if (ptr == a)
+ return Field_bit::key_cmp(b, bytes_in_rec+test(bit_len));
+ else
+ return Field_bit::key_cmp(a, bytes_in_rec+test(bit_len)) * -1;
}
int cmp_binary_offset(uint row_offset)
{ return cmp_offset(row_offset); }
@@ -1974,8 +2069,8 @@ public:
uint pack_length_from_metadata(uint field_metadata);
uint row_pack_length()
{ return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); }
- int compatible_field_size(uint field_metadata,
- const Relay_log_info *rli, uint16 mflags);
+ bool compatible_field_size(uint metadata, Relay_log_info *rli,
+ uint16 mflags, int *order_var);
void sql_type(String &str) const;
virtual uchar *pack(uchar *to, const uchar *from,
uint max_length, bool low_byte_first);
@@ -1983,7 +2078,7 @@ public:
uint param_data, bool low_byte_first);
virtual void set_default();
- Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
+ Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg)
@@ -2078,7 +2173,8 @@ public:
/* Init for a tmp table field. To be extended if need be. */
void init_for_tmp_table(enum_field_types sql_type_arg,
uint32 max_length, uint32 decimals,
- bool maybe_null, bool is_unsigned);
+ bool maybe_null, bool is_unsigned,
+ uint pack_length = ~0U);
bool init(THD *thd, char *field_name, enum_field_types type, char *length,
char *decimals, uint type_modifier, Item *default_value,
@@ -2097,7 +2193,7 @@ public:
A class for sending info to the client
*/
-class Send_field {
+class Send_field :public Sql_alloc {
public:
const char *db_name;
const char *table_name,*org_table_name;
@@ -2200,3 +2296,5 @@ int set_field_to_null_with_conversions(Field *field, bool no_conversions);
#define f_no_default(x) (x & FIELDFLAG_NO_DEFAULT)
#define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR)
#define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE)
+
+#endif /* FIELD_INCLUDED */
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index a4fca6f8ad7..20c647ccc00 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -24,7 +24,8 @@
gives much more speed.
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_class.h" // THD
#include <m_ctype.h>
static void do_field_eq(Copy_field *copy)
@@ -285,7 +286,7 @@ static void do_copy_blob(Copy_field *copy)
{
ulong length=((Field_blob*) copy->from_field)->get_length();
((Field_blob*) copy->to_field)->store_length(length);
- memcpy_fixed(copy->to_ptr,copy->from_ptr,sizeof(char*));
+ memcpy(copy->to_ptr, copy->from_ptr, sizeof(char*));
}
static void do_conv_blob(Copy_field *copy)
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 021cbdd2aad..419f18263cc 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2006 MySQL AB
+/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -21,12 +21,17 @@
Sorts a database
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "filesort.h"
+#include "unireg.h" // REQUIRED by other includes
#ifdef HAVE_STDDEF_H
#include <stddef.h> /* for macro offsetof */
#endif
#include <m_ctype.h>
#include "sql_sort.h"
+#include "probes_mysql.h"
+#include "sql_test.h" // TEST_filesort
+#include "opt_range.h" // SQL_SELECT
#ifndef THREAD
#define SKIP_DBUG_IN_FILESORT
@@ -121,6 +126,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
TABLE_LIST *tab= table->pos_in_table_list;
Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
+ MYSQL_FILESORT_START(table->s->db.str, table->s->table_name.str);
+
/*
Release InnoDB's adaptive hash index latch (if holding) before
running a sort.
@@ -257,7 +264,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
{
if (table_sort.buffpek && table_sort.buffpek_len < maxbuffer)
{
- x_free(table_sort.buffpek);
+ my_free(table_sort.buffpek);
table_sort.buffpek= 0;
}
if (!(table_sort.buffpek=
@@ -297,13 +304,12 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
error =0;
err:
- if (param.tmp_buffer)
- x_free(param.tmp_buffer);
+ my_free(param.tmp_buffer);
if (!subselect || !subselect->is_uncacheable())
{
- x_free((uchar*) sort_keys);
+ my_free(sort_keys);
table_sort.sort_keys= 0;
- x_free((uchar*) buffpek);
+ my_free(buffpek);
table_sort.buffpek= 0;
table_sort.buffpek_len= 0;
}
@@ -333,38 +339,29 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
#endif
memcpy(&table->sort, &table_sort, sizeof(FILESORT_INFO));
DBUG_PRINT("exit",("records: %ld", (long) records));
+ MYSQL_FILESORT_DONE(error, records);
DBUG_RETURN(error ? HA_POS_ERROR : records);
} /* filesort */
void filesort_free_buffers(TABLE *table, bool full)
{
- if (table->sort.record_pointers)
- {
- my_free((uchar*) table->sort.record_pointers,MYF(0));
- table->sort.record_pointers=0;
- }
+ my_free(table->sort.record_pointers);
+ table->sort.record_pointers= NULL;
+
if (full)
{
- if (table->sort.sort_keys )
- {
- x_free((uchar*) table->sort.sort_keys);
- table->sort.sort_keys= 0;
- }
- if (table->sort.buffpek)
- {
- x_free((uchar*) table->sort.buffpek);
- table->sort.buffpek= 0;
- table->sort.buffpek_len= 0;
- }
- }
- if (table->sort.addon_buf)
- {
- my_free((char *) table->sort.addon_buf, MYF(0));
- my_free((char *) table->sort.addon_field, MYF(MY_ALLOW_ZERO_PTR));
- table->sort.addon_buf=0;
- table->sort.addon_field=0;
+ my_free(table->sort.sort_keys);
+ table->sort.sort_keys= NULL;
+ my_free(table->sort.buffpek);
+ table->sort.buffpek= NULL;
+ table->sort.buffpek_len= 0;
}
+
+ my_free(table->sort.addon_buf);
+ my_free(table->sort.addon_field);
+ table->sort.addon_buf= NULL;
+ table->sort.addon_field= NULL;
}
/** Make a array of string pointers. */
@@ -405,7 +402,7 @@ static uchar *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count,
if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
my_b_read(buffpek_pointers, (uchar*) tmp, length))
{
- my_free((char*) tmp, MYF(0));
+ my_free(tmp);
tmp=0;
}
}
@@ -1119,8 +1116,9 @@ uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
{
- if (my_pread(fromfile->file,(uchar*) buffpek->base,
- (length= rec_length*count),buffpek->file_pos,MYF_RW))
+ if (mysql_file_pread(fromfile->file, (uchar*) buffpek->base,
+ (length= rec_length*count),
+ buffpek->file_pos, MYF_RW))
return((uint) -1); /* purecov: inspected */
buffpek->key=buffpek->base;
buffpek->file_pos+= length; /* New filepos */
@@ -1318,7 +1316,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
if (!(error= (int) read_to_buffer(from_file,buffpek,
rec_length)))
{
- VOID(queue_remove(&queue,0));
+ (void) queue_remove(&queue,0);
reuse_freed_buff(&queue, buffpek, rec_length);
break; /* One buffer have been removed */
}
@@ -1667,7 +1665,7 @@ void change_double_for_sort(double nr,uchar *to)
else
{
#ifdef WORDS_BIGENDIAN
- memcpy_fixed(tmp,&nr,sizeof(nr));
+ memcpy(tmp, &nr, sizeof(nr));
#else
{
uchar *ptr= (uchar*) &nr;
diff --git a/sql/filesort.h b/sql/filesort.h
new file mode 100644
index 00000000000..c1a101cc1e8
--- /dev/null
+++ b/sql/filesort.h
@@ -0,0 +1,36 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 FILESORT_INCLUDED
+#define FILESORT_INCLUDED
+
+class SQL_SELECT;
+
+#include "my_global.h" /* uint, uchar */
+#include "my_base.h" /* ha_rows */
+
+class SQL_SELECT;
+class THD;
+struct TABLE;
+typedef struct st_sort_field SORT_FIELD;
+
+ha_rows filesort(THD *thd, TABLE *table, st_sort_field *sortorder,
+ uint s_length, SQL_SELECT *select,
+ ha_rows max_rows, bool sort_positions,
+ ha_rows *examined_rows);
+void filesort_free_buffers(TABLE *table, bool full);
+void change_double_for_sort(double nr,uchar *to);
+
+#endif /* FILESORT_INCLUDED */
diff --git a/sql/frm_crypt.cc b/sql/frm_crypt.cc
index 590205e83ab..821e61c5247 100644
--- a/sql/frm_crypt.cc
+++ b/sql/frm_crypt.cc
@@ -21,7 +21,8 @@
** mysql binary.
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "frm_crypt.h"
#ifdef HAVE_CRYPTED_FRM
diff --git a/sql/frm_crypt.h b/sql/frm_crypt.h
new file mode 100644
index 00000000000..e119dceae35
--- /dev/null
+++ b/sql/frm_crypt.h
@@ -0,0 +1,23 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 FRM_CRYPT_INCLUDED
+#define FRM_CRYPT_INCLUDED
+
+class SQL_CRYPT;
+
+SQL_CRYPT *get_crypt_for_frm(void);
+
+#endif /* FRM_CRYPT_INCLUDED */
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 5a0904f87b9..a9c03f7e2a7 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -77,33 +77,12 @@ So, we can read full search-structure as 32-bit word
*/
#define NO_YACC_SYMBOLS
-#include "my_global.h"
-#include "my_sys.h"
-#include "m_string.h"
-#ifndef __GNU_LIBRARY__
-#define __GNU_LIBRARY__ // Skip warnings in getopt.h
-#endif
-#include <my_getopt.h>
+#include <my_global.h>
#include "mysql_version.h"
#include "lex.h"
-
-const char *default_dbug_option="d:t:o,/tmp/gen_lex_hash.trace";
-
-struct my_option my_long_options[] =
-{
-#ifdef DBUG_OFF
- {"debug", '#', "This is a non-debug version. Catch this and exit",
- 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
-#else
- {"debug", '#', "Output debug log", (uchar**) &default_dbug_option,
- (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
-#endif
- {"help", '?', "Display help and exit",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"version", 'V', "Output version information and exit",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
-};
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
struct hash_lex_struct
{
@@ -340,57 +319,6 @@ void print_find_structs()
}
-static void usage(int version)
-{
- printf("%s Ver 3.6 Distrib %s, for %s (%s)\n",
- my_progname, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
- if (version)
- return;
- puts("Copyright (C) 2001 MySQL AB, by VVA and Monty");
- puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
-and you are welcome to modify and redistribute it under the GPL license\n");
- puts("This program generates a perfect hashing function for the sql_lex.cc");
- printf("Usage: %s [OPTIONS]\n\n", my_progname);
- my_print_help(my_long_options);
-}
-
-
-extern "C" my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument __attribute__((unused)))
-{
- switch(optid) {
- case 'V':
- usage(1);
- exit(0);
- case 'I':
- case '?':
- usage(0);
- exit(0);
- case '#':
- DBUG_PUSH(argument ? argument : default_dbug_option);
- break;
- }
- return 0;
-}
-
-
-static int get_options(int argc, char **argv)
-{
- int ho_error;
-
- if ((ho_error= handle_options(&argc, &argv, my_long_options, get_one_option)))
- exit(ho_error);
-
- if (argc >= 1)
- {
- usage(0);
- exit(1);
- }
- return(0);
-}
-
-
int check_dup_symbols(SYMBOL *s1, SYMBOL *s2)
{
if (s1->length!=s2->length || strncmp(s1->name,s2->name,s1->length))
@@ -441,11 +369,7 @@ int check_duplicates()
int main(int argc,char **argv)
{
- MY_INIT(argv[0]);
- DBUG_PROCESS(argv[0]);
- if (get_options(argc,(char **) argv))
- exit(1);
/* Broken up to indicate that it's not advice to you, gentle reader. */
printf("/*\n\n Do " "not " "edit " "this " "file " "directly!\n\n*/\n");
@@ -562,7 +486,6 @@ static SYMBOL *get_hash_symbol(const char *s,\n\
}\n\
}\n"
);
- my_end(0);
exit(0);
}
diff --git a/sql/gstream.cc b/sql/gstream.cc
index e2bb41b8541..fcb9a91ac50 100644
--- a/sql/gstream.cc
+++ b/sql/gstream.cc
@@ -18,7 +18,9 @@
NOTE: These functions assumes that the string is end \0 terminated!
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "gstream.h"
+#include "m_string.h" // LEX_STRING
enum Gis_read_stream::enum_tok_types Gis_read_stream::get_next_toc_type()
{
diff --git a/sql/gstream.h b/sql/gstream.h
index 1ef90ad5bf0..6bb3c9bac10 100644
--- a/sql/gstream.h
+++ b/sql/gstream.h
@@ -1,3 +1,6 @@
+#ifndef GSTREAM_INCLUDED
+#define GSTREAM_INCLUDED
+
/* Copyright (C) 2000-2004 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -14,6 +17,13 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "my_global.h" /* NULL, NullS */
+#include "my_sys.h" /* MY_ALLOW_ZERO_PTR */
+#include "m_ctype.h" /* my_charset_latin1, my_charset_bin */
+
+typedef struct charset_info_st CHARSET_INFO;
+typedef struct st_mysql_lex_string LEX_STRING;
+
class Gis_read_stream
{
public:
@@ -35,7 +45,7 @@ public:
{}
~Gis_read_stream()
{
- my_free((uchar*) m_err_msg, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(m_err_msg);
}
enum enum_tok_types get_next_toc_type();
@@ -73,3 +83,5 @@ protected:
char *m_err_msg;
CHARSET_INFO *m_charset;
};
+
+#endif /* GSTREAM_INCLUDED */
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 4f99d354754..20745db9ce9 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -26,9 +26,26 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_table.h" // build_table_filename,
+ // tablename_to_filename,
+ // filename_to_tablename
+#include "sql_partition.h" // HA_CAN_*, partition_info, part_id_range
+#include "sql_base.h" // close_cached_tables
+#include "discover.h" // readfrm
+#include "sql_acl.h" // wild_case_compare
#include "rpl_mi.h"
+#include "transaction.h"
+/*
+ There is an incompatibility between GNU ar and the Solaris linker
+ which makes the Solaris linker return an elf error when compiling
+ without NDB support (which makes libndb.a an empty library).
+ To avoid this we add a dummy declaration of a static variable
+ which makes us avoid this bug.
+*/
+int ha_ndb_dummy;
#include <my_dir.h>
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
#include "ha_ndbcluster.h"
@@ -40,33 +57,136 @@
#include "ha_ndbcluster_binlog.h"
#include "ha_ndbcluster_tables.h"
-#include <mysql/plugin.h>
+#include "sql_plugin.h"
+#include "probes_mysql.h"
+#include "sql_show.h" // init_fill_schema_files_row,
+ // schema_table_store_record
+#include "sql_test.h" // print_where
#ifdef ndb_dynamite
#undef assert
#define assert(x) do { if(x) break; ::printf("%s %d: assert failed: %s\n", __FILE__, __LINE__, #x); ::fflush(stdout); ::signal(SIGABRT,SIG_DFL); ::abort(); ::kill(::getpid(),6); ::kill(::getpid(),9); } while (0)
#endif
-// options from from mysqld.cc
-extern my_bool opt_ndb_optimized_node_selection;
-extern const char *opt_ndbcluster_connectstring;
-extern ulong opt_ndb_cache_check_time;
-
-// ndb interface initialization/cleanup
-#ifdef __cplusplus
-extern "C" {
-#endif
-extern void ndb_init_internal();
-extern void ndb_end_internal();
-#ifdef __cplusplus
-}
-#endif
-
-const char *ndb_distribution_names[]= {"KEYHASH", "LINHASH", NullS};
-TYPELIB ndb_distribution_typelib= { array_elements(ndb_distribution_names)-1,
- "", ndb_distribution_names, NULL };
-const char *opt_ndb_distribution= ndb_distribution_names[ND_KEYHASH];
-enum ndb_distribution opt_ndb_distribution_id= ND_KEYHASH;
+// ndb interface initialization/cleanup functions
+extern "C" void ndb_init_internal();
+extern "C" void ndb_end_internal();
+
+static const int DEFAULT_PARALLELISM= 0;
+static const ha_rows DEFAULT_AUTO_PREFETCH= 32;
+static const ulong ONE_YEAR_IN_SECONDS= (ulong) 3600L*24L*365L;
+
+ulong opt_ndb_extra_logging;
+static ulong opt_ndb_cache_check_time;
+static char* opt_ndb_connectstring;
+static char* opt_ndb_mgmd_host;
+static uint opt_ndb_nodeid;
+
+
+static MYSQL_THDVAR_UINT(
+ autoincrement_prefetch_sz, /* name */
+ PLUGIN_VAR_RQCMDARG,
+ "Specify number of autoincrement values that are prefetched.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 1, /* default */
+ 1, /* min */
+ 256, /* max */
+ 0 /* block */
+);
+
+
+static MYSQL_THDVAR_BOOL(
+ force_send, /* name */
+ PLUGIN_VAR_OPCMDARG,
+ "Force send of buffers to ndb immediately without waiting for "
+ "other threads.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 1 /* default */
+);
+
+
+static MYSQL_THDVAR_BOOL(
+ use_exact_count, /* name */
+ PLUGIN_VAR_OPCMDARG,
+ "Use exact records count during query planning and for fast "
+ "select count(*), disable for faster queries.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 1 /* default */
+);
+
+
+static MYSQL_THDVAR_BOOL(
+ use_transactions, /* name */
+ PLUGIN_VAR_OPCMDARG,
+ "Use transactions for large inserts, if enabled then large "
+ "inserts will be split into several smaller transactions",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 1 /* default */
+);
+
+
+static MYSQL_THDVAR_BOOL(
+ use_copying_alter_table, /* name */
+ PLUGIN_VAR_OPCMDARG,
+ "Force ndbcluster to always copy tables at alter table (should "
+ "only be used if on-line alter table fails).",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 0 /* default */
+);
+
+
+static MYSQL_THDVAR_UINT(
+ optimized_node_selection, /* name */
+ PLUGIN_VAR_OPCMDARG,
+ "Select nodes for transactions in a more optimal way.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 3, /* default */
+ 0, /* min */
+ 3, /* max */
+ 0 /* block */
+);
+
+
+static MYSQL_THDVAR_BOOL(
+ index_stat_enable, /* name */
+ PLUGIN_VAR_OPCMDARG,
+ "Use ndb index statistics in query optimization.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ FALSE /* default */
+);
+
+
+static MYSQL_THDVAR_ULONG(
+ index_stat_cache_entries, /* name */
+ PLUGIN_VAR_NOCMDARG,
+ "",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 32, /* default */
+ 0, /* min */
+ ULONG_MAX, /* max */
+ 0 /* block */
+);
+
+
+static MYSQL_THDVAR_ULONG(
+ index_stat_update_freq, /* name */
+ PLUGIN_VAR_NOCMDARG,
+ "",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 20, /* default */
+ 0, /* min */
+ ULONG_MAX, /* max */
+ 0 /* block */
+);
// Default value for parallelism
static const int parallelism= 0;
@@ -85,6 +205,11 @@ static bool ndbcluster_show_status(handlerton *hton, THD*,
static int ndbcluster_alter_tablespace(handlerton *hton,
THD* thd,
st_alter_tablespace *info);
+static int ndbcluster_fill_is_table(handlerton *hton,
+ THD *thd,
+ TABLE_LIST *tables,
+ COND *cond,
+ enum enum_schema_tables);
static int ndbcluster_fill_files_table(handlerton *hton,
THD *thd,
TABLE_LIST *tables,
@@ -128,6 +253,13 @@ static uint ndbcluster_alter_table_flags(uint flags)
DBUG_RETURN(ndb_to_mysql_error(&tmp)); \
}
+#define ERR_RETURN_PREPARE(rc, err) \
+{ \
+ const NdbError& tmp= err; \
+ set_ndb_err(current_thd, tmp); \
+ rc= ndb_to_mysql_error(&tmp); \
+}
+
#define ERR_BREAK(err, code) \
{ \
const NdbError& tmp= err; \
@@ -144,7 +276,7 @@ Ndb_cluster_connection* g_ndb_cluster_connection= NULL;
uchar g_node_id_map[max_ndb_nodes];
/// Handler synchronization
-pthread_mutex_t ndbcluster_mutex;
+mysql_mutex_t ndbcluster_mutex;
/// Table lock handling
HASH ndbcluster_open_tables;
@@ -161,11 +293,10 @@ static int ndb_get_table_statistics(ha_ndbcluster*, bool, Ndb*, const NDBTAB *,
// Util thread variables
pthread_t ndb_util_thread;
int ndb_util_thread_running= 0;
-pthread_mutex_t LOCK_ndb_util_thread;
-pthread_cond_t COND_ndb_util_thread;
-pthread_cond_t COND_ndb_util_ready;
+mysql_mutex_t LOCK_ndb_util_thread;
+mysql_cond_t COND_ndb_util_thread;
+mysql_cond_t COND_ndb_util_ready;
pthread_handler_t ndb_util_thread_func(void *arg);
-ulong ndb_cache_check_time;
/**
Dummy buffer to read zero pack_length fields
@@ -249,11 +380,11 @@ static int ndb_to_mysql_error(const NdbError *ndberr)
- Used by replication to see if the error was temporary
*/
if (ndberr->status == NdbError::TemporaryError)
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_TEMPORARY_ERRMSG, ER(ER_GET_TEMPORARY_ERRMSG),
ndberr->code, ndberr->message, "NDB");
else
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
ndberr->code, ndberr->message, "NDB");
return error;
@@ -300,7 +431,7 @@ int execute_commit(THD *thd, NdbTransaction *trans)
{
return trans->execute(NdbTransaction::Commit,
NdbOperation::AbortOnError,
- thd->variables.ndb_force_send);
+ THDVAR(thd, force_send));
}
inline
@@ -339,8 +470,8 @@ Thd_ndb::Thd_ndb()
m_error_code= 0;
query_state&= NDB_QUERY_NORMAL;
options= 0;
- (void) hash_init(&open_tables, &my_charset_bin, 5, 0, 0,
- (hash_get_key)thd_ndb_share_get_key, 0, 0);
+ (void) my_hash_init(&open_tables, &my_charset_bin, 5, 0, 0,
+ (my_hash_get_key)thd_ndb_share_get_key, 0, 0);
}
Thd_ndb::~Thd_ndb()
@@ -364,7 +495,7 @@ Thd_ndb::~Thd_ndb()
ndb= NULL;
}
changed_tables.empty();
- hash_free(&open_tables);
+ my_hash_free(&open_tables);
}
void
@@ -520,7 +651,7 @@ static void set_ndb_err(THD *thd, const NdbError &err)
{
char buf[FN_REFLEN];
ndb_error_string(thd_ndb->m_error_code, buf, sizeof(buf));
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
thd_ndb->m_error_code, buf, "NDB");
}
@@ -549,7 +680,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans)
bzero((char*) &table_list,sizeof(table_list));
table_list.db= m_dbname;
table_list.alias= table_list.table_name= m_tabname;
- close_cached_tables(thd, &table_list, FALSE, FALSE, FALSE);
+ close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
break;
}
default:
@@ -905,7 +1036,7 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
}
if (loop == 0 && offset > buffer_size)
{
- my_free(buffer, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(buffer);
buffer_size= 0;
DBUG_PRINT("info", ("allocate blobs buffer size %u", offset));
buffer= (uchar*) my_malloc(offset, MYF(MY_WME));
@@ -1058,8 +1189,8 @@ int ha_ndbcluster::get_metadata(const char *path)
if (readfrm(path, &data, &length) ||
packfrm(data, length, &pack_data, &pack_length))
{
- my_free(data, MYF(MY_ALLOW_ZERO_PTR));
- my_free(pack_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(data);
+ my_free(pack_data);
DBUG_RETURN(1);
}
@@ -1078,8 +1209,8 @@ int ha_ndbcluster::get_metadata(const char *path)
DBUG_DUMP("frm", (uchar*) tab->getFrmData(), tab->getFrmLength());
error= HA_ERR_TABLE_DEF_CHANGED;
}
- my_free((char*)data, MYF(0));
- my_free((char*)pack_data, MYF(0));
+ my_free(data);
+ my_free(pack_data);
if (error)
goto err;
@@ -1105,7 +1236,7 @@ static int fix_unique_index_attr_order(NDB_INDEX_DATA &data,
unsigned sz= index->getNoOfIndexColumns();
if (data.unique_index_attrid_map)
- my_free((char*)data.unique_index_attrid_map, MYF(0));
+ my_free(data.unique_index_attrid_map);
data.unique_index_attrid_map= (uchar*)my_malloc(sz,MYF(MY_WME));
if (data.unique_index_attrid_map == 0)
{
@@ -1183,7 +1314,7 @@ static void ndb_clear_index(NDB_INDEX_DATA &data)
{
if (data.unique_index_attrid_map)
{
- my_free((char*)data.unique_index_attrid_map, MYF(0));
+ my_free(data.unique_index_attrid_map);
}
if (data.index_stat)
{
@@ -1229,11 +1360,11 @@ int ha_ndbcluster::add_index_handle(THD *thd, NDBDICT *dict, KEY *key_info,
NDB_INDEX_DATA& d=m_index[index_no];
delete d.index_stat;
d.index_stat=NULL;
- if (thd->variables.ndb_index_stat_enable)
+ if (THDVAR(thd, index_stat_enable))
{
d.index_stat=new NdbIndexStat(index);
- d.index_stat_cache_entries=thd->variables.ndb_index_stat_cache_entries;
- d.index_stat_update_freq=thd->variables.ndb_index_stat_update_freq;
+ d.index_stat_cache_entries=THDVAR(thd, index_stat_cache_entries);
+ d.index_stat_update_freq=THDVAR(thd, index_stat_update_freq);
d.index_stat_query_count=0;
d.index_stat->alloc_cache(d.index_stat_cache_entries);
DBUG_PRINT("info", ("index %s stat=on cache_entries=%u update_freq=%u",
@@ -3603,9 +3734,11 @@ int ha_ndbcluster::index_read(uchar *buf,
{
key_range start_key;
bool descending= FALSE;
+ int rc;
DBUG_ENTER("ha_ndbcluster::index_read");
DBUG_PRINT("enter", ("active_index: %u, key_len: %u, find_flag: %d",
active_index, key_len, find_flag));
+ MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
start_key.key= key;
start_key.length= key_len;
@@ -3621,43 +3754,61 @@ int ha_ndbcluster::index_read(uchar *buf,
default:
break;
}
- DBUG_RETURN(read_range_first_to_buf(&start_key, 0, descending,
- m_sorted, buf));
+ rc= read_range_first_to_buf(&start_key, 0, descending,
+ m_sorted, buf);
+ MYSQL_INDEX_READ_ROW_DONE(rc);
+ DBUG_RETURN(rc);
}
int ha_ndbcluster::index_next(uchar *buf)
{
+ int rc;
DBUG_ENTER("ha_ndbcluster::index_next");
+ MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
ha_statistic_increment(&SSV::ha_read_next_count);
- DBUG_RETURN(next_result(buf));
+ rc= next_result(buf);
+ MYSQL_INDEX_READ_ROW_DONE(rc);
+ DBUG_RETURN(rc);
}
int ha_ndbcluster::index_prev(uchar *buf)
{
+ int rc;
DBUG_ENTER("ha_ndbcluster::index_prev");
+ MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
ha_statistic_increment(&SSV::ha_read_prev_count);
- DBUG_RETURN(next_result(buf));
+ rc= next_result(buf);
+ MYSQL_INDEX_READ_ROW_DONE(rc);
+ DBUG_RETURN(rc);
}
int ha_ndbcluster::index_first(uchar *buf)
{
+ int rc;
DBUG_ENTER("ha_ndbcluster::index_first");
+ MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
ha_statistic_increment(&SSV::ha_read_first_count);
// Start the ordered index scan and fetch the first row
// Only HA_READ_ORDER indexes get called by index_first
- DBUG_RETURN(ordered_index_scan(0, 0, TRUE, FALSE, buf, NULL));
+ rc= ordered_index_scan(0, 0, TRUE, FALSE, buf, NULL);
+ MYSQL_INDEX_READ_ROW_DONE(rc);
+ DBUG_RETURN(rc);
}
int ha_ndbcluster::index_last(uchar *buf)
{
+ int rc;
DBUG_ENTER("ha_ndbcluster::index_last");
+ MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
ha_statistic_increment(&SSV::ha_read_last_count);
- DBUG_RETURN(ordered_index_scan(0, 0, TRUE, TRUE, buf, NULL));
+ rc= ordered_index_scan(0, 0, TRUE, TRUE, buf, NULL);
+ MYSQL_INDEX_READ_ROW_DONE(rc);
+ DBUG_RETURN(rc);
}
int ha_ndbcluster::index_read_last(uchar * buf, const uchar * key, uint key_len)
@@ -3749,16 +3900,24 @@ int ha_ndbcluster::read_range_first(const key_range *start_key,
const key_range *end_key,
bool eq_r, bool sorted)
{
+ int rc;
uchar* buf= table->record[0];
DBUG_ENTER("ha_ndbcluster::read_range_first");
- DBUG_RETURN(read_range_first_to_buf(start_key, end_key, FALSE,
- sorted, buf));
+ MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
+ rc= read_range_first_to_buf(start_key, end_key, FALSE,
+ sorted, buf);
+ MYSQL_INDEX_READ_ROW_DONE(rc);
+ DBUG_RETURN(rc);
}
int ha_ndbcluster::read_range_next()
{
+ int rc;
DBUG_ENTER("ha_ndbcluster::read_range_next");
- DBUG_RETURN(next_result(table->record[0]));
+ MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
+ rc= next_result(table->record[0]);
+ MYSQL_INDEX_READ_ROW_DONE(rc);
+ DBUG_RETURN(rc);
}
@@ -3841,12 +4000,18 @@ int ha_ndbcluster::rnd_end()
int ha_ndbcluster::rnd_next(uchar *buf)
{
+ int rc;
DBUG_ENTER("rnd_next");
+ MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str,
+ TRUE);
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
if (!m_active_cursor)
- DBUG_RETURN(full_table_scan(buf));
- DBUG_RETURN(next_result(buf));
+ rc= full_table_scan(buf);
+ else
+ rc= next_result(buf);
+ MYSQL_READ_ROW_DONE(rc);
+ DBUG_RETURN(rc);
}
@@ -3858,7 +4023,10 @@ int ha_ndbcluster::rnd_next(uchar *buf)
int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos)
{
+ int rc;
DBUG_ENTER("rnd_pos");
+ MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str,
+ FALSE);
ha_statistic_increment(&SSV::ha_read_rnd_count);
// The primary key for the record is stored in pos
// Perform a pk_read using primary key "index"
@@ -3891,7 +4059,9 @@ int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos)
DBUG_PRINT("info", ("partition id %u", part_spec.start_part));
}
DBUG_DUMP("key", pos, key_length);
- DBUG_RETURN(pk_read(pos, key_length, buf, part_spec.start_part));
+ rc= pk_read(pos, key_length, buf, part_spec.start_part);
+ MYSQL_READ_ROW_DONE(rc);
+ DBUG_RETURN(rc);
}
}
@@ -4024,7 +4194,7 @@ int ha_ndbcluster::info(uint flag)
{
DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
}
- if (current_thd->variables.ndb_use_exact_count &&
+ if (THDVAR(current_thd, use_exact_count) &&
(result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat))
== 0)
{
@@ -4080,7 +4250,7 @@ int ha_ndbcluster::info(uint flag)
}
-void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO *stat_info,
+void ha_ndbcluster::get_dynamic_partition_info(PARTITION_STATS *stat_info,
uint part_id)
{
/*
@@ -4088,7 +4258,7 @@ void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO *stat_info,
implement ndb function which retrives the statistics
about ndb partitions.
*/
- bzero((char*) stat_info, sizeof(PARTITION_INFO));
+ bzero((char*) stat_info, sizeof(PARTITION_STATS));
return;
}
@@ -4263,7 +4433,7 @@ int ha_ndbcluster::end_bulk_insert()
}
else
{
- IF_DBUG(int res=) trans->restart();
+ int res __attribute__((unused))= trans->restart();
DBUG_ASSERT(res == 0);
}
}
@@ -4354,12 +4524,12 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd,
#ifndef DBUG_OFF
#define PRINT_OPTION_FLAGS(t) { \
- if (t->options & OPTION_NOT_AUTOCOMMIT) \
- DBUG_PRINT("thd->options", ("OPTION_NOT_AUTOCOMMIT")); \
- if (t->options & OPTION_BEGIN) \
- DBUG_PRINT("thd->options", ("OPTION_BEGIN")); \
- if (t->options & OPTION_TABLE_LOCK) \
- DBUG_PRINT("thd->options", ("OPTION_TABLE_LOCK")); \
+ if (t->variables.option_bits & OPTION_NOT_AUTOCOMMIT) \
+ DBUG_PRINT("thd->variables.option_bits", ("OPTION_NOT_AUTOCOMMIT")); \
+ if (t->variables.option_bits & OPTION_BEGIN) \
+ DBUG_PRINT("thd->variables.option_bits", ("OPTION_BEGIN")); \
+ if (t->variables.option_bits & OPTION_TABLE_LOCK) \
+ DBUG_PRINT("thd->variables.option_bits", ("OPTION_TABLE_LOCK")); \
}
#else
#define PRINT_OPTION_FLAGS(t)
@@ -4446,7 +4616,7 @@ void ha_ndbcluster::transaction_checks(THD *thd)
else if (!thd->transaction.on)
m_transaction_on= FALSE;
else
- m_transaction_on= thd->variables.ndb_use_transactions;
+ m_transaction_on= THDVAR(thd, use_transactions);
}
int ha_ndbcluster::start_statement(THD *thd,
@@ -4459,7 +4629,7 @@ int ha_ndbcluster::start_statement(THD *thd,
trans_register_ha(thd, FALSE, ndbcluster_hton);
if (!thd_ndb->trans)
{
- if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ if (thd->in_multi_stmt_transaction_mode())
trans_register_ha(thd, TRUE, ndbcluster_hton);
DBUG_PRINT("trans",("Starting transaction"));
thd_ndb->trans= ndb->startTransaction();
@@ -4469,7 +4639,7 @@ int ha_ndbcluster::start_statement(THD *thd,
thd_ndb->query_state&= NDB_QUERY_NORMAL;
thd_ndb->trans_options= 0;
thd_ndb->m_slow_path= FALSE;
- if (!(thd->options & OPTION_BIN_LOG) ||
+ if (!(thd->variables.option_bits & OPTION_BIN_LOG) ||
thd->variables.binlog_format == BINLOG_FORMAT_STMT)
{
thd_ndb->trans_options|= TNTO_NO_LOGGING;
@@ -4484,7 +4654,7 @@ int ha_ndbcluster::start_statement(THD *thd,
Check if it should be read or write lock
*/
- if (thd->options & (OPTION_TABLE_LOCK))
+ if (thd->variables.option_bits & OPTION_TABLE_LOCK)
{
//lockThisTable();
DBUG_PRINT("info", ("Locking the table..." ));
@@ -4508,13 +4678,13 @@ int ha_ndbcluster::init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb)
DBUG_ENTER("ha_ndbcluster::init_handler_for_statement");
// store thread specific data first to set the right context
- m_force_send= thd->variables.ndb_force_send;
- m_ha_not_exact_count= !thd->variables.ndb_use_exact_count;
+ m_force_send= THDVAR(thd, force_send);
+ m_ha_not_exact_count= !THDVAR(thd, use_exact_count);
m_autoincrement_prefetch=
- (thd->variables.ndb_autoincrement_prefetch_sz >
- NDB_DEFAULT_AUTO_PREFETCH) ?
- (ha_rows) thd->variables.ndb_autoincrement_prefetch_sz
- : (ha_rows) NDB_DEFAULT_AUTO_PREFETCH;
+ (THDVAR(thd, autoincrement_prefetch_sz) >
+ DEFAULT_AUTO_PREFETCH) ?
+ (ha_rows) THDVAR(thd, autoincrement_prefetch_sz)
+ : (ha_rows) DEFAULT_AUTO_PREFETCH;
m_active_trans= thd_ndb->trans;
DBUG_ASSERT(m_active_trans);
// Start of transaction
@@ -4529,14 +4699,14 @@ int ha_ndbcluster::init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb)
}
#endif
- if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ if (thd->in_multi_stmt_transaction_mode())
{
const void *key= m_table;
HASH_SEARCH_STATE state;
THD_NDB_SHARE *thd_ndb_share=
- (THD_NDB_SHARE*)hash_first(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state);
+ (THD_NDB_SHARE*)my_hash_first(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state);
while (thd_ndb_share && thd_ndb_share->key != key)
- thd_ndb_share= (THD_NDB_SHARE*)hash_next(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state);
+ thd_ndb_share= (THD_NDB_SHARE*)my_hash_next(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state);
if (thd_ndb_share == 0)
{
thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root,
@@ -4610,21 +4780,21 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
{
DBUG_PRINT("info", ("lock_type == F_UNLCK"));
- if (ndb_cache_check_time && m_rows_changed)
+ if (opt_ndb_cache_check_time && m_rows_changed)
{
DBUG_PRINT("info", ("Rows has changed and util thread is running"));
- if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ if (thd->in_multi_stmt_transaction_mode())
{
DBUG_PRINT("info", ("Add share to list of tables to be invalidated"));
/* NOTE push_back allocates memory using transactions mem_root! */
thd_ndb->changed_tables.push_back(m_share, &thd->transaction.mem_root);
}
- pthread_mutex_lock(&m_share->mutex);
+ mysql_mutex_lock(&m_share->mutex);
DBUG_PRINT("info", ("Invalidating commit_count"));
m_share->commit_count= 0;
m_share->commit_count_lock++;
- pthread_mutex_unlock(&m_share->mutex);
+ mysql_mutex_unlock(&m_share->mutex);
}
if (!--thd_ndb->lock_count)
@@ -4632,7 +4802,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
DBUG_PRINT("trans", ("Last external_lock"));
PRINT_OPTION_FLAGS(thd);
- if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ if (!thd->in_multi_stmt_transaction_mode())
{
if (thd_ndb->trans)
{
@@ -4742,8 +4912,7 @@ static int ndbcluster_commit(handlerton *hton, THD *thd, bool all)
PRINT_OPTION_FLAGS(thd);
DBUG_PRINT("enter", ("Commit %s", (all ? "all" : "stmt")));
thd_ndb->start_stmt_count= 0;
- if (trans == NULL || (!all &&
- thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ if (trans == NULL || (!all && thd->in_multi_stmt_transaction_mode()))
{
/*
An odditity in the handler interface is that commit on handlerton
@@ -4785,12 +4954,12 @@ static int ndbcluster_commit(handlerton *hton, THD *thd, bool all)
List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
while ((share= it++))
{
- pthread_mutex_lock(&share->mutex);
+ mysql_mutex_lock(&share->mutex);
DBUG_PRINT("info", ("Invalidate commit_count for %s, share->commit_count: %lu",
share->table_name, (ulong) share->commit_count));
share->commit_count= 0;
share->commit_count_lock++;
- pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
}
thd_ndb->changed_tables.empty();
@@ -4813,7 +4982,7 @@ static int ndbcluster_rollback(handlerton *hton, THD *thd, bool all)
DBUG_ASSERT(ndb);
thd_ndb->start_stmt_count= 0;
if (trans == NULL || (!all &&
- thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ thd->in_multi_stmt_transaction_mode()))
{
/* Ignore end-of-statement until real rollback or commit is called */
DBUG_PRINT("info", ("Rollback before start or end-of-statement only"));
@@ -5231,15 +5400,15 @@ int ha_ndbcluster::create(const char *name,
DBUG_RETURN(1);
if (packfrm(data, length, &pack_data, &pack_length))
{
- my_free((char*)data, MYF(0));
+ my_free(data);
DBUG_RETURN(2);
}
DBUG_PRINT("info",
("setFrm data: 0x%lx len: %lu", (long) pack_data,
(ulong) pack_length));
tab.setFrm(pack_data, pack_length);
- my_free((char*)data, MYF(0));
- my_free((char*)pack_data, MYF(0));
+ my_free(data);
+ my_free(pack_data);
/*
Check for disk options
@@ -5255,7 +5424,7 @@ int ha_ndbcluster::create(const char *name,
{
if (create_info->storage_media == HA_SM_MEMORY)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
ER(ER_ILLEGAL_HA_CREATE_OPTION),
ndbcluster_hton_name,
@@ -5310,7 +5479,7 @@ int ha_ndbcluster::create(const char *name,
case ROW_TYPE_FIXED:
if (field_type_forces_var_part(field->type()))
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
ER(ER_ILLEGAL_HA_CREATE_OPTION),
ndbcluster_hton_name,
@@ -5464,14 +5633,14 @@ int ha_ndbcluster::create(const char *name,
if (!my_errno)
{
NDB_SHARE *share= 0;
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
/*
First make sure we get a "fresh" share here, not an old trailing one...
*/
{
uint length= (uint) strlen(name);
- if ((share= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
- (uchar*) name, length)))
+ if ((share= (NDB_SHARE*) my_hash_search(&ndbcluster_open_tables,
+ (uchar*) name, length)))
handle_trailing_share(share);
}
/*
@@ -5489,7 +5658,7 @@ int ha_ndbcluster::create(const char *name,
DBUG_PRINT("NDB_SHARE", ("%s binlog create use_count: %u",
share->key, share->use_count));
}
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
while (!IS_TMP_PREFIX(m_tabname))
{
@@ -5509,7 +5678,7 @@ int ha_ndbcluster::create(const char *name,
if (!ndbcluster_create_event(ndb, m_table, event_name.c_ptr(), share,
share && do_event_op ? 2 : 1/* push warning */))
{
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: CREATE TABLE Event: %s",
event_name.c_ptr());
if (share &&
@@ -5533,7 +5702,7 @@ int ha_ndbcluster::create(const char *name,
m_table->getObjectVersion(),
(is_truncate) ?
SOT_TRUNCATE_TABLE : SOT_CREATE_TABLE,
- 0, 0, 1);
+ 0, 0);
break;
}
}
@@ -5583,8 +5752,8 @@ int ha_ndbcluster::create_handler_files(const char *file,
packfrm(data, length, &pack_data, &pack_length))
{
DBUG_PRINT("info", ("Missing frm for %s", m_tabname));
- my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(data);
+ my_free(pack_data);
error= 1;
}
else
@@ -5598,8 +5767,8 @@ int ha_ndbcluster::create_handler_files(const char *file,
set_ndb_err(current_thd, dict->getNdbError());
error= ndb_to_mysql_error(&dict->getNdbError());
}
- my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(data);
+ my_free(pack_data);
}
set_ndb_share_state(m_share, NSS_INITIAL);
@@ -5650,7 +5819,7 @@ int ha_ndbcluster::create_index(const char *name, KEY *key_info,
case ORDERED_INDEX:
if (key_info->algorithm == HA_KEY_ALG_HASH)
{
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
ER(ER_ILLEGAL_HA_CREATE_OPTION),
ndbcluster_hton_name,
@@ -5875,7 +6044,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
{
DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
share->key, share->use_count));
- IF_DBUG(int r=) rename_share(share, to);
+ int r __attribute__((unused))= rename_share(share, to);
DBUG_ASSERT(r == 0);
}
#endif
@@ -5899,7 +6068,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
#ifdef HAVE_NDB_BINLOG
if (share)
{
- IF_DBUG(int ret=) rename_share(share, from);
+ int ret __attribute__((unused))= rename_share(share, from);
DBUG_ASSERT(ret == 0);
/* ndb_share reference temporary free */
DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
@@ -5952,7 +6121,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
if (!ndbcluster_create_event(ndb, ndbtab, event_name.c_ptr(), share,
share && ndb_binlog_running ? 2 : 1/* push warning */))
{
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: RENAME Event: %s",
event_name.c_ptr());
if (share &&
@@ -5974,7 +6143,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
old_dbname, m_tabname,
ndb_table_id, ndb_table_version,
SOT_RENAME_TABLE,
- m_dbname, new_tabname, 1);
+ m_dbname, new_tabname);
}
// If we are moving tables between databases, we need to recreate
@@ -6128,7 +6297,7 @@ retry_temporary_error1:
/* the drop table failed for some reason, drop the share anyways */
if (share)
{
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
if (share->state != NSS_DROPPED)
{
/*
@@ -6144,7 +6313,7 @@ retry_temporary_error1:
DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
share->key, share->use_count));
free_share(&share, TRUE);
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
}
#endif
DBUG_RETURN(res);
@@ -6168,7 +6337,7 @@ retry_temporary_error1:
thd->query(), thd->query_length(),
share->db, share->table_name,
ndb_table_id, ndb_table_version,
- SOT_DROP_TABLE, 0, 0, 1);
+ SOT_DROP_TABLE, 0, 0);
}
else if (table_dropped && share && share->op) /* ndbcluster_log_schema_op
will do a force GCP */
@@ -6185,7 +6354,7 @@ retry_temporary_error1:
if (share)
{
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
if (share->state != NSS_DROPPED)
{
/*
@@ -6201,7 +6370,7 @@ retry_temporary_error1:
DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
share->key, share->use_count));
free_share(&share, TRUE);
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
}
#endif
DBUG_RETURN(0);
@@ -6255,10 +6424,9 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment,
m_rows_to_insert+= m_autoincrement_prefetch;
}
uint remaining= m_rows_to_insert - m_rows_inserted;
+ ha_rows prefetch= THDVAR(thd, autoincrement_prefetch_sz);
uint min_prefetch=
- (remaining < thd->variables.ndb_autoincrement_prefetch_sz) ?
- thd->variables.ndb_autoincrement_prefetch_sz
- : remaining;
+ (remaining < prefetch) ? prefetch : remaining;
cache_size= ((remaining < m_autoincrement_prefetch) ?
min_prefetch
: remaining);
@@ -6348,7 +6516,7 @@ ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg):
m_dupkey((uint) -1),
m_ha_not_exact_count(FALSE),
m_force_send(TRUE),
- m_autoincrement_prefetch((ha_rows) NDB_DEFAULT_AUTO_PREFETCH),
+ m_autoincrement_prefetch(DEFAULT_AUTO_PREFETCH),
m_transaction_on(TRUE),
m_cond(NULL),
m_multi_cursor(NULL)
@@ -6398,7 +6566,7 @@ ha_ndbcluster::~ha_ndbcluster()
free_share(&m_share);
}
release_metadata(thd, ndb);
- my_free(m_blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(m_blobs_buffer);
m_blobs_buffer= 0;
// Check for open cursor/transaction
@@ -6744,7 +6912,7 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
DBUG_RETURN(0);
err:
- my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(data);
if (share)
{
/* ndb_share reference temporary free */
@@ -6851,7 +7019,6 @@ int ndbcluster_drop_database_impl(const char *path)
while ((tabname=it++))
{
tablename_to_filename(tabname, tmp, FN_REFLEN - (tmp - full_path)-1);
- VOID(pthread_mutex_lock(&LOCK_open));
if (ha_ndbcluster::delete_table(0, ndb, full_path, dbname, tabname))
{
const NdbError err= dict->getNdbError();
@@ -6861,7 +7028,6 @@ int ndbcluster_drop_database_impl(const char *path)
ret= ndb_to_mysql_error(&err);
}
}
- VOID(pthread_mutex_unlock(&LOCK_open));
}
DBUG_RETURN(ret);
}
@@ -6888,7 +7054,7 @@ static void ndbcluster_drop_database(handlerton *hton, char *path)
ha_ndbcluster::set_dbname(path, db);
ndbcluster_log_schema_op(thd, 0,
thd->query(), thd->query_length(),
- db, "", 0, 0, SOT_DROP_DB, 0, 0, 0);
+ db, "", 0, 0, SOT_DROP_DB, 0, 0);
#endif
DBUG_VOID_RETURN;
}
@@ -6899,7 +7065,6 @@ int ndb_create_table_from_engine(THD *thd, const char *db,
LEX *old_lex= thd->lex, newlex;
thd->lex= &newlex;
newlex.current_select= NULL;
- lex_start(thd);
int res= ha_create_table_from_engine(thd, db, table_name);
thd->lex= old_lex;
return res;
@@ -7011,10 +7176,9 @@ int ndbcluster_find_all_files(THD *thd)
free_share(&share);
}
}
- my_free((char*) data, MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*) pack_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(data);
+ my_free(pack_data);
- pthread_mutex_lock(&LOCK_open);
if (discover)
{
/* ToDo 4.1 database needs to be created if missing */
@@ -7032,7 +7196,6 @@ int ndbcluster_find_all_files(THD *thd)
TRUE);
}
#endif
- pthread_mutex_unlock(&LOCK_open);
}
}
while (unhandled && retries);
@@ -7066,18 +7229,18 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
NdbDictionary::Object::UserTable) != 0)
ERR_RETURN(dict->getNdbError());
- if (hash_init(&ndb_tables, system_charset_info,list.count,0,0,
- (hash_get_key)tables_get_key,0,0))
+ if (my_hash_init(&ndb_tables, system_charset_info,list.count,0,0,
+ (my_hash_get_key)tables_get_key,0,0))
{
DBUG_PRINT("error", ("Failed to init HASH ndb_tables"));
DBUG_RETURN(-1);
}
- if (hash_init(&ok_tables, system_charset_info,32,0,0,
- (hash_get_key)tables_get_key,0,0))
+ if (my_hash_init(&ok_tables, system_charset_info,32,0,0,
+ (my_hash_get_key)tables_get_key,0,0))
{
DBUG_PRINT("error", ("Failed to init HASH ok_tables"));
- hash_free(&ndb_tables);
+ my_hash_free(&ndb_tables);
DBUG_RETURN(-1);
}
@@ -7118,25 +7281,23 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
{
bool file_on_disk= FALSE;
DBUG_PRINT("info", ("%s", file_name->str));
- if (hash_search(&ndb_tables, (uchar*) file_name->str, file_name->length))
+ if (my_hash_search(&ndb_tables, (uchar*) file_name->str,
+ file_name->length))
{
build_table_filename(name, sizeof(name) - 1, db,
file_name->str, reg_ext, 0);
if (my_access(name, F_OK))
{
- pthread_mutex_lock(&LOCK_open);
DBUG_PRINT("info", ("Table %s listed and need discovery",
file_name->str));
if (ndb_create_table_from_engine(thd, db, file_name->str))
{
- pthread_mutex_unlock(&LOCK_open);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TABLE_EXISTS_ERROR,
"Discover of table %s.%s failed",
db, file_name->str);
continue;
}
- pthread_mutex_unlock(&LOCK_open);
}
DBUG_PRINT("info", ("%s existed in NDB _and_ on disk ", file_name->str));
file_on_disk= TRUE;
@@ -7153,10 +7314,10 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
if (file_on_disk)
{
// Ignore this ndb table
- uchar *record= hash_search(&ndb_tables, (uchar*) file_name->str,
- file_name->length);
+ uchar *record= my_hash_search(&ndb_tables, (uchar*) file_name->str,
+ file_name->length);
DBUG_ASSERT(record);
- hash_delete(&ndb_tables, record);
+ my_hash_delete(&ndb_tables, record);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TABLE_EXISTS_ERROR,
"Local table %s.%s shadows ndb table",
@@ -7190,13 +7351,11 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
build_table_filename(name, sizeof(name) - 1, db, "", "", 0);
for (i= 0; i < ok_tables.records; i++)
{
- file_name_str= (char*)hash_element(&ok_tables, i);
+ file_name_str= (char*)my_hash_element(&ok_tables, i);
end= end1 +
tablename_to_filename(file_name_str, end1, sizeof(name) - (end1 - name));
- pthread_mutex_lock(&LOCK_open);
ndbcluster_create_binlog_setup(ndb, name, end-name,
db, file_name_str, TRUE);
- pthread_mutex_unlock(&LOCK_open);
}
}
#endif
@@ -7206,8 +7365,9 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
List<char> create_list;
for (i= 0 ; i < ndb_tables.records ; i++)
{
- file_name_str= (char*) hash_element(&ndb_tables, i);
- if (!hash_search(&ok_tables, (uchar*) file_name_str, strlen(file_name_str)))
+ file_name_str= (char*) my_hash_element(&ndb_tables, i);
+ if (!my_hash_search(&ok_tables, (uchar*) file_name_str,
+ strlen(file_name_str)))
{
build_table_filename(name, sizeof(name) - 1,
db, file_name_str, reg_ext, 0);
@@ -7221,31 +7381,40 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
}
}
- if (!global_read_lock)
- {
- // Delete old files
- List_iterator_fast<char> it3(delete_list);
- while ((file_name_str= it3++))
- {
- DBUG_PRINT("info", ("Remove table %s/%s", db, file_name_str));
- // Delete the table and all related files
- TABLE_LIST table_list;
- bzero((char*) &table_list,sizeof(table_list));
- table_list.db= (char*) db;
- table_list.alias= table_list.table_name= (char*)file_name_str;
- (void)mysql_rm_table_part2(thd, &table_list,
- FALSE, /* if_exists */
- FALSE, /* drop_temporary */
- FALSE, /* drop_view */
- TRUE /* dont_log_query*/);
+ /*
+ Delete old files.
- /* Clear error message that is returned when table is deleted */
- thd->clear_error();
- }
- }
+ ndbcluster_find_files() may be called from I_S code and ndbcluster_binlog
+ thread in situations when some tables are already open. This means that
+ code below will try to obtain exclusive metadata lock on some table
+ while holding shared meta-data lock on other tables. This might lead to a
+ deadlock but such a deadlock should be detected by MDL deadlock detector.
- pthread_mutex_lock(&LOCK_open);
- // Create new files
+ XXX: the scenario described above is not covered with any test.
+ */
+ List_iterator_fast<char> it3(delete_list);
+ while ((file_name_str= it3++))
+ {
+ DBUG_PRINT("info", ("Remove table %s/%s", db, file_name_str));
+ /* Delete the table and all related files. */
+ TABLE_LIST table_list;
+ table_list.init_one_table(db, strlen(db), file_name_str,
+ strlen(file_name_str), file_name_str,
+ TL_WRITE);
+ table_list.mdl_request.set_type(MDL_EXCLUSIVE);
+ (void)mysql_rm_table_part2(thd, &table_list,
+ FALSE, /* if_exists */
+ FALSE, /* drop_temporary */
+ FALSE, /* drop_view */
+ TRUE /* dont_log_query*/);
+ trans_commit_implicit(thd); /* Safety, should be unnecessary. */
+ thd->mdl_context.release_transactional_locks();
+ /* Clear error message that is returned when table is deleted */
+ thd->clear_error();
+ }
+
+ /* Lock mutex before creating .FRM files. */
+ /* Create new files. */
List_iterator_fast<char> it2(create_list);
while ((file_name_str=it2++))
{
@@ -7259,10 +7428,8 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
}
}
- pthread_mutex_unlock(&LOCK_open);
-
- hash_free(&ok_tables);
- hash_free(&ndb_tables);
+ my_hash_free(&ok_tables);
+ my_hash_free(&ndb_tables);
// Delete schema file from files
if (!strcmp(db, NDB_REP_DB))
@@ -7293,7 +7460,7 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
/* Call back after cluster connect */
static int connect_callback()
{
- pthread_mutex_lock(&LOCK_ndb_util_thread);
+ mysql_mutex_lock(&LOCK_ndb_util_thread);
update_status_variables(g_ndb_cluster_connection);
uint node_id, i= 0;
@@ -7302,13 +7469,91 @@ static int connect_callback()
while ((node_id= g_ndb_cluster_connection->get_next_node(node_iter)))
g_node_id_map[node_id]= i++;
- pthread_cond_signal(&COND_ndb_util_thread);
- pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ mysql_cond_signal(&COND_ndb_util_thread);
+ mysql_mutex_unlock(&LOCK_ndb_util_thread);
return 0;
}
extern int ndb_dictionary_is_mysqld;
-extern pthread_mutex_t LOCK_plugin;
+
+#ifdef HAVE_PSI_INTERFACE
+
+#ifdef HAVE_NDB_BINLOG
+PSI_mutex_key key_injector_mutex, key_ndb_schema_share_mutex,
+ key_ndb_schema_object_mutex;
+#endif /* HAVE_NDB_BINLOG */
+
+PSI_mutex_key key_NDB_SHARE_mutex, key_ndbcluster_mutex,
+ key_LOCK_ndb_util_thread;
+
+static PSI_mutex_info all_ndbcluster_mutexes[]=
+{
+#ifdef HAVE_NDB_BINLOG
+ {& key_injector_mutex, "injector_mutex", PSI_FLAG_GLOBAL},
+ {& key_ndb_schema_share_mutex, "ndb_schema_share_mutex", PSI_FLAG_GLOBAL},
+ {& key_ndb_schema_object_mutex, "ndb_schema_object_mutex", PSI_FLAG_GLOBAL},
+#endif /* HAVE_NDB_BINLOG */
+ {& key_NDB_SHARE_mutex, "NDB_SHARE::mutex", PSI_FLAG_GLOBAL},
+ {& key_ndbcluster_mutex, "ndbcluster_mutex", PSI_FLAG_GLOBAL},
+ {& key_LOCK_ndb_util_thread, "LOCK_ndb_util_thread", PSI_FLAG_GLOBAL}
+};
+
+#ifdef HAVE_NDB_BINLOG
+PSI_cond_key key_injector_cond;
+#endif /* HAVE_NDB_BINLOG */
+
+PSI_cond_key key_COND_ndb_util_thread, key_COND_ndb_util_ready;
+
+static PSI_cond_info all_ndbcluster_conds[]=
+{
+#ifdef HAVE_NDB_BINLOG
+ {& key_injector_cond, "injector_cond", PSI_FLAG_GLOBAL},
+#endif /* HAVE_NDB_BINLOG */
+ {& key_COND_ndb_util_thread, "COND_ndb_util_thread", PSI_FLAG_GLOBAL},
+ {& key_COND_ndb_util_ready, "COND_ndb_util_ready", PSI_FLAG_GLOBAL}
+};
+
+#ifdef HAVE_NDB_BINLOG
+PSI_thread_key key_thread_ndb_binlog;
+#endif /* HAVE_NDB_BINLOG */
+PSI_thread_key key_thread_ndb_util;
+
+static PSI_thread_info all_ndbcluster_threads[]=
+{
+#ifdef HAVE_NDB_BINLOG
+ { &key_thread_ndb_binlog, "ndb_binlog", PSI_FLAG_GLOBAL},
+#endif /* HAVE_NDB_BINLOG */
+ { &key_thread_ndb_util, "ndb_util", PSI_FLAG_GLOBAL}
+};
+
+PSI_file_key key_file_ndb;
+
+static PSI_file_info all_ndbcluster_files[]=
+{
+ { &key_file_ndb, "ndb", 0}
+};
+
+void init_ndbcluster_psi_keys()
+{
+ const char* category= "ndbcluster";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_ndbcluster_mutexes);
+ PSI_server->register_mutex(category, all_ndbcluster_mutexes, count);
+
+ count= array_elements(all_ndbcluster_conds);
+ PSI_server->register_cond(category, all_ndbcluster_conds, count);
+
+ count= array_elements(all_ndbcluster_threads);
+ PSI_server->register_thread(category, all_ndbcluster_threads, count);
+
+ count= array_elements(all_ndbcluster_files);
+ PSI_server->register_file(category, all_ndbcluster_files, count);
+}
+#endif /* HAVE_PSI_INTERFACE */
static int ndbcluster_init(void *p)
{
@@ -7318,10 +7563,16 @@ static int ndbcluster_init(void *p)
if (ndbcluster_inited)
DBUG_RETURN(FALSE);
- pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&COND_ndb_util_thread, NULL);
- pthread_cond_init(&COND_ndb_util_ready, NULL);
+#ifdef HAVE_PSI_INTERFACE
+ init_ndbcluster_psi_keys();
+#endif
+
+ mysql_mutex_init(key_ndbcluster_mutex,
+ &ndbcluster_mutex, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_ndb_util_thread,
+ &LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_ndb_util_thread, &COND_ndb_util_thread, NULL);
+ mysql_cond_init(key_COND_ndb_util_ready, &COND_ndb_util_ready, NULL);
ndb_util_thread_running= -1;
ndbcluster_terminating= 0;
ndb_dictionary_is_mysqld= 1;
@@ -7341,7 +7592,7 @@ static int ndbcluster_init(void *p)
h->alter_tablespace= ndbcluster_alter_tablespace; /* Show status */
h->partition_flags= ndbcluster_partition_flags; /* Partition flags */
h->alter_table_flags=ndbcluster_alter_table_flags; /* Alter table flags */
- h->fill_files_table= ndbcluster_fill_files_table;
+ h->fill_is_table= ndbcluster_fill_is_table;
#ifdef HAVE_NDB_BINLOG
ndbcluster_binlog_init_handlerton();
#endif
@@ -7351,17 +7602,31 @@ static int ndbcluster_init(void *p)
h->table_exists_in_engine= ndbcluster_table_exists_in_engine;
}
+ // Format the connect string to be used for connecting to the cluster
+ int pos= 0;
+ char connectstring_buf[1024] = {0};
+ if (opt_ndb_nodeid != 0)
+ pos+= my_snprintf(connectstring_buf, sizeof(connectstring_buf),
+ "nodeid=%u", opt_ndb_nodeid);
+ if (opt_ndb_mgmd_host)
+ pos+= my_snprintf(connectstring_buf+pos, sizeof(connectstring_buf)-pos,
+ "%s%s", pos ? "," : "", opt_ndb_mgmd_host);
+ if (opt_ndb_connectstring)
+ pos+= my_snprintf(connectstring_buf+pos, sizeof(connectstring_buf)-pos,
+ "%s%s", pos ? "," : "", opt_ndb_connectstring);
+
+
// Initialize ndb interface
ndb_init_internal();
// Set connectstring if specified
- if (opt_ndbcluster_connectstring != 0)
- DBUG_PRINT("connectstring", ("%s", opt_ndbcluster_connectstring));
+ if (opt_ndb_connectstring != 0)
+ DBUG_PRINT("connectstring", ("%s", opt_ndb_connectstring));
if ((g_ndb_cluster_connection=
- new Ndb_cluster_connection(opt_ndbcluster_connectstring)) == 0)
+ new Ndb_cluster_connection(opt_ndb_connectstring)) == 0)
{
DBUG_PRINT("error",("Ndb_cluster_connection(%s)",
- opt_ndbcluster_connectstring));
+ opt_ndb_connectstring));
my_errno= HA_ERR_OUT_OF_MEM;
goto ndbcluster_init_error;
}
@@ -7371,7 +7636,7 @@ static int ndbcluster_init(void *p)
g_ndb_cluster_connection->set_name(buf);
}
g_ndb_cluster_connection->set_optimized_node_selection
- (opt_ndb_optimized_node_selection);
+ (THDVAR(0, optimized_node_selection));
// Create a Ndb object to open the connection to NDB
if ( (g_ndb= new Ndb(g_ndb_cluster_connection, "sys")) == 0 )
@@ -7419,42 +7684,42 @@ static int ndbcluster_init(void *p)
goto ndbcluster_init_error;
}
- (void) hash_init(&ndbcluster_open_tables,system_charset_info,32,0,0,
- (hash_get_key) ndbcluster_get_key,0,0);
+ (void) my_hash_init(&ndbcluster_open_tables,system_charset_info,32,0,0,
+ (my_hash_get_key) ndbcluster_get_key,0,0);
#ifdef HAVE_NDB_BINLOG
/* start the ndb injector thread */
if (ndbcluster_binlog_start())
goto ndbcluster_init_error;
#endif /* HAVE_NDB_BINLOG */
- ndb_cache_check_time = opt_ndb_cache_check_time;
// Create utility thread
pthread_t tmp;
- if (pthread_create(&tmp, &connection_attrib, ndb_util_thread_func, 0))
+ if (mysql_thread_create(key_thread_ndb_util,
+ &tmp, &connection_attrib, ndb_util_thread_func, 0))
{
DBUG_PRINT("error", ("Could not create ndb utility thread"));
- hash_free(&ndbcluster_open_tables);
- pthread_mutex_destroy(&ndbcluster_mutex);
- pthread_mutex_destroy(&LOCK_ndb_util_thread);
- pthread_cond_destroy(&COND_ndb_util_thread);
- pthread_cond_destroy(&COND_ndb_util_ready);
+ my_hash_free(&ndbcluster_open_tables);
+ mysql_mutex_destroy(&ndbcluster_mutex);
+ mysql_mutex_destroy(&LOCK_ndb_util_thread);
+ mysql_cond_destroy(&COND_ndb_util_thread);
+ mysql_cond_destroy(&COND_ndb_util_ready);
goto ndbcluster_init_error;
}
/* Wait for the util thread to start */
- pthread_mutex_lock(&LOCK_ndb_util_thread);
+ mysql_mutex_lock(&LOCK_ndb_util_thread);
while (ndb_util_thread_running < 0)
- pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
- pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ mysql_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
+ mysql_mutex_unlock(&LOCK_ndb_util_thread);
if (!ndb_util_thread_running)
{
DBUG_PRINT("error", ("ndb utility thread exited prematurely"));
- hash_free(&ndbcluster_open_tables);
- pthread_mutex_destroy(&ndbcluster_mutex);
- pthread_mutex_destroy(&LOCK_ndb_util_thread);
- pthread_cond_destroy(&COND_ndb_util_thread);
- pthread_cond_destroy(&COND_ndb_util_ready);
+ my_hash_free(&ndbcluster_open_tables);
+ mysql_mutex_destroy(&ndbcluster_mutex);
+ mysql_mutex_destroy(&LOCK_ndb_util_thread);
+ mysql_cond_destroy(&COND_ndb_util_thread);
+ mysql_cond_destroy(&COND_ndb_util_ready);
goto ndbcluster_init_error;
}
@@ -7473,6 +7738,34 @@ ndbcluster_init_error:
DBUG_RETURN(TRUE);
}
+/**
+ Used to fill in INFORMATION_SCHEMA* tables.
+
+ @param hton handle to the handlerton structure
+ @param thd the thread/connection descriptor
+ @param[in,out] tables the information schema table that is filled up
+ @param cond used for conditional pushdown to storage engine
+ @param schema_table_idx the table id that distinguishes the type of table
+
+ @return Operation status
+ */
+static int ndbcluster_fill_is_table(handlerton *hton,
+ THD *thd,
+ TABLE_LIST *tables,
+ COND *cond,
+ enum enum_schema_tables schema_table_idx)
+{
+ int ret= 0;
+
+ if (schema_table_idx == SCH_FILES)
+ {
+ ret= ndbcluster_fill_files_table(hton, thd, tables, cond);
+ }
+
+ return ret;
+}
+
+
static int ndbcluster_end(handlerton *hton, ha_panic_function type)
{
DBUG_ENTER("ndbcluster_end");
@@ -7483,31 +7776,31 @@ static int ndbcluster_end(handlerton *hton, ha_panic_function type)
/* wait for util thread to finish */
sql_print_information("Stopping Cluster Utility thread");
- pthread_mutex_lock(&LOCK_ndb_util_thread);
+ mysql_mutex_lock(&LOCK_ndb_util_thread);
ndbcluster_terminating= 1;
- pthread_cond_signal(&COND_ndb_util_thread);
+ mysql_cond_signal(&COND_ndb_util_thread);
while (ndb_util_thread_running > 0)
- pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
- pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ mysql_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
+ mysql_mutex_unlock(&LOCK_ndb_util_thread);
#ifdef HAVE_NDB_BINLOG
{
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
while (ndbcluster_open_tables.records)
{
NDB_SHARE *share=
- (NDB_SHARE*) hash_element(&ndbcluster_open_tables, 0);
+ (NDB_SHARE*) my_hash_element(&ndbcluster_open_tables, 0);
#ifndef DBUG_OFF
fprintf(stderr, "NDB: table share %s with use_count %d not freed\n",
share->key, share->use_count);
#endif
ndbcluster_real_free_share(&share);
}
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
}
#endif
- hash_free(&ndbcluster_open_tables);
+ my_hash_free(&ndbcluster_open_tables);
if (g_ndb)
{
@@ -7533,10 +7826,10 @@ static int ndbcluster_end(handlerton *hton, ha_panic_function type)
// cleanup ndb interface
ndb_end_internal();
- pthread_mutex_destroy(&ndbcluster_mutex);
- pthread_mutex_destroy(&LOCK_ndb_util_thread);
- pthread_cond_destroy(&COND_ndb_util_thread);
- pthread_cond_destroy(&COND_ndb_util_ready);
+ mysql_mutex_destroy(&ndbcluster_mutex);
+ mysql_mutex_destroy(&LOCK_ndb_util_thread);
+ mysql_cond_destroy(&COND_ndb_util_thread);
+ mysql_cond_destroy(&COND_ndb_util_ready);
DBUG_RETURN(0);
}
@@ -7839,12 +8132,12 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
build_table_filename(name, sizeof(name) - 1,
dbname, tabname, "", 0);
DBUG_PRINT("enter", ("name: %s", name));
- pthread_mutex_lock(&ndbcluster_mutex);
- if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables,
- (uchar*) name,
- strlen(name))))
+ mysql_mutex_lock(&ndbcluster_mutex);
+ if (!(share=(NDB_SHARE*) my_hash_search(&ndbcluster_open_tables,
+ (uchar*) name,
+ strlen(name))))
{
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
DBUG_PRINT("info", ("Table %s not found in ndbcluster_open_tables", name));
DBUG_RETURN(1);
}
@@ -7852,10 +8145,10 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
share->use_count++;
DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
share->key, share->use_count));
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
- pthread_mutex_lock(&share->mutex);
- if (ndb_cache_check_time > 0)
+ mysql_mutex_lock(&share->mutex);
+ if (opt_ndb_cache_check_time > 0)
{
if (share->commit_count != 0)
{
@@ -7865,7 +8158,7 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
#endif
DBUG_PRINT("info", ("Getting commit_count: %s from share",
llstr(share->commit_count, buff)));
- pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
/* ndb_share reference temporary free */
DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
share->key, share->use_count));
@@ -7882,7 +8175,7 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
ERR_RETURN(ndb->getNdbError());
}
uint lock= share->commit_count_lock;
- pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
struct Ndb_statistics stat;
{
@@ -7898,7 +8191,7 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
}
}
- pthread_mutex_lock(&share->mutex);
+ mysql_mutex_lock(&share->mutex);
if (share->commit_count_lock == lock)
{
#ifndef DBUG_OFF
@@ -7914,7 +8207,7 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
DBUG_PRINT("info", ("Discarding commit_count, comit_count_lock changed"));
*commit_count= 0;
}
- pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
/* ndb_share reference temporary free */
DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
share->key, share->use_count));
@@ -7958,17 +8251,15 @@ ndbcluster_cache_retrieval_allowed(THD *thd,
ulonglong *engine_data)
{
Uint64 commit_count;
- bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
char *dbname= full_name;
char *tabname= dbname+strlen(dbname)+1;
#ifndef DBUG_OFF
char buff[22], buff2[22];
#endif
DBUG_ENTER("ndbcluster_cache_retrieval_allowed");
- DBUG_PRINT("enter", ("dbname: %s, tabname: %s, is_autocommit: %d",
- dbname, tabname, is_autocommit));
+ DBUG_PRINT("enter", ("dbname: %s, tabname: %s", dbname, tabname));
- if (!is_autocommit)
+ if (thd->in_multi_stmt_transaction_mode())
{
DBUG_PRINT("exit", ("No, don't use cache in transaction"));
DBUG_RETURN(FALSE);
@@ -8033,12 +8324,10 @@ ha_ndbcluster::register_query_cache_table(THD *thd,
#ifndef DBUG_OFF
char buff[22];
#endif
- bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
DBUG_ENTER("ha_ndbcluster::register_query_cache_table");
- DBUG_PRINT("enter",("dbname: %s, tabname: %s, is_autocommit: %d",
- m_dbname, m_tabname, is_autocommit));
+ DBUG_PRINT("enter",("dbname: %s, tabname: %s", m_dbname, m_tabname));
- if (!is_autocommit)
+ if (thd->in_multi_stmt_transaction_mode())
{
DBUG_PRINT("exit", ("Can't register table during transaction"));
DBUG_RETURN(FALSE);
@@ -8102,7 +8391,7 @@ static void print_ndbcluster_open_tables()
fprintf(DBUG_FILE, ">ndbcluster_open_tables\n");
for (uint i= 0; i < ndbcluster_open_tables.records; i++)
print_share("",
- (NDB_SHARE*)hash_element(&ndbcluster_open_tables, i));
+ (NDB_SHARE*)my_hash_element(&ndbcluster_open_tables, i));
fprintf(DBUG_FILE, "<ndbcluster_open_tables\n");
DBUG_UNLOCK_FILE;
}
@@ -8130,7 +8419,7 @@ static void print_ndbcluster_open_tables()
to avoid segmentation faults. There is a risk that the memory for
this trailing share leaks.
- Must be called with previous pthread_mutex_lock(&ndbcluster_mutex)
+ Must be called with previous mysql_mutex_lock(&ndbcluster_mutex)
*/
int handle_trailing_share(NDB_SHARE *share)
{
@@ -8142,22 +8431,21 @@ int handle_trailing_share(NDB_SHARE *share)
++share->use_count;
DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
share->key, share->use_count));
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list));
table_list.db= share->db;
table_list.alias= table_list.table_name= share->table_name;
- safe_mutex_assert_owner(&LOCK_open);
- close_cached_tables(thd, &table_list, TRUE, FALSE, FALSE);
+ close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
/* ndb_share reference temporary free */
DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
share->key, share->use_count));
if (!--share->use_count)
{
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB_SHARE: trailing share "
"%s(connect_count: %u) "
"released by close_cached_tables at "
@@ -8183,7 +8471,7 @@ int handle_trailing_share(NDB_SHARE *share)
if (share->use_count == 0)
{
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB_SHARE: trailing share "
"%s(connect_count: %u) "
"released after NSS_DROPPED check "
@@ -8213,7 +8501,7 @@ int handle_trailing_share(NDB_SHARE *share)
at the cost of a possible mem leak, by "renaming" the share
- First remove from hash
*/
- hash_delete(&ndbcluster_open_tables, (uchar*) share);
+ my_hash_delete(&ndbcluster_open_tables, (uchar*) share);
/*
now give it a new name, just a running number
@@ -8242,16 +8530,16 @@ int handle_trailing_share(NDB_SHARE *share)
static int rename_share(NDB_SHARE *share, const char *new_key)
{
NDB_SHARE *tmp;
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
uint new_length= (uint) strlen(new_key);
DBUG_PRINT("rename_share", ("old_key: %s old__length: %d",
share->key, share->key_length));
- if ((tmp= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
- (uchar*) new_key, new_length)))
+ if ((tmp= (NDB_SHARE*) my_hash_search(&ndbcluster_open_tables,
+ (uchar*) new_key, new_length)))
handle_trailing_share(tmp);
/* remove the share from hash */
- hash_delete(&ndbcluster_open_tables, (uchar*) share);
+ my_hash_delete(&ndbcluster_open_tables, (uchar*) share);
dbug_print_open_tables();
/* save old stuff if insert should fail */
@@ -8280,7 +8568,7 @@ static int rename_share(NDB_SHARE *share, const char *new_key)
share->key));
}
dbug_print_open_tables();
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
return -1;
}
dbug_print_open_tables();
@@ -8305,7 +8593,7 @@ static int rename_share(NDB_SHARE *share, const char *new_key)
share->old_names= old_key;
// ToDo free old_names after ALTER EVENT
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
return 0;
}
#endif
@@ -8316,12 +8604,12 @@ static int rename_share(NDB_SHARE *share, const char *new_key)
*/
NDB_SHARE *ndbcluster_get_share(NDB_SHARE *share)
{
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
share->use_count++;
dbug_print_open_tables();
dbug_print_share("ndbcluster_get_share:", share);
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
return share;
}
@@ -8338,7 +8626,7 @@ NDB_SHARE *ndbcluster_get_share(NDB_SHARE *share)
create_if_not_exists == FALSE:
returns 0 if share does not exist
- have_lock == TRUE, pthread_mutex_lock(&ndbcluster_mutex) already taken
+ have_lock == TRUE, mysql_mutex_lock(&ndbcluster_mutex) already taken
*/
NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
@@ -8351,16 +8639,16 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
DBUG_PRINT("enter", ("key: '%s'", key));
if (!have_lock)
- pthread_mutex_lock(&ndbcluster_mutex);
- if (!(share= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
- (uchar*) key,
- length)))
+ mysql_mutex_lock(&ndbcluster_mutex);
+ if (!(share= (NDB_SHARE*) my_hash_search(&ndbcluster_open_tables,
+ (uchar*) key,
+ length)))
{
if (!create_if_not_exists)
{
DBUG_PRINT("error", ("get_share: %s does not exist", key));
if (!have_lock)
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(0);
}
if ((share= (NDB_SHARE*) my_malloc(sizeof(*share),
@@ -8379,14 +8667,14 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
if (my_hash_insert(&ndbcluster_open_tables, (uchar*) share))
{
free_root(&share->mem_root, MYF(0));
- my_free((uchar*) share, 0);
+ my_free(share);
*root_ptr= old_root;
if (!have_lock)
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(0);
}
thr_lock_init(&share->lock);
- pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_NDB_SHARE_mutex, &share->mutex, MY_MUTEX_INIT_FAST);
share->commit_count= 0;
share->commit_count_lock= 0;
share->db= share->key + length + 1;
@@ -8400,7 +8688,7 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
ndbcluster_real_free_share(&share);
*root_ptr= old_root;
if (!have_lock)
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(0);
}
#endif
@@ -8410,7 +8698,7 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
{
DBUG_PRINT("error", ("get_share: failed to alloc share"));
if (!have_lock)
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
my_error(ER_OUTOFMEMORY, MYF(0), sizeof(*share));
DBUG_RETURN(0);
}
@@ -8420,7 +8708,7 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
dbug_print_open_tables();
dbug_print_share("ndbcluster_get_share:", share);
if (!have_lock)
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(share);
}
@@ -8430,9 +8718,9 @@ void ndbcluster_real_free_share(NDB_SHARE **share)
DBUG_ENTER("ndbcluster_real_free_share");
dbug_print_share("ndbcluster_real_free_share:", *share);
- hash_delete(&ndbcluster_open_tables, (uchar*) *share);
+ my_hash_delete(&ndbcluster_open_tables, (uchar*) *share);
thr_lock_delete(&(*share)->lock);
- pthread_mutex_destroy(&(*share)->mutex);
+ mysql_mutex_destroy(&(*share)->mutex);
#ifdef HAVE_NDB_BINLOG
if ((*share)->table)
@@ -8450,7 +8738,7 @@ void ndbcluster_real_free_share(NDB_SHARE **share)
}
#endif
free_root(&(*share)->mem_root, MYF(0));
- my_free((uchar*) *share, MYF(0));
+ my_free(*share);
*share= 0;
dbug_print_open_tables();
@@ -8461,7 +8749,7 @@ void ndbcluster_real_free_share(NDB_SHARE **share)
void ndbcluster_free_share(NDB_SHARE **share, bool have_lock)
{
if (!have_lock)
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
if ((*share)->util_lock == current_thd)
(*share)->util_lock= 0;
if (!--(*share)->use_count)
@@ -8474,7 +8762,7 @@ void ndbcluster_free_share(NDB_SHARE **share, bool have_lock)
dbug_print_share("ndbcluster_free_share:", *share);
}
if (!have_lock)
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
}
@@ -8634,11 +8922,12 @@ int ha_ndbcluster::write_ndb_file(const char *name)
(void)strxnmov(path, FN_REFLEN-1,
mysql_data_home,"/",name,ha_ndb_ext,NullS);
- if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
+ if ((file= mysql_file_create(key_file_ndb, path, CREATE_MODE,
+ O_RDWR | O_TRUNC, MYF(MY_WME))) >= 0)
{
// It's an empty file
error=0;
- my_close(file,MYF(0));
+ mysql_file_close(file, MYF(0));
}
DBUG_RETURN(error);
}
@@ -8723,6 +9012,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
sorted,
buffer));
}
+ MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
thd_ndb->query_state|= NDB_QUERY_MULTI_READ_RANGE;
m_disable_multi_read= FALSE;
@@ -8804,7 +9094,13 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
(op->setPartitionId(part_spec.start_part), TRUE)))
curr += reclength;
else
- ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError());
+ {
+ ERR_RETURN_PREPARE(res,
+ op ? op->getNdbError() :
+ m_active_trans->getNdbError())
+ MYSQL_INDEX_READ_ROW_DONE(res);
+ DBUG_RETURN(res);
+ }
break;
}
break;
@@ -8824,7 +9120,13 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
!define_read_attrs(curr, op))
curr += reclength;
else
- ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError());
+ {
+ ERR_RETURN_PREPARE(res,
+ op ? op->getNdbError() :
+ m_active_trans->getNdbError());
+ MYSQL_INDEX_READ_ROW_DONE(res);
+ DBUG_RETURN(res);
+ }
break;
}
case ORDERED_INDEX: {
@@ -8839,7 +9141,11 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
DBUG_ASSERT(scanOp->getLockMode() ==
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type));
if (scanOp->reset_bounds(m_force_send))
- DBUG_RETURN(ndb_err(m_active_trans));
+ {
+ res= ndb_err(m_active_trans);
+ MYSQL_INDEX_READ_ROW_DONE(res);
+ DBUG_RETURN(res);
+ }
end_of_buffer -= reclength;
}
@@ -8854,8 +9160,11 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
}
else
{
- ERR_RETURN(scanOp ? scanOp->getNdbError() :
- m_active_trans->getNdbError());
+ ERR_RETURN_PREPARE(res,
+ scanOp ? scanOp->getNdbError() :
+ m_active_trans->getNdbError());
+ MYSQL_INDEX_READ_ROW_DONE(res);
+ DBUG_RETURN(res);
}
}
@@ -8863,11 +9172,15 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
&multi_range_curr->end_key };
if ((res= set_bounds(scanOp, active_index, FALSE, keys,
multi_range_curr-ranges)))
+ {
+ MYSQL_INDEX_READ_ROW_DONE(res);
DBUG_RETURN(res);
+ }
break;
}
case UNDEFINED_INDEX:
DBUG_ASSERT(FALSE);
+ MYSQL_INDEX_READ_ROW_DONE(1);
DBUG_RETURN(1);
break;
}
@@ -8898,9 +9211,13 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
m_multi_range_defined= multi_range_curr;
multi_range_curr= ranges;
m_multi_range_result_ptr= (uchar*)buffer->buffer;
- DBUG_RETURN(read_multi_range_next(found_range_p));
+ res= loc_read_multi_range_next(found_range_p);
+ MYSQL_INDEX_READ_ROW_DONE(res);
+ DBUG_RETURN(res);
}
- ERR_RETURN(m_active_trans->getNdbError());
+ ERR_RETURN_PREPARE(res, m_active_trans->getNdbError());
+ MYSQL_INDEX_READ_ROW_DONE(res);
+ DBUG_RETURN(res);
}
#if 0
@@ -8912,17 +9229,28 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
int
ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p)
{
+ int rc;
DBUG_ENTER("ha_ndbcluster::read_multi_range_next");
if (m_disable_multi_read)
{
DBUG_MULTI_RANGE(11);
DBUG_RETURN(handler::read_multi_range_next(multi_range_found_p));
}
-
+ MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
+ rc= loc_read_multi_range_next(multi_range_found_p);
+ MYSQL_INDEX_READ_ROW_DONE(rc);
+ DBUG_RETURN(rc);
+}
+
+int ha_ndbcluster::loc_read_multi_range_next(
+ KEY_MULTI_RANGE **multi_range_found_p)
+{
int res;
int range_no;
ulong reclength= table_share->reclength;
const NdbOperation* op= m_current_multi_operation;
+ DBUG_ENTER("ha_ndbcluster::loc_read_multi_range_next");
+
for (;multi_range_curr < m_multi_range_defined; multi_range_curr++)
{
DBUG_MULTI_RANGE(12);
@@ -9029,6 +9357,7 @@ close_scan:
/*
* Read remaining ranges
*/
+ MYSQL_INDEX_READ_ROW_DONE(1);
DBUG_RETURN(read_multi_range_first(multi_range_found_p,
multi_range_curr,
multi_range_end - multi_range_curr,
@@ -9149,9 +9478,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
my_thread_init();
DBUG_ENTER("ndb_util_thread");
- DBUG_PRINT("enter", ("ndb_cache_check_time: %lu", ndb_cache_check_time));
+ DBUG_PRINT("enter", ("cache_check_time: %lu", opt_ndb_cache_check_time));
- pthread_mutex_lock(&LOCK_ndb_util_thread);
+ mysql_mutex_lock(&LOCK_ndb_util_thread);
thd= new THD; /* note that contructor of THD uses DBUG_ */
if (thd == NULL)
@@ -9166,14 +9495,14 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
thd->thread_stack= (char*)&thd; /* remember where our stack is */
if (thd->store_globals())
goto ndb_util_thread_fail;
- lex_start(thd);
thd->init_for_queries();
- thd->version=refresh_version;
thd->main_security_ctx.host_or_ip= "";
thd->client_capabilities = 0;
my_net_init(&thd->net, 0);
thd->main_security_ctx.master_access= ~0;
- thd->main_security_ctx.priv_user = 0;
+ thd->main_security_ctx.priv_user[0] = 0;
+ /* Do not use user-supplied timeout value for system threads. */
+ thd->variables.lock_wait_timeout= LONG_TIMEOUT;
CHARSET_INFO *charset_connection;
charset_connection= get_charset_by_csname("utf8",
@@ -9185,52 +9514,52 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
/* Signal successful initialization */
ndb_util_thread_running= 1;
- pthread_cond_signal(&COND_ndb_util_ready);
- pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ mysql_cond_signal(&COND_ndb_util_ready);
+ mysql_mutex_unlock(&LOCK_ndb_util_thread);
/*
wait for mysql server to start
*/
- pthread_mutex_lock(&LOCK_server_started);
+ mysql_mutex_lock(&LOCK_server_started);
while (!mysqld_server_started)
{
set_timespec(abstime, 1);
- pthread_cond_timedwait(&COND_server_started, &LOCK_server_started,
- &abstime);
+ mysql_cond_timedwait(&COND_server_started, &LOCK_server_started,
+ &abstime);
if (ndbcluster_terminating)
{
- pthread_mutex_unlock(&LOCK_server_started);
- pthread_mutex_lock(&LOCK_ndb_util_thread);
+ mysql_mutex_unlock(&LOCK_server_started);
+ mysql_mutex_lock(&LOCK_ndb_util_thread);
goto ndb_util_thread_end;
}
}
- pthread_mutex_unlock(&LOCK_server_started);
+ mysql_mutex_unlock(&LOCK_server_started);
/*
Wait for cluster to start
*/
- pthread_mutex_lock(&LOCK_ndb_util_thread);
+ mysql_mutex_lock(&LOCK_ndb_util_thread);
while (!ndb_cluster_node_id && (ndbcluster_hton->slot != ~(uint)0))
{
/* ndb not connected yet */
- pthread_cond_wait(&COND_ndb_util_thread, &LOCK_ndb_util_thread);
+ mysql_cond_wait(&COND_ndb_util_thread, &LOCK_ndb_util_thread);
if (ndbcluster_terminating)
goto ndb_util_thread_end;
}
- pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ mysql_mutex_unlock(&LOCK_ndb_util_thread);
/* Get thd_ndb for this thread */
if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
{
sql_print_error("Could not allocate Thd_ndb object");
- pthread_mutex_lock(&LOCK_ndb_util_thread);
+ mysql_mutex_lock(&LOCK_ndb_util_thread);
goto ndb_util_thread_end;
}
set_thd_ndb(thd, thd_ndb);
thd_ndb->options|= TNO_NO_LOG_SCHEMA_OP;
#ifdef HAVE_NDB_BINLOG
- if (ndb_extra_logging && ndb_binlog_running)
+ if (opt_ndb_extra_logging && ndb_binlog_running)
sql_print_information("NDB Binlog: Ndb tables initially read only.");
/* create tables needed by the replication */
ndbcluster_setup_binlog_table_shares(thd);
@@ -9244,17 +9573,17 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
set_timespec(abstime, 0);
for (;;)
{
- pthread_mutex_lock(&LOCK_ndb_util_thread);
+ mysql_mutex_lock(&LOCK_ndb_util_thread);
if (!ndbcluster_terminating)
- pthread_cond_timedwait(&COND_ndb_util_thread,
- &LOCK_ndb_util_thread,
- &abstime);
+ mysql_cond_timedwait(&COND_ndb_util_thread,
+ &LOCK_ndb_util_thread,
+ &abstime);
if (ndbcluster_terminating) /* Shutting down server */
goto ndb_util_thread_end;
- pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ mysql_mutex_unlock(&LOCK_ndb_util_thread);
#ifdef NDB_EXTRA_DEBUG_UTIL_THREAD
- DBUG_PRINT("ndb_util_thread", ("Started, ndb_cache_check_time: %lu",
- ndb_cache_check_time));
+ DBUG_PRINT("ndb_util_thread", ("Started, opt_ndb_cache_check_time: %lu",
+ opt_ndb_cache_check_time));
#endif
#ifdef HAVE_NDB_BINLOG
@@ -9267,7 +9596,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
ndbcluster_setup_binlog_table_shares(thd);
#endif
- if (ndb_cache_check_time == 0)
+ if (opt_ndb_cache_check_time == 0)
{
/* Wake up in 1 second to check if value has changed */
set_timespec(abstime, 1);
@@ -9276,7 +9605,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
/* Lock mutex and fill list with pointers to all open tables */
NDB_SHARE *share;
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
uint i, open_count, record_count= ndbcluster_open_tables.records;
if (share_list_size < record_count)
{
@@ -9285,7 +9614,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
{
sql_print_warning("ndb util thread: malloc failure, "
"query cache not maintained properly");
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
goto next; // At least do not crash
}
delete [] share_list;
@@ -9294,7 +9623,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
}
for (i= 0, open_count= 0; i < record_count; i++)
{
- share= (NDB_SHARE *)hash_element(&ndbcluster_open_tables, i);
+ share= (NDB_SHARE *)my_hash_element(&ndbcluster_open_tables, i);
#ifdef HAVE_NDB_BINLOG
if ((share->use_count - (int) (share->op != 0) - (int) (share->op != 0))
<= 0)
@@ -9312,7 +9641,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
/* Store pointer to table */
share_list[open_count++]= share;
}
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
/* Iterate through the open files list */
for (i= 0; i < open_count; i++)
@@ -9337,9 +9666,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
struct Ndb_statistics stat;
uint lock;
- pthread_mutex_lock(&share->mutex);
+ mysql_mutex_lock(&share->mutex);
lock= share->commit_count_lock;
- pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
{
/* Contact NDB to get commit count for table */
Ndb* ndb= thd_ndb->ndb;
@@ -9370,10 +9699,10 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
}
}
loop_next:
- pthread_mutex_lock(&share->mutex);
+ mysql_mutex_lock(&share->mutex);
if (share->commit_count_lock == lock)
share->commit_count= stat.commit_count;
- pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
/* ndb_share reference temporary free */
DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
@@ -9383,7 +9712,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
next:
/* Calculate new time to wake up */
int secs= 0;
- int msecs= ndb_cache_check_time;
+ int msecs= opt_ndb_cache_check_time;
struct timeval tick_time;
gettimeofday(&tick_time, 0);
@@ -9403,7 +9732,7 @@ next:
}
}
- pthread_mutex_lock(&LOCK_ndb_util_thread);
+ mysql_mutex_lock(&LOCK_ndb_util_thread);
ndb_util_thread_end:
net_end(&thd->net);
@@ -9415,8 +9744,8 @@ ndb_util_thread_fail:
/* signal termination */
ndb_util_thread_running= 0;
- pthread_cond_signal(&COND_ndb_util_ready);
- pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ mysql_cond_signal(&COND_ndb_util_ready);
+ mysql_mutex_unlock(&LOCK_ndb_util_thread);
DBUG_PRINT("exit", ("ndb_util_thread"));
DBUG_LEAVE; // Must match DBUG_ENTER()
@@ -9505,11 +9834,11 @@ char* ha_ndbcluster::get_tablespace_name(THD *thd, char* name, uint name_len)
}
err:
if (ndberr.status == NdbError::TemporaryError)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_TEMPORARY_ERRMSG, ER(ER_GET_TEMPORARY_ERRMSG),
ndberr.code, ndberr.message, "NDB");
else
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
ndberr.code, ndberr.message, "NDB");
return 0;
@@ -9659,12 +9988,33 @@ int ha_ndbcluster::get_default_no_partitions(HA_CREATE_INFO *create_info)
and partition by hidden key otherwise.
*/
+
+enum ndb_distribution_enum { ND_KEYHASH= 0, ND_LINHASH= 1 };
+static const char* distribution_names[]= { "KEYHASH", "LINHASH", NullS };
+static ulong default_ndb_distribution= ND_KEYHASH;
+static TYPELIB distribution_typelib= {
+ array_elements(distribution_names) - 1,
+ "",
+ distribution_names,
+ NULL
+};
+static MYSQL_SYSVAR_ENUM(
+ distribution, /* name */
+ default_ndb_distribution, /* var */
+ PLUGIN_VAR_RQCMDARG,
+ "Default distribution for new tables in ndb",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ ND_KEYHASH, /* default */
+ &distribution_typelib /* typelib */
+);
+
void ha_ndbcluster::set_auto_partitions(partition_info *part_info)
{
DBUG_ENTER("ha_ndbcluster::set_auto_partitions");
part_info->list_of_part_fields= TRUE;
part_info->part_type= HASH_PARTITION;
- switch (opt_ndb_distribution_id)
+ switch (default_ndb_distribution)
{
case ND_KEYHASH:
part_info->linear_hash_ind= FALSE;
@@ -9680,7 +10030,7 @@ void ha_ndbcluster::set_auto_partitions(partition_info *part_info)
int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info)
{
NDBTAB *tab= (NDBTAB*)tab_ref;
- int32 *range_data= (int32*)my_malloc(part_info->no_parts*sizeof(int32),
+ int32 *range_data= (int32*)my_malloc(part_info->num_parts*sizeof(int32),
MYF(0));
uint i;
int error= 0;
@@ -9689,17 +10039,17 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info)
if (!range_data)
{
- mem_alloc_error(part_info->no_parts*sizeof(int32));
+ mem_alloc_error(part_info->num_parts*sizeof(int32));
DBUG_RETURN(1);
}
- for (i= 0; i < part_info->no_parts; i++)
+ for (i= 0; i < part_info->num_parts; i++)
{
longlong range_val= part_info->range_int_array[i];
if (unsigned_flag)
range_val-= 0x8000000000000000ULL;
if (range_val < INT_MIN32 || range_val >= INT_MAX32)
{
- if ((i != part_info->no_parts - 1) ||
+ if ((i != part_info->num_parts - 1) ||
(range_val != LONGLONG_MAX))
{
my_error(ER_LIMITED_PART_RANGE, MYF(0), "NDB");
@@ -9710,16 +10060,16 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info)
}
range_data[i]= (int32)range_val;
}
- tab->setRangeListData(range_data, sizeof(int32)*part_info->no_parts);
+ tab->setRangeListData(range_data, sizeof(int32)*part_info->num_parts);
error:
- my_free((char*)range_data, MYF(0));
+ my_free(range_data);
DBUG_RETURN(error);
}
int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info)
{
NDBTAB *tab= (NDBTAB*)tab_ref;
- int32 *list_data= (int32*)my_malloc(part_info->no_list_values * 2
+ int32 *list_data= (int32*)my_malloc(part_info->num_list_values * 2
* sizeof(int32), MYF(0));
uint32 *part_id, i;
int error= 0;
@@ -9728,10 +10078,10 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info)
if (!list_data)
{
- mem_alloc_error(part_info->no_list_values*2*sizeof(int32));
+ mem_alloc_error(part_info->num_list_values*2*sizeof(int32));
DBUG_RETURN(1);
}
- for (i= 0; i < part_info->no_list_values; i++)
+ for (i= 0; i < part_info->num_list_values; i++)
{
LIST_PART_ENTRY *list_entry= &part_info->list_array[i];
longlong list_val= list_entry->list_value;
@@ -9747,9 +10097,9 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info)
part_id= (uint32*)&list_data[2*i+1];
*part_id= list_entry->partition_id;
}
- tab->setRangeListData(list_data, 2*sizeof(int32)*part_info->no_list_values);
+ tab->setRangeListData(list_data, 2*sizeof(int32)*part_info->num_list_values);
error:
- my_free((char*)list_data, MYF(0));
+ my_free(list_data);
DBUG_RETURN(error);
}
@@ -9803,7 +10153,7 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info,
{
if (!current_thd->variables.new_mode)
{
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
ER(ER_ILLEGAL_HA_CREATE_OPTION),
ndbcluster_hton_name,
@@ -9869,11 +10219,11 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info,
ng= 0;
ts_names[fd_index]= part_elem->tablespace_name;
frag_data[fd_index++]= ng;
- } while (++j < part_info->no_subparts);
+ } while (++j < part_info->num_subparts);
}
first= FALSE;
- } while (++i < part_info->no_parts);
- tab->setDefaultNoPartitionsFlag(part_info->use_default_no_partitions);
+ } while (++i < part_info->num_parts);
+ tab->setDefaultNoPartitionsFlag(part_info->use_default_num_partitions);
tab->setLinearFlag(part_info->linear_hash_ind);
{
ha_rows max_rows= table_share->max_rows;
@@ -9900,7 +10250,7 @@ bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *create_info,
uint i;
const NDBTAB *tab= (const NDBTAB *) m_table;
- if (current_thd->variables.ndb_use_copying_alter_table)
+ if (THDVAR(current_thd, use_copying_alter_table))
{
DBUG_PRINT("info", ("On-line alter table disabled"));
DBUG_RETURN(COMPATIBLE_DATA_NO);
@@ -10246,13 +10596,13 @@ int ndbcluster_alter_tablespace(handlerton *hton,
thd->query(), thd->query_length(),
"", alter_info->tablespace_name,
0, 0,
- SOT_TABLESPACE, 0, 0, 0);
+ SOT_TABLESPACE, 0, 0);
else
ndbcluster_log_schema_op(thd, 0,
thd->query(), thd->query_length(),
"", alter_info->logfile_group_name,
0, 0,
- SOT_LOGFILE_GROUP, 0, 0, 0);
+ SOT_LOGFILE_GROUP, 0, 0);
#endif
DBUG_RETURN(FALSE);
@@ -10267,7 +10617,7 @@ ndberror2:
}
-bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts)
+bool ha_ndbcluster::get_no_parts(const char *name, uint *num_parts)
{
Ndb *ndb;
NDBDICT *dict;
@@ -10289,7 +10639,7 @@ bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts)
Ndb_table_guard ndbtab_g(dict= ndb->getDictionary(), m_tabname);
if (!ndbtab_g.get_table())
ERR_BREAK(dict->getNdbError(), err);
- *no_parts= ndbtab_g.get_table()->getFragmentCount();
+ *num_parts= ndbtab_g.get_table()->getFragmentCount();
DBUG_RETURN(FALSE);
}
@@ -10346,7 +10696,8 @@ static int ndbcluster_fill_files_table(handlerton *hton,
continue;
ERR_RETURN(ndberr);
}
-
+ table->field[IS_FILES_TABLE_CATALOG]->store(STRING_WITH_LEN("def"),
+ system_charset_info);
table->field[IS_FILES_FILE_NAME]->set_notnull();
table->field[IS_FILES_FILE_NAME]->store(elt.name, strlen(elt.name),
system_charset_info);
@@ -10531,6 +10882,132 @@ SHOW_VAR ndb_status_variables_export[]= {
{NullS, NullS, SHOW_LONG}
};
+static MYSQL_SYSVAR_ULONG(
+ cache_check_time, /* name */
+ opt_ndb_cache_check_time, /* var */
+ PLUGIN_VAR_RQCMDARG,
+ "A dedicated thread is created to, at the given "
+ "millisecond interval, invalidate the query cache "
+ "if another MySQL server in the cluster has changed "
+ "the data in the database.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 0, /* default */
+ 0, /* min */
+ ONE_YEAR_IN_SECONDS, /* max */
+ 0 /* block */
+);
+
+
+static MYSQL_SYSVAR_ULONG(
+ extra_logging, /* name */
+ opt_ndb_extra_logging, /* var */
+ PLUGIN_VAR_OPCMDARG,
+ "Turn on more logging in the error log.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 1, /* default */
+ 0, /* min */
+ 0, /* max */
+ 0 /* block */
+);
+
+
+ulong opt_ndb_report_thresh_binlog_epoch_slip;
+static MYSQL_SYSVAR_ULONG(
+ report_thresh_binlog_epoch_slip, /* name */
+ opt_ndb_report_thresh_binlog_epoch_slip,/* var */
+ PLUGIN_VAR_RQCMDARG,
+ "Threshold on number of epochs to be behind before reporting binlog "
+ "status. E.g. 3 means that if the difference between what epoch has "
+ "been received from the storage nodes and what has been applied to "
+ "the binlog is 3 or more, a status message will be sent to the cluster "
+ "log.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 3, /* default */
+ 0, /* min */
+ 256, /* max */
+ 0 /* block */
+);
+
+
+ulong opt_ndb_report_thresh_binlog_mem_usage;
+static MYSQL_SYSVAR_ULONG(
+ report_thresh_binlog_mem_usage, /* name */
+ opt_ndb_report_thresh_binlog_mem_usage,/* var */
+ PLUGIN_VAR_RQCMDARG,
+ "Threshold on percentage of free memory before reporting binlog "
+ "status. E.g. 10 means that if amount of available memory for "
+ "receiving binlog data from the storage nodes goes below 10%, "
+ "a status message will be sent to the cluster log.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 10, /* default */
+ 0, /* min */
+ 100, /* max */
+ 0 /* block */
+);
+
+
+static MYSQL_SYSVAR_STR(
+ connectstring, /* name */
+ opt_ndb_connectstring, /* var */
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Connect string for ndbcluster.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ NULL /* default */
+);
+
+
+static MYSQL_SYSVAR_STR(
+ mgmd_host, /* name */
+ opt_ndb_mgmd_host, /* var */
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Set host and port for ndb_mgmd. Syntax: hostname[:port]",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ NULL /* default */
+);
+
+
+static MYSQL_SYSVAR_UINT(
+ nodeid, /* name */
+ opt_ndb_nodeid, /* var */
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Nodeid for this mysqld in the cluster.",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 0, /* default */
+ 0, /* min */
+ 255, /* max */
+ 0 /* block */
+);
+
+static struct st_mysql_sys_var* system_variables[]= {
+ MYSQL_SYSVAR(cache_check_time),
+ MYSQL_SYSVAR(extra_logging),
+ MYSQL_SYSVAR(report_thresh_binlog_mem_usage),
+ MYSQL_SYSVAR(report_thresh_binlog_epoch_slip),
+ MYSQL_SYSVAR(distribution),
+ MYSQL_SYSVAR(autoincrement_prefetch_sz),
+ MYSQL_SYSVAR(force_send),
+ MYSQL_SYSVAR(use_exact_count),
+ MYSQL_SYSVAR(use_transactions),
+ MYSQL_SYSVAR(use_copying_alter_table),
+ MYSQL_SYSVAR(optimized_node_selection),
+ MYSQL_SYSVAR(index_stat_enable),
+ MYSQL_SYSVAR(index_stat_cache_entries),
+ MYSQL_SYSVAR(index_stat_update_freq),
+ MYSQL_SYSVAR(connectstring),
+ MYSQL_SYSVAR(mgmd_host),
+ MYSQL_SYSVAR(nodeid),
+
+ NULL
+};
+
+
struct st_mysql_storage_engine ndbcluster_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
@@ -10546,7 +11023,7 @@ mysql_declare_plugin(ndbcluster)
NULL, /* Plugin Deinit */
0x0100 /* 1.0 */,
ndb_status_variables_export,/* status variables */
- NULL, /* system variables */
+ system_variables, /* system variables */
NULL /* config options */
}
mysql_declare_plugin_end;
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index a17323d3fd6..de1e36b61d2 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -1,4 +1,7 @@
-/* Copyright (C) 2000-2003 MySQL AB
+#ifndef HA_NDBCLUSTER_INCLUDED
+#define HA_NDBCLUSTER_INCLUDED
+
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -31,7 +34,10 @@
#include <ndbapi_limits.h>
#define NDB_HIDDEN_PRIMARY_KEY_LENGTH 8
-#define NDB_DEFAULT_AUTO_PREFETCH 32
+
+#ifdef HAVE_PSI_INTERFACE
+extern PSI_file_key key_file_ndb;
+#endif /* HAVE_PSI_INTERFACE */
class Ndb; // Forward declaration
@@ -45,13 +51,10 @@ class NdbIndexStat;
class NdbEventOperation;
class ha_ndbcluster_cond;
+#include "sql_partition.h" /* part_id_range */
+
// connectstring to cluster if given by mysqld
extern const char *ndbcluster_connectstring;
-extern ulong ndb_cache_check_time;
-#ifdef HAVE_NDB_BINLOG
-extern ulong ndb_report_thresh_binlog_epoch_slip;
-extern ulong ndb_report_thresh_binlog_mem_usage;
-#endif
typedef enum ndb_index_type {
UNDEFINED_INDEX = 0,
@@ -105,7 +108,7 @@ typedef struct st_ndbcluster_share {
NDB_SHARE_STATE state;
MEM_ROOT mem_root;
THR_LOCK lock;
- pthread_mutex_t mutex;
+ mysql_mutex_t mutex;
char *key;
uint key_length;
THD *util_lock;
@@ -134,9 +137,9 @@ NDB_SHARE_STATE
get_ndb_share_state(NDB_SHARE *share)
{
NDB_SHARE_STATE state;
- pthread_mutex_lock(&share->mutex);
+ mysql_mutex_lock(&share->mutex);
state= share->state;
- pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
return state;
}
@@ -144,19 +147,19 @@ inline
void
set_ndb_share_state(NDB_SHARE *share, NDB_SHARE_STATE state)
{
- pthread_mutex_lock(&share->mutex);
+ mysql_mutex_lock(&share->mutex);
share->state= state;
- pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
}
struct Ndb_tuple_id_range_guard {
Ndb_tuple_id_range_guard(NDB_SHARE* _share) :
share(_share),
range(share->tuple_id_range) {
- pthread_mutex_lock(&share->mutex);
+ mysql_mutex_lock(&share->mutex);
}
~Ndb_tuple_id_range_guard() {
- pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
}
NDB_SHARE* share;
Ndb::TupleIdRange& range;
@@ -272,7 +275,7 @@ class ha_ndbcluster: public handler
ha_rows estimate_rows_upper_bound()
{ return HA_POS_ERROR; }
int info(uint);
- void get_dynamic_partition_info(PARTITION_INFO *stat_info, uint part_id);
+ void get_dynamic_partition_info(PARTITION_STATS *stat_info, uint part_id);
int extra(enum ha_extra_function operation);
int extra_opt(enum ha_extra_function operation, ulong cache_size);
int reset();
@@ -385,6 +388,7 @@ static void set_tabname(const char *pathname, char *tabname);
uint table_changes);
private:
+ int loc_read_multi_range_next(KEY_MULTI_RANGE **found_range_p);
friend int ndbcluster_drop_database_impl(const char *path);
friend int ndb_handle_schema_change(THD *thd,
Ndb *ndb, NdbEventOperation *pOp,
@@ -580,4 +584,6 @@ static const char ndbcluster_hton_name[]= "ndbcluster";
static const int ndbcluster_hton_name_length=sizeof(ndbcluster_hton_name)-1;
extern int ndbcluster_terminating;
extern int ndb_util_thread_running;
-extern pthread_cond_t COND_ndb_util_ready;
+extern mysql_cond_t COND_ndb_util_ready;
+
+#endif /* HA_NDBCLUSTER_INCLUDED */
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index 27af3f2cf2f..e46b6b25f9c 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -14,7 +14,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
#include "sql_show.h"
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
#include "ha_ndbcluster.h"
@@ -28,11 +29,22 @@
#include "ndb_cluster_connection.hpp"
#include <util/NdbAutoPtr.hpp>
+#include "sql_base.h" // close_thread_tables
+#include "sql_table.h" // build_table_filename
+#include "table.h" // open_table_from_share
+#include "discover.h" // readfrm, writefrm
+#include "lock.h" // MYSQL_LOCK_IGNORE_FLUSH,
+ // mysql_unlock_tables
+#include "sql_parse.h" // mysql_parse
+#include "transaction.h"
+
#ifdef ndb_dynamite
#undef assert
#define assert(x) do { if(x) break; ::printf("%s %d: assert failed: %s\n", __FILE__, __LINE__, #x); ::fflush(stdout); ::signal(SIGABRT,SIG_DFL); ::abort(); ::kill(::getpid(),6); ::kill(::getpid(),9); } while (0)
#endif
+extern my_bool opt_ndb_log_binlog_index;
+extern ulong opt_ndb_extra_logging;
/*
defines for cluster replication table names
*/
@@ -44,14 +56,16 @@
Timeout for syncing schema events between
mysql servers, and between mysql server and the binlog
*/
-const int opt_ndb_sync_timeout= 120;
+static const int DEFAULT_SYNC_TIMEOUT= 120;
+
/*
Flag showing if the ndb injector thread is running, if so == 1
-1 if it was started but later stopped for some reason
0 if never started
*/
-int ndb_binlog_thread_running= 0;
+static int ndb_binlog_thread_running= 0;
+
/*
Flag showing if the ndb binlog should be created, if so == TRUE
FALSE if not
@@ -75,7 +89,7 @@ THD *injector_thd= 0;
to enable ndb injector thread receiving events.
Must therefore always be used with a surrounding
- pthread_mutex_lock(&injector_mutex), when doing create/dropEventOperation
+ mysql_mutex_lock(&injector_mutex), when doing create/dropEventOperation
*/
static Ndb *injector_ndb= 0;
static Ndb *schema_ndb= 0;
@@ -102,8 +116,8 @@ static int ndbcluster_binlog_terminating= 0;
and injector thread
*/
pthread_t ndb_binlog_thread;
-pthread_mutex_t injector_mutex;
-pthread_cond_t injector_cond;
+mysql_mutex_t injector_mutex;
+mysql_cond_t injector_cond;
/* NDB Injector thread (used for binlog creation) */
static ulonglong ndb_latest_applied_binlog_epoch= 0;
@@ -112,7 +126,7 @@ static ulonglong ndb_latest_received_binlog_epoch= 0;
NDB_SHARE *ndb_apply_status_share= 0;
NDB_SHARE *ndb_schema_share= 0;
-pthread_mutex_t ndb_schema_share_mutex;
+mysql_mutex_t ndb_schema_share_mutex;
extern my_bool opt_log_slave_updates;
static my_bool g_ndb_log_slave_updates;
@@ -120,7 +134,7 @@ static my_bool g_ndb_log_slave_updates;
/* Schema object distribution handling */
HASH ndb_schema_objects;
typedef struct st_ndb_schema_object {
- pthread_mutex_t mutex;
+ mysql_mutex_t mutex;
char *key;
uint key_length;
uint use_count;
@@ -247,24 +261,27 @@ static void run_query(THD *thd, char *buf, char *end,
struct system_status_var save_thd_status_var= thd->status_var;
THD_TRANS save_thd_transaction_all= thd->transaction.all;
THD_TRANS save_thd_transaction_stmt= thd->transaction.stmt;
- ulonglong save_thd_options= thd->options;
- DBUG_ASSERT(sizeof(save_thd_options) == sizeof(thd->options));
+ ulonglong save_thd_options= thd->variables.option_bits;
+ DBUG_ASSERT(sizeof(save_thd_options) == sizeof(thd->variables.option_bits));
NET save_thd_net= thd->net;
- const char* found_semicolon= NULL;
bzero((char*) &thd->net, sizeof(NET));
thd->set_query(buf, (uint) (end - buf));
thd->variables.pseudo_thread_id= thread_id;
thd->transaction.stmt.modified_non_trans_table= FALSE;
if (disable_binlog)
- thd->options&= ~OPTION_BIN_LOG;
+ thd->variables.option_bits&= ~OPTION_BIN_LOG;
DBUG_PRINT("query", ("%s", thd->query()));
DBUG_ASSERT(!thd->in_sub_stmt);
- DBUG_ASSERT(!thd->prelocked_mode);
+ DBUG_ASSERT(!thd->locked_tables_mode);
- mysql_parse(thd, thd->query(), thd->query_length(), &found_semicolon);
+ {
+ Parser_state parser_state;
+ if (!parser_state.init(thd, thd->query(), thd->query_length()))
+ mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
+ }
if (no_print_error && thd->is_slave_error)
{
@@ -272,17 +289,16 @@ static void run_query(THD *thd, char *buf, char *end,
Thd_ndb *thd_ndb= get_thd_ndb(thd);
for (i= 0; no_print_error[i]; i++)
if ((thd_ndb->m_error_code == no_print_error[i]) ||
- (thd->main_da.sql_errno() == (unsigned) no_print_error[i]))
+ (thd->stmt_da->sql_errno() == (unsigned) no_print_error[i]))
break;
if (!no_print_error[i])
sql_print_error("NDB: %s: error %s %d(ndb: %d) %d %d",
buf,
- thd->main_da.message(),
- thd->main_da.sql_errno(),
+ thd->stmt_da->message(),
+ thd->stmt_da->sql_errno(),
thd_ndb->m_error_code,
(int) thd->is_error(), thd->is_slave_error);
}
- close_thread_tables(thd);
/*
XXX: this code is broken. mysql_parse()/mysql_reset_thd_for_next_command()
can not be called from within a statement, and
@@ -293,15 +309,16 @@ static void run_query(THD *thd, char *buf, char *end,
is called from ndbcluster_reset_logs(), which is called from
mysql_flush().
*/
- thd->main_da.reset_diagnostics_area();
+ thd->stmt_da->reset_diagnostics_area();
- thd->options= save_thd_options;
+ thd->variables.option_bits= save_thd_options;
thd->set_query(save_thd_query, save_thd_query_length);
thd->variables.pseudo_thread_id= save_thread_id;
thd->status_var= save_thd_status_var;
thd->transaction.all= save_thd_transaction_all;
thd->transaction.stmt= save_thd_transaction_stmt;
thd->net= save_thd_net;
+ thd->set_current_stmt_binlog_format_row();
if (thd == injector_thd)
{
@@ -343,7 +360,6 @@ ndbcluster_binlog_open_table(THD *thd, NDB_SHARE *share,
int error;
DBUG_ENTER("ndbcluster_binlog_open_table");
- safe_mutex_assert_owner(&LOCK_open);
init_tmp_table_share(thd, table_share, share->db, 0, share->table_name,
share->key);
if ((error= open_table_def(thd, table_share, 0)))
@@ -359,7 +375,9 @@ ndbcluster_binlog_open_table(THD *thd, NDB_SHARE *share,
free_table_share(table_share);
DBUG_RETURN(error);
}
+ mysql_mutex_lock(&LOCK_open);
assign_new_table_id(table_share);
+ mysql_mutex_unlock(&LOCK_open);
if (!reopen)
{
@@ -608,7 +626,7 @@ ndbcluster_binlog_log_query(handlerton *hton, THD *thd, enum_binlog_command binl
{
ndbcluster_log_schema_op(thd, 0, query, query_length,
db, table_name, 0, 0, type,
- 0, 0, 0);
+ 0, 0);
}
DBUG_VOID_RETURN;
}
@@ -637,28 +655,28 @@ static int ndbcluster_binlog_end(THD *thd)
however be a likely case as the ndbcluster_binlog_end is supposed to
be called before ndb_cluster_end().
*/
- pthread_mutex_lock(&LOCK_ndb_util_thread);
+ mysql_mutex_lock(&LOCK_ndb_util_thread);
/* Ensure mutex are not freed if ndb_cluster_end is running at same time */
ndb_util_thread_running++;
ndbcluster_terminating= 1;
- pthread_cond_signal(&COND_ndb_util_thread);
+ mysql_cond_signal(&COND_ndb_util_thread);
while (ndb_util_thread_running > 1)
- pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
+ mysql_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
ndb_util_thread_running--;
- pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ mysql_mutex_unlock(&LOCK_ndb_util_thread);
}
/* wait for injector thread to finish */
ndbcluster_binlog_terminating= 1;
- pthread_mutex_lock(&injector_mutex);
- pthread_cond_signal(&injector_cond);
+ mysql_mutex_lock(&injector_mutex);
+ mysql_cond_signal(&injector_cond);
while (ndb_binlog_thread_running > 0)
- pthread_cond_wait(&injector_cond, &injector_mutex);
- pthread_mutex_unlock(&injector_mutex);
+ mysql_cond_wait(&injector_cond, &injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
- pthread_mutex_destroy(&injector_mutex);
- pthread_cond_destroy(&injector_cond);
- pthread_mutex_destroy(&ndb_schema_share_mutex);
+ mysql_mutex_destroy(&injector_mutex);
+ mysql_cond_destroy(&injector_cond);
+ mysql_mutex_destroy(&ndb_schema_share_mutex);
#endif
DBUG_RETURN(0);
@@ -738,14 +756,14 @@ void ndbcluster_binlog_init_handlerton()
*/
static NDB_SHARE *ndbcluster_check_ndb_apply_status_share()
{
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
- void *share= hash_search(&ndbcluster_open_tables,
- (uchar*) NDB_APPLY_TABLE_FILE,
- sizeof(NDB_APPLY_TABLE_FILE) - 1);
+ void *share= my_hash_search(&ndbcluster_open_tables,
+ (uchar*) NDB_APPLY_TABLE_FILE,
+ sizeof(NDB_APPLY_TABLE_FILE) - 1);
DBUG_PRINT("info",("ndbcluster_check_ndb_apply_status_share %s 0x%lx",
NDB_APPLY_TABLE_FILE, (long) share));
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
return (NDB_SHARE*) share;
}
@@ -756,14 +774,14 @@ static NDB_SHARE *ndbcluster_check_ndb_apply_status_share()
*/
static NDB_SHARE *ndbcluster_check_ndb_schema_share()
{
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
- void *share= hash_search(&ndbcluster_open_tables,
- (uchar*) NDB_SCHEMA_TABLE_FILE,
- sizeof(NDB_SCHEMA_TABLE_FILE) - 1);
+ void *share= my_hash_search(&ndbcluster_open_tables,
+ (uchar*) NDB_SCHEMA_TABLE_FILE,
+ sizeof(NDB_SCHEMA_TABLE_FILE) - 1);
DBUG_PRINT("info",("ndbcluster_check_ndb_schema_share %s 0x%lx",
NDB_SCHEMA_TABLE_FILE, (long) share));
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
return (NDB_SHARE*) share;
}
@@ -788,7 +806,7 @@ static int ndbcluster_create_ndb_apply_status_table(THD *thd)
char buf[1024 + 1], *end;
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB: Creating " NDB_REP_DB "." NDB_APPLY_TABLE);
/*
@@ -798,7 +816,7 @@ static int ndbcluster_create_ndb_apply_status_table(THD *thd)
{
build_table_filename(buf, sizeof(buf) - 1,
NDB_REP_DB, NDB_APPLY_TABLE, reg_ext, 0);
- my_delete(buf, MYF(0));
+ mysql_file_delete(key_file_frm, buf, MYF(0));
}
/*
@@ -846,7 +864,7 @@ static int ndbcluster_create_schema_table(THD *thd)
char buf[1024 + 1], *end;
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB: Creating " NDB_REP_DB "." NDB_SCHEMA_TABLE);
/*
@@ -856,7 +874,7 @@ static int ndbcluster_create_schema_table(THD *thd)
{
build_table_filename(buf, sizeof(buf) - 1,
NDB_REP_DB, NDB_SCHEMA_TABLE, reg_ext, 0);
- my_delete(buf, MYF(0));
+ mysql_file_delete(key_file_frm, buf, MYF(0));
}
/*
@@ -891,9 +909,7 @@ int ndbcluster_setup_binlog_table_shares(THD *thd)
if (!ndb_schema_share &&
ndbcluster_check_ndb_schema_share() == 0)
{
- pthread_mutex_lock(&LOCK_open);
ndb_create_table_from_engine(thd, NDB_REP_DB, NDB_SCHEMA_TABLE);
- pthread_mutex_unlock(&LOCK_open);
if (!ndb_schema_share)
{
ndbcluster_create_schema_table(thd);
@@ -905,9 +921,7 @@ int ndbcluster_setup_binlog_table_shares(THD *thd)
if (!ndb_apply_status_share &&
ndbcluster_check_ndb_apply_status_share() == 0)
{
- pthread_mutex_lock(&LOCK_open);
ndb_create_table_from_engine(thd, NDB_REP_DB, NDB_APPLY_TABLE);
- pthread_mutex_unlock(&LOCK_open);
if (!ndb_apply_status_share)
{
ndbcluster_create_ndb_apply_status_table(thd);
@@ -917,14 +931,12 @@ int ndbcluster_setup_binlog_table_shares(THD *thd)
}
if (!ndbcluster_find_all_files(thd))
{
- pthread_mutex_lock(&LOCK_open);
ndb_binlog_tables_inited= TRUE;
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: ndb tables writable");
- close_cached_tables(NULL, NULL, TRUE, FALSE, FALSE);
- pthread_mutex_unlock(&LOCK_open);
+ close_cached_tables(NULL, NULL, FALSE, LONG_TIMEOUT);
/* Signal injector thread that all is setup */
- pthread_cond_signal(&injector_cond);
+ mysql_cond_signal(&injector_cond);
}
return 0;
}
@@ -963,6 +975,21 @@ struct Cluster_schema
uint32 any_value;
};
+static void print_could_not_discover_error(THD *thd,
+ const Cluster_schema *schema)
+{
+ sql_print_error("NDB Binlog: Could not discover table '%s.%s' from "
+ "binlog schema event '%s' from node %d. "
+ "my_errno: %d",
+ schema->db, schema->name, schema->query,
+ schema->node_id, my_errno);
+ List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
+ MYSQL_ERROR *err;
+ while ((err= it++))
+ sql_print_warning("NDB Binlog: (%d)%s", err->get_sql_errno(),
+ err->get_message_text());
+}
+
/*
Transfer schema table data into corresponding struct
*/
@@ -982,7 +1009,7 @@ static void ndbcluster_get_schema(NDB_SHARE *share,
ptrdiff);
if (ret != 0)
{
- my_free(blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(blobs_buffer);
DBUG_PRINT("info", ("blob read error"));
DBUG_ASSERT(FALSE);
}
@@ -1033,7 +1060,7 @@ static void ndbcluster_get_schema(NDB_SHARE *share,
field++;
s->type= ((Field_long *)*field)->val_int();
/* free blobs buffer */
- my_free(blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(blobs_buffer);
dbug_tmp_restore_column_map(table->read_set, old_map);
}
@@ -1198,7 +1225,7 @@ ndbcluster_update_slock(THD *thd,
}
if (ndb_error)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
ndb_error->code,
ndb_error->message,
@@ -1220,12 +1247,12 @@ static void ndb_report_waiting(const char *key,
{
ulonglong ndb_latest_epoch= 0;
const char *proc_info= "<no info>";
- pthread_mutex_lock(&injector_mutex);
+ mysql_mutex_lock(&injector_mutex);
if (injector_ndb)
ndb_latest_epoch= injector_ndb->getLatestGCI();
if (injector_thd)
proc_info= injector_thd->proc_info;
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
sql_print_information("NDB %s:"
" waiting max %u sec for %s %s."
" epochs: (%u,%u,%u)"
@@ -1244,8 +1271,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
uint32 ndb_table_id,
uint32 ndb_table_version,
enum SCHEMA_OP_TYPE type,
- const char *new_db, const char *new_table_name,
- int have_lock_open)
+ const char *new_db, const char *new_table_name)
{
DBUG_ENTER("ndbcluster_log_schema_op");
Thd_ndb *thd_ndb= get_thd_ndb(thd);
@@ -1338,15 +1364,15 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
bitmap_set_all(&schema_subscribers);
/* begin protect ndb_schema_share */
- pthread_mutex_lock(&ndb_schema_share_mutex);
+ mysql_mutex_lock(&ndb_schema_share_mutex);
if (ndb_schema_share == 0)
{
- pthread_mutex_unlock(&ndb_schema_share_mutex);
+ mysql_mutex_unlock(&ndb_schema_share_mutex);
if (ndb_schema_object)
ndb_free_schema_object(&ndb_schema_object, FALSE);
DBUG_RETURN(0);
}
- (void) pthread_mutex_lock(&ndb_schema_share->mutex);
+ mysql_mutex_lock(&ndb_schema_share->mutex);
for (i= 0; i < no_storage_nodes; i++)
{
MY_BITMAP *table_subscribers= &ndb_schema_share->subscriber_bitmap[i];
@@ -1357,8 +1383,8 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
updated= 1;
}
}
- (void) pthread_mutex_unlock(&ndb_schema_share->mutex);
- pthread_mutex_unlock(&ndb_schema_share_mutex);
+ mysql_mutex_unlock(&ndb_schema_share->mutex);
+ mysql_mutex_unlock(&ndb_schema_share_mutex);
/* end protect ndb_schema_share */
if (updated)
@@ -1378,10 +1404,10 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
if (ndb_schema_object)
{
- (void) pthread_mutex_lock(&ndb_schema_object->mutex);
+ mysql_mutex_lock(&ndb_schema_object->mutex);
memcpy(ndb_schema_object->slock, schema_subscribers.bitmap,
sizeof(ndb_schema_object->slock));
- (void) pthread_mutex_unlock(&ndb_schema_object->mutex);
+ mysql_mutex_unlock(&ndb_schema_object->mutex);
}
DBUG_DUMP("schema_subscribers", (uchar*)schema_subscribers.bitmap,
@@ -1483,7 +1509,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
r|= op->setValue(SCHEMA_TYPE_I, log_type);
DBUG_ASSERT(r == 0);
/* any value */
- if (!(thd->options & OPTION_BIN_LOG))
+ if (!(thd->variables.option_bits & OPTION_BIN_LOG))
r|= op->setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
else
r|= op->setAnyValue(thd->server_id);
@@ -1521,7 +1547,7 @@ err:
}
end:
if (ndb_error)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
ndb_error->code,
ndb_error->message,
@@ -1546,33 +1572,28 @@ end:
else
dict->forceGCPWait();
- int max_timeout= opt_ndb_sync_timeout;
- (void) pthread_mutex_lock(&ndb_schema_object->mutex);
- if (have_lock_open)
- {
- safe_mutex_assert_owner(&LOCK_open);
- (void) pthread_mutex_unlock(&LOCK_open);
- }
+ int max_timeout= DEFAULT_SYNC_TIMEOUT;
+ mysql_mutex_lock(&ndb_schema_object->mutex);
while (1)
{
struct timespec abstime;
int i;
int no_storage_nodes= g_ndb_cluster_connection->no_db_nodes();
set_timespec(abstime, 1);
- int ret= pthread_cond_timedwait(&injector_cond,
- &ndb_schema_object->mutex,
- &abstime);
+ int ret= mysql_cond_timedwait(&injector_cond,
+ &ndb_schema_object->mutex,
+ &abstime);
if (thd->killed)
break;
/* begin protect ndb_schema_share */
- pthread_mutex_lock(&ndb_schema_share_mutex);
+ mysql_mutex_lock(&ndb_schema_share_mutex);
if (ndb_schema_share == 0)
{
- pthread_mutex_unlock(&ndb_schema_share_mutex);
+ mysql_mutex_unlock(&ndb_schema_share_mutex);
break;
}
- (void) pthread_mutex_lock(&ndb_schema_share->mutex);
+ mysql_mutex_lock(&ndb_schema_share->mutex);
for (i= 0; i < no_storage_nodes; i++)
{
/* remove any unsubscribed from schema_subscribers */
@@ -1580,8 +1601,8 @@ end:
if (!bitmap_is_clear_all(tmp))
bitmap_intersect(&schema_subscribers, tmp);
}
- (void) pthread_mutex_unlock(&ndb_schema_share->mutex);
- pthread_mutex_unlock(&ndb_schema_share_mutex);
+ mysql_mutex_unlock(&ndb_schema_share->mutex);
+ mysql_mutex_unlock(&ndb_schema_share_mutex);
/* end protect ndb_schema_share */
/* remove any unsubscribed from ndb_schema_object->slock */
@@ -1603,16 +1624,12 @@ end:
type_str, ndb_schema_object->key);
break;
}
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
ndb_report_waiting(type_str, max_timeout,
"distributing", ndb_schema_object->key);
}
}
- if (have_lock_open)
- {
- (void) pthread_mutex_lock(&LOCK_open);
- }
- (void) pthread_mutex_unlock(&ndb_schema_object->mutex);
+ mysql_mutex_unlock(&ndb_schema_object->mutex);
}
if (ndb_schema_object)
@@ -1694,14 +1711,13 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
{
DBUG_DUMP("frm", (uchar*) altered_table->getFrmData(),
altered_table->getFrmLength());
- pthread_mutex_lock(&LOCK_open);
Ndb_table_guard ndbtab_g(dict, tabname);
const NDBTAB *old= ndbtab_g.get_table();
if (!old &&
old->getObjectVersion() != altered_table->getObjectVersion())
dict->putTable(altered_table);
- my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(data);
data= NULL;
if ((error= unpackfrm(&data, &length,
(const uchar*) altered_table->getFrmData())) ||
@@ -1720,7 +1736,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
bzero((char*) &table_list,sizeof(table_list));
table_list.db= (char *)dbname;
table_list.alias= table_list.table_name= (char *)tabname;
- close_cached_tables(thd, &table_list, TRUE, FALSE, FALSE);
+ close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
if ((error= ndbcluster_binlog_open_table(thd, share,
table_share, table, 1)))
@@ -1731,28 +1747,26 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
table_share= share->table_share;
dbname= table_share->db.str;
tabname= table_share->table_name.str;
-
- pthread_mutex_unlock(&LOCK_open);
}
- my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(data);
+ my_free(pack_data);
}
// If only frm was changed continue replicating
if (is_online_alter_table)
{
/* Signal ha_ndbcluster::alter_table that drop is done */
- (void) pthread_cond_signal(&injector_cond);
+ mysql_cond_signal(&injector_cond);
DBUG_RETURN(0);
}
- (void) pthread_mutex_lock(&share->mutex);
+ mysql_mutex_lock(&share->mutex);
if (is_rename_table && !is_remote_change)
{
DBUG_PRINT("info", ("Detected name change of table %s.%s",
share->db, share->table_name));
/* ToDo: remove printout */
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: rename table %s%s/%s -> %s.",
share_prefix, share->table->s->db.str,
share->table->s->table_name.str,
@@ -1782,10 +1796,10 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
// either just us or drop table handling as well
/* Signal ha_ndbcluster::delete/rename_table that drop is done */
- (void) pthread_mutex_unlock(&share->mutex);
- (void) pthread_cond_signal(&injector_cond);
+ mysql_mutex_unlock(&share->mutex);
+ mysql_cond_signal(&injector_cond);
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
/* ndb_share reference binlog free */
DBUG_PRINT("NDB_SHARE", ("%s binlog free use_count: %u",
share->key, share->use_count));
@@ -1811,14 +1825,14 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
}
else
share= 0;
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
pOp->setCustomData(0);
- pthread_mutex_lock(&injector_mutex);
+ mysql_mutex_lock(&injector_mutex);
ndb->dropEventOperation(pOp);
pOp= 0;
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
if (do_close_cached_tables)
{
@@ -1826,7 +1840,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
bzero((char*) &table_list,sizeof(table_list));
table_list.db= (char *)dbname;
table_list.alias= table_list.table_name= (char *)tabname;
- close_cached_tables(thd, &table_list, FALSE, FALSE, FALSE);
+ close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
/* ndb_share reference create free */
DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
share->key, share->use_count));
@@ -1855,7 +1869,7 @@ static void ndb_binlog_query(THD *thd, Cluster_schema *schema)
thd->db= schema->db;
int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
thd->binlog_query(THD::STMT_QUERY_TYPE, schema->query,
- schema->query_length, FALSE,
+ schema->query_length, FALSE, TRUE,
schema->name[0] == 0 || thd->db[0] == 0,
errcode);
thd->server_id= thd_server_id_save;
@@ -1947,7 +1961,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
bzero((char*) &table_list,sizeof(table_list));
table_list.db= schema->db;
table_list.alias= table_list.table_name= schema->name;
- close_cached_tables(thd, &table_list, FALSE, FALSE, FALSE);
+ close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
}
/* ndb_share reference temporary free */
if (share)
@@ -1959,7 +1973,6 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
}
// fall through
case SOT_CREATE_TABLE:
- pthread_mutex_lock(&LOCK_open);
if (ndbcluster_check_if_local_table(schema->db, schema->name))
{
DBUG_PRINT("info", ("NDB Binlog: Skipping locally defined table '%s.%s'",
@@ -1971,17 +1984,8 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
}
else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
{
- sql_print_error("NDB Binlog: Could not discover table '%s.%s' from "
- "binlog schema event '%s' from node %d. "
- "my_errno: %d",
- schema->db, schema->name, schema->query,
- schema->node_id, my_errno);
- List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
- MYSQL_ERROR *err;
- while ((err= it++))
- sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg);
+ print_could_not_discover_error(thd, schema);
}
- pthread_mutex_unlock(&LOCK_open);
log_query= 1;
break;
case SOT_DROP_DB:
@@ -2050,18 +2054,18 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
// skip
break;
case NDBEVENT::TE_CLUSTER_FAILURE:
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: cluster failure for %s at epoch %u.",
ndb_schema_share->key, (unsigned) pOp->getGCI());
// fall through
case NDBEVENT::TE_DROP:
- if (ndb_extra_logging &&
+ if (opt_ndb_extra_logging &&
ndb_binlog_tables_inited && ndb_binlog_running)
sql_print_information("NDB Binlog: ndb tables initially "
"read only on reconnect.");
/* begin protect ndb_schema_share */
- pthread_mutex_lock(&ndb_schema_share_mutex);
+ mysql_mutex_lock(&ndb_schema_share_mutex);
/* ndb_share reference binlog extra free */
DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
ndb_schema_share->key,
@@ -2069,10 +2073,10 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
free_share(&ndb_schema_share);
ndb_schema_share= 0;
ndb_binlog_tables_inited= 0;
- pthread_mutex_unlock(&ndb_schema_share_mutex);
+ mysql_mutex_unlock(&ndb_schema_share_mutex);
/* end protect ndb_schema_share */
- close_cached_tables(NULL, NULL, FALSE, FALSE, FALSE);
+ close_cached_tables(NULL, NULL, FALSE, LONG_TIMEOUT);
// fall through
case NDBEVENT::TE_ALTER:
ndb_handle_schema_change(thd, ndb, pOp, tmp_share);
@@ -2081,10 +2085,10 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
{
uint8 node_id= g_node_id_map[pOp->getNdbdNodeId()];
DBUG_ASSERT(node_id != 0xFF);
- (void) pthread_mutex_lock(&tmp_share->mutex);
+ mysql_mutex_lock(&tmp_share->mutex);
bitmap_clear_all(&tmp_share->subscriber_bitmap[node_id]);
DBUG_PRINT("info",("NODE_FAILURE UNSUBSCRIBE[%d]", node_id));
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
{
sql_print_information("NDB Binlog: Node: %d, down,"
" Subscriber bitmask %x%x",
@@ -2092,8 +2096,8 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
tmp_share->subscriber_bitmap[node_id].bitmap[1],
tmp_share->subscriber_bitmap[node_id].bitmap[0]);
}
- (void) pthread_mutex_unlock(&tmp_share->mutex);
- (void) pthread_cond_signal(&injector_cond);
+ mysql_mutex_unlock(&tmp_share->mutex);
+ mysql_cond_signal(&injector_cond);
break;
}
case NDBEVENT::TE_SUBSCRIBE:
@@ -2101,10 +2105,10 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
uint8 node_id= g_node_id_map[pOp->getNdbdNodeId()];
uint8 req_id= pOp->getReqNodeId();
DBUG_ASSERT(req_id != 0 && node_id != 0xFF);
- (void) pthread_mutex_lock(&tmp_share->mutex);
+ mysql_mutex_lock(&tmp_share->mutex);
bitmap_set_bit(&tmp_share->subscriber_bitmap[node_id], req_id);
DBUG_PRINT("info",("SUBSCRIBE[%d] %d", node_id, req_id));
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
{
sql_print_information("NDB Binlog: Node: %d, subscribe from node %d,"
" Subscriber bitmask %x%x",
@@ -2113,8 +2117,8 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
tmp_share->subscriber_bitmap[node_id].bitmap[1],
tmp_share->subscriber_bitmap[node_id].bitmap[0]);
}
- (void) pthread_mutex_unlock(&tmp_share->mutex);
- (void) pthread_cond_signal(&injector_cond);
+ mysql_mutex_unlock(&tmp_share->mutex);
+ mysql_cond_signal(&injector_cond);
break;
}
case NDBEVENT::TE_UNSUBSCRIBE:
@@ -2122,10 +2126,10 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
uint8 node_id= g_node_id_map[pOp->getNdbdNodeId()];
uint8 req_id= pOp->getReqNodeId();
DBUG_ASSERT(req_id != 0 && node_id != 0xFF);
- (void) pthread_mutex_lock(&tmp_share->mutex);
+ mysql_mutex_lock(&tmp_share->mutex);
bitmap_clear_bit(&tmp_share->subscriber_bitmap[node_id], req_id);
DBUG_PRINT("info",("UNSUBSCRIBE[%d] %d", node_id, req_id));
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
{
sql_print_information("NDB Binlog: Node: %d, unsubscribe from node %d,"
" Subscriber bitmask %x%x",
@@ -2134,8 +2138,8 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
tmp_share->subscriber_bitmap[node_id].bitmap[1],
tmp_share->subscriber_bitmap[node_id].bitmap[0]);
}
- (void) pthread_mutex_unlock(&tmp_share->mutex);
- (void) pthread_cond_signal(&injector_cond);
+ mysql_mutex_unlock(&tmp_share->mutex);
+ mysql_cond_signal(&injector_cond);
break;
}
default:
@@ -2175,22 +2179,22 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
build_table_filename(key, sizeof(key) - 1, schema->db, schema->name, "", 0);
if (schema_type == SOT_CLEAR_SLOCK)
{
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
NDB_SCHEMA_OBJECT *ndb_schema_object=
- (NDB_SCHEMA_OBJECT*) hash_search(&ndb_schema_objects,
- (uchar*) key, strlen(key));
+ (NDB_SCHEMA_OBJECT*) my_hash_search(&ndb_schema_objects,
+ (uchar*) key, strlen(key));
if (ndb_schema_object)
{
- pthread_mutex_lock(&ndb_schema_object->mutex);
+ mysql_mutex_lock(&ndb_schema_object->mutex);
memcpy(ndb_schema_object->slock, schema->slock,
sizeof(ndb_schema_object->slock));
DBUG_DUMP("ndb_schema_object->slock_bitmap.bitmap",
(uchar*)ndb_schema_object->slock_bitmap.bitmap,
no_bytes_in_map(&ndb_schema_object->slock_bitmap));
- pthread_mutex_unlock(&ndb_schema_object->mutex);
- pthread_cond_signal(&injector_cond);
+ mysql_mutex_unlock(&ndb_schema_object->mutex);
+ mysql_cond_signal(&injector_cond);
}
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
continue;
}
/* ndb_share reference temporary, free below */
@@ -2229,7 +2233,7 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
bzero((char*) &table_list,sizeof(table_list));
table_list.db= schema->db;
table_list.alias= table_list.table_name= schema->name;
- close_cached_tables(thd, &table_list, FALSE, FALSE, FALSE);
+ close_cached_tables(thd, &table_list, FALSE, LONG_TIMEOUT);
}
if (schema_type != SOT_ALTER_TABLE)
break;
@@ -2250,7 +2254,6 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
free_share(&share);
share= 0;
}
- pthread_mutex_lock(&LOCK_open);
if (ndbcluster_check_if_local_table(schema->db, schema->name))
{
DBUG_PRINT("info", ("NDB Binlog: Skipping locally defined table '%s.%s'",
@@ -2262,16 +2265,8 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
}
else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
{
- sql_print_error("NDB Binlog: Could not discover table '%s.%s' from "
- "binlog schema event '%s' from node %d. my_errno: %d",
- schema->db, schema->name, schema->query,
- schema->node_id, my_errno);
- List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
- MYSQL_ERROR *err;
- while ((err= it++))
- sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg);
+ print_could_not_discover_error(thd, schema);
}
- pthread_mutex_unlock(&LOCK_open);
}
break;
default:
@@ -2323,29 +2318,27 @@ struct ndb_binlog_index_row {
/*
Open the ndb_binlog_index table
*/
-static int open_ndb_binlog_index(THD *thd, TABLE_LIST *tables,
- TABLE **ndb_binlog_index)
+static int open_ndb_binlog_index(THD *thd, TABLE **ndb_binlog_index)
{
static char repdb[]= NDB_REP_DB;
static char reptable[]= NDB_REP_TABLE;
const char *save_proc_info= thd->proc_info;
+ TABLE_LIST *tables= &binlog_tables;
- bzero((char*) tables, sizeof(*tables));
- tables->db= repdb;
- tables->alias= tables->table_name= reptable;
- tables->lock_type= TL_WRITE;
+ tables->init_one_table(repdb, strlen(repdb), reptable, strlen(reptable),
+ reptable, TL_WRITE);
thd->proc_info= "Opening " NDB_REP_DB "." NDB_REP_TABLE;
+
tables->required_type= FRMTYPE_TABLE;
- uint counter;
thd->clear_error();
- if (open_tables(thd, &tables, &counter, MYSQL_LOCK_IGNORE_FLUSH))
+ if (open_and_lock_tables(thd, tables, FALSE, 0))
{
if (thd->killed)
sql_print_error("NDB Binlog: Opening ndb_binlog_index: killed");
else
sql_print_error("NDB Binlog: Opening ndb_binlog_index: %d, '%s'",
- thd->main_da.sql_errno(),
- thd->main_da.message());
+ thd->stmt_da->sql_errno(),
+ thd->stmt_da->message());
thd->proc_info= save_proc_info;
return -1;
}
@@ -2364,36 +2357,18 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row)
{
ndb_binlog_index_row &row= *(ndb_binlog_index_row *) _row;
int error= 0;
- bool need_reopen;
/*
Turn of binlogging to prevent the table changes to be written to
the binary log.
*/
- ulong saved_options= thd->options;
- thd->options&= ~(OPTION_BIN_LOG);
+ ulong saved_options= thd->variables.option_bits;
+ thd->variables.option_bits&= ~OPTION_BIN_LOG;
- for ( ; ; ) /* loop for need_reopen */
+ if (!ndb_binlog_index && open_ndb_binlog_index(thd, &ndb_binlog_index))
{
- if (!ndb_binlog_index && open_ndb_binlog_index(thd, &binlog_tables, &ndb_binlog_index))
- {
- error= -1;
- goto add_ndb_binlog_index_err;
- }
-
- if (lock_tables(thd, &binlog_tables, 1, &need_reopen))
- {
- if (need_reopen)
- {
- TABLE_LIST *p_binlog_tables= &binlog_tables;
- close_tables_for_reopen(thd, &p_binlog_tables);
- ndb_binlog_index= 0;
- continue;
- }
- sql_print_error("NDB Binlog: Unable to lock table ndb_binlog_index");
- error= -1;
- goto add_ndb_binlog_index_err;
- }
- break;
+ sql_print_error("NDB Binlog: Unable to lock table ndb_binlog_index");
+ error= -1;
+ goto add_ndb_binlog_index_err;
}
/*
@@ -2418,14 +2393,14 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row)
goto add_ndb_binlog_index_err;
}
- mysql_unlock_tables(thd, thd->lock);
- thd->lock= 0;
- thd->options= saved_options;
- return 0;
add_ndb_binlog_index_err:
+ thd->stmt_da->can_overwrite_status= TRUE;
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ thd->stmt_da->can_overwrite_status= FALSE;
close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
ndb_binlog_index= 0;
- thd->options= saved_options;
+ thd->variables.option_bits= saved_options;
return error;
}
@@ -2458,27 +2433,29 @@ int ndbcluster_binlog_start()
DBUG_RETURN(-1);
}
- pthread_mutex_init(&injector_mutex, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&injector_cond, NULL);
- pthread_mutex_init(&ndb_schema_share_mutex, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_injector_mutex, &injector_mutex, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_injector_cond, &injector_cond, NULL);
+ mysql_mutex_init(key_ndb_schema_share_mutex,
+ &ndb_schema_share_mutex, MY_MUTEX_INIT_FAST);
/* Create injector thread */
- if (pthread_create(&ndb_binlog_thread, &connection_attrib,
- ndb_binlog_thread_func, 0))
+ if (mysql_thread_create(key_thread_ndb_binlog,
+ &ndb_binlog_thread, &connection_attrib,
+ ndb_binlog_thread_func, 0))
{
DBUG_PRINT("error", ("Could not create ndb injector thread"));
- pthread_cond_destroy(&injector_cond);
- pthread_mutex_destroy(&injector_mutex);
+ mysql_cond_destroy(&injector_cond);
+ mysql_mutex_destroy(&injector_mutex);
DBUG_RETURN(-1);
}
ndbcluster_binlog_inited= 1;
/* Wait for the injector thread to start */
- pthread_mutex_lock(&injector_mutex);
+ mysql_mutex_lock(&injector_mutex);
while (!ndb_binlog_thread_running)
- pthread_cond_wait(&injector_cond, &injector_mutex);
- pthread_mutex_unlock(&injector_mutex);
+ mysql_cond_wait(&injector_cond, &injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
if (ndb_binlog_thread_running < 0)
DBUG_RETURN(-1);
@@ -2568,11 +2545,11 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
DBUG_ASSERT(! IS_NDB_BLOB_PREFIX(table_name));
DBUG_ASSERT(strlen(key) == key_len);
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
/* Handle any trailing share */
- NDB_SHARE *share= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
- (uchar*) key, key_len);
+ NDB_SHARE *share= (NDB_SHARE*) my_hash_search(&ndbcluster_open_tables,
+ (uchar*) key, key_len);
if (share && share_may_exist)
{
@@ -2580,7 +2557,7 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
share->op != 0 ||
share->op_old != 0)
{
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(0); // replication already setup, or should not
}
}
@@ -2590,7 +2567,7 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
if (share->op || share->op_old)
{
my_errno= HA_ERR_TABLE_EXIST;
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(1);
}
if (!share_may_exist || share->connect_count !=
@@ -2633,10 +2610,10 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
if (!do_event_op)
{
share->flags|= NSF_NO_BINLOG;
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(0);
}
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
while (share && !IS_TMP_PREFIX(table_name))
{
@@ -2655,7 +2632,7 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
const NDBTAB *ndbtab= ndbtab_g.get_table();
if (ndbtab == 0)
{
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: Failed to get table %s from ndb: "
"%s, %d", key, dict->getNdbError().message,
dict->getNdbError().code);
@@ -2677,7 +2654,7 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
event_name.c_ptr());
break; // error
}
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: "
"CREATE (DISCOVER) TABLE Event: %s",
event_name.c_ptr());
@@ -2685,7 +2662,7 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
else
{
delete ev;
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: DISCOVER TABLE Event: %s",
event_name.c_ptr());
}
@@ -2741,7 +2718,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
"with BLOB attribute and no PK is not supported",
share->key);
if (push_warning)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
ER(ER_ILLEGAL_HA_CREATE_OPTION),
ndbcluster_hton_name,
@@ -2785,7 +2762,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
failed, print a warning
*/
if (push_warning > 1)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
dict->getNdbError().code,
dict->getNdbError().message, "NDB");
@@ -2813,7 +2790,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
dict->dropEvent(my_event.getName()))
{
if (push_warning > 1)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
dict->getNdbError().code,
dict->getNdbError().message, "NDB");
@@ -2832,7 +2809,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
if (dict->createEvent(my_event))
{
if (push_warning > 1)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
dict->getNdbError().code,
dict->getNdbError().message, "NDB");
@@ -2845,7 +2822,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab,
DBUG_RETURN(-1);
}
#ifdef NDB_BINLOG_EXTRA_WARNINGS
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
0, "NDB Binlog: Removed trailing event",
"NDB");
@@ -2929,14 +2906,14 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
int retry_sleep= 100;
while (1)
{
- pthread_mutex_lock(&injector_mutex);
+ mysql_mutex_lock(&injector_mutex);
Ndb *ndb= injector_ndb;
if (do_ndb_schema_share)
ndb= schema_ndb;
if (ndb == 0)
{
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
DBUG_RETURN(-1);
}
@@ -2956,12 +2933,12 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
{
sql_print_error("NDB Binlog: Creating NdbEventOperation failed for"
" %s",event_name);
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
ndb->getNdbError().code,
ndb->getNdbError().message,
"NDB");
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
DBUG_RETURN(-1);
}
@@ -3005,13 +2982,13 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
sql_print_error("NDB Binlog: Creating NdbEventOperation"
" blob field %u handles failed (code=%d) for %s",
j, op->getNdbError().code, event_name);
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
op->getNdbError().code,
op->getNdbError().message,
"NDB");
ndb->dropEventOperation(op);
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
DBUG_RETURN(-1);
}
}
@@ -3044,7 +3021,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
retries= 0;
if (retries == 0)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
op->getNdbError().code, op->getNdbError().message,
"NDB");
@@ -3053,7 +3030,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
op->getNdbError().code, op->getNdbError().message);
}
ndb->dropEventOperation(op);
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
if (retries)
{
my_sleep(retry_sleep);
@@ -3061,7 +3038,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
}
DBUG_RETURN(-1);
}
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
break;
}
@@ -3075,7 +3052,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
ndb_apply_status_share= get_share(share);
DBUG_PRINT("NDB_SHARE", ("%s binlog extra use_count: %u",
share->key, share->use_count));
- (void) pthread_cond_signal(&injector_cond);
+ mysql_cond_signal(&injector_cond);
}
else if (do_ndb_schema_share)
{
@@ -3083,13 +3060,13 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
ndb_schema_share= get_share(share);
DBUG_PRINT("NDB_SHARE", ("%s binlog extra use_count: %u",
share->key, share->use_count));
- (void) pthread_cond_signal(&injector_cond);
+ mysql_cond_signal(&injector_cond);
}
DBUG_PRINT("info",("%s share->op: 0x%lx share->use_count: %u",
share->key, (long) share->op, share->use_count));
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: logging %s", share->key);
DBUG_RETURN(0);
}
@@ -3112,7 +3089,7 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
if (dict->getNdbError().code != 4710)
{
/* drop event failed for some reason, issue a warning */
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
dict->getNdbError().code,
dict->getNdbError().message, "NDB");
@@ -3154,17 +3131,15 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
#define SYNC_DROP_
#ifdef SYNC_DROP_
thd->proc_info= "Syncing ndb table schema operation and binlog";
- (void) pthread_mutex_lock(&share->mutex);
- safe_mutex_assert_owner(&LOCK_open);
- (void) pthread_mutex_unlock(&LOCK_open);
- int max_timeout= opt_ndb_sync_timeout;
+ mysql_mutex_lock(&share->mutex);
+ int max_timeout= DEFAULT_SYNC_TIMEOUT;
while (share->op)
{
struct timespec abstime;
set_timespec(abstime, 1);
- int ret= pthread_cond_timedwait(&injector_cond,
- &share->mutex,
- &abstime);
+ int ret= mysql_cond_timedwait(&injector_cond,
+ &share->mutex,
+ &abstime);
if (thd->killed ||
share->op == 0)
break;
@@ -3177,18 +3152,17 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
type_str, share->key);
break;
}
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
ndb_report_waiting(type_str, max_timeout,
type_str, share->key);
}
}
- (void) pthread_mutex_lock(&LOCK_open);
- (void) pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
#else
- (void) pthread_mutex_lock(&share->mutex);
+ mysql_mutex_lock(&share->mutex);
share->op_old= share->op;
share->op= 0;
- (void) pthread_mutex_unlock(&share->mutex);
+ mysql_mutex_unlock(&share->mutex);
#endif
thd->proc_info= save_proc_info;
@@ -3255,12 +3229,12 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb,
switch (type)
{
case NDBEVENT::TE_CLUSTER_FAILURE:
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: cluster failure for %s at epoch %u.",
share->key, (unsigned) pOp->getGCI());
if (ndb_apply_status_share == share)
{
- if (ndb_extra_logging &&
+ if (opt_ndb_extra_logging &&
ndb_binlog_tables_inited && ndb_binlog_running)
sql_print_information("NDB Binlog: ndb tables initially "
"read only on reconnect.");
@@ -3280,7 +3254,7 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb,
case NDBEVENT::TE_DROP:
if (ndb_apply_status_share == share)
{
- if (ndb_extra_logging &&
+ if (opt_ndb_extra_logging &&
ndb_binlog_tables_inited && ndb_binlog_running)
sql_print_information("NDB Binlog: ndb tables initially "
"read only on reconnect.");
@@ -3292,7 +3266,7 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb,
ndb_binlog_tables_inited= 0;
}
/* ToDo: remove printout */
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
sql_print_information("NDB Binlog: drop table %s.", share->key);
// fall through
case NDBEVENT::TE_ALTER:
@@ -3390,14 +3364,14 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= 0;
- IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0],
+ int ret __attribute__((unused))= get_ndb_blobs_value(table, share->ndb_value[0],
blobs_buffer[0],
blobs_buffer_size[0],
ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[0], &b, table->record[0]);
- IF_DBUG(int ret=) trans.write_row(originating_server_id,
+ int ret __attribute__((unused))= trans.write_row(originating_server_id,
injector::transaction::table(table,
TRUE),
&b, n_fields, table->record[0]);
@@ -3429,7 +3403,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= table->record[n] - table->record[0];
- IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[n],
+ int ret __attribute__((unused))= get_ndb_blobs_value(table, share->ndb_value[n],
blobs_buffer[n],
blobs_buffer_size[n],
ptrdiff);
@@ -3437,7 +3411,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
}
ndb_unpack_record(table, share->ndb_value[n], &b, table->record[n]);
DBUG_EXECUTE("info", print_records(table, table->record[n]););
- IF_DBUG(int ret =) trans.delete_row(originating_server_id,
+ int ret __attribute__((unused))= trans.delete_row(originating_server_id,
injector::transaction::table(table,
TRUE),
&b, n_fields, table->record[n]);
@@ -3452,7 +3426,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= 0;
- IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0],
+ int ret __attribute__((unused))= get_ndb_blobs_value(table, share->ndb_value[0],
blobs_buffer[0],
blobs_buffer_size[0],
ptrdiff);
@@ -3480,7 +3454,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= table->record[1] - table->record[0];
- IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[1],
+ int ret __attribute__((unused))= get_ndb_blobs_value(table, share->ndb_value[1],
blobs_buffer[1],
blobs_buffer_size[1],
ptrdiff);
@@ -3488,7 +3462,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
}
ndb_unpack_record(table, share->ndb_value[1], &b, table->record[1]);
DBUG_EXECUTE("info", print_records(table, table->record[1]););
- IF_DBUG(int ret =) trans.update_row(originating_server_id,
+ int ret __attribute__((unused))= trans.update_row(originating_server_id,
injector::transaction::table(table,
TRUE),
&b, n_fields,
@@ -3506,8 +3480,8 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
- my_free(blobs_buffer[0], MYF(MY_ALLOW_ZERO_PTR));
- my_free(blobs_buffer[1], MYF(MY_ALLOW_ZERO_PTR));
+ my_free(blobs_buffer[0]);
+ my_free(blobs_buffer[1]);
}
return 0;
@@ -3556,11 +3530,11 @@ static NDB_SCHEMA_OBJECT *ndb_get_schema_object(const char *key,
DBUG_PRINT("enter", ("key: '%s'", key));
if (!have_lock)
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
while (!(ndb_schema_object=
- (NDB_SCHEMA_OBJECT*) hash_search(&ndb_schema_objects,
- (uchar*) key,
- length)))
+ (NDB_SCHEMA_OBJECT*) my_hash_search(&ndb_schema_objects,
+ (uchar*) key,
+ length)))
{
if (!create_if_not_exists)
{
@@ -3579,10 +3553,10 @@ static NDB_SCHEMA_OBJECT *ndb_get_schema_object(const char *key,
ndb_schema_object->key_length= length;
if (my_hash_insert(&ndb_schema_objects, (uchar*) ndb_schema_object))
{
- my_free((uchar*) ndb_schema_object, 0);
+ my_free(ndb_schema_object);
break;
}
- pthread_mutex_init(&ndb_schema_object->mutex, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_ndb_schema_object_mutex, &ndb_schema_object->mutex, MY_MUTEX_INIT_FAST);
bitmap_init(&ndb_schema_object->slock_bitmap, ndb_schema_object->slock,
sizeof(ndb_schema_object->slock)*8, FALSE);
bitmap_clear_all(&ndb_schema_object->slock_bitmap);
@@ -3594,7 +3568,7 @@ static NDB_SCHEMA_OBJECT *ndb_get_schema_object(const char *key,
DBUG_PRINT("info", ("use_count: %d", ndb_schema_object->use_count));
}
if (!have_lock)
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(ndb_schema_object);
}
@@ -3605,13 +3579,13 @@ static void ndb_free_schema_object(NDB_SCHEMA_OBJECT **ndb_schema_object,
DBUG_ENTER("ndb_free_schema_object");
DBUG_PRINT("enter", ("key: '%s'", (*ndb_schema_object)->key));
if (!have_lock)
- pthread_mutex_lock(&ndbcluster_mutex);
+ mysql_mutex_lock(&ndbcluster_mutex);
if (!--(*ndb_schema_object)->use_count)
{
DBUG_PRINT("info", ("use_count: %d", (*ndb_schema_object)->use_count));
- hash_delete(&ndb_schema_objects, (uchar*) *ndb_schema_object);
- pthread_mutex_destroy(&(*ndb_schema_object)->mutex);
- my_free((uchar*) *ndb_schema_object, MYF(0));
+ my_hash_delete(&ndb_schema_objects, (uchar*) *ndb_schema_object);
+ mysql_mutex_destroy(&(*ndb_schema_object)->mutex);
+ my_free(*ndb_schema_object);
*ndb_schema_object= 0;
}
else
@@ -3619,10 +3593,12 @@ static void ndb_free_schema_object(NDB_SCHEMA_OBJECT **ndb_schema_object,
DBUG_PRINT("info", ("use_count: %d", (*ndb_schema_object)->use_count));
}
if (!have_lock)
- pthread_mutex_unlock(&ndbcluster_mutex);
+ mysql_mutex_unlock(&ndbcluster_mutex);
DBUG_VOID_RETURN;
}
+extern ulong opt_ndb_report_thresh_binlog_epoch_slip;
+extern ulong opt_ndb_report_thresh_binlog_mem_usage;
pthread_handler_t ndb_binlog_thread_func(void *arg)
{
@@ -3638,7 +3614,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
Timer main_timer;
#endif
- pthread_mutex_lock(&injector_mutex);
+ mysql_mutex_lock(&injector_mutex);
/*
Set up the Thread
*/
@@ -3647,13 +3623,16 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
thd= new THD; /* note that contructor of THD uses DBUG_ */
THD_CHECK_SENTRY(thd);
+ thd->set_current_stmt_binlog_format_row();
/* We need to set thd->thread_id before thd->store_globals, or it will
set an invalid value for thd->variables.pseudo_thread_id.
*/
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->thread_id= thread_id++;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ mysql_thread_set_psi_id(thd->thread_id);
thd->thread_stack= (char*) &thd; /* remember where our stack is */
if (thd->store_globals())
@@ -3661,25 +3640,25 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
thd->cleanup();
delete thd;
ndb_binlog_thread_running= -1;
- pthread_mutex_unlock(&injector_mutex);
- pthread_cond_signal(&injector_cond);
+ mysql_mutex_unlock(&injector_mutex);
+ mysql_cond_signal(&injector_cond);
DBUG_LEAVE; // Must match DBUG_ENTER()
my_thread_end();
pthread_exit(0);
return NULL; // Avoid compiler warnings
}
- lex_start(thd);
thd->init_for_queries();
thd->command= COM_DAEMON;
thd->system_thread= SYSTEM_THREAD_NDBCLUSTER_BINLOG;
- thd->version= refresh_version;
thd->main_security_ctx.host_or_ip= "";
thd->client_capabilities= 0;
my_net_init(&thd->net, 0);
thd->main_security_ctx.master_access= ~0;
- thd->main_security_ctx.priv_user= 0;
+ thd->main_security_ctx.priv_user[0]= 0;
+ /* Do not use user-supplied timeout value for system threads. */
+ thd->variables.lock_wait_timeout= LONG_TIMEOUT;
/*
Set up ndb binlog
@@ -3688,9 +3667,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
pthread_detach_this_thread();
thd->real_id= pthread_self();
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
threads.append(thd);
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
thd->lex->start_transaction_opt= 0;
if (!(s_ndb= new Ndb(g_ndb_cluster_connection, "")) ||
@@ -3698,8 +3677,8 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
{
sql_print_error("NDB Binlog: Getting Schema Ndb object failed");
ndb_binlog_thread_running= -1;
- pthread_mutex_unlock(&injector_mutex);
- pthread_cond_signal(&injector_cond);
+ mysql_mutex_unlock(&injector_mutex);
+ mysql_cond_signal(&injector_cond);
goto err;
}
@@ -3709,21 +3688,21 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
{
sql_print_error("NDB Binlog: Getting Ndb object failed");
ndb_binlog_thread_running= -1;
- pthread_mutex_unlock(&injector_mutex);
- pthread_cond_signal(&injector_cond);
+ mysql_mutex_unlock(&injector_mutex);
+ mysql_cond_signal(&injector_cond);
goto err;
}
/* init hash for schema object distribution */
- (void) hash_init(&ndb_schema_objects, system_charset_info, 32, 0, 0,
- (hash_get_key)ndb_schema_objects_get_key, 0, 0);
+ (void) my_hash_init(&ndb_schema_objects, system_charset_info, 32, 0, 0,
+ (my_hash_get_key)ndb_schema_objects_get_key, 0, 0);
/*
Expose global reference to our ndb object.
Used by both sql client thread and binlog thread to interact
with the storage
- pthread_mutex_lock(&injector_mutex);
+ mysql_mutex_lock(&injector_mutex);
*/
injector_thd= thd;
injector_ndb= i_ndb;
@@ -3738,27 +3717,27 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
/* Thread start up completed */
ndb_binlog_thread_running= 1;
- pthread_mutex_unlock(&injector_mutex);
- pthread_cond_signal(&injector_cond);
+ mysql_mutex_unlock(&injector_mutex);
+ mysql_cond_signal(&injector_cond);
/*
wait for mysql server to start (so that the binlog is started
and thus can receive the first GAP event)
*/
- pthread_mutex_lock(&LOCK_server_started);
+ mysql_mutex_lock(&LOCK_server_started);
while (!mysqld_server_started)
{
struct timespec abstime;
set_timespec(abstime, 1);
- pthread_cond_timedwait(&COND_server_started, &LOCK_server_started,
- &abstime);
+ mysql_cond_timedwait(&COND_server_started, &LOCK_server_started,
+ &abstime);
if (ndbcluster_terminating)
{
- pthread_mutex_unlock(&LOCK_server_started);
+ mysql_mutex_unlock(&LOCK_server_started);
goto err;
}
}
- pthread_mutex_unlock(&LOCK_server_started);
+ mysql_mutex_unlock(&LOCK_server_started);
restart:
/*
Main NDB Injector loop
@@ -3792,7 +3771,7 @@ restart:
{ C_STRING_WITH_LEN("mysqld startup") },
{ C_STRING_WITH_LEN("cluster disconnect")}
};
- IF_DBUG(int error=)
+ int error __attribute__((unused))=
inj->record_incident(thd, INCIDENT_LOST_EVENTS, msg[incident_id]);
DBUG_ASSERT(!error);
break;
@@ -3801,21 +3780,21 @@ restart:
{
thd->proc_info= "Waiting for ndbcluster to start";
- pthread_mutex_lock(&injector_mutex);
+ mysql_mutex_lock(&injector_mutex);
while (!ndb_schema_share ||
(ndb_binlog_running && !ndb_apply_status_share))
{
/* ndb not connected yet */
struct timespec abstime;
set_timespec(abstime, 1);
- pthread_cond_timedwait(&injector_cond, &injector_mutex, &abstime);
+ mysql_cond_timedwait(&injector_cond, &injector_mutex, &abstime);
if (ndbcluster_binlog_terminating)
{
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
goto err;
}
}
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
if (thd_ndb == NULL)
{
@@ -3882,7 +3861,7 @@ restart:
"Changes to the database that occured while "
"disconnected will not be in the binlog");
}
- if (ndb_extra_logging)
+ if (opt_ndb_extra_logging)
{
sql_print_information("NDB Binlog: starting log at epoch %u",
(unsigned)schema_gci);
@@ -3892,9 +3871,6 @@ restart:
{
static char db[]= "";
thd->db= db;
- if (ndb_binlog_running)
- open_ndb_binlog_index(thd, &binlog_tables, &ndb_binlog_index);
- thd->db= db;
}
do_ndbcluster_binlog_close_connection= BCCC_running;
for ( ; !((ndbcluster_binlog_terminating ||
@@ -3962,11 +3938,13 @@ restart:
!ndb_binlog_running))
break; /* Shutting down server */
- if (ndb_binlog_index && ndb_binlog_index->s->version < refresh_version)
+ if (ndb_binlog_index && ndb_binlog_index->s->has_old_version())
{
- if (ndb_binlog_index->s->version < refresh_version)
+ if (ndb_binlog_index->s->has_old_version())
{
+ trans_commit_stmt(thd);
close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
ndb_binlog_index= 0;
}
}
@@ -3984,9 +3962,9 @@ restart:
{
thd->proc_info= "Processing events from schema table";
s_ndb->
- setReportThreshEventGCISlip(ndb_report_thresh_binlog_epoch_slip);
+ setReportThreshEventGCISlip(opt_ndb_report_thresh_binlog_epoch_slip);
s_ndb->
- setReportThreshEventFreeMem(ndb_report_thresh_binlog_mem_usage);
+ setReportThreshEventFreeMem(opt_ndb_report_thresh_binlog_mem_usage);
NdbEventOperation *pOp= s_ndb->nextEvent();
while (pOp != NULL)
{
@@ -4049,8 +4027,8 @@ restart:
/* initialize some variables for this epoch */
g_ndb_log_slave_updates= opt_log_slave_updates;
i_ndb->
- setReportThreshEventGCISlip(ndb_report_thresh_binlog_epoch_slip);
- i_ndb->setReportThreshEventFreeMem(ndb_report_thresh_binlog_mem_usage);
+ setReportThreshEventGCISlip(opt_ndb_report_thresh_binlog_epoch_slip);
+ i_ndb->setReportThreshEventFreeMem(opt_ndb_report_thresh_binlog_mem_usage);
bzero((char*) &row, sizeof(row));
thd->variables.character_set_client= &my_charset_latin1;
@@ -4107,7 +4085,7 @@ restart:
DBUG_PRINT("info", ("use_table: %.*s",
(int) name.length, name.str));
injector::transaction::table tbl(table, TRUE);
- IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
+ int ret __attribute__((unused))= trans.use_table(::server_id, tbl);
DBUG_ASSERT(ret == 0);
}
}
@@ -4123,7 +4101,7 @@ restart:
(int) name.length, name.str));
#endif
injector::transaction::table tbl(table, TRUE);
- IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
+ int ret __attribute__((unused))= trans.use_table(::server_id, tbl);
DBUG_ASSERT(ret == 0);
/*
@@ -4193,7 +4171,7 @@ restart:
else
{
// set injector_ndb database/schema from table internal name
- IF_DBUG(int ret=)
+ int ret __attribute__((unused))=
i_ndb->setDatabaseAndSchemaName(pOp->getEvent()->getTable());
DBUG_ASSERT(ret == 0);
ndb_binlog_thread_handle_non_data_event(thd, i_ndb, pOp, row);
@@ -4277,7 +4255,9 @@ restart:
if (do_ndbcluster_binlog_close_connection == BCCC_restart)
{
ndb_binlog_tables_inited= FALSE;
+ trans_commit_stmt(thd);
close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
ndb_binlog_index= 0;
goto restart;
}
@@ -4285,14 +4265,18 @@ err:
sql_print_information("Stopping Cluster Binlog");
DBUG_PRINT("info",("Shutting down cluster binlog thread"));
thd->proc_info= "Shutting down";
+ thd->stmt_da->can_overwrite_status= TRUE;
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ thd->stmt_da->can_overwrite_status= FALSE;
close_thread_tables(thd);
- pthread_mutex_lock(&injector_mutex);
+ thd->mdl_context.release_transactional_locks();
+ mysql_mutex_lock(&injector_mutex);
/* don't mess with the injector_ndb anymore from other threads */
injector_thd= 0;
injector_ndb= 0;
p_latest_trans_gci= 0;
schema_ndb= 0;
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
thd->db= 0; // as not to try to free memory
if (ndb_apply_status_share)
@@ -4307,7 +4291,7 @@ err:
if (ndb_schema_share)
{
/* begin protect ndb_schema_share */
- pthread_mutex_lock(&ndb_schema_share_mutex);
+ mysql_mutex_lock(&ndb_schema_share_mutex);
/* ndb_share reference binlog extra free */
DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
ndb_schema_share->key,
@@ -4315,7 +4299,7 @@ err:
free_share(&ndb_schema_share);
ndb_schema_share= 0;
ndb_binlog_tables_inited= 0;
- pthread_mutex_unlock(&ndb_schema_share_mutex);
+ mysql_mutex_unlock(&ndb_schema_share_mutex);
/* end protect ndb_schema_share */
}
@@ -4367,7 +4351,7 @@ err:
i_ndb= 0;
}
- hash_free(&ndb_schema_objects);
+ my_hash_free(&ndb_schema_objects);
net_end(&thd->net);
thd->cleanup();
@@ -4375,7 +4359,7 @@ err:
ndb_binlog_thread_running= -1;
ndb_binlog_running= FALSE;
- (void) pthread_cond_signal(&injector_cond);
+ mysql_cond_signal(&injector_cond);
DBUG_PRINT("exit", ("ndb_binlog_thread"));
@@ -4394,12 +4378,12 @@ ndbcluster_show_status_binlog(THD* thd, stat_print_fn *stat_print,
ulonglong ndb_latest_epoch= 0;
DBUG_ENTER("ndbcluster_show_status_binlog");
- pthread_mutex_lock(&injector_mutex);
+ mysql_mutex_lock(&injector_mutex);
if (injector_ndb)
{
char buff1[22],buff2[22],buff3[22],buff4[22],buff5[22];
ndb_latest_epoch= injector_ndb->getLatestGCI();
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
buflen=
snprintf(buf, sizeof(buf),
@@ -4419,7 +4403,7 @@ ndbcluster_show_status_binlog(THD* thd, stat_print_fn *stat_print,
DBUG_RETURN(TRUE);
}
else
- pthread_mutex_unlock(&injector_mutex);
+ mysql_mutex_unlock(&injector_mutex);
DBUG_RETURN(FALSE);
}
diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h
index 1cad643e5ec..5dbcf0fa43f 100644
--- a/sql/ha_ndbcluster_binlog.h
+++ b/sql/ha_ndbcluster_binlog.h
@@ -1,4 +1,7 @@
-/* Copyright (C) 2000-2003 MySQL AB
+#ifndef HA_NDBCLUSTER_BINLOG_INCLUDED
+#define HA_NDBCLUSTER_BINLOG_INCLUDED
+
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -14,6 +17,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "sql_class.h" /* THD */
+
// Typedefs for long names
typedef NdbDictionary::Object NDBOBJ;
typedef NdbDictionary::Column NDBCOL;
@@ -24,8 +29,6 @@ typedef NdbDictionary::Event NDBEVENT;
#define IS_TMP_PREFIX(A) (is_prefix(A, tmp_file_prefix))
-extern ulong ndb_extra_logging;
-
#define INJECTOR_EVENT_LEN 200
#define NDB_INVALID_SCHEMA_OBJECT 241
@@ -103,16 +106,24 @@ private:
};
#ifdef HAVE_NDB_BINLOG
+
+#ifdef HAVE_PSI_INTERFACE
+extern PSI_mutex_key key_injector_mutex, key_ndb_schema_share_mutex,
+ key_ndb_schema_object_mutex;
+extern PSI_cond_key key_injector_cond;
+extern PSI_thread_key key_thread_ndb_binlog;
+#endif /* HAVE_PSI_INTERFACE */
+
extern pthread_t ndb_binlog_thread;
-extern pthread_mutex_t injector_mutex;
-extern pthread_cond_t injector_cond;
+extern mysql_mutex_t injector_mutex;
+extern mysql_cond_t injector_cond;
extern unsigned char g_node_id_map[max_ndb_nodes];
extern pthread_t ndb_util_thread;
-extern pthread_mutex_t LOCK_ndb_util_thread;
-extern pthread_cond_t COND_ndb_util_thread;
+extern mysql_mutex_t LOCK_ndb_util_thread;
+extern mysql_cond_t COND_ndb_util_thread;
extern int ndbcluster_util_inited;
-extern pthread_mutex_t ndbcluster_mutex;
+extern mysql_mutex_t ndbcluster_mutex;
extern HASH ndbcluster_open_tables;
extern Ndb_cluster_connection* g_ndb_cluster_connection;
extern long ndb_number_of_storage_nodes;
@@ -147,8 +158,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
uint32 ndb_table_version,
enum SCHEMA_OP_TYPE type,
const char *new_db,
- const char *new_table_name,
- int have_lock_open);
+ const char *new_table_name);
int ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name,
NDB_SHARE *share,
const char *type_str);
@@ -225,3 +235,5 @@ set_thd_ndb(THD *thd, Thd_ndb *thd_ndb)
{ thd_set_ha_data(thd, ndbcluster_hton, thd_ndb); }
Ndb* check_ndb_in_thd(THD* thd);
+
+#endif /* HA_NDBCLUSTER_BINLOG_INCLUDED */
diff --git a/sql/ha_ndbcluster_cond.cc b/sql/ha_ndbcluster_cond.cc
index bb35211944b..8a96ae41453 100644
--- a/sql/ha_ndbcluster_cond.cc
+++ b/sql/ha_ndbcluster_cond.cc
@@ -22,7 +22,10 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_class.h" // set_var.h: THD
+#include "my_global.h" // WITH_*
+#include "log.h" // sql_print_error
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
#include <ndbapi/NdbApi.hpp>
@@ -32,6 +35,110 @@
typedef NdbDictionary::Column NDBCOL;
typedef NdbDictionary::Table NDBTAB;
+
+/**
+ Serialize a constant item into a Ndb_cond node.
+
+ @param const_type item's result type
+ @param item item to be serialized
+ @param curr_cond Ndb_cond node the item to be serialized into
+ @param context Traverse context
+*/
+
+static void ndb_serialize_const(Item_result const_type, const Item *item,
+ Ndb_cond *curr_cond,
+ Ndb_cond_traverse_context *context)
+{
+ DBUG_ASSERT(item->const_item());
+ switch (const_type) {
+ case STRING_RESULT:
+ {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::STRING_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(STRING_RESULT);
+ context->expect_collation(item->collation.collation);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ // Check that string result have correct collation
+ if (!context->expecting_collation(item->collation.collation))
+ {
+ DBUG_PRINT("info", ("Found non-matching collation %s",
+ item->collation.collation->name));
+ context->supported= FALSE;
+ }
+ }
+ break;
+ }
+ case REAL_RESULT:
+ {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::REAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(REAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ break;
+ }
+ case INT_RESULT:
+ {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::INT_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(INT_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::DECIMAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(DECIMAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
/*
Serialize the item tree into a linked list represented by Ndb_cond
for fast generation of NbdScanFilter. Adds information such as
@@ -110,7 +217,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
to ndb_serialize_cond and end of rewrite statement
is wrapped in end of ndb_serialize_cond
*/
- if (context->expecting(item->type()))
+ if (context->expecting(item->type()) || item->const_item())
{
// This is the <field>|<const> item, save it in the rewrite context
rewrite_context2->left_hand_item= item;
@@ -594,108 +701,12 @@ void ndb_serialize_cond(const Item *item, void *arg)
DBUG_PRINT("info", ("result type %d", func_item->result_type()));
if (func_item->const_item())
{
- switch (func_item->result_type()) {
- case STRING_RESULT:
- {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::STRING_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(STRING_RESULT);
- context->expect_collation(func_item->collation.collation);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- // Check that string result have correct collation
- if (!context->expecting_collation(item->collation.collation))
- {
- DBUG_PRINT("info", ("Found non-matching collation %s",
- item->collation.collation->name));
- context->supported= FALSE;
- }
- }
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- case REAL_RESULT:
- {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::REAL_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(REAL_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
-
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- case INT_RESULT:
- {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::INT_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(INT_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
-
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- case DECIMAL_RESULT:
- {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::DECIMAL_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(DECIMAL_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- default:
- break;
- }
+ ndb_serialize_const(func_item->result_type(), item, curr_cond,
+ context);
+
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
}
else
// Function does not return constant expression
@@ -880,6 +891,19 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
break;
}
+ case Item::CACHE_ITEM:
+ {
+ DBUG_PRINT("info", ("CACHE_ITEM"));
+ if (item->const_item())
+ {
+ ndb_serialize_const(((Item_cache*)item)->result_type(), item,
+ curr_cond, context);
+ }
+ else
+ context->supported= FALSE;
+
+ break;
+ }
default:
{
DBUG_PRINT("info", ("Found item of type %d", item->type()));
diff --git a/sql/ha_ndbcluster_cond.h b/sql/ha_ndbcluster_cond.h
index 4401a93c9e1..442eac2fafd 100644
--- a/sql/ha_ndbcluster_cond.h
+++ b/sql/ha_ndbcluster_cond.h
@@ -1,3 +1,6 @@
+#ifndef HA_NDBCLUSTER_COND_INCLUDED
+#define HA_NDBCLUSTER_COND_INCLUDED
+
/* Copyright (C) 2000-2007 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -22,6 +25,13 @@
#pragma interface /* gcc class implementation */
#endif
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "set_var.h" /* Item, Item_field */
+
typedef enum ndb_item_type {
NDB_VALUE = 0, // Qualified more with Item::Type
NDB_FIELD = 1, // Qualified from table definition
@@ -486,3 +496,5 @@ private:
Ndb_cond_stack *m_cond_stack;
};
+
+#endif /* HA_NDBCLUSTER_COND_INCLUDED */
diff --git a/sql/ha_ndbcluster_tables.h b/sql/ha_ndbcluster_tables.h
index c6bc8f577f8..ba2e8ec251b 100644
--- a/sql/ha_ndbcluster_tables.h
+++ b/sql/ha_ndbcluster_tables.h
@@ -1,3 +1,6 @@
+#ifndef HA_NDBCLUSTER_TABLES_INCLUDED
+#define HA_NDBCLUSTER_TABLES_INCLUDED
+
/* Copyright (C) 2000-2003 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -21,3 +24,5 @@
#define OLD_NDB_APPLY_TABLE "apply_status"
#define NDB_SCHEMA_TABLE "ndb_schema"
#define OLD_NDB_SCHEMA_TABLE "schema"
+
+#endif /* HA_NDBCLUSTER_TABLES_INCLUDED */
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 7bcbd241541..4e0fb7c804a 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -1,4 +1,4 @@
-/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -51,20 +51,19 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_parse.h" // append_file_to_dir
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
-
-#include <mysql/plugin.h>
+#include "sql_table.h" // tablename_to_filename
+#include "key.h"
+#include "sql_plugin.h"
+#include "table.h" /* HA_DATA_PARTITION */
#include "debug_sync.h"
static const char *ha_par_ext= ".par";
-#ifdef NOT_USED
-static int free_share(PARTITION_SHARE * share);
-static PARTITION_SHARE *get_share(const char *table_name, TABLE * table);
-#endif
/****************************************************************************
MODULE create/delete handler object
@@ -251,7 +250,7 @@ void ha_partition::init_handler_variables()
/*
this allows blackhole to work properly
*/
- m_no_locks= 0;
+ m_num_locks= 0;
#ifdef DONT_HAVE_TO_BE_INITALIZED
m_start_key.flag= 0;
@@ -286,7 +285,7 @@ ha_partition::~ha_partition()
for (i= 0; i < m_tot_parts; i++)
delete m_file[i];
}
- my_free((char*) m_ordered_rec_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(m_ordered_rec_buffer);
clear_handler_file();
DBUG_VOID_RETURN;
@@ -361,7 +360,7 @@ bool ha_partition::initialize_partition(MEM_ROOT *mem_root)
}
else if (get_from_handler_file(table_share->normalized_path.str, mem_root))
{
- my_message(ER_UNKNOWN_ERROR, "Failed to read from the .par file", MYF(0));
+ my_error(ER_FAILED_READ_FROM_PAR_FILE, MYF(0));
DBUG_RETURN(1);
}
/*
@@ -506,9 +505,9 @@ int ha_partition::create_handler_files(const char *path,
strxmov(name, path, ha_par_ext, NullS);
strxmov(old_name, old_path, ha_par_ext, NullS);
if ((action_flag == CHF_DELETE_FLAG &&
- my_delete(name, MYF(MY_WME))) ||
+ mysql_file_delete(key_file_partition, name, MYF(MY_WME))) ||
(action_flag == CHF_RENAME_FLAG &&
- my_rename(old_name, name, MYF(MY_WME))))
+ mysql_file_rename(key_file_partition, old_name, name, MYF(MY_WME))))
{
DBUG_RETURN(TRUE);
}
@@ -586,8 +585,8 @@ int ha_partition::drop_partitions(const char *path)
{
List_iterator<partition_element> part_it(m_part_info->partitions);
char part_name_buff[FN_REFLEN];
- uint no_parts= m_part_info->partitions.elements;
- uint no_subparts= m_part_info->no_subparts;
+ uint num_parts= m_part_info->partitions.elements;
+ uint num_subparts= m_part_info->num_subparts;
uint i= 0;
uint name_variant;
int ret_error;
@@ -617,7 +616,7 @@ int ha_partition::drop_partitions(const char *path)
do
{
partition_element *sub_elem= sub_it++;
- part= i * no_subparts + j;
+ part= i * num_subparts + j;
create_subpartition_name(part_name_buff, path,
part_elem->partition_name,
sub_elem->partition_name, name_variant);
@@ -627,7 +626,7 @@ int ha_partition::drop_partitions(const char *path)
error= ret_error;
if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos))
error= 1;
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
else
{
@@ -646,8 +645,8 @@ int ha_partition::drop_partitions(const char *path)
else
part_elem->part_state= PART_IS_DROPPED;
}
- } while (++i < no_parts);
- VOID(sync_ddl_log());
+ } while (++i < num_parts);
+ (void) sync_ddl_log();
DBUG_RETURN(error);
}
@@ -677,9 +676,9 @@ int ha_partition::rename_partitions(const char *path)
List_iterator<partition_element> temp_it(m_part_info->temp_partitions);
char part_name_buff[FN_REFLEN];
char norm_name_buff[FN_REFLEN];
- uint no_parts= m_part_info->partitions.elements;
+ uint num_parts= m_part_info->partitions.elements;
uint part_count= 0;
- uint no_subparts= m_part_info->no_subparts;
+ uint num_subparts= m_part_info->num_subparts;
uint i= 0;
uint j= 0;
int error= 0;
@@ -729,7 +728,7 @@ int ha_partition::rename_partitions(const char *path)
error= 1;
else
sub_elem->log_entry= NULL; /* Indicate success */
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
else
{
@@ -746,7 +745,7 @@ int ha_partition::rename_partitions(const char *path)
part_elem->log_entry= NULL; /* Indicate success */
}
} while (++i < temp_partitions);
- VOID(sync_ddl_log());
+ (void) sync_ddl_log();
}
i= 0;
do
@@ -785,7 +784,7 @@ int ha_partition::rename_partitions(const char *path)
do
{
sub_elem= sub_it++;
- part= i * no_subparts + j;
+ part= i * num_subparts + j;
create_subpartition_name(norm_name_buff, path,
part_elem->partition_name,
sub_elem->partition_name,
@@ -798,7 +797,7 @@ int ha_partition::rename_partitions(const char *path)
error= ret_error;
else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos))
error= 1;
- VOID(sync_ddl_log());
+ (void) sync_ddl_log();
}
file= m_new_file[part];
create_subpartition_name(part_name_buff, path,
@@ -814,7 +813,7 @@ int ha_partition::rename_partitions(const char *path)
error= 1;
else
sub_elem->log_entry= NULL;
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
else
{
@@ -829,7 +828,7 @@ int ha_partition::rename_partitions(const char *path)
error= ret_error;
else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos))
error= 1;
- VOID(sync_ddl_log());
+ (void) sync_ddl_log();
}
file= m_new_file[i];
create_partition_name(part_name_buff, path,
@@ -846,8 +845,8 @@ int ha_partition::rename_partitions(const char *path)
part_elem->log_entry= NULL;
}
}
- } while (++i < no_parts);
- VOID(sync_ddl_log());
+ } while (++i < num_parts);
+ (void) sync_ddl_log();
DBUG_RETURN(error);
}
@@ -856,9 +855,12 @@ int ha_partition::rename_partitions(const char *path)
#define ANALYZE_PARTS 2
#define CHECK_PARTS 3
#define REPAIR_PARTS 4
+#define ASSIGN_KEYCACHE_PARTS 5
+#define PRELOAD_KEYS_PARTS 6
static const char *opt_op_name[]= {NULL,
- "optimize", "analyze", "check", "repair" };
+ "optimize", "analyze", "check", "repair",
+ "assign_to_keycache", "preload_keys"};
/*
Optimize table
@@ -943,7 +945,44 @@ int ha_partition::repair(THD *thd, HA_CHECK_OPT *check_opt)
DBUG_RETURN(handle_opt_partitions(thd, check_opt, REPAIR_PARTS));
}
+/**
+ Assign to keycache
+
+ @param thd Thread object
+ @param check_opt Check/analyze/repair/optimize options
+
+ @return
+ @retval >0 Error
+ @retval 0 Success
+*/
+
+int ha_partition::assign_to_keycache(THD *thd, HA_CHECK_OPT *check_opt)
+{
+ DBUG_ENTER("ha_partition::assign_to_keycache");
+
+ DBUG_RETURN(handle_opt_partitions(thd, check_opt, ASSIGN_KEYCACHE_PARTS));
+}
+
+/**
+ Preload to keycache
+
+ @param thd Thread object
+ @param check_opt Check/analyze/repair/optimize options
+
+ @return
+ @retval >0 Error
+ @retval 0 Success
+*/
+
+int ha_partition::preload_keys(THD *thd, HA_CHECK_OPT *check_opt)
+{
+ DBUG_ENTER("ha_partition::preload_keys");
+
+ DBUG_RETURN(handle_opt_partitions(thd, check_opt, PRELOAD_KEYS_PARTS));
+}
+
+
/*
Handle optimize/analyze/check/repair of one partition
@@ -974,6 +1013,10 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt,
error= file->ha_check(thd, check_opt);
else if (flag == REPAIR_PARTS)
error= file->ha_repair(thd, check_opt);
+ else if (flag == ASSIGN_KEYCACHE_PARTS)
+ error= file->assign_to_keycache(thd, check_opt);
+ else if (flag == PRELOAD_KEYS_PARTS)
+ error= file->preload_keys(thd, check_opt);
else
{
DBUG_ASSERT(FALSE);
@@ -1056,8 +1099,8 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
uint flag)
{
List_iterator<partition_element> part_it(m_part_info->partitions);
- uint no_parts= m_part_info->no_parts;
- uint no_subparts= m_part_info->no_subparts;
+ uint num_parts= m_part_info->num_parts;
+ uint num_subparts= m_part_info->num_subparts;
uint i= 0;
int error;
DBUG_ENTER("ha_partition::handle_opt_partitions");
@@ -1071,7 +1114,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
it should only do named partitions, otherwise all partitions
*/
if (!(thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION) ||
- part_elem->part_state == PART_CHANGED)
+ part_elem->part_state == PART_ADMIN)
{
if (m_is_sub_partitioned)
{
@@ -1081,16 +1124,9 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
do
{
sub_elem= subpart_it++;
- part= i * no_subparts + j;
+ part= i * num_subparts + j;
DBUG_PRINT("info", ("Optimize subpartition %u (%s)",
part, sub_elem->partition_name));
-#ifdef NOT_USED
- if (print_admin_msg(thd, "note", table_share->db.str, table->alias,
- opt_op_name[flag],
- "Start to operate on subpartition %s",
- sub_elem->partition_name))
- DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR);
-#endif
if ((error= handle_opt_part(thd, check_opt, m_file[part], flag)))
{
/* print a line which partition the error belongs to */
@@ -1103,21 +1139,20 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
"Subpartition %s returned error",
sub_elem->partition_name);
}
+ /* reset part_state for the remaining partitions */
+ do
+ {
+ if (part_elem->part_state == PART_ADMIN)
+ part_elem->part_state= PART_NORMAL;
+ } while ((part_elem= part_it++));
DBUG_RETURN(error);
}
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
else
{
DBUG_PRINT("info", ("Optimize partition %u (%s)", i,
part_elem->partition_name));
-#ifdef NOT_USED
- if (print_admin_msg(thd, "note", table_share->db.str, table->alias,
- opt_op_name[flag],
- "Start to operate on partition %s",
- part_elem->partition_name))
- DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR);
-#endif
if ((error= handle_opt_part(thd, check_opt, m_file[i], flag)))
{
/* print a line which partition the error belongs to */
@@ -1129,11 +1164,18 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
opt_op_name[flag], "Partition %s returned error",
part_elem->partition_name);
}
+ /* reset part_state for the remaining partitions */
+ do
+ {
+ if (part_elem->part_state == PART_ADMIN)
+ part_elem->part_state= PART_NORMAL;
+ } while ((part_elem= part_it++));
DBUG_RETURN(error);
}
}
+ part_elem->part_state= PART_NORMAL;
}
- } while (++i < no_parts);
+ } while (++i < num_parts);
DBUG_RETURN(FALSE);
}
@@ -1250,15 +1292,15 @@ int ha_partition::prepare_new_partition(TABLE *tbl,
assumes that external_lock() is last call that may fail here.
Otherwise see description for cleanup_new_partition().
*/
- if ((error= file->ha_external_lock(ha_thd(), m_lock_type)))
+ if ((error= file->ha_external_lock(ha_thd(), F_WRLCK)))
goto error_external_lock;
DBUG_PRINT("info", ("partition %s external locked", part_name));
DBUG_RETURN(0);
error_external_lock:
- VOID(file->close());
+ (void) file->close();
error_open:
- VOID(file->ha_delete_table(part_name));
+ (void) file->ha_delete_table(part_name);
error_create:
DBUG_RETURN(error);
}
@@ -1355,10 +1397,10 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
List_iterator<partition_element> part_it(m_part_info->partitions);
List_iterator <partition_element> t_it(m_part_info->temp_partitions);
char part_name_buff[FN_REFLEN];
- uint no_parts= m_part_info->partitions.elements;
- uint no_subparts= m_part_info->no_subparts;
+ uint num_parts= m_part_info->partitions.elements;
+ uint num_subparts= m_part_info->num_subparts;
uint i= 0;
- uint no_remain_partitions, part_count, orig_count;
+ uint num_remain_partitions, part_count, orig_count;
handler **new_file_array;
int error= 1;
bool first;
@@ -1374,7 +1416,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
part_name_buff)));
m_reorged_parts= 0;
if (!m_part_info->is_sub_partitioned())
- no_subparts= 1;
+ num_subparts= 1;
/*
Step 1:
@@ -1383,7 +1425,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
*/
if (temp_partitions)
{
- m_reorged_parts= temp_partitions * no_subparts;
+ m_reorged_parts= temp_partitions * num_subparts;
}
else
{
@@ -1393,9 +1435,9 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
if (part_elem->part_state == PART_CHANGED ||
part_elem->part_state == PART_REORGED_DROPPED)
{
- m_reorged_parts+= no_subparts;
+ m_reorged_parts+= num_subparts;
}
- } while (++i < no_parts);
+ } while (++i < num_parts);
}
if (m_reorged_parts &&
!(m_reorged_file= (handler**)sql_calloc(sizeof(handler*)*
@@ -1410,10 +1452,10 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
Calculate number of partitions after change and allocate space for
their handler references.
*/
- no_remain_partitions= 0;
+ num_remain_partitions= 0;
if (temp_partitions)
{
- no_remain_partitions= no_parts * no_subparts;
+ num_remain_partitions= num_parts * num_subparts;
}
else
{
@@ -1426,17 +1468,17 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
part_elem->part_state == PART_TO_BE_ADDED ||
part_elem->part_state == PART_CHANGED)
{
- no_remain_partitions+= no_subparts;
+ num_remain_partitions+= num_subparts;
}
- } while (++i < no_parts);
+ } while (++i < num_parts);
}
if (!(new_file_array= (handler**)sql_calloc(sizeof(handler*)*
- (2*(no_remain_partitions + 1)))))
+ (2*(num_remain_partitions + 1)))))
{
- mem_alloc_error(sizeof(handler*)*2*(no_remain_partitions+1));
+ mem_alloc_error(sizeof(handler*)*2*(num_remain_partitions+1));
DBUG_RETURN(ER_OUTOFMEMORY);
}
- m_added_file= &new_file_array[no_remain_partitions + 1];
+ m_added_file= &new_file_array[num_remain_partitions + 1];
/*
Step 3:
@@ -1455,9 +1497,9 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
part_elem->part_state == PART_REORGED_DROPPED)
{
memcpy((void*)&m_reorged_file[part_count],
- (void*)&m_file[i*no_subparts],
- sizeof(handler*)*no_subparts);
- part_count+= no_subparts;
+ (void*)&m_file[i*num_subparts],
+ sizeof(handler*)*num_subparts);
+ part_count+= num_subparts;
}
else if (first && temp_partitions &&
part_elem->part_state == PART_TO_BE_ADDED)
@@ -1472,11 +1514,11 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
ones used to be.
*/
first= FALSE;
- DBUG_ASSERT(((i*no_subparts) + m_reorged_parts) <= m_file_tot_parts);
- memcpy((void*)m_reorged_file, &m_file[i*no_subparts],
+ DBUG_ASSERT(((i*num_subparts) + m_reorged_parts) <= m_file_tot_parts);
+ memcpy((void*)m_reorged_file, &m_file[i*num_subparts],
sizeof(handler*)*m_reorged_parts);
}
- } while (++i < no_parts);
+ } while (++i < num_parts);
}
/*
@@ -1494,11 +1536,11 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
partition_element *part_elem= part_it++;
if (part_elem->part_state == PART_NORMAL)
{
- DBUG_ASSERT(orig_count + no_subparts <= m_file_tot_parts);
+ DBUG_ASSERT(orig_count + num_subparts <= m_file_tot_parts);
memcpy((void*)&new_file_array[part_count], (void*)&m_file[orig_count],
- sizeof(handler*)*no_subparts);
- part_count+= no_subparts;
- orig_count+= no_subparts;
+ sizeof(handler*)*num_subparts);
+ part_count+= num_subparts;
+ orig_count+= num_subparts;
}
else if (part_elem->part_state == PART_CHANGED ||
part_elem->part_state == PART_TO_BE_ADDED)
@@ -1514,16 +1556,16 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
mem_alloc_error(sizeof(handler));
DBUG_RETURN(ER_OUTOFMEMORY);
}
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
if (part_elem->part_state == PART_CHANGED)
- orig_count+= no_subparts;
+ orig_count+= num_subparts;
else if (temp_partitions && first)
{
- orig_count+= (no_subparts * temp_partitions);
+ orig_count+= (num_subparts * temp_partitions);
first= FALSE;
}
}
- } while (++i < no_parts);
+ } while (++i < num_parts);
first= FALSE;
/*
Step 5:
@@ -1560,7 +1602,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
part_elem->partition_name,
sub_elem->partition_name,
name_variant);
- part= i * no_subparts + j;
+ part= i * num_subparts + j;
DBUG_PRINT("info", ("Add subpartition %s", part_name_buff));
if ((error= prepare_new_partition(table, create_info,
new_file_array[part],
@@ -1571,7 +1613,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
DBUG_RETURN(error);
}
m_added_file[part_count++]= new_file_array[part];
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
else
{
@@ -1590,7 +1632,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
m_added_file[part_count++]= new_file_array[i];
}
}
- } while (++i < no_parts);
+ } while (++i < num_parts);
/*
Step 6:
@@ -1607,7 +1649,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
part_elem->part_state= PART_IS_CHANGED;
else if (part_elem->part_state == PART_REORGED_DROPPED)
part_elem->part_state= PART_TO_BE_DROPPED;
- } while (++i < no_parts);
+ } while (++i < num_parts);
for (i= 0; i < temp_partitions; i++)
{
partition_element *part_elem= t_it++;
@@ -1656,9 +1698,9 @@ int ha_partition::copy_partitions(ulonglong * const copied,
if (m_part_info->linear_hash_ind)
{
if (m_part_info->part_type == HASH_PARTITION)
- set_linear_hash_mask(m_part_info, m_part_info->no_parts);
+ set_linear_hash_mask(m_part_info, m_part_info->num_parts);
else
- set_linear_hash_mask(m_part_info, m_part_info->no_subparts);
+ set_linear_hash_mask(m_part_info, m_part_info->num_subparts);
}
while (reorg_part < m_reorged_parts)
@@ -1851,7 +1893,7 @@ uint ha_partition::del_ren_cre_table(const char *from,
if (get_from_handler_file(from, ha_thd()->mem_root))
DBUG_RETURN(TRUE);
DBUG_ASSERT(m_file_buffer);
- DBUG_PRINT("enter", ("from: (%s) to: (%s)", from, to));
+ DBUG_PRINT("enter", ("from: (%s) to: (%s)", from, to ? to : "(nil)"));
name_buffer_ptr= m_name_buffer_ptr;
file= m_file;
if (to == NULL && table_arg == NULL)
@@ -1955,7 +1997,7 @@ partition_element *ha_partition::find_partition_element(uint part_id)
uint curr_part_id= 0;
List_iterator_fast <partition_element> part_it(m_part_info->partitions);
- for (i= 0; i < m_part_info->no_parts; i++)
+ for (i= 0; i < m_part_info->num_parts; i++)
{
partition_element *part_elem;
part_elem= part_it++;
@@ -1963,7 +2005,7 @@ partition_element *ha_partition::find_partition_element(uint part_id)
{
uint j;
List_iterator_fast <partition_element> sub_it(part_elem->subpartitions);
- for (j= 0; j < m_part_info->no_subparts; j++)
+ for (j= 0; j < m_part_info->num_subparts; j++)
{
part_elem= sub_it++;
if (part_id == curr_part_id++)
@@ -1974,8 +2016,7 @@ partition_element *ha_partition::find_partition_element(uint part_id)
return part_elem;
}
DBUG_ASSERT(0);
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- current_thd->fatal_error(); // Abort
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
return NULL;
}
@@ -2084,7 +2125,7 @@ bool ha_partition::create_handler_file(const char *name)
{
partition_element *part_elem, *subpart_elem;
uint i, j, part_name_len, subpart_name_len;
- uint tot_partition_words, tot_name_len, no_parts;
+ uint tot_partition_words, tot_name_len, num_parts;
uint tot_parts= 0;
uint tot_len_words, tot_len_byte, chksum, tot_name_words;
char *name_buffer_ptr;
@@ -2097,11 +2138,11 @@ bool ha_partition::create_handler_file(const char *name)
List_iterator_fast <partition_element> part_it(m_part_info->partitions);
DBUG_ENTER("create_handler_file");
- no_parts= m_part_info->partitions.elements;
- DBUG_PRINT("info", ("table name = %s, no_parts = %u", name,
- no_parts));
+ num_parts= m_part_info->partitions.elements;
+ DBUG_PRINT("info", ("table name = %s, num_parts = %u", name,
+ num_parts));
tot_name_len= 0;
- for (i= 0; i < no_parts; i++)
+ for (i= 0; i < num_parts; i++)
{
part_elem= part_it++;
if (part_elem->part_state != PART_NORMAL &&
@@ -2119,7 +2160,7 @@ bool ha_partition::create_handler_file(const char *name)
else
{
List_iterator_fast <partition_element> sub_it(part_elem->subpartitions);
- for (j= 0; j < m_part_info->no_subparts; j++)
+ for (j= 0; j < m_part_info->num_subparts; j++)
{
subpart_elem= sub_it++;
tablename_to_filename(subpart_elem->partition_name,
@@ -2153,7 +2194,7 @@ bool ha_partition::create_handler_file(const char *name)
engine_array= (file_buffer + 12);
name_buffer_ptr= (char*) (file_buffer + ((4 + tot_partition_words) * 4));
part_it.rewind();
- for (i= 0; i < no_parts; i++)
+ for (i= 0; i < num_parts; i++)
{
part_elem= part_it++;
if (part_elem->part_state != PART_NORMAL &&
@@ -2171,7 +2212,7 @@ bool ha_partition::create_handler_file(const char *name)
else
{
List_iterator_fast <partition_element> sub_it(part_elem->subpartitions);
- for (j= 0; j < m_part_info->no_subparts; j++)
+ for (j= 0; j < m_part_info->num_subparts; j++)
{
subpart_elem= sub_it++;
tablename_to_filename(part_elem->partition_name, part_name,
@@ -2200,16 +2241,17 @@ bool ha_partition::create_handler_file(const char *name)
to be used at open, delete_table and rename_table
*/
fn_format(file_name, name, "", ha_par_ext, MY_APPEND_EXT);
- if ((file= my_create(file_name, CREATE_MODE, O_RDWR | O_TRUNC,
- MYF(MY_WME))) >= 0)
+ if ((file= mysql_file_create(key_file_partition,
+ file_name, CREATE_MODE, O_RDWR | O_TRUNC,
+ MYF(MY_WME))) >= 0)
{
- result= my_write(file, (uchar *) file_buffer, tot_len_byte,
- MYF(MY_WME | MY_NABP)) != 0;
- VOID(my_close(file, MYF(0)));
+ result= mysql_file_write(file, (uchar *) file_buffer, tot_len_byte,
+ MYF(MY_WME | MY_NABP)) != 0;
+ (void) mysql_file_close(file, MYF(0));
}
else
result= TRUE;
- my_free((char*) file_buffer, MYF(0));
+ my_free(file_buffer);
DBUG_RETURN(result);
}
@@ -2227,8 +2269,8 @@ void ha_partition::clear_handler_file()
{
if (m_engine_array)
plugin_unlock_list(NULL, m_engine_array, m_tot_parts);
- my_free((char*) m_file_buffer, MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*) m_engine_array, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(m_file_buffer);
+ my_free(m_engine_array);
m_file_buffer= NULL;
m_engine_array= NULL;
}
@@ -2307,7 +2349,7 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root)
}
m_file_tot_parts= m_tot_parts;
bzero((char*) m_file, alloc_len);
- DBUG_ASSERT(m_part_info->no_parts > 0);
+ DBUG_ASSERT(m_part_info->num_parts > 0);
i= 0;
part_count= 0;
@@ -2320,7 +2362,7 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root)
part_elem= part_it++;
if (m_is_sub_partitioned)
{
- for (j= 0; j < m_part_info->no_subparts; j++)
+ for (j= 0; j < m_part_info->num_subparts; j++)
{
if (!(m_file[part_count++]= get_new_handler(table_share, mem_root,
part_elem->engine_type)))
@@ -2337,7 +2379,7 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root)
DBUG_PRINT("info", ("engine_type: %u",
(uint) ha_legacy_type(part_elem->engine_type)));
}
- } while (++i < m_part_info->no_parts);
+ } while (++i < m_part_info->num_parts);
if (part_elem->engine_type == myisam_hton)
{
DBUG_PRINT("info", ("MyISAM"));
@@ -2382,17 +2424,18 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
DBUG_RETURN(FALSE);
fn_format(buff, name, "", ha_par_ext, MY_APPEND_EXT);
- /* Following could be done with my_stat to read in whole file */
- if ((file= my_open(buff, O_RDONLY | O_SHARE, MYF(0))) < 0)
+ /* Following could be done with mysql_file_stat to read in whole file */
+ if ((file= mysql_file_open(key_file_partition,
+ buff, O_RDONLY | O_SHARE, MYF(0))) < 0)
DBUG_RETURN(TRUE);
- if (my_read(file, (uchar *) & buff[0], 8, MYF(MY_NABP)))
+ if (mysql_file_read(file, (uchar *) &buff[0], 8, MYF(MY_NABP)))
goto err1;
len_words= uint4korr(buff);
len_bytes= 4 * len_words;
if (!(file_buffer= (char*) my_malloc(len_bytes, MYF(0))))
goto err1;
- VOID(my_seek(file, 0, MY_SEEK_SET, MYF(0)));
- if (my_read(file, (uchar *) file_buffer, len_bytes, MYF(MY_NABP)))
+ mysql_file_seek(file, 0, MY_SEEK_SET, MYF(0));
+ if (mysql_file_read(file, (uchar *) file_buffer, len_bytes, MYF(MY_NABP)))
goto err2;
chksum= 0;
@@ -2418,7 +2461,7 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
if (len_words != (tot_partition_words + tot_name_words + 4))
goto err3;
name_buffer_ptr= file_buffer + 16 + 4 * tot_partition_words;
- VOID(my_close(file, MYF(0)));
+ (void) mysql_file_close(file, MYF(0));
m_file_buffer= file_buffer; // Will be freed in clear_handler_file()
m_name_buffer_ptr= name_buffer_ptr;
@@ -2441,9 +2484,9 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
err3:
my_afree((gptr) engine_array);
err2:
- my_free(file_buffer, MYF(0));
+ my_free(file_buffer);
err1:
- VOID(my_close(file, MYF(0)));
+ (void) mysql_file_close(file, MYF(0));
DBUG_RETURN(TRUE);
}
@@ -2457,12 +2500,11 @@ err1:
A destructor for partition-specific TABLE_SHARE data.
*/
-void ha_data_partition_destroy(void *ha_data)
+void ha_data_partition_destroy(HA_DATA_PARTITION* ha_part_data)
{
- if (ha_data)
+ if (ha_part_data)
{
- HA_DATA_PARTITION *ha_part_data= (HA_DATA_PARTITION*) ha_data;
- pthread_mutex_destroy(&ha_part_data->LOCK_auto_inc);
+ mysql_mutex_destroy(&ha_part_data->LOCK_auto_inc);
}
}
@@ -2560,7 +2602,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
if ((error= (*file)->ha_open(table, (const char*) name_buff, mode,
test_if_locked)))
goto err_handler;
- m_no_locks+= (*file)->lock_count();
+ m_num_locks+= (*file)->lock_count();
name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
set_if_bigger(ref_length, ((*file)->ref_length));
/*
@@ -2602,31 +2644,33 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
goto err_handler;
/*
- Use table_share->ha_data to share auto_increment_value among all handlers
- for the same table.
+ Use table_share->ha_part_data to share auto_increment_value among
+ all handlers for the same table.
*/
if (is_not_tmp_table)
- pthread_mutex_lock(&table_share->mutex);
- if (!table_share->ha_data)
+ mysql_mutex_lock(&table_share->LOCK_ha_data);
+ if (!table_share->ha_part_data)
{
- HA_DATA_PARTITION *ha_data;
/* currently only needed for auto_increment */
- table_share->ha_data= ha_data= (HA_DATA_PARTITION*)
+ table_share->ha_part_data= (HA_DATA_PARTITION*)
alloc_root(&table_share->mem_root,
sizeof(HA_DATA_PARTITION));
- if (!ha_data)
+ if (!table_share->ha_part_data)
{
if (is_not_tmp_table)
- pthread_mutex_unlock(&table_share->mutex);
+ mysql_mutex_unlock(&table_share->LOCK_ha_data);
goto err_handler;
}
- DBUG_PRINT("info", ("table_share->ha_data 0x%p", ha_data));
- bzero(ha_data, sizeof(HA_DATA_PARTITION));
- table_share->ha_data_destroy= ha_data_partition_destroy;
- VOID(pthread_mutex_init(&ha_data->LOCK_auto_inc, MY_MUTEX_INIT_FAST));
+ DBUG_PRINT("info", ("table_share->ha_part_data 0x%p",
+ table_share->ha_part_data));
+ bzero(table_share->ha_part_data, sizeof(HA_DATA_PARTITION));
+ table_share->ha_part_data_destroy= ha_data_partition_destroy;
+ mysql_mutex_init(key_PARTITION_LOCK_auto_inc,
+ &table_share->ha_part_data->LOCK_auto_inc,
+ MY_MUTEX_INIT_FAST);
}
if (is_not_tmp_table)
- pthread_mutex_unlock(&table_share->mutex);
+ mysql_mutex_unlock(&table_share->LOCK_ha_data);
/*
Some handlers update statistics as part of the open call. This will in
some cases corrupt the statistics of the partition handler and thus
@@ -2910,8 +2954,8 @@ int ha_partition::start_stmt(THD *thd, thr_lock_type lock_type)
uint ha_partition::lock_count() const
{
DBUG_ENTER("ha_partition::lock_count");
- DBUG_PRINT("info", ("m_no_locks %d", m_no_locks));
- DBUG_RETURN(m_no_locks);
+ DBUG_PRINT("info", ("m_num_locks %d", m_num_locks));
+ DBUG_RETURN(m_num_locks);
}
@@ -3048,7 +3092,6 @@ int ha_partition::write_row(uchar * buf)
longlong func_value;
bool have_auto_increment= table->next_number_field && buf == table->record[0];
my_bitmap_map *old_map;
- HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
THD *thd= ha_thd();
timestamp_auto_set_type saved_timestamp_type= table->timestamp_field_type;
ulong saved_sql_mode= thd->variables.sql_mode;
@@ -3070,8 +3113,8 @@ int ha_partition::write_row(uchar * buf)
*/
if (have_auto_increment)
{
- if (!ha_data->auto_inc_initialized &&
- !table->s->next_number_keypart)
+ if (!table_share->ha_part_data->auto_inc_initialized &&
+ !table_share->next_number_keypart)
{
/*
If auto_increment in table_share is not initialized, start by
@@ -3242,7 +3285,7 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data)
exit:
/*
if updating an auto_increment column, update
- table_share->ha_data->next_auto_inc_val if needed.
+ table_share->ha_part_data->next_auto_inc_val if needed.
(not to be used if auto_increment on secondary field in a multi-column
index)
mysql_update does not set table->next_number_field, so we use
@@ -3251,8 +3294,7 @@ exit:
if (table->found_next_number_field && new_data == table->record[0] &&
!table->s->next_number_keypart)
{
- HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
- if (!ha_data->auto_inc_initialized)
+ if (!table_share->ha_part_data->auto_inc_initialized)
info(HA_STATUS_AUTO);
set_auto_increment_if_higher(table->found_next_number_field);
}
@@ -3333,33 +3375,123 @@ int ha_partition::delete_row(const uchar *buf)
int ha_partition::delete_all_rows()
{
int error;
- bool truncate= FALSE;
handler **file;
- THD *thd= ha_thd();
DBUG_ENTER("ha_partition::delete_all_rows");
- if (thd->lex->sql_command == SQLCOM_TRUNCATE)
- {
- HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
- lock_auto_increment();
- ha_data->next_auto_inc_val= 0;
- ha_data->auto_inc_initialized= FALSE;
- unlock_auto_increment();
- truncate= TRUE;
- }
file= m_file;
do
{
if ((error= (*file)->ha_delete_all_rows()))
DBUG_RETURN(error);
- /* Ignore the error */
- if (truncate)
- (void) (*file)->ha_reset_auto_increment(0);
} while (*(++file));
DBUG_RETURN(0);
}
+/**
+ Manually truncate the table.
+
+ @retval 0 Success.
+ @retval > 0 Error code.
+*/
+
+int ha_partition::truncate()
+{
+ int error;
+ handler **file;
+ DBUG_ENTER("ha_partition::truncate");
+
+ /*
+ TRUNCATE also means resetting auto_increment. Hence, reset
+ it so that it will be initialized again at the next use.
+ */
+ lock_auto_increment();
+ table_share->ha_part_data->next_auto_inc_val= 0;
+ table_share->ha_part_data->auto_inc_initialized= FALSE;
+ unlock_auto_increment();
+
+ file= m_file;
+ do
+ {
+ if ((error= (*file)->ha_truncate()))
+ DBUG_RETURN(error);
+ } while (*(++file));
+ DBUG_RETURN(0);
+}
+
+
+/**
+ Truncate a set of specific partitions.
+
+ @remark Auto increment value will be truncated in that partition as well!
+
+ ALTER TABLE t TRUNCATE PARTITION ...
+*/
+
+int ha_partition::truncate_partition(Alter_info *alter_info, bool *binlog_stmt)
+{
+ int error= 0;
+ List_iterator<partition_element> part_it(m_part_info->partitions);
+ uint num_parts= m_part_info->num_parts;
+ uint num_subparts= m_part_info->num_subparts;
+ uint i= 0;
+ uint num_parts_set= alter_info->partition_names.elements;
+ uint num_parts_found= set_part_state(alter_info, m_part_info,
+ PART_ADMIN);
+ DBUG_ENTER("ha_partition::truncate_partition");
+
+ /* Only binlog when it starts any call to the partitions handlers */
+ *binlog_stmt= false;
+
+ /*
+ TRUNCATE also means resetting auto_increment. Hence, reset
+ it so that it will be initialized again at the next use.
+ */
+ lock_auto_increment();
+ table_share->ha_part_data->next_auto_inc_val= 0;
+ table_share->ha_part_data->auto_inc_initialized= FALSE;
+ unlock_auto_increment();
+
+ if (num_parts_set != num_parts_found &&
+ (!(alter_info->flags & ALTER_ALL_PARTITION)))
+ DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
+
+ *binlog_stmt= true;
+
+ do
+ {
+ partition_element *part_elem= part_it++;
+ if (part_elem->part_state == PART_ADMIN)
+ {
+ if (m_is_sub_partitioned)
+ {
+ List_iterator<partition_element>
+ subpart_it(part_elem->subpartitions);
+ partition_element *sub_elem;
+ uint j= 0, part;
+ do
+ {
+ sub_elem= subpart_it++;
+ part= i * num_subparts + j;
+ DBUG_PRINT("info", ("truncate subpartition %u (%s)",
+ part, sub_elem->partition_name));
+ if ((error= m_file[part]->ha_truncate()))
+ break;
+ } while (++j < num_subparts);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("truncate partition %u (%s)", i,
+ part_elem->partition_name));
+ error= m_file[i]->ha_truncate();
+ }
+ part_elem->part_state= PART_NORMAL;
+ }
+ } while (!error && (++i < num_parts));
+ DBUG_RETURN(error);
+}
+
+
/*
Start a large batch of insert rows
@@ -4099,10 +4231,9 @@ int ha_partition::index_read_map(uchar *buf, const uchar *key,
int ha_partition::common_index_read(uchar *buf, bool have_start_key)
{
int error;
- uint key_len;
+ uint UNINIT_VAR(key_len); /* used if have_start_key==TRUE */
bool reverse_order= FALSE;
DBUG_ENTER("ha_partition::common_index_read");
- LINT_INIT(key_len); /* used if have_start_key==TRUE */
DBUG_PRINT("info", ("m_ordered %u m_ordered_scan_ong %u have_start_key %u",
m_ordered, m_ordered_scan_ongoing, have_start_key));
@@ -5046,22 +5177,22 @@ int ha_partition::info(uint flag)
if (flag & HA_STATUS_AUTO)
{
bool auto_inc_is_first_in_idx= (table_share->next_number_keypart == 0);
- HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
DBUG_PRINT("info", ("HA_STATUS_AUTO"));
if (!table->found_next_number_field)
stats.auto_increment_value= 0;
- else if (ha_data->auto_inc_initialized)
+ else if (table_share->ha_part_data->auto_inc_initialized)
{
lock_auto_increment();
- stats.auto_increment_value= ha_data->next_auto_inc_val;
+ stats.auto_increment_value= table_share->ha_part_data->next_auto_inc_val;
unlock_auto_increment();
}
else
{
lock_auto_increment();
/* to avoid two concurrent initializations, check again when locked */
- if (ha_data->auto_inc_initialized)
- stats.auto_increment_value= ha_data->next_auto_inc_val;
+ if (table_share->ha_part_data->auto_inc_initialized)
+ stats.auto_increment_value=
+ table_share->ha_part_data->next_auto_inc_val;
else
{
handler *file, **file_array;
@@ -5081,10 +5212,11 @@ int ha_partition::info(uint flag)
stats.auto_increment_value= auto_increment_value;
if (auto_inc_is_first_in_idx)
{
- set_if_bigger(ha_data->next_auto_inc_val, auto_increment_value);
- ha_data->auto_inc_initialized= TRUE;
+ set_if_bigger(table_share->ha_part_data->next_auto_inc_val,
+ auto_increment_value);
+ table_share->ha_part_data->auto_inc_initialized= TRUE;
DBUG_PRINT("info", ("initializing next_auto_inc_val to %lu",
- (ulong) ha_data->next_auto_inc_val));
+ (ulong) table_share->ha_part_data->next_auto_inc_val));
}
}
unlock_auto_increment();
@@ -5259,7 +5391,7 @@ int ha_partition::info(uint flag)
}
-void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
+void ha_partition::get_dynamic_partition_info(PARTITION_STATS *stat_info,
uint part_id)
{
handler *file= m_file[part_id];
@@ -5282,34 +5414,35 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
}
-/*
- General function to prepare handler for certain behavior
+/**
+ General function to prepare handler for certain behavior.
- SYNOPSIS
- extra()
+ @param[in] operation operation to execute
operation Operation type for extra call
- RETURN VALUE
- >0 Error code
- 0 Success
+ @return status
+ @retval 0 success
+ @retval >0 error code
+
+ @detail
- DESCRIPTION
extra() is called whenever the server wishes to send a hint to
the storage engine. The MyISAM engine implements the most hints.
We divide the parameters into the following categories:
- 1) Parameters used by most handlers
- 2) Parameters used by some non-MyISAM handlers
- 3) Parameters used only by MyISAM
- 4) Parameters only used by temporary tables for query processing
- 5) Parameters only used by MyISAM internally
- 6) Parameters not used at all
- 7) Parameters only used by federated tables for query processing
- 8) Parameters only used by NDB
+ 1) Operations used by most handlers
+ 2) Operations used by some non-MyISAM handlers
+ 3) Operations used only by MyISAM
+ 4) Operations only used by temporary tables for query processing
+ 5) Operations only used by MyISAM internally
+ 6) Operations not used at all
+ 7) Operations only used by federated tables for query processing
+ 8) Operations only used by NDB
+ 9) Operations only used by MERGE
The partition handler need to handle category 1), 2) and 3).
- 1) Parameters used by most handlers
+ 1) Operations used by most handlers
-----------------------------------
HA_EXTRA_RESET:
This option is used by most handlers and it resets the handler state
@@ -5348,7 +5481,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
ensure disk based tables are flushed at end of query execution.
Currently is never used.
- 2) Parameters used by some non-MyISAM handlers
+ 2) Operations used by some non-MyISAM handlers
----------------------------------------------
HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
This is a strictly InnoDB feature that is more or less undocumented.
@@ -5367,7 +5500,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
SQL constructs.
Not used by MyISAM.
- 3) Parameters used only by MyISAM
+ 3) Operations used only by MyISAM
---------------------------------
HA_EXTRA_NORMAL:
Only used in MyISAM to reset quick mode, not implemented by any other
@@ -5496,7 +5629,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
Only used by MyISAM, called when altering table, closing tables to
enforce a reopen of the table files.
- 4) Parameters only used by temporary tables for query processing
+ 4) Operations only used by temporary tables for query processing
----------------------------------------------------------------
HA_EXTRA_RESET_STATE:
Same as reset() except that buffers are not released. If there is
@@ -5527,7 +5660,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
tables used in query processing.
Not handled by partition handler.
- 5) Parameters only used by MyISAM internally
+ 5) Operations only used by MyISAM internally
--------------------------------------------
HA_EXTRA_REINIT_CACHE:
This call reinitializes the READ CACHE described above if there is one
@@ -5562,19 +5695,19 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
Only used by MyISAM, never called.
- 6) Parameters not used at all
+ 6) Operations not used at all
-----------------------------
HA_EXTRA_KEY_CACHE:
HA_EXTRA_NO_KEY_CACHE:
This parameters are no longer used and could be removed.
- 7) Parameters only used by federated tables for query processing
+ 7) Operations only used by federated tables for query processing
----------------------------------------------------------------
HA_EXTRA_INSERT_WITH_UPDATE:
Inform handler that an "INSERT...ON DUPLICATE KEY UPDATE" will be
executed. This condition is unset by HA_EXTRA_NO_IGNORE_DUP_KEY.
- 8) Parameters only used by NDB
+ 8) Operations only used by NDB
------------------------------
HA_EXTRA_DELETE_CANNOT_BATCH:
HA_EXTRA_UPDATE_CANNOT_BATCH:
@@ -5582,6 +5715,14 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
and should perform them immediately. This may be needed when table has
AFTER DELETE/UPDATE triggers which access to subject table.
These flags are reset by the handler::extra(HA_EXTRA_RESET) call.
+
+ 9) Operations only used by MERGE
+ ------------------------------
+ HA_EXTRA_ADD_CHILDREN_LIST:
+ HA_EXTRA_ATTACH_CHILDREN:
+ HA_EXTRA_IS_ATTACHED_CHILDREN:
+ HA_EXTRA_DETACH_CHILDREN:
+ Special actions for MERGE tables. Ignore.
*/
int ha_partition::extra(enum ha_extra_function operation)
@@ -5621,7 +5762,7 @@ int ha_partition::extra(enum ha_extra_function operation)
if (!m_extra_cache)
m_extra_cache_part_id= m_part_spec.start_part;
DBUG_ASSERT(m_extra_cache_part_id == m_part_spec.start_part);
- VOID(m_file[m_part_spec.start_part]->extra(HA_EXTRA_PREPARE_FOR_UPDATE));
+ (void) m_file[m_part_spec.start_part]->extra(HA_EXTRA_PREPARE_FOR_UPDATE);
}
break;
case HA_EXTRA_NORMAL:
@@ -5699,13 +5840,22 @@ int ha_partition::extra(enum ha_extra_function operation)
/* Category 7), used by federated handlers */
case HA_EXTRA_INSERT_WITH_UPDATE:
DBUG_RETURN(loop_extra(operation));
- /* Category 8) Parameters only used by NDB */
+ /* Category 8) Operations only used by NDB */
case HA_EXTRA_DELETE_CANNOT_BATCH:
case HA_EXTRA_UPDATE_CANNOT_BATCH:
{
/* Currently only NDB use the *_CANNOT_BATCH */
break;
}
+ /* Category 9) Operations only used by MERGE */
+ case HA_EXTRA_ADD_CHILDREN_LIST:
+ case HA_EXTRA_ATTACH_CHILDREN:
+ case HA_EXTRA_IS_ATTACHED_CHILDREN:
+ case HA_EXTRA_DETACH_CHILDREN:
+ {
+ /* Special actions for MERGE tables. Ignore. */
+ break;
+ }
/*
http://dev.mysql.com/doc/refman/5.1/en/partitioning-limitations.html
says we no longer support logging to partitioned tables, so we fail
@@ -5892,13 +6042,13 @@ void ha_partition::late_extra_cache(uint partition_id)
if (m_extra_cache)
{
if (m_extra_cache_size == 0)
- VOID(file->extra(HA_EXTRA_CACHE));
+ (void) file->extra(HA_EXTRA_CACHE);
else
- VOID(file->extra_opt(HA_EXTRA_CACHE, m_extra_cache_size));
+ (void) file->extra_opt(HA_EXTRA_CACHE, m_extra_cache_size);
}
if (m_extra_prepare_for_update)
{
- VOID(file->extra(HA_EXTRA_PREPARE_FOR_UPDATE));
+ (void) file->extra(HA_EXTRA_PREPARE_FOR_UPDATE);
}
m_extra_cache_part_id= partition_id;
DBUG_VOID_RETURN;
@@ -5924,7 +6074,7 @@ void ha_partition::late_extra_no_cache(uint partition_id)
if (!m_extra_cache && !m_extra_prepare_for_update)
DBUG_VOID_RETURN;
file= m_file[partition_id];
- VOID(file->extra(HA_EXTRA_NO_CACHE));
+ (void) file->extra(HA_EXTRA_NO_CACHE);
DBUG_ASSERT(partition_id == m_extra_cache_part_id);
m_extra_cache_part_id= NO_CURRENT_PART_ID;
DBUG_VOID_RETURN;
@@ -6225,12 +6375,14 @@ enum row_type ha_partition::get_row_type() const
void ha_partition::print_error(int error, myf errflag)
{
+ THD *thd= ha_thd();
DBUG_ENTER("ha_partition::print_error");
/* Should probably look for my own errors first */
DBUG_PRINT("enter", ("error: %d", error));
- if (error == HA_ERR_NO_PARTITION_FOUND)
+ if ((error == HA_ERR_NO_PARTITION_FOUND) &&
+ ! (thd->lex->alter_info.flags & ALTER_TRUNCATE_PARTITION))
m_part_info->print_no_partition_found(table);
else
{
@@ -6267,9 +6419,42 @@ bool ha_partition::get_error_message(int error, String *buf)
*/
uint ha_partition::alter_table_flags(uint flags)
{
+ uint flags_to_return, flags_to_check;
DBUG_ENTER("ha_partition::alter_table_flags");
- DBUG_RETURN(ht->alter_table_flags(flags) |
- m_file[0]->alter_table_flags(flags));
+
+ flags_to_return= ht->alter_table_flags(flags);
+ flags_to_return|= m_file[0]->alter_table_flags(flags);
+
+ /*
+ If one partition fails we must be able to revert the change for the other,
+ already altered, partitions. So both ADD and DROP can only be supported in
+ pairs.
+ */
+ flags_to_check= HA_ONLINE_ADD_INDEX_NO_WRITES;
+ flags_to_check|= HA_ONLINE_DROP_INDEX_NO_WRITES;
+ if ((flags_to_return & flags_to_check) != flags_to_check)
+ flags_to_return&= ~flags_to_check;
+ flags_to_check= HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES;
+ flags_to_check|= HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES;
+ if ((flags_to_return & flags_to_check) != flags_to_check)
+ flags_to_return&= ~flags_to_check;
+ flags_to_check= HA_ONLINE_ADD_PK_INDEX_NO_WRITES;
+ flags_to_check|= HA_ONLINE_DROP_PK_INDEX_NO_WRITES;
+ if ((flags_to_return & flags_to_check) != flags_to_check)
+ flags_to_return&= ~flags_to_check;
+ flags_to_check= HA_ONLINE_ADD_INDEX;
+ flags_to_check|= HA_ONLINE_DROP_INDEX;
+ if ((flags_to_return & flags_to_check) != flags_to_check)
+ flags_to_return&= ~flags_to_check;
+ flags_to_check= HA_ONLINE_ADD_UNIQUE_INDEX;
+ flags_to_check|= HA_ONLINE_DROP_UNIQUE_INDEX;
+ if ((flags_to_return & flags_to_check) != flags_to_check)
+ flags_to_return&= ~flags_to_check;
+ flags_to_check= HA_ONLINE_ADD_PK_INDEX;
+ flags_to_check|= HA_ONLINE_DROP_PK_INDEX;
+ if ((flags_to_return & flags_to_check) != flags_to_check)
+ flags_to_return&= ~flags_to_check;
+ DBUG_RETURN(flags_to_return);
}
@@ -6304,6 +6489,7 @@ int ha_partition::add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys)
handler **file;
int ret= 0;
+ DBUG_ENTER("ha_partition::add_index");
/*
There has already been a check in fix_partition_func in mysql_alter_table
before this call, which checks for unique/primary key violations of the
@@ -6311,8 +6497,28 @@ int ha_partition::add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys)
*/
for (file= m_file; *file; file++)
if ((ret= (*file)->add_index(table_arg, key_info, num_of_keys)))
- break;
- return ret;
+ goto err;
+ DBUG_RETURN(ret);
+err:
+ if (file > m_file)
+ {
+ uint *key_numbers= (uint*) ha_thd()->alloc(sizeof(uint) * num_of_keys);
+ uint old_num_of_keys= table_arg->s->keys;
+ uint i;
+ /* The newly created keys have the last id's */
+ for (i= 0; i < num_of_keys; i++)
+ key_numbers[i]= i + old_num_of_keys;
+ if (!table_arg->key_info)
+ table_arg->key_info= key_info;
+ while (--file >= m_file)
+ {
+ (void) (*file)->prepare_drop_index(table_arg, key_numbers, num_of_keys);
+ (void) (*file)->final_drop_index(table_arg);
+ }
+ if (table_arg->key_info == key_info)
+ table_arg->key_info= NULL;
+ }
+ DBUG_RETURN(ret);
}
@@ -6493,11 +6699,10 @@ int ha_partition::reset_auto_increment(ulonglong value)
{
handler **file= m_file;
int res;
- HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
DBUG_ENTER("ha_partition::reset_auto_increment");
lock_auto_increment();
- ha_data->auto_inc_initialized= FALSE;
- ha_data->next_auto_inc_val= 0;
+ table_share->ha_part_data->auto_inc_initialized= FALSE;
+ table_share->ha_part_data->next_auto_inc_val= 0;
do
{
if ((res= (*file)->ha_reset_auto_increment(value)) != 0)
@@ -6511,7 +6716,7 @@ int ha_partition::reset_auto_increment(ulonglong value)
/**
This method is called by update_auto_increment which in turn is called
by the individual handlers as part of write_row. We use the
- table_share->ha_data->next_auto_inc_val, or search all
+ table_share->ha_part_data->next_auto_inc_val, or search all
partitions for the highest auto_increment_value if not initialized or
if auto_increment field is a secondary part of a key, we must search
every partition when holding a mutex to be sure of correctness.
@@ -6564,13 +6769,12 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment,
else
{
THD *thd= ha_thd();
- HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
/*
This is initialized in the beginning of the first write_row call.
*/
- DBUG_ASSERT(ha_data->auto_inc_initialized);
+ DBUG_ASSERT(table_share->ha_part_data->auto_inc_initialized);
/*
- Get a lock for handling the auto_increment in table_share->ha_data
+ Get a lock for handling the auto_increment in table_share->ha_part_data
for avoiding two concurrent statements getting the same number.
*/
@@ -6589,16 +6793,17 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment,
if (!auto_increment_safe_stmt_log_lock &&
thd->lex->sql_command != SQLCOM_INSERT &&
mysql_bin_log.is_open() &&
- !thd->current_stmt_binlog_row_based &&
- (thd->options & OPTION_BIN_LOG))
+ !thd->is_current_stmt_binlog_format_row() &&
+ (thd->variables.option_bits & OPTION_BIN_LOG))
{
DBUG_PRINT("info", ("locking auto_increment_safe_stmt_log_lock"));
auto_increment_safe_stmt_log_lock= TRUE;
}
/* this gets corrected (for offset/increment) in update_auto_increment */
- *first_value= ha_data->next_auto_inc_val;
- ha_data->next_auto_inc_val+= nb_desired_values * increment;
+ *first_value= table_share->ha_part_data->next_auto_inc_val;
+ table_share->ha_part_data->next_auto_inc_val+=
+ nb_desired_values * increment;
unlock_auto_increment();
DBUG_PRINT("info", ("*first_value: %lu", (ulong) *first_value));
@@ -6618,10 +6823,9 @@ void ha_partition::release_auto_increment()
}
else if (next_insert_id)
{
- HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
ulonglong next_auto_inc_val;
lock_auto_increment();
- next_auto_inc_val= ha_data->next_auto_inc_val;
+ next_auto_inc_val= table_share->ha_part_data->next_auto_inc_val;
/*
If the current auto_increment values is lower than the reserved
value, and the reserved value was reserved by this thread,
@@ -6636,10 +6840,10 @@ void ha_partition::release_auto_increment()
with SET INSERT_ID, i.e. forced/non generated values.
*/
if (thd->auto_inc_intervals_forced.maximum() < next_insert_id)
- ha_data->next_auto_inc_val= next_insert_id;
+ table_share->ha_part_data->next_auto_inc_val= next_insert_id;
}
- DBUG_PRINT("info", ("ha_data->next_auto_inc_val: %lu",
- (ulong) ha_data->next_auto_inc_val));
+ DBUG_PRINT("info", ("table_share->ha_part_data->next_auto_inc_val: %lu",
+ (ulong) table_share->ha_part_data->next_auto_inc_val));
/* Unlock the multi row statement lock taken in get_auto_increment */
if (auto_increment_safe_stmt_log_lock)
@@ -6739,127 +6943,6 @@ int ha_partition::indexes_are_disabled(void)
}
-/****************************************************************************
- MODULE Partition Share
-****************************************************************************/
-/*
- Service routines for ... methods.
--------------------------------------------------------------------------
- Variables for partition share methods. A hash used to track open tables.
- A mutex for the hash table and an init variable to check if hash table
- is initialized.
- There is also a constant ending of the partition handler file name.
-*/
-
-#ifdef NOT_USED
-static HASH partition_open_tables;
-static pthread_mutex_t partition_mutex;
-static int partition_init= 0;
-
-
-/*
- Function we use in the creation of our hash to get key.
-*/
-
-static uchar *partition_get_key(PARTITION_SHARE *share, size_t *length,
- my_bool not_used __attribute__ ((unused)))
-{
- *length= share->table_name_length;
- return (uchar *) share->table_name;
-}
-
-/*
- Example of simple lock controls. The "share" it creates is structure we
- will pass to each partition handler. Do you have to have one of these?
- Well, you have pieces that are used for locking, and they are needed to
- function.
-*/
-
-static PARTITION_SHARE *get_share(const char *table_name, TABLE *table)
-{
- PARTITION_SHARE *share;
- uint length;
- char *tmp_name;
-
- /*
- So why does this exist? There is no way currently to init a storage
- engine.
- Innodb and BDB both have modifications to the server to allow them to
- do this. Since you will not want to do this, this is probably the next
- best method.
- */
- if (!partition_init)
- {
- /* Hijack a mutex for init'ing the storage engine */
- pthread_mutex_lock(&LOCK_mysql_create_db);
- if (!partition_init)
- {
- partition_init++;
- VOID(pthread_mutex_init(&partition_mutex, MY_MUTEX_INIT_FAST));
- (void) hash_init(&partition_open_tables, system_charset_info, 32, 0, 0,
- (hash_get_key) partition_get_key, 0, 0);
- }
- pthread_mutex_unlock(&LOCK_mysql_create_db);
- }
- pthread_mutex_lock(&partition_mutex);
- length= (uint) strlen(table_name);
-
- if (!(share= (PARTITION_SHARE *) hash_search(&partition_open_tables,
- (uchar *) table_name, length)))
- {
- if (!(share= (PARTITION_SHARE *)
- my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &share, (uint) sizeof(*share),
- &tmp_name, (uint) length + 1, NullS)))
- {
- pthread_mutex_unlock(&partition_mutex);
- return NULL;
- }
-
- share->use_count= 0;
- share->table_name_length= length;
- share->table_name= tmp_name;
- strmov(share->table_name, table_name);
- if (my_hash_insert(&partition_open_tables, (uchar *) share))
- goto error;
- thr_lock_init(&share->lock);
- pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
- }
- share->use_count++;
- pthread_mutex_unlock(&partition_mutex);
-
- return share;
-
-error:
- pthread_mutex_unlock(&partition_mutex);
- my_free((uchar*) share, MYF(0));
-
- return NULL;
-}
-
-
-/*
- Free lock controls. We call this whenever we close a table. If the table
- had the last reference to the share then we free memory associated with
- it.
-*/
-
-static int free_share(PARTITION_SHARE *share)
-{
- pthread_mutex_lock(&partition_mutex);
- if (!--share->use_count)
- {
- hash_delete(&partition_open_tables, (uchar *) share);
- thr_lock_delete(&share->lock);
- pthread_mutex_destroy(&share->mutex);
- my_free((uchar*) share, MYF(0));
- }
- pthread_mutex_unlock(&partition_mutex);
-
- return 0;
-}
-#endif /* NOT_USED */
-
struct st_mysql_storage_engine partition_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 76b91e160ca..57456ddf8ae 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -1,4 +1,7 @@
-/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+#ifndef HA_PARTITION_INCLUDED
+#define HA_PARTITION_INCLUDED
+
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -17,36 +20,15 @@
#pragma interface /* gcc class implementation */
#endif
+#include "sql_partition.h" /* part_id_range, partition_element */
+#include "queues.h" /* QUEUE */
+
enum partition_keywords
{
- PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR
+ PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR,
+ PKW_COLUMNS
};
-/*
- PARTITION_SHARE is a structure that will be shared amoung all open handlers
- The partition implements the minimum of what you will probably need.
-*/
-
-#ifdef NOT_USED
-typedef struct st_partition_share
-{
- char *table_name;
- uint table_name_length, use_count;
- pthread_mutex_t mutex;
- THR_LOCK lock;
-} PARTITION_SHARE;
-#endif
-
-/**
- Partition specific ha_data struct.
- @todo: move all partition specific data from TABLE_SHARE here.
-*/
-typedef struct st_ha_data_partition
-{
- ulonglong next_auto_inc_val; /**< first non reserved value */
- pthread_mutex_t LOCK_auto_inc;
- bool auto_inc_initialized;
-} HA_DATA_PARTITION;
#define PARTITION_BYTES_IN_POS 2
#define PARTITION_ENABLED_TABLE_FLAGS (HA_FILE_BASED | HA_REC_NOT_IN_SEQ)
@@ -111,7 +93,7 @@ private:
uint m_reorged_parts; // Number of reorganised parts
uint m_tot_parts; // Total number of partitions;
- uint m_no_locks; // For engines like ha_blackhole, which needs no locks
+ uint m_num_locks; // For engines like ha_blackhole, which needs no locks
uint m_last_part; // Last file that we update,write,read
int m_lock_type; // Remembers type of last
// external_lock
@@ -165,9 +147,6 @@ private:
Variables for lock structures.
*/
THR_LOCK_DATA lock; /* MySQL lock */
-#ifdef NOT_USED
- PARTITION_SHARE *share; /* Shared lock info */
-#endif
/*
TRUE <=> this object was created with ha_partition::clone and doesn't
@@ -247,10 +226,10 @@ public:
size_t pack_frm_len);
virtual int drop_partitions(const char *path);
virtual int rename_partitions(const char *path);
- bool get_no_parts(const char *name, uint *no_parts)
+ bool get_no_parts(const char *name, uint *num_parts)
{
DBUG_ENTER("ha_partition::get_no_parts");
- *no_parts= m_tot_parts;
+ *num_parts= m_tot_parts;
DBUG_RETURN(0);
}
virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share);
@@ -367,6 +346,7 @@ public:
virtual int update_row(const uchar * old_data, uchar * new_data);
virtual int delete_row(const uchar * buf);
virtual int delete_all_rows(void);
+ virtual int truncate();
virtual void start_bulk_insert(ha_rows rows);
virtual int end_bulk_insert();
private:
@@ -375,6 +355,15 @@ private:
long estimate_read_buffer_size(long original_size);
public:
+ /*
+ Method for truncating a specific partition.
+ (i.e. ALTER TABLE t1 TRUNCATE PARTITION p).
+
+ @remark This method is a partitioning-specific hook
+ and thus not a member of the general SE API.
+ */
+ int truncate_partition(Alter_info *, bool *binlog_stmt);
+
virtual bool is_fatal_error(int error, uint flags)
{
if (!handler::is_fatal_error(error, flags) ||
@@ -527,7 +516,7 @@ public:
-------------------------------------------------------------------------
*/
virtual int info(uint);
- void get_dynamic_partition_info(PARTITION_INFO *stat_info,
+ void get_dynamic_partition_info(PARTITION_STATS *stat_info,
uint part_id);
virtual int extra(enum ha_extra_function operation);
virtual int extra_opt(enum ha_extra_function operation, ulong cachesize);
@@ -946,17 +935,16 @@ private:
/* lock already taken */
if (auto_increment_safe_stmt_log_lock)
return;
- DBUG_ASSERT(table_share->ha_data && !auto_increment_lock);
+ DBUG_ASSERT(table_share->ha_part_data && !auto_increment_lock);
if(table_share->tmp_table == NO_TMP_TABLE)
{
- HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
auto_increment_lock= TRUE;
- pthread_mutex_lock(&ha_data->LOCK_auto_inc);
+ mysql_mutex_lock(&table_share->ha_part_data->LOCK_auto_inc);
}
}
virtual void unlock_auto_increment()
{
- DBUG_ASSERT(table_share->ha_data);
+ DBUG_ASSERT(table_share->ha_part_data);
/*
If auto_increment_safe_stmt_log_lock is true, we have to keep the lock.
It will be set to false and thus unlocked at the end of the statement by
@@ -964,21 +952,19 @@ private:
*/
if(auto_increment_lock && !auto_increment_safe_stmt_log_lock)
{
- HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
- pthread_mutex_unlock(&ha_data->LOCK_auto_inc);
+ mysql_mutex_unlock(&table_share->ha_part_data->LOCK_auto_inc);
auto_increment_lock= FALSE;
}
}
virtual void set_auto_increment_if_higher(Field *field)
{
- HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
ulonglong nr= (((Field_num*) field)->unsigned_flag ||
field->val_int() > 0) ? field->val_int() : 0;
lock_auto_increment();
- DBUG_ASSERT(ha_data->auto_inc_initialized == TRUE);
+ DBUG_ASSERT(table_share->ha_part_data->auto_inc_initialized == TRUE);
/* must check when the mutex is taken */
- if (nr >= ha_data->next_auto_inc_val)
- ha_data->next_auto_inc_val= nr + 1;
+ if (nr >= table_share->ha_part_data->next_auto_inc_val)
+ table_share->ha_part_data->next_auto_inc_val= nr + 1;
unlock_auto_increment();
}
@@ -1096,12 +1082,13 @@ public:
virtual int backup(TD* thd, HA_CHECK_OPT *check_opt);
virtual int restore(THD* thd, HA_CHECK_OPT *check_opt);
- virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt);
- virtual int preload_keys(THD *thd, HA_CHECK_OPT *check_opt);
virtual int dump(THD* thd, int fd = -1);
virtual int net_read_dump(NET* net);
virtual uint checksum() const;
*/
+ /* Enabled keycache for performance reasons, WL#4571 */
+ virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt);
+ virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt);
/*
-------------------------------------------------------------------------
@@ -1125,3 +1112,5 @@ public:
virtual void append_create_info(String *packet)
*/
};
+
+#endif /* HA_PARTITION_INCLUDED */
diff --git a/sql/handler.cc b/sql/handler.cc
index 18381bc552c..4c48298d9e9 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -23,10 +23,23 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "rpl_handler.h"
+#include "sql_cache.h" // query_cache, query_cache_*
+#include "key.h" // key_copy, key_unpack, key_cmp_if_same, key_cmp
+#include "sql_table.h" // build_table_filename
+#include "sql_parse.h" // check_stack_overrun
+#include "sql_acl.h" // SUPER_ACL
+#include "sql_base.h" // free_io_cache
+#include "discover.h" // writefrm
+#include "log_event.h" // *_rows_log_event
#include "rpl_filter.h"
#include <myisampack.h>
+#include "transaction.h"
#include <errno.h>
+#include "probes_mysql.h"
+#include "debug_sync.h" // DEBUG_SYNC
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
@@ -43,7 +56,8 @@ static handlerton *installed_htons[128];
#define BITMAP_STACKBUF_SIZE (128/8)
-KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NullS,0} };
+KEY_CREATE_INFO default_key_create_info=
+ { HA_KEY_ALG_UNDEF, 0, {NullS, 0}, {NullS, 0} };
/* number of entries in handlertons[] */
ulong total_ha= 0;
@@ -175,15 +189,6 @@ plugin_ref ha_lock_engine(THD *thd, const handlerton *hton)
}
-#ifdef NOT_USED
-static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root)
-{
- handlerton *hton= ha_default_handlerton(current_thd);
- return (hton && hton->create) ? hton->create(hton, table, mem_root) : NULL;
-}
-#endif
-
-
handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type)
{
plugin_ref plugin;
@@ -221,11 +226,9 @@ handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
return NULL;
}
+ RUN_HOOK(transaction, after_rollback, (thd, FALSE));
+
switch (database_type) {
-#ifndef NO_HASH
- case DB_TYPE_HASH:
- return ha_resolve_by_legacy_type(thd, DB_TYPE_HASH);
-#endif
case DB_TYPE_MRG_ISAM:
return ha_resolve_by_legacy_type(thd, DB_TYPE_MRG_MYISAM);
default:
@@ -282,6 +285,16 @@ handler *get_ha_partition(partition_info *part_info)
#endif
+static const char **handler_errmsgs;
+
+C_MODE_START
+static const char **get_handler_errmsgs()
+{
+ return handler_errmsgs;
+}
+C_MODE_END
+
+
/**
Register handler error messages for use with my_error().
@@ -293,61 +306,60 @@ handler *get_ha_partition(partition_info *part_info)
int ha_init_errors(void)
{
-#define SETMSG(nr, msg) errmsgs[(nr) - HA_ERR_FIRST]= (msg)
- const char **errmsgs;
+#define SETMSG(nr, msg) handler_errmsgs[(nr) - HA_ERR_FIRST]= (msg)
/* Allocate a pointer array for the error message strings. */
/* Zerofill it to avoid uninitialized gaps. */
- if (! (errmsgs= (const char**) my_malloc(HA_ERR_ERRORS * sizeof(char*),
- MYF(MY_WME | MY_ZEROFILL))))
+ if (! (handler_errmsgs= (const char**) my_malloc(HA_ERR_ERRORS * sizeof(char*),
+ MYF(MY_WME | MY_ZEROFILL))))
return 1;
/* Set the dedicated error messages. */
- SETMSG(HA_ERR_KEY_NOT_FOUND, ER(ER_KEY_NOT_FOUND));
- SETMSG(HA_ERR_FOUND_DUPP_KEY, ER(ER_DUP_KEY));
+ SETMSG(HA_ERR_KEY_NOT_FOUND, ER_DEFAULT(ER_KEY_NOT_FOUND));
+ SETMSG(HA_ERR_FOUND_DUPP_KEY, ER_DEFAULT(ER_DUP_KEY));
SETMSG(HA_ERR_RECORD_CHANGED, "Update wich is recoverable");
SETMSG(HA_ERR_WRONG_INDEX, "Wrong index given to function");
- SETMSG(HA_ERR_CRASHED, ER(ER_NOT_KEYFILE));
- SETMSG(HA_ERR_WRONG_IN_RECORD, ER(ER_CRASHED_ON_USAGE));
+ SETMSG(HA_ERR_CRASHED, ER_DEFAULT(ER_NOT_KEYFILE));
+ SETMSG(HA_ERR_WRONG_IN_RECORD, ER_DEFAULT(ER_CRASHED_ON_USAGE));
SETMSG(HA_ERR_OUT_OF_MEM, "Table handler out of memory");
SETMSG(HA_ERR_NOT_A_TABLE, "Incorrect file format '%.64s'");
SETMSG(HA_ERR_WRONG_COMMAND, "Command not supported");
- SETMSG(HA_ERR_OLD_FILE, ER(ER_OLD_KEYFILE));
+ SETMSG(HA_ERR_OLD_FILE, ER_DEFAULT(ER_OLD_KEYFILE));
SETMSG(HA_ERR_NO_ACTIVE_RECORD, "No record read in update");
SETMSG(HA_ERR_RECORD_DELETED, "Intern record deleted");
- SETMSG(HA_ERR_RECORD_FILE_FULL, ER(ER_RECORD_FILE_FULL));
+ SETMSG(HA_ERR_RECORD_FILE_FULL, ER_DEFAULT(ER_RECORD_FILE_FULL));
SETMSG(HA_ERR_INDEX_FILE_FULL, "No more room in index file '%.64s'");
SETMSG(HA_ERR_END_OF_FILE, "End in next/prev/first/last");
- SETMSG(HA_ERR_UNSUPPORTED, ER(ER_ILLEGAL_HA));
+ SETMSG(HA_ERR_UNSUPPORTED, ER_DEFAULT(ER_ILLEGAL_HA));
SETMSG(HA_ERR_TO_BIG_ROW, "Too big row");
SETMSG(HA_WRONG_CREATE_OPTION, "Wrong create option");
- SETMSG(HA_ERR_FOUND_DUPP_UNIQUE, ER(ER_DUP_UNIQUE));
+ SETMSG(HA_ERR_FOUND_DUPP_UNIQUE, ER_DEFAULT(ER_DUP_UNIQUE));
SETMSG(HA_ERR_UNKNOWN_CHARSET, "Can't open charset");
- SETMSG(HA_ERR_WRONG_MRG_TABLE_DEF, ER(ER_WRONG_MRG_TABLE));
- SETMSG(HA_ERR_CRASHED_ON_REPAIR, ER(ER_CRASHED_ON_REPAIR));
- SETMSG(HA_ERR_CRASHED_ON_USAGE, ER(ER_CRASHED_ON_USAGE));
- SETMSG(HA_ERR_LOCK_WAIT_TIMEOUT, ER(ER_LOCK_WAIT_TIMEOUT));
- SETMSG(HA_ERR_LOCK_TABLE_FULL, ER(ER_LOCK_TABLE_FULL));
- SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER(ER_READ_ONLY_TRANSACTION));
- SETMSG(HA_ERR_LOCK_DEADLOCK, ER(ER_LOCK_DEADLOCK));
- SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER(ER_CANNOT_ADD_FOREIGN));
- SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW_2));
- SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED_2));
+ SETMSG(HA_ERR_WRONG_MRG_TABLE_DEF, ER_DEFAULT(ER_WRONG_MRG_TABLE));
+ SETMSG(HA_ERR_CRASHED_ON_REPAIR, ER_DEFAULT(ER_CRASHED_ON_REPAIR));
+ SETMSG(HA_ERR_CRASHED_ON_USAGE, ER_DEFAULT(ER_CRASHED_ON_USAGE));
+ SETMSG(HA_ERR_LOCK_WAIT_TIMEOUT, ER_DEFAULT(ER_LOCK_WAIT_TIMEOUT));
+ SETMSG(HA_ERR_LOCK_TABLE_FULL, ER_DEFAULT(ER_LOCK_TABLE_FULL));
+ SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER_DEFAULT(ER_READ_ONLY_TRANSACTION));
+ SETMSG(HA_ERR_LOCK_DEADLOCK, ER_DEFAULT(ER_LOCK_DEADLOCK));
+ SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER_DEFAULT(ER_CANNOT_ADD_FOREIGN));
+ SETMSG(HA_ERR_NO_REFERENCED_ROW, ER_DEFAULT(ER_NO_REFERENCED_ROW_2));
+ SETMSG(HA_ERR_ROW_IS_REFERENCED, ER_DEFAULT(ER_ROW_IS_REFERENCED_2));
SETMSG(HA_ERR_NO_SAVEPOINT, "No savepoint with that name");
SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE, "Non unique key block size");
SETMSG(HA_ERR_NO_SUCH_TABLE, "No such table: '%.64s'");
- SETMSG(HA_ERR_TABLE_EXIST, ER(ER_TABLE_EXISTS_ERROR));
+ SETMSG(HA_ERR_TABLE_EXIST, ER_DEFAULT(ER_TABLE_EXISTS_ERROR));
SETMSG(HA_ERR_NO_CONNECTION, "Could not connect to storage engine");
- SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER(ER_TABLE_DEF_CHANGED));
+ SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER_DEFAULT(ER_TABLE_DEF_CHANGED));
SETMSG(HA_ERR_FOREIGN_DUPLICATE_KEY, "FK constraint would lead to duplicate key");
- SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER(ER_TABLE_NEEDS_UPGRADE));
- SETMSG(HA_ERR_TABLE_READONLY, ER(ER_OPEN_AS_READONLY));
- SETMSG(HA_ERR_AUTOINC_READ_FAILED, ER(ER_AUTOINC_READ_FAILED));
- SETMSG(HA_ERR_AUTOINC_ERANGE, ER(ER_WARN_DATA_OUT_OF_RANGE));
- SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER(ER_TOO_MANY_CONCURRENT_TRXS));
+ SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER_DEFAULT(ER_TABLE_NEEDS_UPGRADE));
+ SETMSG(HA_ERR_TABLE_READONLY, ER_DEFAULT(ER_OPEN_AS_READONLY));
+ SETMSG(HA_ERR_AUTOINC_READ_FAILED, ER_DEFAULT(ER_AUTOINC_READ_FAILED));
+ SETMSG(HA_ERR_AUTOINC_ERANGE, ER_DEFAULT(ER_WARN_DATA_OUT_OF_RANGE));
+ SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER_DEFAULT(ER_TOO_MANY_CONCURRENT_TRXS));
/* Register the error messages for use with my_error(). */
- return my_error_register(errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
+ return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
}
@@ -366,7 +378,7 @@ static int ha_finish_errors(void)
/* Allocate a pointer array for the error message strings. */
if (! (errmsgs= my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST)))
return 1;
- my_free((uchar*) errmsgs, MYF(0));
+ my_free(errmsgs);
return 0;
}
@@ -413,9 +425,15 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
reuse an array slot. Otherwise the number of uninstall/install
cycles would be limited.
*/
- hton2plugin[hton->slot]= NULL;
+ if (hton->slot != HA_SLOT_UNDEF)
+ {
+ /* Make sure we are not unpluging another plugin */
+ DBUG_ASSERT(hton2plugin[hton->slot] == plugin);
+ DBUG_ASSERT(hton->slot < MAX_HA);
+ hton2plugin[hton->slot]= NULL;
+ }
- my_free((uchar*)hton, MYF(0));
+ my_free(hton);
end:
DBUG_RETURN(0);
@@ -430,6 +448,15 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
hton= (handlerton *)my_malloc(sizeof(handlerton),
MYF(MY_WME | MY_ZEROFILL));
+
+ if (hton == NULL)
+ {
+ sql_print_error("Unable to allocate memory for plugin '%s' handlerton.",
+ plugin->name.str);
+ goto err_no_hton_memory;
+ }
+
+ hton->slot= HA_SLOT_UNDEF;
/* Historical Requirement */
plugin->data= hton; // shortcut for the future
if (plugin->plugin->init && plugin->plugin->init(hton))
@@ -539,7 +566,8 @@ err_deinit:
(void) plugin->plugin->deinit(NULL);
err:
- my_free((uchar*) hton, MYF(0));
+ my_free(hton);
+err_no_hton_memory:
plugin->data= NULL;
DBUG_RETURN(1);
}
@@ -863,16 +891,16 @@ void ha_close_connection(THD* thd)
a transaction in a given engine is read-write and will not
involve the two-phase commit protocol!
- At the end of a statement, server call
- ha_autocommit_or_rollback() is invoked. This call in turn
- invokes handlerton::prepare() for every involved engine.
- Prepare is followed by a call to handlerton::commit_one_phase()
- If a one-phase commit will suffice, handlerton::prepare() is not
- invoked and the server only calls handlerton::commit_one_phase().
- At statement commit, the statement-related read-write engine
- flag is propagated to the corresponding flag in the normal
- transaction. When the commit is complete, the list of registered
- engines is cleared.
+ At the end of a statement, server call trans_commit_stmt is
+ invoked. This call in turn invokes handlerton::prepare()
+ for every involved engine. Prepare is followed by a call
+ to handlerton::commit_one_phase() If a one-phase commit
+ will suffice, handlerton::prepare() is not invoked and
+ the server only calls handlerton::commit_one_phase().
+ At statement commit, the statement-related read-write
+ engine flag is propagated to the corresponding flag in the
+ normal transaction. When the commit is complete, the list
+ of registered engines is cleared.
Rollback is handled in a similar fashion.
@@ -883,7 +911,7 @@ void ha_close_connection(THD* thd)
do not "register" in thd->transaction lists, and thus do not
modify the transaction state. Besides, each DDL in
MySQL is prefixed with an implicit normal transaction commit
- (a call to end_active_trans()), and thus leaves nothing
+ (a call to trans_commit_implicit()), and thus leaves nothing
to modify.
However, as it has been pointed out with CREATE TABLE .. SELECT,
some DDL statements can start a *new* transaction.
@@ -967,7 +995,7 @@ int ha_prepare(THD *thd)
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
Ha_trx_info *ha_info= trans->ha_list;
DBUG_ENTER("ha_prepare");
-#ifdef USING_TRANSACTIONS
+
if (ha_info)
{
for (; ha_info; ha_info= ha_info->next())
@@ -993,7 +1021,7 @@ int ha_prepare(THD *thd)
}
}
}
-#endif /* USING_TRANSACTIONS */
+
DBUG_RETURN(error);
}
@@ -1103,6 +1131,7 @@ int ha_commit_trans(THD *thd, bool all)
if (thd->in_sub_stmt)
{
+ DBUG_ASSERT(0);
/*
Since we don't support nested statement transactions in 5.0,
we can't commit or rollback stmt transactions while we are inside
@@ -1117,15 +1146,15 @@ int ha_commit_trans(THD *thd, bool all)
bail out with error even before ha_commit_trans() call. To be 100% safe
let us throw error in non-debug builds.
*/
- DBUG_ASSERT(0);
my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
DBUG_RETURN(2);
}
-#ifdef USING_TRANSACTIONS
+
if (ha_info)
{
uint rw_ha_count;
bool rw_trans;
+ MDL_request mdl_request;
DBUG_EXECUTE_IF("crash_commit_before", DBUG_SUICIDE(););
@@ -1137,11 +1166,27 @@ int ha_commit_trans(THD *thd, bool all)
/* rw_trans is TRUE when we in a transaction changing data */
rw_trans= is_real_trans && (rw_ha_count > 0);
- if (rw_trans &&
- wait_if_global_read_lock(thd, 0, 0))
+ if (rw_trans)
{
- ha_rollback_trans(thd, all);
- DBUG_RETURN(1);
+ /*
+ Acquire a metadata lock which will ensure that COMMIT is blocked
+ by an active FLUSH TABLES WITH READ LOCK (and vice versa:
+ COMMIT in progress blocks FTWRL).
+
+ We allow the owner of FTWRL to COMMIT; we assume that it knows
+ what it does.
+ */
+ mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_EXPLICIT);
+
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
+ {
+ ha_rollback_trans(thd, all);
+ DBUG_RETURN(1);
+ }
+
+ DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock");
}
if (rw_trans &&
@@ -1198,21 +1243,36 @@ int ha_commit_trans(THD *thd, bool all)
goto end;
}
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
+ RUN_HOOK(transaction, after_commit, (thd, FALSE));
end:
- if (rw_trans)
- start_waiting_global_read_lock(thd);
+ if (rw_trans && mdl_request.ticket)
+ {
+ /*
+ We do not always immediately release transactional locks
+ after ha_commit_trans() (see uses of ha_enable_transaction()),
+ thus we release the commit blocker lock as soon as it's
+ not needed.
+ */
+ thd->mdl_context.release_lock(mdl_request.ticket);
+ }
}
/* Free resources and perform other cleanup even for 'empty' transactions. */
else if (is_real_trans)
thd->transaction.cleanup();
-#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
/**
@note
This function does not care about global read lock. A caller should.
+
+ @param[in] all Is set in case of explicit commit
+ (COMMIT statement), or implicit commit
+ issued by DDL. Is not set when called
+ at the end of statement, even if
+ autocommit=1.
*/
+
int ha_commit_one_phase(THD *thd, bool all)
{
int error=0;
@@ -1220,14 +1280,20 @@ int ha_commit_one_phase(THD *thd, bool all)
/*
"real" is a nick name for a transaction for which a commit will
make persistent changes. E.g. a 'stmt' transaction inside a 'all'
- transation is not 'real': even though it's possible to commit it,
+ transaction is not 'real': even though it's possible to commit it,
the changes are not durable as they might be rolled back if the
enclosing 'all' transaction is rolled back.
+ We establish the value of 'is_real_trans' by checking
+ if it's an explicit COMMIT/BEGIN statement, or implicit
+ commit issued by DDL (all == TRUE), or if we're running
+ in autocommit mode (it's only in the autocommit mode
+ ha_commit_one_phase() can be called with an empty
+ transaction.all.ha_list, see why in trans_register_ha()).
*/
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
DBUG_ENTER("ha_commit_one_phase");
-#ifdef USING_TRANSACTIONS
+
if (ha_info)
{
for (; ha_info; ha_info= ha_info_next)
@@ -1251,13 +1317,12 @@ int ha_commit_one_phase(THD *thd, bool all)
if (thd->transaction.changed_tables)
query_cache.invalidate(thd->transaction.changed_tables);
#endif
- thd->variables.tx_isolation=thd->session_tx_isolation;
}
}
/* Free resources and perform other cleanup even for 'empty' transactions. */
if (is_real_trans)
thd->transaction.cleanup();
-#endif /* USING_TRANSACTIONS */
+
DBUG_RETURN(error);
}
@@ -1270,9 +1335,15 @@ int ha_rollback_trans(THD *thd, bool all)
/*
"real" is a nick name for a transaction for which a commit will
make persistent changes. E.g. a 'stmt' transaction inside a 'all'
- transation is not 'real': even though it's possible to commit it,
+ transaction is not 'real': even though it's possible to commit it,
the changes are not durable as they might be rolled back if the
enclosing 'all' transaction is rolled back.
+ We establish the value of 'is_real_trans' by checking
+ if it's an explicit COMMIT or BEGIN statement, or implicit
+ commit issued by DDL (in these cases all == TRUE),
+ or if we're running in autocommit mode (it's only in the autocommit mode
+ ha_commit_one_phase() is called with an empty
+ transaction.all.ha_list, see why in trans_register_ha()).
*/
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
DBUG_ENTER("ha_rollback_trans");
@@ -1286,6 +1357,7 @@ int ha_rollback_trans(THD *thd, bool all)
if (thd->in_sub_stmt)
{
+ DBUG_ASSERT(0);
/*
If we are inside stored function or trigger we should not commit or
rollback current statement transaction. See comment in ha_commit_trans()
@@ -1293,11 +1365,10 @@ int ha_rollback_trans(THD *thd, bool all)
*/
if (!all)
DBUG_RETURN(0);
- DBUG_ASSERT(0);
my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
DBUG_RETURN(1);
}
-#ifdef USING_TRANSACTIONS
+
if (ha_info)
{
/* Close all cursors that can not survive ROLLBACK */
@@ -1321,14 +1392,11 @@ int ha_rollback_trans(THD *thd, bool all)
trans->no_2pc=0;
if (is_real_trans && thd->transaction_rollback_request &&
thd->transaction.xid_state.xa_state != XA_NOTR)
- thd->transaction.xid_state.rm_error= thd->main_da.sql_errno();
- if (all)
- thd->variables.tx_isolation=thd->session_tx_isolation;
+ thd->transaction.xid_state.rm_error= thd->stmt_da->sql_errno();
}
- /* Always cleanup. Even if there nht==0. There may be savepoints. */
+ /* Always cleanup. Even if nht==0. There may be savepoints. */
if (is_real_trans)
thd->transaction.cleanup();
-#endif /* USING_TRANSACTIONS */
if (all)
thd->transaction_rollback_request= FALSE;
@@ -1346,41 +1414,7 @@ int ha_rollback_trans(THD *thd, bool all)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
- DBUG_RETURN(error);
-}
-
-/**
- This is used to commit or rollback a single statement depending on
- the value of error.
-
- @note
- Note that if the autocommit is on, then the following call inside
- InnoDB will commit or rollback the whole transaction (= the statement). The
- autocommit mechanism built into InnoDB is based on counting locks, but if
- the user has used LOCK TABLES then that mechanism does not know to do the
- commit.
-*/
-int ha_autocommit_or_rollback(THD *thd, int error)
-{
- DBUG_ENTER("ha_autocommit_or_rollback");
-#ifdef USING_TRANSACTIONS
- if (thd->transaction.stmt.ha_list)
- {
- if (!error)
- {
- if (ha_commit_trans(thd, 0))
- error=1;
- }
- else
- {
- (void) ha_rollback_trans(thd, 0);
- if (thd->transaction_rollback_request && !thd->in_sub_stmt)
- (void) ha_rollback(thd);
- }
-
- thd->variables.tx_isolation=thd->session_tx_isolation;
- }
-#endif
+ RUN_HOOK(transaction, after_rollback, (thd, FALSE));
DBUG_RETURN(error);
}
@@ -1541,7 +1575,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
}
// recovery mode
if (info->commit_list ?
- hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
+ my_hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
{
#ifndef DBUG_OFF
@@ -1611,7 +1645,7 @@ int ha_recover(HASH *commit_list)
plugin_foreach(NULL, xarecover_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &info);
- my_free((uchar*)info.list, MYF(0));
+ my_free(info.list);
if (info.found_foreign_xids)
sql_print_warning("Found %d prepared XA transactions",
info.found_foreign_xids);
@@ -1652,12 +1686,12 @@ bool mysql_xa_recover(THD *thd)
field_list.push_back(new Item_int("bqual_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
field_list.push_back(new Item_empty_string("data",XIDDATASIZE));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(1);
- pthread_mutex_lock(&LOCK_xid_cache);
- while ((xs= (XID_STATE*)hash_element(&xid_cache, i++)))
+ mysql_mutex_lock(&LOCK_xid_cache);
+ while ((xs= (XID_STATE*) my_hash_element(&xid_cache, i++)))
{
if (xs->xa_state==XA_PREPARED)
{
@@ -1669,13 +1703,13 @@ bool mysql_xa_recover(THD *thd)
&my_charset_bin);
if (protocol->write())
{
- pthread_mutex_unlock(&LOCK_xid_cache);
+ mysql_mutex_unlock(&LOCK_xid_cache);
DBUG_RETURN(1);
}
}
}
- pthread_mutex_unlock(&LOCK_xid_cache);
+ mysql_mutex_unlock(&LOCK_xid_cache);
my_eof(thd);
DBUG_RETURN(0);
}
@@ -1782,7 +1816,7 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
&thd->transaction.all);
Ha_trx_info *ha_info= trans->ha_list;
DBUG_ENTER("ha_savepoint");
-#ifdef USING_TRANSACTIONS
+
for (; ha_info; ha_info= ha_info->next())
{
int err;
@@ -1806,7 +1840,7 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
engines are prepended to the beginning of the list.
*/
sv->ha_list= trans->ha_list;
-#endif /* USING_TRANSACTIONS */
+
DBUG_RETURN(error);
}
@@ -1952,23 +1986,28 @@ const char *get_canonical_filename(handler *file, const char *path,
struct Ha_delete_table_error_handler: public Internal_error_handler
{
public:
- virtual bool handle_error(uint sql_errno,
- const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd);
+ virtual bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl);
char buff[MYSQL_ERRMSG_SIZE];
};
bool
Ha_delete_table_error_handler::
-handle_error(uint sql_errno,
- const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd)
-{
+handle_condition(THD *,
+ uint,
+ const char*,
+ MYSQL_ERROR::enum_warning_level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
+{
+ *cond_hdl= NULL;
/* Grab the error message */
- strmake(buff, message, sizeof(buff)-1);
+ strmake(buff, msg, sizeof(buff)-1);
return TRUE;
}
@@ -2027,7 +2066,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
XXX: should we convert *all* errors to warnings here?
What if the error is fatal?
*/
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error,
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, error,
ha_delete_table_error_handler.buff);
}
delete file;
@@ -2073,6 +2112,10 @@ THD *handler::ha_thd(void) const
return (table && table->in_use) ? table->in_use : current_thd;
}
+PSI_table_share *handler::ha_table_share_psi(const TABLE_SHARE *share) const
+{
+ return share->m_psi;
+}
/** @brief
Open database-handler.
@@ -2455,7 +2498,7 @@ int handler::update_auto_increment()
variables->auto_increment_increment);
auto_inc_intervals_count++;
/* Row-based replication does not need to store intervals in binlog */
- if (mysql_bin_log.is_open() && !thd->current_stmt_binlog_row_based)
+ if (mysql_bin_log.is_open() && !thd->is_current_stmt_binlog_format_row())
thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(),
auto_inc_interval_for_cur_row.values(),
variables->auto_increment_increment);
@@ -2780,6 +2823,9 @@ void handler::print_error(int error, myf errflag)
case HA_ERR_TABLE_NEEDS_UPGRADE:
textno=ER_TABLE_NEEDS_UPGRADE;
break;
+ case HA_ERR_NO_PARTITION_FOUND:
+ textno=ER_WRONG_PARTITION_NAME;
+ break;
case HA_ERR_TABLE_READONLY:
textno= ER_OPEN_AS_READONLY;
break;
@@ -2959,27 +3005,21 @@ static bool update_frm_version(TABLE *table)
strxmov(path, table->s->normalized_path.str, reg_ext, NullS);
- if ((file= my_open(path, O_RDWR|O_BINARY, MYF(MY_WME))) >= 0)
+ if ((file= mysql_file_open(key_file_frm,
+ path, O_RDWR|O_BINARY, MYF(MY_WME))) >= 0)
{
uchar version[4];
- char *key= table->s->table_cache_key.str;
- uint key_length= table->s->table_cache_key.length;
- TABLE *entry;
- HASH_SEARCH_STATE state;
int4store(version, MYSQL_VERSION_ID);
- if ((result= my_pwrite(file,(uchar*) version,4,51L,MYF_RW)))
+ if ((result= mysql_file_pwrite(file, (uchar*) version, 4, 51L, MYF_RW)))
goto err;
- for (entry=(TABLE*) hash_first(&open_cache,(uchar*) key,key_length, &state);
- entry;
- entry= (TABLE*) hash_next(&open_cache,(uchar*) key,key_length, &state))
- entry->s->mysql_version= MYSQL_VERSION_ID;
+ table->s->mysql_version= MYSQL_VERSION_ID;
}
err:
if (file >= 0)
- VOID(my_close(file,MYF(MY_WME)));
+ (void) mysql_file_close(file, MYF(MY_WME));
DBUG_RETURN(result);
}
@@ -3026,7 +3066,7 @@ int handler::delete_table(const char *name)
for (const char **ext=bas_ext(); *ext ; ext++)
{
fn_format(buff, name, "", *ext, MY_UNPACK_FILENAME|MY_APPEND_EXT);
- if (my_delete_with_symlink(buff, MYF(0)))
+ if (mysql_file_delete_with_symlink(key_file_misc, buff, MYF(0)))
{
if (my_errno != ENOENT)
{
@@ -3197,47 +3237,32 @@ handler::ha_delete_all_rows()
/**
- Reset auto increment: public interface.
+ Truncate table: public interface.
- @sa handler::reset_auto_increment()
+ @sa handler::truncate()
*/
int
-handler::ha_reset_auto_increment(ulonglong value)
+handler::ha_truncate()
{
mark_trx_read_write();
- return reset_auto_increment(value);
+ return truncate();
}
/**
- Backup table: public interface.
-
- @sa handler::backup()
-*/
-
-int
-handler::ha_backup(THD* thd, HA_CHECK_OPT* check_opt)
-{
- mark_trx_read_write();
-
- return backup(thd, check_opt);
-}
-
-
-/**
- Restore table: public interface.
+ Reset auto increment: public interface.
- @sa handler::restore()
+ @sa handler::reset_auto_increment()
*/
int
-handler::ha_restore(THD* thd, HA_CHECK_OPT* check_opt)
+handler::ha_reset_auto_increment(ulonglong value)
{
mark_trx_read_write();
- return restore(thd, check_opt);
+ return reset_auto_increment(value);
}
@@ -3498,7 +3523,7 @@ int ha_enable_transaction(THD *thd, bool on)
So, let's commit an open transaction (if any) now.
*/
if (!(error= ha_commit_trans(thd, 0)))
- error= end_trans(thd, COMMIT);
+ error= trans_commit_implicit(thd);
}
DBUG_RETURN(error);
}
@@ -3555,7 +3580,7 @@ int handler::index_next_same(uchar *buf, const uchar *key, uint keylen)
}
-void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info,
+void handler::get_dynamic_partition_info(PARTITION_STATS *stat_info,
uint part_id)
{
info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE |
@@ -3612,7 +3637,7 @@ int ha_create_table(THD *thd, const char *path,
name= get_canonical_filename(table.file, share.path.str, name_buff);
error= table.file->ha_create(name, &table, create_info);
- VOID(closefrm(&table, 0));
+ (void) closefrm(&table, 0);
if (error)
{
strxmov(name_buff, db, ".", table_name, NullS);
@@ -3663,7 +3688,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
build_table_filename(path, sizeof(path) - 1, db, name, "", 0);
// Save the frm file
error= writefrm(path, frmblob, frmlen);
- my_free(frmblob, MYF(0));
+ my_free(frmblob);
if (error)
DBUG_RETURN(2);
@@ -3683,15 +3708,42 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
get_canonical_filename(table.file, path, path);
error=table.file->ha_create(path, &table, &create_info);
- VOID(closefrm(&table, 1));
+ (void) closefrm(&table, 1);
DBUG_RETURN(error != 0);
}
+
+/**
+ Try to find a table in a storage engine.
+
+ @param db Normalized table schema name
+ @param name Normalized table name.
+ @param[out] exists Only valid if the function succeeded.
+
+ @retval TRUE An error is found
+ @retval FALSE Success, check *exists
+*/
+
+bool
+ha_check_if_table_exists(THD* thd, const char *db, const char *name,
+ bool *exists)
+{
+ uchar *frmblob= NULL;
+ size_t frmlen;
+ DBUG_ENTER("ha_check_if_table_exists");
+
+ *exists= ! ha_discover(thd, db, name, &frmblob, &frmlen);
+ if (*exists)
+ my_free(frmblob);
+
+ DBUG_RETURN(FALSE);
+}
+
+
void st_ha_check_opt::init()
{
flags= sql_flags= 0;
- sort_buffer_size = current_thd->variables.myisam_sort_buff_size;
}
@@ -3714,12 +3766,12 @@ int ha_init_key_cache(const char *name, KEY_CACHE *key_cache)
if (!key_cache->key_cache_inited)
{
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
size_t tmp_buff_size= (size_t) key_cache->param_buff_size;
uint tmp_block_size= (uint) key_cache->param_block_size;
uint division_limit= key_cache->param_division_limit;
uint age_threshold= key_cache->param_age_threshold;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
DBUG_RETURN(!init_key_cache(key_cache,
tmp_block_size,
tmp_buff_size,
@@ -3738,12 +3790,12 @@ int ha_resize_key_cache(KEY_CACHE *key_cache)
if (key_cache->key_cache_inited)
{
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
size_t tmp_buff_size= (size_t) key_cache->param_buff_size;
long tmp_block_size= (long) key_cache->param_block_size;
uint division_limit= key_cache->param_division_limit;
uint age_threshold= key_cache->param_age_threshold;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
DBUG_RETURN(!resize_key_cache(key_cache, tmp_block_size,
tmp_buff_size,
division_limit, age_threshold));
@@ -3759,25 +3811,16 @@ int ha_change_key_cache_param(KEY_CACHE *key_cache)
{
if (key_cache->key_cache_inited)
{
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
uint division_limit= key_cache->param_division_limit;
uint age_threshold= key_cache->param_age_threshold;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
change_key_cache_param(key_cache, division_limit, age_threshold);
}
return 0;
}
/**
- Free memory allocated by a key cache.
-*/
-int ha_end_key_cache(KEY_CACHE *key_cache)
-{
- end_key_cache(key_cache, 1); // Can never fail
- return 0;
-}
-
-/**
Move all tables from one key cache to another one.
*/
int ha_change_key_cache(KEY_CACHE *old_key_cache,
@@ -4430,7 +4473,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
field_list.push_back(new Item_empty_string("Name",FN_REFLEN));
field_list.push_back(new Item_empty_string("Status",10));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
return TRUE;
@@ -4482,9 +4525,9 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
DBUG_ASSERT(table->s->cached_row_logging_check == 0 ||
table->s->cached_row_logging_check == 1);
- return (thd->current_stmt_binlog_row_based &&
+ return (thd->is_current_stmt_binlog_format_row() &&
table->s->cached_row_logging_check &&
- (thd->options & OPTION_BIN_LOG) &&
+ (thd->variables.option_bits & OPTION_BIN_LOG) &&
mysql_bin_log.is_open());
}
@@ -4499,9 +4542,7 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
DESCRIPTION
This function will generate and write table maps for all tables
- that are locked by the thread 'thd'. Either manually locked
- (stored in THD::locked_tables) and automatically locked (stored
- in THD::lock) are considered.
+ that are locked by the thread 'thd'.
RETURN VALUE
0 All OK
@@ -4509,25 +4550,22 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
SEE ALSO
THD::lock
- THD::locked_tables
*/
static int write_locked_table_maps(THD *thd)
{
DBUG_ENTER("write_locked_table_maps");
- DBUG_PRINT("enter", ("thd: 0x%lx thd->lock: 0x%lx thd->locked_tables: 0x%lx "
+ DBUG_PRINT("enter", ("thd: 0x%lx thd->lock: 0x%lx "
"thd->extra_lock: 0x%lx",
- (long) thd, (long) thd->lock,
- (long) thd->locked_tables, (long) thd->extra_lock));
+ (long) thd, (long) thd->lock, (long) thd->extra_lock));
DBUG_PRINT("debug", ("get_binlog_table_maps(): %d", thd->get_binlog_table_maps()));
if (thd->get_binlog_table_maps() == 0)
{
- MYSQL_LOCK *locks[3];
+ MYSQL_LOCK *locks[2];
locks[0]= thd->extra_lock;
locks[1]= thd->lock;
- locks[2]= thd->locked_tables;
for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
{
MYSQL_LOCK const *const lock= locks[i];
@@ -4544,7 +4582,21 @@ static int write_locked_table_maps(THD *thd)
if (table->current_lock == F_WRLCK &&
check_table_binlog_row_based(thd, table))
{
- int const has_trans= table->file->has_transactions();
+ /*
+ We need to have a transactional behavior for SQLCOM_CREATE_TABLE
+ (e.g. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
+ compatible behavior with the STMT based replication even when
+ the table is not transactional. In other words, if the operation
+ fails while executing the insert phase nothing is written to the
+ binlog.
+
+ Note that at this point, we check the type of a set of tables to
+ create the table map events. In the function binlog_log_row(),
+ which calls the current function, we check the type of the table
+ of the current row.
+ */
+ bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
+ table->file->has_transactions();
int const error= thd->binlog_write_table_map(table, has_trans);
/*
If an error occurs, it is the responsibility of the caller to
@@ -4593,10 +4645,20 @@ static int binlog_log_row(TABLE* table,
{
bitmap_set_all(&cols);
if (likely(!(error= write_locked_table_maps(thd))))
- error= (*log_func)(thd, table, table->file->has_transactions(),
- &cols, table->s->fields,
+ {
+ /*
+ We need to have a transactional behavior for SQLCOM_CREATE_TABLE
+ (i.e. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
+ compatible behavior with the STMT based replication even when
+ the table is not transactional. In other words, if the operation
+ fails while executing the insert phase nothing is written to the
+ binlog.
+ */
+ bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
+ table->file->has_transactions();
+ error= (*log_func)(thd, table, has_trans, &cols, table->s->fields,
before_record, after_record);
-
+ }
if (!use_bitbuf)
bitmap_free(&cols);
}
@@ -4614,13 +4676,53 @@ int handler::ha_external_lock(THD *thd, int lock_type)
*/
DBUG_ASSERT(next_insert_id == 0);
+ if (MYSQL_HANDLER_RDLOCK_START_ENABLED() ||
+ MYSQL_HANDLER_WRLOCK_START_ENABLED() ||
+ MYSQL_HANDLER_UNLOCK_START_ENABLED())
+ {
+ if (lock_type == F_RDLCK)
+ {
+ MYSQL_HANDLER_RDLOCK_START(table_share->db.str,
+ table_share->table_name.str);
+ }
+ else if (lock_type == F_WRLCK)
+ {
+ MYSQL_HANDLER_WRLOCK_START(table_share->db.str,
+ table_share->table_name.str);
+ }
+ else if (lock_type == F_UNLCK)
+ {
+ MYSQL_HANDLER_UNLOCK_START(table_share->db.str,
+ table_share->table_name.str);
+ }
+ }
+
/*
We cache the table flags if the locking succeeded. Otherwise, we
keep them as they were when they were fetched in ha_open().
*/
int error= external_lock(thd, lock_type);
+
if (error == 0)
cached_table_flags= table_flags();
+
+ if (MYSQL_HANDLER_RDLOCK_DONE_ENABLED() ||
+ MYSQL_HANDLER_WRLOCK_DONE_ENABLED() ||
+ MYSQL_HANDLER_UNLOCK_DONE_ENABLED())
+ {
+ if (lock_type == F_RDLCK)
+ {
+ MYSQL_HANDLER_RDLOCK_DONE(error);
+ }
+ else if (lock_type == F_WRLCK)
+ {
+ MYSQL_HANDLER_WRLOCK_DONE(error);
+ }
+ else if (lock_type == F_UNLCK)
+ {
+ MYSQL_HANDLER_UNLOCK_DONE(error);
+ }
+ }
DBUG_RETURN(error);
}
@@ -4653,10 +4755,14 @@ int handler::ha_write_row(uchar *buf)
Log_func *log_func= Write_rows_log_event::binlog_row_logging_function;
DBUG_ENTER("handler::ha_write_row");
+ MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
- if (unlikely(error= write_row(buf)))
+ error= write_row(buf);
+ MYSQL_INSERT_ROW_DONE(error);
+ if (unlikely(error))
DBUG_RETURN(error);
+
if (unlikely(error= binlog_log_row(table, 0, buf, log_func)))
DBUG_RETURN(error); /* purecov: inspected */
DBUG_RETURN(0);
@@ -4674,9 +4780,12 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
*/
DBUG_ASSERT(new_data == table->record[0]);
+ MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
- if (unlikely(error= update_row(old_data, new_data)))
+ error= update_row(old_data, new_data);
+ MYSQL_UPDATE_ROW_DONE(error);
+ if (unlikely(error))
return error;
if (unlikely(error= binlog_log_row(table, old_data, new_data, log_func)))
return error;
@@ -4688,9 +4797,12 @@ int handler::ha_delete_row(const uchar *buf)
int error;
Log_func *log_func= Delete_rows_log_event::binlog_row_logging_function;
+ MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
- if (unlikely(error= delete_row(buf)))
+ error= delete_row(buf);
+ MYSQL_DELETE_ROW_DONE(error);
+ if (unlikely(error))
return error;
if (unlikely(error= binlog_log_row(table, buf, 0, log_func)))
return error;
@@ -4750,7 +4862,8 @@ int example_of_iterator_using_for_logs_cleanup(handlerton *hton)
{
printf("%s\n", data.filename.str);
if (data.status == HA_LOG_STATUS_FREE &&
- my_delete(data.filename.str, MYF(MY_WME)))
+ mysql_file_delete(INSTRUMENT_ME,
+ data.filename.str, MYF(MY_WME)))
goto err;
}
res= 0;
@@ -4778,7 +4891,7 @@ err:
enum log_status fl_get_log_status(char *log)
{
MY_STAT stat_buff;
- if (my_stat(log, &stat_buff, MYF(0)))
+ if (mysql_file_stat(INSTRUMENT_ME, log, &stat_buff, MYF(0)))
return HA_LOG_STATUS_INUSE;
return HA_LOG_STATUS_NOSUCHLOG;
}
@@ -4810,7 +4923,7 @@ int fl_log_iterator_next(struct handler_iterator *iterator,
void fl_log_iterator_destroy(struct handler_iterator *iterator)
{
- my_free((uchar*)iterator->buffer, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(iterator->buffer);
}
diff --git a/sql/handler.h b/sql/handler.h
index dabc179079a..0e03ea17dde 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1,4 +1,7 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+#ifndef HANDLER_INCLUDED
+#define HANDLER_INCLUDED
+
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -13,23 +16,23 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
/* Definitions for parameters to do with handler-routines */
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
+#include "sql_const.h"
+#include "mysqld.h" /* server_id */
+#include "sql_plugin.h" /* plugin_ref, st_plugin_int, plugin */
+#include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA */
+#include "sql_cache.h"
+#include "structs.h" /* SHOW_COMP_OPTION */
+
#include <my_handler.h>
#include <ft_global.h>
#include <keycache.h>
-#ifndef NO_HASH
-#define NO_HASH /* Not yet implemented */
-#endif
-
-#define USING_TRANSACTIONS
-
// the following is for checking tables
#define HA_ADMIN_ALREADY_DONE 1
@@ -127,6 +130,29 @@
*/
#define HA_BINLOG_ROW_CAPABLE (LL(1) << 34)
#define HA_BINLOG_STMT_CAPABLE (LL(1) << 35)
+/*
+ When a multiple key conflict happens in a REPLACE command mysql
+ expects the conflicts to be reported in the ascending order of
+ key names.
+
+ For e.g.
+
+ CREATE TABLE t1 (a INT, UNIQUE (a), b INT NOT NULL, UNIQUE (b), c INT NOT
+ NULL, INDEX(c));
+
+ REPLACE INTO t1 VALUES (1,1,1),(2,2,2),(2,1,3);
+
+ MySQL expects the conflict with 'a' to be reported before the conflict with
+ 'b'.
+
+ If the underlying storage engine does not report the conflicting keys in
+ ascending order, it causes unexpected errors when the REPLACE command is
+ executed.
+
+ This flag helps the underlying SE to inform the server that the keys are not
+ ordered.
+*/
+#define HA_DUPLICATE_KEY_NOT_IN_ORDER (LL(1) << 36)
/*
Set of all binlog flags. Currently only contain the capabilities
@@ -148,6 +174,8 @@
/*
These bits are set if different kinds of indexes can be created
off-line without re-create of the table (but with a table lock).
+ Partitioning needs both ADD and DROP to be supported by its underlying
+ handlers, due to error handling, see bug#57778.
*/
#define HA_ONLINE_ADD_INDEX_NO_WRITES (1L << 0) /*add index w/lock*/
#define HA_ONLINE_DROP_INDEX_NO_WRITES (1L << 1) /*drop index w/lock*/
@@ -217,6 +245,13 @@
#define MAX_HA 15
/*
+ Use this instead of 0 as the initial value for the slot number of
+ handlerton, so that we can distinguish uninitialized slot number
+ from slot 0.
+*/
+#define HA_SLOT_UNDEF ((uint)-1)
+
+/*
Parameters for open() (in register form->filestat)
HA_GET_INFO does an implicit HA_ABORT_IF_LOCKED
*/
@@ -277,6 +312,8 @@ enum legacy_db_type
DB_TYPE_MEMCACHE,
DB_TYPE_FALCON,
DB_TYPE_MARIA,
+ /** Performance schema engine. */
+ DB_TYPE_PERFORMANCE_SCHEMA,
DB_TYPE_FIRST_DYNAMIC=42,
DB_TYPE_DEFAULT=127 // Must be last
};
@@ -422,11 +459,7 @@ typedef struct xid_t XID;
/* for recover() handlerton call */
#define MIN_XID_LIST_SIZE 128
-#ifdef SAFEMALLOC
-#define MAX_XID_LIST_SIZE 256
-#else
#define MAX_XID_LIST_SIZE (1024*128)
-#endif
/*
These structures are used to pass information from a set of SQL commands
@@ -507,9 +540,50 @@ class st_alter_tablespace : public Sql_alloc
/* The handler for a table type. Will be included in the TABLE structure */
-struct st_table;
-typedef struct st_table TABLE;
-typedef struct st_table_share TABLE_SHARE;
+struct TABLE;
+
+/*
+ Make sure that the order of schema_tables and enum_schema_tables are the same.
+*/
+enum enum_schema_tables
+{
+ SCH_CHARSETS= 0,
+ SCH_COLLATIONS,
+ SCH_COLLATION_CHARACTER_SET_APPLICABILITY,
+ SCH_COLUMNS,
+ SCH_COLUMN_PRIVILEGES,
+ SCH_ENGINES,
+ SCH_EVENTS,
+ SCH_FILES,
+ SCH_GLOBAL_STATUS,
+ SCH_GLOBAL_VARIABLES,
+ SCH_KEY_COLUMN_USAGE,
+ SCH_OPEN_TABLES,
+ SCH_PARAMETERS,
+ SCH_PARTITIONS,
+ SCH_PLUGINS,
+ SCH_PROCESSLIST,
+ SCH_PROFILES,
+ SCH_REFERENTIAL_CONSTRAINTS,
+ SCH_PROCEDURES,
+ SCH_SCHEMATA,
+ SCH_SCHEMA_PRIVILEGES,
+ SCH_SESSION_STATUS,
+ SCH_SESSION_VARIABLES,
+ SCH_STATISTICS,
+ SCH_STATUS,
+ SCH_TABLES,
+ SCH_TABLESPACES,
+ SCH_TABLE_CONSTRAINTS,
+ SCH_TABLE_NAMES,
+ SCH_TABLE_PRIVILEGES,
+ SCH_TRIGGERS,
+ SCH_USER_PRIVILEGES,
+ SCH_VARIABLES,
+ SCH_VIEWS
+};
+
+struct TABLE_SHARE;
struct st_foreign_key_info;
typedef struct st_foreign_key_info FOREIGN_KEY_INFO;
typedef bool (stat_print_fn)(THD *thd, const char *type, uint type_len,
@@ -584,6 +658,7 @@ struct handler_iterator {
void *buffer;
};
+class handler;
/*
handlerton is a singleton structure - one instance per storage engine -
to provide access to storage engine functionality that works on the
@@ -672,9 +747,9 @@ struct handlerton
uint (*partition_flags)();
uint (*alter_table_flags)(uint flags);
int (*alter_tablespace)(handlerton *hton, THD *thd, st_alter_tablespace *ts_info);
- int (*fill_files_table)(handlerton *hton, THD *thd,
- TABLE_LIST *tables,
- class Item *cond);
+ int (*fill_is_table)(handlerton *hton, THD *thd, TABLE_LIST *tables,
+ class Item *cond,
+ enum enum_schema_tables);
uint32 flags; /* global handler flags */
/*
Those handlerton functions below are properly initialized at handler
@@ -769,6 +844,7 @@ struct THD_TRANS
bool modified_non_trans_table;
void reset() { no_2pc= FALSE; modified_non_trans_table= FALSE; }
+ bool is_empty() const { return ha_list == NULL; }
};
@@ -872,9 +948,6 @@ enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
ISO_REPEATABLE_READ, ISO_SERIALIZABLE};
-enum ndb_distribution { ND_KEYHASH= 0, ND_LINHASH= 1 };
-
-
typedef struct {
ulonglong data_file_length;
ulonglong max_data_file_length;
@@ -886,7 +959,7 @@ typedef struct {
ulong check_time;
ulong update_time;
ulonglong check_sum;
-} PARTITION_INFO;
+} PARTITION_STATS;
#define UNDEF_NODEGROUP 65535
class Item;
@@ -930,7 +1003,6 @@ typedef struct st_ha_create_information
uint merge_insert_method;
uint extra_size; /* length of extra data segment */
enum enum_ha_unused unused1;
- bool table_existed; /* 1 in create if table existed */
bool frm_only; /* 1 if no ha_create_table() */
bool varchar; /* 1 if table has a VARCHAR */
enum ha_storage_media storage_media; /* DEFAULT, DISK or MEMORY */
@@ -943,6 +1015,7 @@ typedef struct st_key_create_information
enum ha_key_alg algorithm;
ulong block_size;
LEX_STRING parser_name;
+ LEX_STRING comment;
} KEY_CREATE_INFO;
@@ -1006,7 +1079,6 @@ typedef class Item COND;
typedef struct st_ha_check_opt
{
st_ha_check_opt() {} /* Remove gcc warning */
- ulong sort_buffer_size;
uint flags; /* isam layer flags (e.g. for myisamchk) */
uint sql_flags; /* sql layer flags - for something myisamchk cannot do */
KEY_CACHE *key_cache; /* new key cache when changing key cache */
@@ -1087,8 +1159,8 @@ class handler :public Sql_alloc
public:
typedef ulonglong Table_flags;
protected:
- struct st_table_share *table_share; /* The table definition */
- struct st_table *table; /* The current open table */
+ TABLE_SHARE *table_share; /* The table definition */
+ TABLE *table; /* The current open table */
Table_flags cached_table_flags; /* Set on init() and open() */
ha_rows estimation_rows_to_insert;
@@ -1151,6 +1223,20 @@ public:
*/
uint auto_inc_intervals_count;
+ /**
+ Instrumented table associated with this handler.
+ This member should be set to NULL when no instrumentation is in place,
+ so that linking an instrumented/non instrumented server/plugin works.
+ For example:
+ - the server is compiled with the instrumentation.
+ The server expects either NULL or valid pointers in m_psi.
+ - an engine plugin is compiled without instrumentation.
+ The plugin can not leave this pointer uninitialized,
+ or can not leave a trash value on purpose in this pointer,
+ as this would crash the server.
+ */
+ PSI_table *m_psi;
+
handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
:table_share(share_arg), table(0),
estimation_rows_to_insert(0), ht(ht_arg),
@@ -1159,12 +1245,13 @@ public:
ft_handler(0), inited(NONE),
locked(FALSE), implicit_emptied(0),
pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0),
- auto_inc_intervals_count(0)
+ auto_inc_intervals_count(0),
+ m_psi(NULL)
{}
virtual ~handler(void)
{
DBUG_ASSERT(locked == FALSE);
- /* TODO: DBUG_ASSERT(inited == NONE); */
+ DBUG_ASSERT(inited == NONE);
}
virtual handler *clone(MEM_ROOT *mem_root);
/** This is called after create to allow us to set up cached variables */
@@ -1246,9 +1333,8 @@ public:
int ha_bulk_update_row(const uchar *old_data, uchar *new_data,
uint *dup_key_found);
int ha_delete_all_rows();
+ int ha_truncate();
int ha_reset_auto_increment(ulonglong value);
- int ha_backup(THD* thd, HA_CHECK_OPT* check_opt);
- int ha_restore(THD* thd, HA_CHECK_OPT* check_opt);
int ha_optimize(THD* thd, HA_CHECK_OPT* check_opt);
int ha_analyze(THD* thd, HA_CHECK_OPT* check_opt);
bool ha_check_and_repair(THD *thd);
@@ -1477,7 +1563,7 @@ public:
*/
virtual void position(const uchar *record)=0;
virtual int info(uint)=0; // see my_base.h for full description
- virtual void get_dynamic_partition_info(PARTITION_INFO *stat_info,
+ virtual void get_dynamic_partition_info(PARTITION_STATS *stat_info,
uint part_id);
virtual int extra(enum ha_extra_function operation)
{ return 0; }
@@ -1539,9 +1625,7 @@ public:
{ return HA_ADMIN_NOT_IMPLEMENTED; }
/* end of the list of admin commands */
- virtual int dump(THD* thd, int fd = -1) { return HA_ERR_WRONG_COMMAND; }
virtual int indexes_are_disabled(void) {return 0;}
- virtual int net_read_dump(NET* net) { return HA_ERR_WRONG_COMMAND; }
virtual char *update_table_comment(const char * comment)
{ return (char*) comment;}
virtual void append_create_info(String *packet) {}
@@ -1563,8 +1647,33 @@ public:
{ return(NULL);} /* gets tablespace name from handler */
/** used in ALTER TABLE; 1 if changing storage engine is allowed */
virtual bool can_switch_engines() { return 1; }
- /** used in REPLACE; is > 0 if table is referred by a FOREIGN KEY */
- virtual int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
+ /**
+ Get the list of foreign keys in this table.
+
+ @remark Returns the set of foreign keys where this table is the
+ dependent or child table.
+
+ @param thd The thread handle.
+ @param f_key_list[out] The list of foreign keys.
+
+ @return The handler error code or zero for success.
+ */
+ virtual int
+ get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
+ { return 0; }
+ /**
+ Get the list of foreign keys referencing this table.
+
+ @remark Returns the set of foreign keys where this table is the
+ referenced or parent table.
+
+ @param thd The thread handle.
+ @param f_key_list[out] The list of foreign keys.
+
+ @return The handler error code or zero for success.
+ */
+ virtual int
+ get_parent_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
{ return 0; }
virtual uint referenced_by_foreign_key() { return 0;}
virtual void init_table_handle_for_HANDLER()
@@ -1769,6 +1878,39 @@ protected:
THD *ha_thd(void) const;
/**
+ Acquire the instrumented table information from a table share.
+ @param share a table share
+ @return an instrumented table share, or NULL.
+ */
+ PSI_table_share *ha_table_share_psi(const TABLE_SHARE *share) const;
+
+ inline void psi_open()
+ {
+ DBUG_ASSERT(m_psi == NULL);
+ DBUG_ASSERT(table_share != NULL);
+#ifdef HAVE_PSI_INTERFACE
+ if (PSI_server)
+ {
+ PSI_table_share *share_psi= ha_table_share_psi(table_share);
+ if (share_psi)
+ m_psi= PSI_server->open_table(share_psi, this);
+ }
+#endif
+ }
+
+ inline void psi_close()
+ {
+#ifdef HAVE_PSI_INTERFACE
+ if (PSI_server && m_psi)
+ {
+ PSI_server->close_table(m_psi);
+ m_psi= NULL; /* instrumentation handle, invalid after close_table() */
+ }
+#endif
+ DBUG_ASSERT(m_psi == NULL);
+ }
+
+ /**
Default rename_table() and delete_table() rename/delete files with a
given name and extensions from bas_ext().
@@ -1896,27 +2038,37 @@ private:
This is called to delete all rows in a table
If the handler don't support this, then this function will
return HA_ERR_WRONG_COMMAND and MySQL will delete the rows one
- by one. It should reset auto_increment if
- thd->lex->sql_command == SQLCOM_TRUNCATE.
+ by one.
*/
virtual int delete_all_rows()
{ return (my_errno=HA_ERR_WRONG_COMMAND); }
/**
- Reset the auto-increment counter to the given value, i.e. the next row
- inserted will get the given value. This is called e.g. after TRUNCATE
- is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
- returned by storage engines that don't support this operation.
+ Quickly remove all rows from a table.
+
+ @remark This method is responsible for implementing MySQL's TRUNCATE
+ TABLE statement, which is a DDL operation. As such, a engine
+ can bypass certain integrity checks and in some cases avoid
+ fine-grained locking (e.g. row locks) which would normally be
+ required for a DELETE statement.
+
+ @remark Typically, truncate is not used if it can result in integrity
+ violation. For example, truncate is not used when a foreign
+ key references the table, but it might be used if foreign key
+ checks are disabled.
+
+ @remark Engine is responsible for resetting the auto-increment counter.
+
+ @remark The table is locked in exclusive mode.
*/
- virtual int reset_auto_increment(ulonglong value)
+ virtual int truncate()
{ return HA_ERR_WRONG_COMMAND; }
- virtual int backup(THD* thd, HA_CHECK_OPT* check_opt)
- { return HA_ADMIN_NOT_IMPLEMENTED; }
/**
- Restore assumes .frm file must exist, and that generate_table() has been
- called; It will just copy the data file and run repair.
+ Reset the auto-increment counter to the given value, i.e. the next row
+ inserted will get the given value. HA_ERR_WRONG_COMMAND is returned by
+ storage engines that don't support this operation.
*/
- virtual int restore(THD* thd, HA_CHECK_OPT* check_opt)
- { return HA_ADMIN_NOT_IMPLEMENTED; }
+ virtual int reset_auto_increment(ulonglong value)
+ { return HA_ERR_WRONG_COMMAND; }
virtual int optimize(THD* thd, HA_CHECK_OPT* check_opt)
{ return HA_ADMIN_NOT_IMPLEMENTED; }
virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt)
@@ -1954,13 +2106,9 @@ extern const char *ha_row_type[];
extern MYSQL_PLUGIN_IMPORT const char *tx_isolation_names[];
extern MYSQL_PLUGIN_IMPORT const char *binlog_format_names[];
extern TYPELIB tx_isolation_typelib;
-extern TYPELIB myisam_stats_method_typelib;
+extern const char *myisam_stats_method_names[];
extern ulong total_ha, total_ha_2pc;
- /* Wrapper functions */
-#define ha_commit(thd) (ha_commit_trans((thd), TRUE))
-#define ha_rollback(thd) (ha_rollback_trans((thd), TRUE))
-
/* lookups */
handlerton *ha_default_handlerton(THD *thd);
plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name);
@@ -2017,6 +2165,8 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat);
/* discovery */
int ha_create_table_from_engine(THD* thd, const char *db, const char *name);
+bool ha_check_if_table_exists(THD* thd, const char *db, const char *name,
+ bool *exists);
int ha_discover(THD* thd, const char* dbname, const char* name,
uchar** frmblob, size_t* frmlen);
int ha_find_files(THD *thd,const char *db,const char *path,
@@ -2028,7 +2178,6 @@ extern "C" int ha_init_key_cache(const char *name, KEY_CACHE *key_cache);
int ha_resize_key_cache(KEY_CACHE *key_cache);
int ha_change_key_cache_param(KEY_CACHE *key_cache);
int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache);
-int ha_end_key_cache(KEY_CACHE *key_cache);
/* report to InnoDB that control passes to the client */
int ha_release_temporary_latches(THD *thd);
@@ -2037,13 +2186,12 @@ int ha_release_temporary_latches(THD *thd);
int ha_start_consistent_snapshot(THD *thd);
int ha_commit_or_rollback_by_xid(XID *xid, bool commit);
int ha_commit_one_phase(THD *thd, bool all);
+int ha_commit_trans(THD *thd, bool all);
int ha_rollback_trans(THD *thd, bool all);
int ha_prepare(THD *thd);
int ha_recover(HASH *commit_list);
/* transactions: these functions never call handlerton functions directly */
-int ha_commit_trans(THD *thd, bool all);
-int ha_autocommit_or_rollback(THD *thd, int error);
int ha_enable_transaction(THD *thd, bool on);
/* savepoints */
@@ -2080,3 +2228,15 @@ int ha_binlog_end(THD *thd);
#define ha_binlog_wait(a) do {} while (0)
#define ha_binlog_end(a) do {} while (0)
#endif
+
+const char *get_canonical_filename(handler *file, const char *path,
+ char *tmp_path);
+bool mysql_xa_recover(THD *thd);
+
+
+inline const char *table_case_name(HA_CREATE_INFO *info, const char *name)
+{
+ return ((lower_case_table_names == 2 && info->alias) ? info->alias : name);
+}
+
+#endif /* HANDLER_INCLUDED */
diff --git a/sql/hash_filo.cc b/sql/hash_filo.cc
index 9303120e18a..d10b7fa4907 100644
--- a/sql/hash_filo.cc
+++ b/sql/hash_filo.cc
@@ -23,5 +23,5 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
#include "hash_filo.h"
diff --git a/sql/hash_filo.h b/sql/hash_filo.h
index ab13d338695..859b4713940 100644
--- a/sql/hash_filo.h
+++ b/sql/hash_filo.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003, 2005 MySQL AB
+/* Copyright (C) 2000-2003, 2005 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -26,6 +26,10 @@
#pragma interface /* gcc class interface */
#endif
+#include "hash.h" /* my_hash_get_key, my_hash_free_key, HASH */
+#include "m_string.h" /* bzero */
+#include "mysqld.h" /* key_hash_filo_lock */
+
class hash_filo_element
{
hash_filo_element *next_used,*prev_used;
@@ -38,18 +42,18 @@ class hash_filo_element
class hash_filo
{
const uint size, key_offset, key_length;
- const hash_get_key get_key;
- hash_free_key free_element;
+ const my_hash_get_key get_key;
+ my_hash_free_key free_element;
bool init;
CHARSET_INFO *hash_charset;
hash_filo_element *first_link,*last_link;
public:
- pthread_mutex_t lock;
+ mysql_mutex_t lock;
HASH cache;
hash_filo(uint size_arg, uint key_offset_arg , uint key_length_arg,
- hash_get_key get_key_arg, hash_free_key free_element_arg,
+ my_hash_get_key get_key_arg, my_hash_free_key free_element_arg,
CHARSET_INFO *hash_charset_arg)
:size(size_arg), key_offset(key_offset_arg), key_length(key_length_arg),
get_key(get_key_arg), free_element(free_element_arg),init(0),
@@ -63,8 +67,8 @@ public:
if (init)
{
if (cache.array.buffer) /* Avoid problems with thread library */
- (void) hash_free(&cache);
- pthread_mutex_destroy(&lock);
+ (void) my_hash_free(&cache);
+ mysql_mutex_destroy(&lock);
}
}
void clear(bool locked=0)
@@ -72,22 +76,22 @@ public:
if (!init)
{
init=1;
- (void) pthread_mutex_init(&lock,MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_hash_filo_lock, &lock, MY_MUTEX_INIT_FAST);
}
if (!locked)
- (void) pthread_mutex_lock(&lock);
- (void) hash_free(&cache);
- (void) hash_init(&cache,hash_charset,size,key_offset,
+ mysql_mutex_lock(&lock);
+ (void) my_hash_free(&cache);
+ (void) my_hash_init(&cache,hash_charset,size,key_offset,
key_length, get_key, free_element,0);
if (!locked)
- (void) pthread_mutex_unlock(&lock);
+ mysql_mutex_unlock(&lock);
first_link=last_link=0;
}
hash_filo_element *search(uchar* key, size_t length)
{
hash_filo_element *entry=(hash_filo_element*)
- hash_search(&cache,(uchar*) key,length);
+ my_hash_search(&cache,(uchar*) key,length);
if (entry)
{ // Found; link it first
if (entry != first_link)
@@ -113,7 +117,7 @@ public:
{
hash_filo_element *tmp=last_link;
last_link=last_link->prev_used;
- hash_delete(&cache,(uchar*) tmp);
+ my_hash_delete(&cache,(uchar*) tmp);
}
if (my_hash_insert(&cache,(uchar*) entry))
{
diff --git a/sql/hostname.cc b/sql/hostname.cc
index c8cf46383a9..5311d9ada73 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2006 MySQL AB
+/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -18,15 +18,24 @@
@file
@brief
- Get hostname for an IP.
+ Get hostname for an IP address.
- Hostnames are checked with reverse name lookup and
- checked that they doesn't resemble an ip.
+ Hostnames are checked with reverse name lookup and checked that they
+ doesn't resemble an IP address.
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "hostname.h"
+#include "my_global.h"
+#ifndef __WIN__
+#include <netdb.h> // getservbyname, servent
+#endif
#include "hash_filo.h"
#include <m_ctype.h>
+#include "log.h" // sql_print_warning,
+ // sql_print_information
+#include "violite.h" // vio_getnameinfo,
+ // vio_get_normalized_ip_string
#ifdef __cplusplus
extern "C" { // Because of SCO 3.2V4.2
#endif
@@ -34,24 +43,54 @@ extern "C" { // Because of SCO 3.2V4.2
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
-#include <netdb.h>
#include <sys/utsname.h>
#endif // __WIN__
#ifdef __cplusplus
}
#endif
+/*
+ HOST_ENTRY_KEY_SIZE -- size of IP address string in the hash cache.
+*/
+
+#define HOST_ENTRY_KEY_SIZE INET6_ADDRSTRLEN
+
+/**
+ An entry in the hostname hash table cache.
+
+ Host name cache does two things:
+ - caches host names to save DNS look ups;
+ - counts connect errors from IP.
-class host_entry :public hash_filo_element
+ Host name can be NULL (that means DNS look up failed), but connect errors
+ still are counted.
+*/
+
+class Host_entry :public hash_filo_element
{
public:
- char ip[sizeof(((struct in_addr *) 0)->s_addr)];
- uint errors;
- char *hostname;
+ /**
+ Client IP address. This is the key used with the hash table.
+
+ The client IP address is always expressed in IPv6, even when the
+ network IPv6 stack is not present.
+
+ This IP address is never used to connect to a socket.
+ */
+ char ip_key[HOST_ENTRY_KEY_SIZE];
+
+ /**
+ Number of errors during handshake phase from the IP address.
+ */
+ uint connect_errors;
+
+ /**
+ One of the host names for the IP address. May be NULL.
+ */
+ const char *hostname;
};
static hash_filo *hostname_cache;
-static pthread_mutex_t LOCK_hostname;
void hostname_cache_refresh()
{
@@ -60,219 +99,468 @@ void hostname_cache_refresh()
bool hostname_cache_init()
{
- host_entry tmp;
- uint offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp);
- if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset,
- sizeof(struct in_addr),NULL,
- (hash_free_key) free,
- &my_charset_bin)))
+ Host_entry tmp;
+ uint key_offset= (uint) ((char*) (&tmp.ip_key) - (char*) &tmp);
+
+ if (!(hostname_cache= new hash_filo(HOST_CACHE_SIZE,
+ key_offset, HOST_ENTRY_KEY_SIZE,
+ NULL, (my_hash_free_key) free,
+ &my_charset_bin)))
return 1;
+
hostname_cache->clear();
- (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
+
return 0;
}
void hostname_cache_free()
{
- if (hostname_cache)
- {
- (void) pthread_mutex_destroy(&LOCK_hostname);
- delete hostname_cache;
- hostname_cache= 0;
- }
+ delete hostname_cache;
+ hostname_cache= NULL;
}
+static void prepare_hostname_cache_key(const char *ip_string,
+ char *ip_key)
+{
+ int ip_string_length= strlen(ip_string);
+ DBUG_ASSERT(ip_string_length < HOST_ENTRY_KEY_SIZE);
-static void add_hostname(struct in_addr *in,const char *name)
+ memset(ip_key, 0, HOST_ENTRY_KEY_SIZE);
+ memcpy(ip_key, ip_string, ip_string_length);
+}
+
+static inline Host_entry *hostname_cache_search(const char *ip_key)
{
- if (!(specialflag & SPECIAL_NO_HOST_CACHE))
+ return (Host_entry *) hostname_cache->search((uchar *) ip_key, 0);
+}
+
+static bool add_hostname_impl(const char *ip_key, const char *hostname)
+{
+ if (hostname_cache_search(ip_key))
+ return FALSE;
+
+ size_t hostname_size= hostname ? strlen(hostname) + 1 : 0;
+
+ Host_entry *entry= (Host_entry *) malloc(sizeof (Host_entry) + hostname_size);
+
+ if (!entry)
+ return TRUE;
+
+ char *hostname_copy;
+
+ memcpy(&entry->ip_key, ip_key, HOST_ENTRY_KEY_SIZE);
+
+ if (hostname_size)
{
- VOID(pthread_mutex_lock(&hostname_cache->lock));
- host_entry *entry;
- if (!(entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
- {
- uint length=name ? (uint) strlen(name) : 0;
+ hostname_copy= (char *) (entry + 1);
+ memcpy(hostname_copy, hostname, hostname_size);
- if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1)))
- {
- char *new_name;
- memcpy_fixed(&entry->ip, &in->s_addr, sizeof(in->s_addr));
- if (length)
- memcpy(new_name= (char *) (entry+1), name, length+1);
- else
- new_name=0;
- entry->hostname=new_name;
- entry->errors=0;
- (void) hostname_cache->add(entry);
- }
- }
- VOID(pthread_mutex_unlock(&hostname_cache->lock));
+ DBUG_PRINT("info", ("Adding '%s' -> '%s' to the hostname cache...'",
+ (const char *) ip_key,
+ (const char *) hostname_copy));
+ }
+ else
+ {
+ hostname_copy= NULL;
+
+ DBUG_PRINT("info", ("Adding '%s' -> NULL to the hostname cache...'",
+ (const char *) ip_key));
}
+
+ entry->hostname= hostname_copy;
+ entry->connect_errors= 0;
+
+ return hostname_cache->add(entry);
}
+static bool add_hostname(const char *ip_key, const char *hostname)
+{
+ if (specialflag & SPECIAL_NO_HOST_CACHE)
+ return FALSE;
+
+ mysql_mutex_lock(&hostname_cache->lock);
+
+ bool err_status= add_hostname_impl(ip_key, hostname);
-inline void add_wrong_ip(struct in_addr *in)
+ mysql_mutex_unlock(&hostname_cache->lock);
+
+ return err_status;
+}
+
+void inc_host_errors(const char *ip_string)
{
- add_hostname(in,NullS);
+ if (!ip_string)
+ return;
+
+ char ip_key[HOST_ENTRY_KEY_SIZE];
+ prepare_hostname_cache_key(ip_string, ip_key);
+
+ mysql_mutex_lock(&hostname_cache->lock);
+
+ Host_entry *entry= hostname_cache_search(ip_key);
+
+ if (entry)
+ entry->connect_errors++;
+
+ mysql_mutex_unlock(&hostname_cache->lock);
}
-void inc_host_errors(struct in_addr *in)
+
+void reset_host_errors(const char *ip_string)
{
- VOID(pthread_mutex_lock(&hostname_cache->lock));
- host_entry *entry;
- if ((entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
- entry->errors++;
- VOID(pthread_mutex_unlock(&hostname_cache->lock));
+ if (!ip_string)
+ return;
+
+ char ip_key[HOST_ENTRY_KEY_SIZE];
+ prepare_hostname_cache_key(ip_string, ip_key);
+
+ mysql_mutex_lock(&hostname_cache->lock);
+
+ Host_entry *entry= hostname_cache_search(ip_key);
+
+ if (entry)
+ entry->connect_errors= 0;
+
+ mysql_mutex_unlock(&hostname_cache->lock);
}
-void reset_host_errors(struct in_addr *in)
+
+static inline bool is_ip_loopback(const struct sockaddr *ip)
{
- VOID(pthread_mutex_lock(&hostname_cache->lock));
- host_entry *entry;
- if ((entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
- entry->errors=0;
- VOID(pthread_mutex_unlock(&hostname_cache->lock));
+ switch (ip->sa_family) {
+ case AF_INET:
+ {
+ /* Check for IPv4 127.0.0.1. */
+ struct in_addr *ip4= &((struct sockaddr_in *) ip)->sin_addr;
+ return ntohl(ip4->s_addr) == INADDR_LOOPBACK;
+ }
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ /* Check for IPv6 ::1. */
+ struct in6_addr *ip6= &((struct sockaddr_in6 *) ip)->sin6_addr;
+ return IN6_IS_ADDR_LOOPBACK(ip6);
+ }
+#endif /* HAVE_IPV6 */
+
+ default:
+ return FALSE;
+ }
}
-/* Deal with systems that don't defined INADDR_LOOPBACK */
-#ifndef INADDR_LOOPBACK
-#define INADDR_LOOPBACK 0x7f000001UL
-#endif
+static inline bool is_hostname_valid(const char *hostname)
+{
+ /*
+ A hostname is invalid if it starts with a number followed by a dot
+ (IPv4 address).
+ */
+
+ if (!my_isdigit(&my_charset_latin1, hostname[0]))
+ return TRUE;
+
+ const char *p= hostname + 1;
+
+ while (my_isdigit(&my_charset_latin1, *p))
+ ++p;
+
+ return *p != '.';
+}
+
+/**
+ Resolve IP-address to host name.
-char * ip_to_hostname(struct in_addr *in, uint *errors)
+ This function does the following things:
+ - resolves IP-address;
+ - employs Forward Confirmed Reverse DNS technique to validate IP-address;
+ - returns host name if IP-address is validated;
+ - set value to out-variable connect_errors -- this variable represents the
+ number of connection errors from the specified IP-address.
+
+ NOTE: connect_errors are counted (are supported) only for the clients
+ where IP-address can be resolved and FCrDNS check is passed.
+
+ @param [in] ip_storage IP address (sockaddr). Must be set.
+ @param [in] ip_string IP address (string). Must be set.
+ @param [out] hostname
+ @param [out] connect_errors
+
+ @return Error status
+ @retval FALSE Success
+ @retval TRUE Error
+
+ The function does not set/report MySQL server error in case of failure.
+ It's caller's responsibility to handle failures of this function
+ properly.
+*/
+
+bool ip_to_hostname(struct sockaddr_storage *ip_storage,
+ const char *ip_string,
+ char **hostname, uint *connect_errors)
{
- uint i;
- host_entry *entry;
+ const struct sockaddr *ip= (const sockaddr *) ip_storage;
+ int err_code;
+ bool err_status;
+
DBUG_ENTER("ip_to_hostname");
- *errors=0;
+ DBUG_PRINT("info", ("IP address: '%s'; family: %d.",
+ (const char *) ip_string,
+ (int) ip->sa_family));
+
+ /* Check if we have loopback address (127.0.0.1 or ::1). */
+
+ if (is_ip_loopback(ip))
+ {
+ DBUG_PRINT("info", ("Loopback address detected."));
- /* We always treat the loopback address as "localhost". */
- if (in->s_addr == htonl(INADDR_LOOPBACK)) // is expanded inline by gcc
- DBUG_RETURN((char *)my_localhost);
+ *connect_errors= 0; /* Do not count connect errors from localhost. */
+ *hostname= (char *) my_localhost;
+
+ DBUG_RETURN(FALSE);
+ }
+
+ /* Prepare host name cache key. */
+
+ char ip_key[HOST_ENTRY_KEY_SIZE];
+ prepare_hostname_cache_key(ip_string, ip_key);
+
+ /* Check first if we have host name in the cache. */
- /* Check first if we have name in cache */
if (!(specialflag & SPECIAL_NO_HOST_CACHE))
{
- VOID(pthread_mutex_lock(&hostname_cache->lock));
- if ((entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
+ mysql_mutex_lock(&hostname_cache->lock);
+
+ Host_entry *entry= hostname_cache_search(ip_key);
+
+ if (entry)
{
- char *name;
- if (!entry->hostname)
- name=0; // Don't allow connection
- else
- name=my_strdup(entry->hostname,MYF(0));
- *errors= entry->errors;
- VOID(pthread_mutex_unlock(&hostname_cache->lock));
- DBUG_RETURN(name);
+ *connect_errors= entry->connect_errors;
+ *hostname= NULL;
+
+ if (entry->hostname)
+ *hostname= my_strdup(entry->hostname, MYF(0));
+
+ DBUG_PRINT("info",("IP (%s) has been found in the cache. "
+ "Hostname: '%s'; connect_errors: %d",
+ (const char *) ip_key,
+ (const char *) (*hostname? *hostname : "null"),
+ (int) *connect_errors));
+
+ mysql_mutex_unlock(&hostname_cache->lock);
+
+ DBUG_RETURN(FALSE);
}
- VOID(pthread_mutex_unlock(&hostname_cache->lock));
- }
- struct hostent *hp, *check;
- char *name;
- LINT_INIT(check);
-#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
- char buff[GETHOSTBYADDR_BUFF_SIZE],buff2[GETHOSTBYNAME_BUFF_SIZE];
- int tmp_errno;
- struct hostent tmp_hostent, tmp_hostent2;
-#ifdef HAVE_purify
- bzero(buff,sizeof(buff)); // Bug in purify
-#endif
- if (!(hp=gethostbyaddr_r((char*) in,sizeof(*in),
- AF_INET,
- &tmp_hostent,buff,sizeof(buff),&tmp_errno)))
- {
- DBUG_PRINT("error",("gethostbyaddr_r returned %d",tmp_errno));
- return 0;
+ mysql_mutex_unlock(&hostname_cache->lock);
}
- if (!(check=my_gethostbyname_r(hp->h_name,&tmp_hostent2,buff2,sizeof(buff2),
- &tmp_errno)))
+
+ /*
+ Resolve host name. Return an error if a host name can not be resolved
+ (instead of returning the numeric form of the host name).
+ */
+
+ char hostname_buffer[NI_MAXHOST];
+
+ DBUG_PRINT("info", ("Resolving '%s'...", (const char *) ip_key));
+
+ err_code= vio_getnameinfo(ip, hostname_buffer, NI_MAXHOST, NULL, 0,
+ NI_NAMEREQD);
+
+ if (err_code == EAI_NONAME)
{
- DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno));
/*
- Don't cache responses when the DSN server is down, as otherwise
- transient DNS failure may leave any number of clients (those
- that attempted to connect during the outage) unable to connect
- indefinitely.
+ There is no reverse address mapping for the IP address. A host name
+ can not be resolved.
*/
- if (tmp_errno == HOST_NOT_FOUND || tmp_errno == NO_DATA)
- add_wrong_ip(in);
- my_gethostbyname_r_free();
- DBUG_RETURN(0);
- }
- if (!hp->h_name[0])
- {
- DBUG_PRINT("error",("Got an empty hostname"));
- add_wrong_ip(in);
- my_gethostbyname_r_free();
- DBUG_RETURN(0); // Don't allow empty hostnames
- }
- if (!(name=my_strdup(hp->h_name,MYF(0))))
- {
- my_gethostbyname_r_free();
- DBUG_RETURN(0); // out of memory
+
+ DBUG_PRINT("error", ("IP address '%s' could not be resolved: "
+ "no reverse address mapping.",
+ (const char *) ip_key));
+
+ sql_print_warning("IP address '%s' could not be resolved: "
+ "no reverse address mapping.",
+ (const char *) ip_key);
+
+ err_status= add_hostname(ip_key, NULL);
+
+ *hostname= NULL;
+ *connect_errors= 0; /* New IP added to the cache. */
+
+ DBUG_RETURN(err_status);
}
- my_gethostbyname_r_free();
-#else
- VOID(pthread_mutex_lock(&LOCK_hostname));
- if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET)))
+ else if (err_code)
{
- VOID(pthread_mutex_unlock(&LOCK_hostname));
- DBUG_PRINT("error",("gethostbyaddr returned %d",errno));
+ DBUG_PRINT("error", ("IP address '%s' could not be resolved: "
+ "getnameinfo() returned %d.",
+ (const char *) ip_key,
+ (int) err_code));
- if (errno == HOST_NOT_FOUND || errno == NO_DATA)
- goto add_wrong_ip_and_return;
- /* Failure, don't cache responce */
- DBUG_RETURN(0);
+ sql_print_warning("IP address '%s' could not be resolved: "
+ "getnameinfo() returned error (code: %d).",
+ (const char *) ip_key,
+ (int) err_code);
+
+ DBUG_RETURN(TRUE);
}
- if (!hp->h_name[0]) // Don't allow empty hostnames
+
+ DBUG_PRINT("info", ("IP '%s' resolved to '%s'.",
+ (const char *) ip_key,
+ (const char *) hostname_buffer));
+
+ /*
+ Validate hostname: the server does not accept host names, which
+ resemble IP addresses.
+
+ The thing is that theoretically, a host name can be in a form of IPv4
+ address (123.example.org, or 1.2 or even 1.2.3.4). We have to deny such
+ host names because ACL-systems is not designed to work with them.
+
+ For example, it is possible to specify a host name mask (like
+ 192.168.1.%) for an ACL rule. Then, if IPv4-like hostnames are allowed,
+ there is a security hole: instead of allowing access for
+ 192.168.1.0/255 network (which was assumed by the user), the access
+ will be allowed for host names like 192.168.1.example.org.
+ */
+
+ if (!is_hostname_valid(hostname_buffer))
{
- VOID(pthread_mutex_unlock(&LOCK_hostname));
- DBUG_PRINT("error",("Got an empty hostname"));
- goto add_wrong_ip_and_return;
+ DBUG_PRINT("error", ("IP address '%s' has been resolved "
+ "to the host name '%s', which resembles "
+ "IPv4-address itself.",
+ (const char *) ip_key,
+ (const char *) hostname_buffer));
+
+ sql_print_warning("IP address '%s' has been resolved "
+ "to the host name '%s', which resembles "
+ "IPv4-address itself.",
+ (const char *) ip_key,
+ (const char *) hostname_buffer);
+
+ err_status= add_hostname(ip_key, NULL);
+
+ *hostname= NULL;
+ *connect_errors= 0; /* New IP added to the cache. */
+
+ DBUG_RETURN(err_status);
}
- if (!(name=my_strdup(hp->h_name,MYF(0))))
+
+ /* Get IP-addresses for the resolved host name (FCrDNS technique). */
+
+ struct addrinfo hints;
+ struct addrinfo *addr_info_list;
+
+ memset(&hints, 0, sizeof (struct addrinfo));
+ hints.ai_flags= AI_PASSIVE;
+ hints.ai_socktype= SOCK_STREAM;
+ hints.ai_family= AF_UNSPEC;
+
+ DBUG_PRINT("info", ("Getting IP addresses for hostname '%s'...",
+ (const char *) hostname_buffer));
+
+ err_code= getaddrinfo(hostname_buffer, NULL, &hints, &addr_info_list);
+
+ if (err_code == EAI_NONAME)
{
- VOID(pthread_mutex_unlock(&LOCK_hostname));
- DBUG_RETURN(0); // out of memory
+ /*
+ Don't cache responses when the DNS server is down, as otherwise
+ transient DNS failure may leave any number of clients (those
+ that attempted to connect during the outage) unable to connect
+ indefinitely.
+ */
+
+ err_status= add_hostname(ip_key, NULL);
+
+ *hostname= NULL;
+ *connect_errors= 0; /* New IP added to the cache. */
+
+ DBUG_RETURN(err_status);
}
- check=gethostbyname(name);
- VOID(pthread_mutex_unlock(&LOCK_hostname));
- if (!check)
+ else if (err_code)
{
- DBUG_PRINT("error",("gethostbyname returned %d",errno));
- my_free(name,MYF(0));
- DBUG_RETURN(0);
+ DBUG_PRINT("error", ("getaddrinfo() failed with error code %d.", err_code));
+ DBUG_RETURN(TRUE);
}
-#endif
- /* Don't accept hostnames that starts with digits because they may be
- false ip:s */
- if (my_isdigit(&my_charset_latin1,name[0]))
+ /* Check that getaddrinfo() returned the used IP (FCrDNS technique). */
+
+ DBUG_PRINT("info", ("The following IP addresses found for '%s':",
+ (const char *) hostname_buffer));
+
+ for (struct addrinfo *addr_info= addr_info_list;
+ addr_info; addr_info= addr_info->ai_next)
{
- char *pos;
- for (pos= name+1 ; my_isdigit(&my_charset_latin1,*pos); pos++) ;
- if (*pos == '.')
+ char ip_buffer[HOST_ENTRY_KEY_SIZE];
+
{
- DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'"));
- my_free(name,MYF(0));
- goto add_wrong_ip_and_return;
+ err_status=
+ vio_get_normalized_ip_string(addr_info->ai_addr, addr_info->ai_addrlen,
+ ip_buffer, sizeof (ip_buffer));
+ DBUG_ASSERT(!err_status);
+ }
+
+ DBUG_PRINT("info", (" - '%s'", (const char *) ip_buffer));
+
+ if (strcmp(ip_key, ip_buffer) == 0)
+ {
+ /* Copy host name string to be stored in the cache. */
+
+ *hostname= my_strdup(hostname_buffer, MYF(0));
+
+ if (!*hostname)
+ {
+ DBUG_PRINT("error", ("Out of memory."));
+
+ freeaddrinfo(addr_info_list);
+ DBUG_RETURN(TRUE);
+ }
+
+ break;
}
}
- /* Check that 'gethostbyname' returned the used ip */
- for (i=0; check->h_addr_list[i]; i++)
+ /* Log resolved IP-addresses if no match was found. */
+
+ if (!*hostname)
{
- if (*(uint32*)(check->h_addr_list)[i] == in->s_addr)
+ sql_print_information("Hostname '%s' does not resolve to '%s'.",
+ (const char *) hostname_buffer,
+ (const char *) ip_key);
+ sql_print_information("Hostname '%s' has the following IP addresses:",
+ (const char *) hostname_buffer);
+
+ for (struct addrinfo *addr_info= addr_info_list;
+ addr_info; addr_info= addr_info->ai_next)
{
- add_hostname(in,name);
- DBUG_RETURN(name);
+ char ip_buffer[HOST_ENTRY_KEY_SIZE];
+
+ err_status=
+ vio_get_normalized_ip_string(addr_info->ai_addr, addr_info->ai_addrlen,
+ ip_buffer, sizeof (ip_buffer));
+ DBUG_ASSERT(!err_status);
+
+ sql_print_information(" - %s\n", (const char *) ip_buffer);
}
}
- DBUG_PRINT("error",("Couldn't verify hostname with gethostbyname"));
- my_free(name,MYF(0));
-add_wrong_ip_and_return:
- add_wrong_ip(in);
- DBUG_RETURN(0);
+ /* Free the result of getaddrinfo(). */
+
+ freeaddrinfo(addr_info_list);
+
+ /* Add an entry for the IP to the cache. */
+
+ if (*hostname)
+ {
+ err_status= add_hostname(ip_key, *hostname);
+ *connect_errors= 0;
+ }
+ else
+ {
+ DBUG_PRINT("error",("Couldn't verify hostname with getaddrinfo()."));
+
+ err_status= add_hostname(ip_key, NULL);
+ *hostname= NULL;
+ *connect_errors= 0;
+ }
+
+ DBUG_RETURN(err_status);
}
diff --git a/sql/hostname.h b/sql/hostname.h
new file mode 100644
index 00000000000..03611bb5813
--- /dev/null
+++ b/sql/hostname.h
@@ -0,0 +1,30 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 HOSTNAME_INCLUDED
+#define HOSTNAME_INCLUDED
+
+#include "my_global.h" /* uint */
+
+bool ip_to_hostname(struct sockaddr_storage *ip_storage,
+ const char *ip_string,
+ char **hostname, uint *connect_errors);
+void inc_host_errors(const char *ip_string);
+void reset_host_errors(const char *ip_string);
+bool hostname_cache_init();
+void hostname_cache_free();
+void hostname_cache_refresh(void);
+
+#endif /* HOSTNAME_INCLUDED */
diff --git a/sql/init.cc b/sql/init.cc
index afda36b6b9d..e43b12787ab 100644
--- a/sql/init.cc
+++ b/sql/init.cc
@@ -21,14 +21,19 @@
Init and dummy functions for interface with unireg
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "init.h"
+#include "my_sys.h"
+#include "mysqld.h" // abort_loop, ...
+#include "my_time.h" // my_init_time
+#include "unireg.h" // SPECIAL_SAME_DB_NAME
#include <m_ctype.h>
void unireg_init(ulong options)
{
DBUG_ENTER("unireg_init");
- MYSYS_PROGRAM_DONT_USE_CURSES();
+ error_handler_hook = my_message_stderr;
abort_loop=0;
my_disable_async_io=1; /* aioread is only in shared library */
@@ -40,7 +45,7 @@ void unireg_init(ulong options)
my_abort_hook=unireg_abort; /* Abort with close of databases */
#endif
- VOID(strmov(reg_ext,".frm"));
+ (void) strmov(reg_ext,".frm");
reg_ext_length= 4;
specialflag=SPECIAL_SAME_DB_NAME | options; /* Set options from argv */
DBUG_VOID_RETURN;
diff --git a/sql/init.h b/sql/init.h
new file mode 100644
index 00000000000..2c160879223
--- /dev/null
+++ b/sql/init.h
@@ -0,0 +1,24 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 INIT_INCLUDED
+#define INIT_INCLUDED
+
+#include "my_global.h" /* ulong */
+
+void unireg_init(ulong options);
+void unireg_end(void) __attribute__((noreturn));
+
+#endif /* INIT_INCLUDED */
diff --git a/sql/item.cc b/sql/item.cc
index d88a6e80bfe..e14c3c95934 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,9 @@
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
#include <mysql.h>
#include <m_ctype.h>
#include "my_dir.h"
@@ -25,6 +27,19 @@
#include "sp_head.h"
#include "sql_trigger.h"
#include "sql_select.h"
+#include "sql_show.h" // append_identifier
+#include "sql_view.h" // VIEW_ANY_SQL
+#include "sql_time.h" // str_to_datetime_with_warn,
+ // make_truncated_value_warning
+#include "sql_acl.h" // get_column_grant,
+ // SELECT_ACL, UPDATE_ACL,
+ // INSERT_ACL,
+ // check_grant_column
+#include "sql_base.h" // enum_resolution_type,
+ // REPORT_EXCEPT_NOT_FOUND,
+ // find_item_in_list,
+ // RESOLVED_AGAINST_ALIAS, ...
+#include "log_event.h" // append_query_string
const String my_null_string("NULL", 4, default_charset_info);
@@ -201,6 +216,35 @@ bool Item::val_bool()
}
+/*
+ For the items which don't have its own fast val_str_ascii()
+ implementation we provide a generic slower version,
+ which converts from the Item character set to ASCII.
+ For better performance conversion happens only in
+ case of a "tricky" Item character set (e.g. UCS2).
+ Normally conversion does not happen.
+*/
+String *Item::val_str_ascii(String *str)
+{
+ if (!(collation.collation->state & MY_CS_NONASCII))
+ return val_str(str);
+
+ DBUG_ASSERT(str != &str_value);
+
+ uint errors;
+ String *res= val_str(&str_value);
+ if (!res)
+ return 0;
+
+ if ((null_value= str->copy(res->ptr(), res->length(),
+ collation.collation, &my_charset_latin1,
+ &errors)))
+ return 0;
+
+ return str;
+}
+
+
String *Item::val_string_from_real(String *str)
{
double nr= val_real();
@@ -263,10 +307,11 @@ my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value)
res->ptr(), res->length(), res->charset(),
decimal_value) & E_DEC_BAD_NUM)
{
+ ErrConvString err(res);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE), "DECIMAL",
- str_value.c_ptr());
+ err.ptr());
}
return decimal_value;
}
@@ -441,10 +486,11 @@ uint Item::decimal_precision() const
if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT))
{
uint prec=
- my_decimal_length_to_precision(max_length, decimals, unsigned_flag);
+ my_decimal_length_to_precision(max_char_length(), decimals,
+ unsigned_flag);
return min(prec, DECIMAL_MAX_PRECISION);
}
- return min(max_length, DECIMAL_MAX_PRECISION);
+ return min(max_char_length(), DECIMAL_MAX_PRECISION);
}
@@ -793,15 +839,40 @@ Item *Item::safe_charset_converter(CHARSET_INFO *tocs)
*/
Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs)
{
+ /*
+ Item_num returns pure ASCII result,
+ so conversion is needed only in case of "tricky" character
+ sets like UCS2. If tocs is not "tricky", return the item itself.
+ */
+ if (!(tocs->state & MY_CS_NONASCII))
+ return this;
+
Item_string *conv;
- char buf[64];
- String *s, tmp(buf, sizeof(buf), &my_charset_bin);
- s= val_str(&tmp);
- if ((conv= new Item_string(s->ptr(), s->length(), s->charset())))
+ uint conv_errors;
+ char buf[64], buf2[64];
+ String tmp(buf, sizeof(buf), &my_charset_bin);
+ String cstr(buf2, sizeof(buf2), &my_charset_bin);
+ String *ostr= val_str(&tmp);
+ char *ptr;
+ cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
+ if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
+ cstr.charset(),
+ collation.derivation)))
{
- conv->str_value.copy();
- conv->str_value.mark_as_const();
+ /*
+ Safe conversion is not possible (or EOM).
+ We could not convert a string into the requested character set
+ without data loss. The target charset does not cover all the
+ characters from the string. Operation cannot be done correctly.
+ */
+ return NULL;
}
+ if (!(ptr= current_thd->strmake(cstr.ptr(), cstr.length())))
+ return NULL;
+ conv->str_value.set(ptr, cstr.length(), cstr.charset());
+ /* Ensure that no one is going to change the result string */
+ conv->str_value.mark_as_const();
+ conv->fix_char_length(max_char_length());
return conv;
}
@@ -864,7 +935,7 @@ Item *Item_param::safe_charset_converter(CHARSET_INFO *tocs)
cnvitem->max_length= cnvitem->str_value.numchars() * tocs->mbmaxlen;
return cnvitem;
}
- return NULL;
+ return Item::safe_charset_converter(tocs);
}
@@ -920,7 +991,7 @@ bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate)
char buff[40];
String tmp(buff,sizeof(buff), &my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->ptr(), res->length(),
+ str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
goto err;
}
@@ -955,8 +1026,8 @@ bool Item::get_time(MYSQL_TIME *ltime)
{
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
- if (!(res=val_str(&tmp)) ||
- str_to_time_with_warn(res->ptr(), res->length(), ltime))
+ if (!(res=val_str_ascii(&tmp)) ||
+ str_to_time_with_warn(res->charset(), res->ptr(), res->length(), ltime))
{
bzero((char*) ltime,sizeof(*ltime));
return 1;
@@ -985,7 +1056,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);
- ulong sql_mode= thd->variables.sql_mode;
+ ulonglong sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
res= save_in_field(field, no_conversions);
@@ -1112,7 +1183,9 @@ Item_splocal::Item_splocal(const LEX_STRING &sp_var_name,
enum_field_types sp_var_type,
uint pos_in_q, uint len_in_q)
:Item_sp_variable(sp_var_name.str, sp_var_name.length),
- m_var_idx(sp_var_idx), pos_in_query(pos_in_q), len_in_query(len_in_q)
+ m_var_idx(sp_var_idx),
+ limit_clause_param(FALSE),
+ pos_in_query(pos_in_q), len_in_query(len_in_q)
{
maybe_null= TRUE;
@@ -1206,7 +1279,7 @@ void Item_case_expr::print(String *str, enum_query_type)
{
if (str->reserve(MAX_INT_WIDTH + sizeof("case_expr@")))
return; /* purecov: inspected */
- VOID(str->append(STRING_WITH_LEN("case_expr@")));
+ (void) str->append(STRING_WITH_LEN("case_expr@"));
str->qs_append(m_case_expr_id);
}
@@ -1446,7 +1519,12 @@ left_is_superset(DTCollation *left, DTCollation *right)
if (left->collation->state & MY_CS_UNICODE &&
(left->derivation < right->derivation ||
(left->derivation == right->derivation &&
- !(right->collation->state & MY_CS_UNICODE))))
+ (!(right->collation->state & MY_CS_UNICODE) ||
+ /* The code below makes 4-byte utf8 a superset over 3-byte utf8 */
+ (left->collation->state & MY_CS_UNICODE_SUPPLEMENT &&
+ !(right->collation->state & MY_CS_UNICODE_SUPPLEMENT) &&
+ left->collation->mbmaxlen > right->collation->mbmaxlen &&
+ left->collation->mbminlen == right->collation->mbminlen)))))
return TRUE;
/* Allow convert from ASCII */
if (right->repertoire == MY_REPERTOIRE_ASCII &&
@@ -1660,6 +1738,11 @@ bool agg_item_collations(DTCollation &c, const char *fname,
my_coll_agg_error(av, count, fname, item_sep);
return TRUE;
}
+
+ /* If all arguments where numbers, reset to @@collation_connection */
+ if (c.derivation == DERIVATION_NUMERIC)
+ c.set(Item::default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_NUMERIC);
+
return FALSE;
}
@@ -1698,18 +1781,35 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
In case we're in statement prepare, create conversion item
in its memory: it will be reused on each execute.
*/
- arena= thd->is_stmt_prepare() ? thd->activate_stmt_arena_if_needed(&backup)
- : NULL;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
for (i= 0, arg= args; i < nargs; i++, arg+= item_sep)
{
Item* conv;
uint32 dummy_offset;
- if (!String::needs_conversion(0, (*arg)->collation.collation,
+ if (!String::needs_conversion(1, (*arg)->collation.collation,
coll.collation,
&dummy_offset))
continue;
+ /*
+ No needs to add converter if an "arg" is NUMERIC or DATETIME
+ value (which is pure ASCII) and at the same time target DTCollation
+ is ASCII-compatible. For example, no needs to rewrite:
+ SELECT * FROM t1 WHERE datetime_field = '2010-01-01';
+ to
+ SELECT * FROM t1 WHERE CONVERT(datetime_field USING cs) = '2010-01-01';
+
+ TODO: avoid conversion of any values with
+ repertoire ASCII and 7bit-ASCII-compatible,
+ not only numeric/datetime origin.
+ */
+ if ((*arg)->collation.derivation == DERIVATION_NUMERIC &&
+ (*arg)->collation.repertoire == MY_REPERTOIRE_ASCII &&
+ !((*arg)->collation.collation->state & MY_CS_NONASCII) &&
+ !(coll.collation->state & MY_CS_NONASCII))
+ continue;
+
if (!(conv= (*arg)->safe_charset_converter(coll.collation)) &&
((*arg)->collation.repertoire == MY_REPERTOIRE_ASCII))
{
@@ -1751,11 +1851,12 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
*arg= conv;
else
thd->change_item_tree(arg, conv);
- /*
- We do not check conv->fixed, because Item_func_conv_charset which can
- be return by safe_charset_converter can't be fixed at creation
- */
- conv->fix_fields(thd, arg);
+
+ if (conv->fix_fields(thd, arg))
+ {
+ res= TRUE;
+ break; // we cannot return here, we need to restore "arena".
+ }
}
if (arena)
thd->restore_active_arena(arena, &backup);
@@ -1914,13 +2015,14 @@ void Item_field::set_field(Field *field_par)
field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null();
decimals= field->decimals();
- max_length= field_par->max_display_length();
table_name= *field_par->table_name;
field_name= field_par->field_name;
db_name= field_par->table->s->db.str;
alias_name_used= field_par->table->alias_name_used;
unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
- collation.set(field_par->charset(), field_par->derivation());
+ collation.set(field_par->charset(), field_par->derivation(),
+ field_par->repertoire());
+ fix_char_length(field_par->char_length());
fixed= 1;
if (field->table->s->tmp_table == SYSTEM_TMP_TABLE)
any_privileges= 0;
@@ -2229,7 +2331,7 @@ String *Item_int::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
- str->set_int(value, unsigned_flag, &my_charset_bin);
+ str->set_int(value, unsigned_flag, collation.collation);
return str;
}
@@ -2259,7 +2361,7 @@ String *Item_uint::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
- str->set((ulonglong) value, &my_charset_bin);
+ str->set((ulonglong) value, collation.collation);
return str;
}
@@ -2359,7 +2461,7 @@ double Item_decimal::val_real()
String *Item_decimal::val_str(String *result)
{
- result->set_charset(&my_charset_bin);
+ result->set_charset(&my_charset_numeric);
my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, result);
return result;
}
@@ -2467,6 +2569,7 @@ double_from_string_with_check (CHARSET_INFO *cs, const char *cptr, char *end)
tmp= my_strntod(cs, (char*) cptr, end - cptr, &end, &error);
if (error || (end != org_end && !check_if_only_end_space(cs, end, org_end)))
{
+ ErrConvString err(cptr, cs);
/*
We can use str_value.ptr() here as Item_string is gurantee to put an
end \0 here.
@@ -2474,7 +2577,7 @@ double_from_string_with_check (CHARSET_INFO *cs, const char *cptr, char *end)
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE), "DOUBLE",
- cptr);
+ err.ptr());
}
return tmp;
}
@@ -2504,10 +2607,11 @@ longlong_from_string_with_check (CHARSET_INFO *cs, const char *cptr, char *end)
(err > 0 ||
(end != org_end && !check_if_only_end_space(cs, end, org_end))))
{
+ ErrConvString err(cptr, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER",
- cptr);
+ err.ptr());
}
return tmp;
}
@@ -2594,7 +2698,8 @@ Item_param::Item_param(uint pos_in_query_arg) :
param_type(MYSQL_TYPE_VARCHAR),
pos_in_query(pos_in_query_arg),
set_param_func(default_set_param_func),
- limit_clause_param(FALSE)
+ limit_clause_param(FALSE),
+ m_out_param_info(NULL)
{
name= (char*) "?";
/*
@@ -2676,6 +2781,17 @@ void Item_param::set_decimal(const char *str, ulong length)
DBUG_VOID_RETURN;
}
+void Item_param::set_decimal(const my_decimal *dv)
+{
+ state= DECIMAL_VALUE;
+
+ my_decimal2decimal(dv, &decimal_value);
+
+ decimals= (uint8) decimal_value.frac;
+ unsigned_flag= !decimal_value.sign();
+ max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
+ decimals, unsigned_flag);
+}
/**
Set parameter value from MYSQL_TIME value.
@@ -3298,6 +3414,155 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
str_value_ptr.swap(src->str_value_ptr);
}
+
+/**
+ This operation is intended to store some item value in Item_param to be
+ used later.
+
+ @param thd thread context
+ @param ctx stored procedure runtime context
+ @param it a pointer to an item in the tree
+
+ @return Error status
+ @retval TRUE on error
+ @retval FALSE on success
+*/
+
+bool
+Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
+{
+ Item *arg= *it;
+
+ if (arg->is_null())
+ {
+ set_null();
+ return FALSE;
+ }
+
+ null_value= FALSE;
+
+ switch (arg->result_type()) {
+ case STRING_RESULT:
+ {
+ char str_buffer[STRING_BUFFER_USUAL_SIZE];
+ String sv_buffer(str_buffer, sizeof(str_buffer), &my_charset_bin);
+ String *sv= arg->val_str(&sv_buffer);
+
+ if (!sv)
+ return TRUE;
+
+ set_str(sv->c_ptr_safe(), sv->length());
+ str_value_ptr.set(str_value.ptr(),
+ str_value.length(),
+ str_value.charset());
+ collation.set(str_value.charset(), DERIVATION_COERCIBLE);
+ decimals= 0;
+
+ break;
+ }
+
+ case REAL_RESULT:
+ set_double(arg->val_real());
+ break;
+
+ case INT_RESULT:
+ set_int(arg->val_int(), arg->max_length);
+ break;
+
+ case DECIMAL_RESULT:
+ {
+ my_decimal dv_buf;
+ my_decimal *dv= arg->val_decimal(&dv_buf);
+
+ if (!dv)
+ return TRUE;
+
+ set_decimal(dv);
+ break;
+ }
+
+ default:
+ /* That can not happen. */
+
+ DBUG_ASSERT(TRUE); // Abort in debug mode.
+
+ set_null(); // Set to NULL in release mode.
+ return FALSE;
+ }
+
+ item_result_type= arg->result_type();
+ item_type= arg->type();
+ return FALSE;
+}
+
+
+/**
+ Setter of Item_param::m_out_param_info.
+
+ m_out_param_info is used to store information about store routine
+ OUT-parameters, such as stored routine name, database, stored routine
+ variable name. It is supposed to be set in sp_head::execute() after
+ Item_param::set_value() is called.
+*/
+
+void
+Item_param::set_out_param_info(Send_field *info)
+{
+ m_out_param_info= info;
+ param_type= m_out_param_info->type;
+}
+
+
+/**
+ Getter of Item_param::m_out_param_info.
+
+ m_out_param_info is used to store information about store routine
+ OUT-parameters, such as stored routine name, database, stored routine
+ variable name. It is supposed to be retrieved in
+ Protocol_binary::send_out_parameters() during creation of OUT-parameter
+ result set.
+*/
+
+const Send_field *
+Item_param::get_out_param_info() const
+{
+ return m_out_param_info;
+}
+
+
+/**
+ Fill meta-data information for the corresponding column in a result set.
+ If this is an OUT-parameter of a stored procedure, preserve meta-data of
+ stored-routine variable.
+
+ @param field container for meta-data to be filled
+*/
+
+void Item_param::make_field(Send_field *field)
+{
+ Item::make_field(field);
+
+ if (!m_out_param_info)
+ return;
+
+ /*
+ This is an OUT-parameter of stored procedure. We should use
+ OUT-parameter info to fill out the names.
+ */
+
+ field->db_name= m_out_param_info->db_name;
+ field->table_name= m_out_param_info->table_name;
+ field->org_table_name= m_out_param_info->org_table_name;
+ field->col_name= m_out_param_info->col_name;
+ field->org_col_name= m_out_param_info->org_col_name;
+
+ field->length= m_out_param_info->length;
+ field->charsetnr= m_out_param_info->charsetnr;
+ field->flags= m_out_param_info->flags;
+ field->decimals= m_out_param_info->decimals;
+ field->type= m_out_param_info->type;
+}
+
/****************************************************************************
Item_copy
****************************************************************************/
@@ -3529,7 +3794,7 @@ void Item_copy_decimal::copy()
/*
- Functions to convert item to field (for send_fields)
+ Functions to convert item to field (for send_result_set_metadata)
*/
/* ARGSUSED */
@@ -4643,11 +4908,8 @@ Item *Item_field::equal_fields_propagator(uchar *arg)
e.g. <bin_col> = <int_col> AND <bin_col> = <hex_string>) since
Items don't know the context they are in and there are functions like
IF (<hex_string>, 'yes', 'no').
- The same problem occurs when comparing a DATE/TIME field with a
- DATE/TIME represented as an int and as a string.
*/
- if (!item ||
- (cmp_context != (Item_result)-1 && item->cmp_context != cmp_context))
+ if (!item || !has_compatible_context(item))
item= this;
else if (field && (field->flags & ZEROFILL_FLAG) && IS_NUM(field->type()))
{
@@ -4711,8 +4973,7 @@ Item *Item_field::replace_equal_field(uchar *arg)
Item *const_item= item_equal->get_const();
if (const_item)
{
- if (cmp_context != (Item_result)-1 &&
- const_item->cmp_context != cmp_context)
+ if (!has_compatible_context(const_item))
return this;
return const_item;
}
@@ -4735,7 +4996,7 @@ void Item::init_make_field(Send_field *tmp_field,
tmp_field->col_name= name;
tmp_field->charsetnr= collation.collation->number;
tmp_field->flags= (maybe_null ? 0 : NOT_NULL_FLAG) |
- (my_binary_compare(collation.collation) ?
+ (my_binary_compare(charset_for_protocol()) ?
BINARY_FLAG : 0);
tmp_field->type= field_type_arg;
tmp_field->length=max_length;
@@ -4782,21 +5043,6 @@ enum_field_types Item::field_type() const
}
-bool Item::is_datetime()
-{
- switch (field_type())
- {
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- return TRUE;
- default:
- break;
- }
- return FALSE;
-}
-
-
String *Item::check_well_formed_result(String *str, bool send_error)
{
/* Check whether we got a well-formed string */
@@ -4809,7 +5055,6 @@ String *Item::check_well_formed_result(String *str, bool send_error)
{
THD *thd= current_thd;
char hexbuf[7];
- enum MYSQL_ERROR::enum_warning_level level;
uint diff= str->length() - wlen;
set_if_smaller(diff, 3);
octet2hex(hexbuf, str->ptr() + wlen, diff);
@@ -4822,16 +5067,14 @@ String *Item::check_well_formed_result(String *str, bool send_error)
if ((thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
{
- level= MYSQL_ERROR::WARN_LEVEL_ERROR;
null_value= 1;
str= 0;
}
else
{
- level= MYSQL_ERROR::WARN_LEVEL_WARN;
str->length(wlen);
}
- push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_INVALID_CHARACTER_STRING,
ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf);
}
return str;
@@ -4897,7 +5140,7 @@ Field *Item::make_string_field(TABLE *table)
DBUG_ASSERT(collation.collation);
if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB)
field= new Field_blob(max_length, maybe_null, name,
- collation.collation);
+ collation.collation, TRUE);
/* Item_type_holder holds the exact type, do not change it */
else if (max_length > 0 &&
(type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING))
@@ -5139,9 +5382,7 @@ int Item_null::save_safe_in_field(Field *field)
int Item::save_in_field(Field *field, bool no_conversions)
{
int error;
- if (result_type() == STRING_RESULT ||
- (result_type() == REAL_RESULT &&
- field->result_type() == STRING_RESULT))
+ if (result_type() == STRING_RESULT)
{
String *result;
CHARSET_INFO *cs= collation.collation;
@@ -5160,11 +5401,20 @@ int Item::save_in_field(Field *field, bool no_conversions)
error=field->store(result->ptr(),result->length(),cs);
str_value.set_quick(0, 0, cs);
}
+ else if (result_type() == REAL_RESULT &&
+ field->result_type() == STRING_RESULT)
+ {
+ double nr= val_real();
+ if (null_value)
+ return set_field_to_null_with_conversions(field, no_conversions);
+ field->set_notnull();
+ error= field->store(nr);
+ }
else if (result_type() == REAL_RESULT)
{
double nr= val_real();
if (null_value)
- return set_field_to_null(field);
+ return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
error=field->store(nr);
}
@@ -5277,10 +5527,27 @@ static uint nr_of_decimals(const char *str, const char *end)
break;
}
decimal_point= str;
- for (; my_isdigit(system_charset_info, *str) ; str++)
+ for ( ; str < end && my_isdigit(system_charset_info, *str) ; str++)
;
- if (*str == 'e' || *str == 'E')
+ if (str < end && (*str == 'e' || *str == 'E'))
return NOT_FIXED_DEC;
+ /*
+ QQ:
+ The number of decimal digist in fact should be (str - decimal_point - 1).
+ But it seems the result of nr_of_decimals() is never used!
+
+ In case of 'e' and 'E' nr_of_decimals returns NOT_FIXED_DEC.
+ In case if there is no 'e' or 'E' parser code in sql_yacc.yy
+ never calls Item_float::Item_float() - it creates Item_decimal instead.
+
+ The only piece of code where we call Item_float::Item_float(str, len)
+ without having 'e' or 'E' is item_xmlfunc.cc, but this Item_float
+ never appears in metadata itself. Changing the code to return
+ (str - decimal_point - 1) does not make any changes in the test results.
+
+ This should be addressed somehow.
+ Looks like a reminder from before real DECIMAL times.
+ */
return (uint) (str - decimal_point);
}
@@ -5662,6 +5929,68 @@ bool Item::send(Protocol *protocol, String *buffer)
}
+/**
+ Check if an item is a constant one and can be cached.
+
+ @param arg [out] TRUE <=> Cache this item.
+
+ @return TRUE Go deeper in item tree.
+ @return FALSE Don't go deeper in item tree.
+*/
+
+bool Item::cache_const_expr_analyzer(uchar **arg)
+{
+ bool *cache_flag= (bool*)*arg;
+ if (!*cache_flag)
+ {
+ Item *item= real_item();
+ /*
+ Cache constant items unless it's a basic constant, constant field or
+ a subselect (they use their own cache).
+ */
+ if (const_item() &&
+ !(basic_const_item() || item->basic_const_item() ||
+ item->type() == Item::FIELD_ITEM ||
+ item->type() == SUBSELECT_ITEM ||
+ /*
+ Do not cache GET_USER_VAR() function as its const_item() may
+ return TRUE for the current thread but it still may change
+ during the execution.
+ */
+ (item->type() == Item::FUNC_ITEM &&
+ ((Item_func*)item)->functype() == Item_func::GUSERVAR_FUNC)))
+ *cache_flag= TRUE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Cache item if needed.
+
+ @param arg TRUE <=> Cache this item.
+
+ @return cache if cache needed.
+ @return this otherwise.
+*/
+
+Item* Item::cache_const_expr_transformer(uchar *arg)
+{
+ if (*(bool*)arg)
+ {
+ *((bool*)arg)= FALSE;
+ Item_cache *cache= Item_cache::get_cache(this);
+ if (!cache)
+ return NULL;
+ cache->setup(this);
+ cache->store(this);
+ return cache;
+ }
+ return this;
+}
+
+
bool Item_field::send(Protocol *protocol, String *buffer)
{
return protocol->store(result_field);
@@ -7045,6 +7374,12 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type)
case DECIMAL_RESULT:
return new Item_cache_decimal();
case STRING_RESULT:
+ /* Not all functions that return DATE/TIME are actually DATE/TIME funcs. */
+ if ((item->field_type() == MYSQL_TYPE_DATE ||
+ item->field_type() == MYSQL_TYPE_DATETIME ||
+ item->field_type() == MYSQL_TYPE_TIME) &&
+ (const_cast<Item*>(item))->result_as_longlong())
+ return new Item_cache_datetime(item->field_type());
return new Item_cache_str(item);
case ROW_RESULT:
return new Item_cache_row();
@@ -7098,7 +7433,7 @@ void Item_cache_int::store(Item *item, longlong val_arg)
String *Item_cache_int::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if (!has_value())
return NULL;
str->set(value, default_charset());
return str;
@@ -7108,7 +7443,7 @@ String *Item_cache_int::val_str(String *str)
my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if (!has_value())
return NULL;
int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
return decimal_val;
@@ -7117,7 +7452,7 @@ my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
double Item_cache_int::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if (!has_value())
return 0.0;
return (double) value;
}
@@ -7125,11 +7460,136 @@ double Item_cache_int::val_real()
longlong Item_cache_int::val_int()
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if (!has_value())
return 0;
return value;
}
+bool Item_cache_datetime::cache_value_int()
+{
+ if (!example)
+ return FALSE;
+
+ value_cached= TRUE;
+ // Mark cached string value obsolete
+ str_value_cached= FALSE;
+ /* Assume here that the underlying item will do correct conversion.*/
+ int_value= example->val_int_result();
+ null_value= example->null_value;
+ unsigned_flag= example->unsigned_flag;
+ return TRUE;
+}
+
+
+bool Item_cache_datetime::cache_value()
+{
+ if (!example)
+ return FALSE;
+
+ if (cmp_context == INT_RESULT)
+ return cache_value_int();
+
+ str_value_cached= TRUE;
+ // Mark cached int value obsolete
+ value_cached= FALSE;
+ /* Assume here that the underlying item will do correct conversion.*/
+ String *res= example->str_result(&str_value);
+ if (res && res != &str_value)
+ str_value.copy(*res);
+ null_value= example->null_value;
+ unsigned_flag= example->unsigned_flag;
+ return TRUE;
+}
+
+
+void Item_cache_datetime::store(Item *item, longlong val_arg)
+{
+ /* An explicit values is given, save it. */
+ value_cached= TRUE;
+ int_value= val_arg;
+ null_value= item->null_value;
+ unsigned_flag= item->unsigned_flag;
+}
+
+
+String *Item_cache_datetime::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (!str_value_cached)
+ {
+ /*
+ When it's possible the Item_cache_datetime uses INT datetime
+ representation due to speed reasons. But still, it always has the STRING
+ result type and thus it can be asked to return a string value.
+ It is possible that at this time cached item doesn't contain correct
+ string value, thus we have to convert cached int value to string and
+ return it.
+ */
+ if (value_cached)
+ {
+ MYSQL_TIME ltime;
+ if (str_value.alloc(MAX_DATE_STRING_REP_LENGTH))
+ return NULL;
+ if (cached_field_type == MYSQL_TYPE_TIME)
+ {
+ longlong time= int_value;
+ set_zero_time(&ltime, MYSQL_TIMESTAMP_TIME);
+ if (time < 0)
+ {
+ time= -time;
+ ltime.neg= TRUE;
+ }
+ DBUG_ASSERT(time <= TIME_MAX_VALUE);
+ ltime.second= time % 100;
+ time/= 100;
+ ltime.minute= time % 100;
+ time/= 100;
+ ltime.hour= time;
+ }
+ else
+ {
+ int was_cut;
+ longlong res;
+ res= number_to_datetime(val_int(), &ltime, TIME_FUZZY_DATE, &was_cut);
+ if (res == -1)
+ return NULL;
+ }
+ str_value.length(my_TIME_to_str(&ltime,
+ const_cast<char*>(str_value.ptr())));
+ str_value_cached= TRUE;
+ }
+ else if (!cache_value())
+ return NULL;
+ }
+ return &str_value;
+}
+
+
+my_decimal *Item_cache_datetime::val_decimal(my_decimal *decimal_val)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (!has_value())
+ return NULL;
+ int2my_decimal(E_DEC_FATAL_ERROR, int_value, unsigned_flag, decimal_val);
+ return decimal_val;
+}
+
+double Item_cache_datetime::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+ if (!value_cached && !cache_value_int())
+ return 0.0;
+ return (double) int_value;
+}
+
+longlong Item_cache_datetime::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ if (!value_cached && !cache_value_int())
+ return 0;
+ return int_value;
+}
+
bool Item_cache_real::cache_value()
{
if (!example)
@@ -7144,7 +7604,7 @@ bool Item_cache_real::cache_value()
double Item_cache_real::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if (!has_value())
return 0.0;
return value;
}
@@ -7152,7 +7612,7 @@ double Item_cache_real::val_real()
longlong Item_cache_real::val_int()
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if (!has_value())
return 0;
return (longlong) rint(value);
}
@@ -7161,7 +7621,7 @@ longlong Item_cache_real::val_int()
String* Item_cache_real::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if (!has_value())
return NULL;
str->set_real(value, decimals, default_charset());
return str;
@@ -7171,7 +7631,7 @@ String* Item_cache_real::val_str(String *str)
my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val)
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if (!has_value())
return NULL;
double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
return decimal_val;
@@ -7193,7 +7653,7 @@ double Item_cache_decimal::val_real()
{
DBUG_ASSERT(fixed);
double res;
- if (!value_cached && !cache_value())
+ if (!has_value())
return 0.0;
my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
return res;
@@ -7203,7 +7663,7 @@ longlong Item_cache_decimal::val_int()
{
DBUG_ASSERT(fixed);
longlong res;
- if (!value_cached && !cache_value())
+ if (!has_value())
return 0;
my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
return res;
@@ -7212,7 +7672,7 @@ longlong Item_cache_decimal::val_int()
String* Item_cache_decimal::val_str(String *str)
{
DBUG_ASSERT(fixed);
- if (!value_cached && !cache_value())
+ if (!has_value())
return NULL;
my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
&decimal_value);
@@ -7223,7 +7683,7 @@ String* Item_cache_decimal::val_str(String *str)
my_decimal *Item_cache_decimal::val_decimal(my_decimal *val)
{
DBUG_ASSERT(fixed);
- if (!value_cached && !cache_value())
+ if (!has_value())
return NULL;
return &decimal_value;
}
@@ -7259,7 +7719,7 @@ double Item_cache_str::val_real()
DBUG_ASSERT(fixed == 1);
int err_not_used;
char *end_not_used;
- if (!value_cached && !cache_value())
+ if (!has_value())
return 0.0;
if (value)
return my_strntod(value->charset(), (char*) value->ptr(),
@@ -7272,7 +7732,7 @@ longlong Item_cache_str::val_int()
{
DBUG_ASSERT(fixed == 1);
int err;
- if (!value_cached && !cache_value())
+ if (!has_value())
return 0;
if (value)
return my_strntoll(value->charset(), value->ptr(),
@@ -7285,7 +7745,7 @@ longlong Item_cache_str::val_int()
String* Item_cache_str::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if (!has_value())
return 0;
return value;
}
@@ -7294,7 +7754,7 @@ String* Item_cache_str::val_str(String *str)
my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if (!has_value())
return NULL;
if (value)
string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
@@ -7306,7 +7766,7 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
int Item_cache_str::save_in_field(Field *field, bool no_conversions)
{
- if (!value_cached && !cache_value())
+ if (!has_value())
return 0;
int res= Item_cache::save_in_field(field, no_conversions);
return (is_varbinary && field->type() == MYSQL_TYPE_STRING &&
diff --git a/sql/item.h b/sql/item.h
index 57abb43010e..e65bacf4cb7 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1,3 +1,6 @@
+#ifndef ITEM_INCLUDED
+#define ITEM_INCLUDED
+
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
@@ -18,10 +21,27 @@
#pragma interface /* gcc class implementation */
#endif
+#include "sql_priv.h" /* STRING_BUFFER_USUAL_SIZE */
+#include "unireg.h"
+#include "sql_const.h" /* RAND_TABLE_BIT, MAX_FIELD_NAME */
+#include "unireg.h" // REQUIRED: for other includes
+#include "thr_malloc.h" /* sql_calloc */
+#include "field.h" /* Derivation */
+
class Protocol;
struct TABLE_LIST;
void item_init(void); /* Init item functions */
class Item_field;
+class user_var_entry;
+
+
+static inline uint32
+char_to_byte_length_safe(uint32 char_length_arg, uint32 mbmaxlen_arg)
+{
+ ulonglong tmp= ((ulonglong) char_length_arg) * mbmaxlen_arg;
+ return (tmp > UINT_MAX32) ? (uint32) UINT_MAX32 : (uint32) tmp;
+}
+
/*
"Declared Type Collation"
@@ -41,9 +61,10 @@ class Item_field;
#define MY_COLL_ALLOW_SUPERSET_CONV 1
#define MY_COLL_ALLOW_COERCIBLE_CONV 2
-#define MY_COLL_ALLOW_CONV 3
#define MY_COLL_DISALLOW_NONE 4
-#define MY_COLL_CMP_CONV 7
+
+#define MY_COLL_ALLOW_CONV (MY_COLL_ALLOW_SUPERSET_CONV | MY_COLL_ALLOW_COERCIBLE_CONV)
+#define MY_COLL_CMP_CONV (MY_COLL_ALLOW_CONV | MY_COLL_DISALLOW_NONE)
class DTCollation {
public:
@@ -88,6 +109,12 @@ 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;
@@ -102,6 +129,7 @@ public:
{
switch(derivation)
{
+ case DERIVATION_NUMERIC: return "NUMERIC";
case DERIVATION_IGNORABLE: return "IGNORABLE";
case DERIVATION_COERCIBLE: return "COERCIBLE";
case DERIVATION_IMPLICIT: return "IMPLICIT";
@@ -450,6 +478,11 @@ public:
TRUE if error has occured.
*/
virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it)= 0;
+
+ virtual void set_out_param_info(Send_field *info) {}
+
+ virtual const Send_field *get_out_param_info() const
+ { return NULL; }
};
@@ -514,7 +547,7 @@ public:
@see Query_arena::free_list
*/
Item *next;
- uint32 max_length;
+ uint32 max_length; /* Maximum length, in bytes */
uint name_length; /* Length of name */
int8 marker;
uint8 decimals;
@@ -682,6 +715,77 @@ public:
If value is not null null_value flag will be reset to FALSE.
*/
virtual String *val_str(String *str)=0;
+
+ /*
+ Returns string representation of this item in ASCII format.
+
+ SYNOPSIS
+ val_str_ascii()
+ str - similar to val_str();
+
+ NOTE
+ This method is introduced for performance optimization purposes.
+
+ 1. val_str() result of some Items in string context
+ depends on @@character_set_results.
+ @@character_set_results can be set to a "real multibyte" character
+ set like UCS2, UTF16, UTF32. (We'll use only UTF32 in the examples
+ below for convenience.)
+
+ So the default string result of such functions
+ in these circumstances is real multi-byte character set, like UTF32.
+
+ For example, all numbers in string context
+ return result in @@character_set_results:
+
+ SELECT CONCAT(20010101); -> UTF32
+
+ We do sprintf() first (to get ASCII representation)
+ and then convert to UTF32;
+
+ So these kind "data sources" can use ASCII representation
+ internally, but return multi-byte data only because
+ @@character_set_results wants so.
+ Therefore, conversion from ASCII to UTF32 is applied internally.
+
+
+ 2. Some other functions need in fact ASCII input.
+
+ For example,
+ inet_aton(), GeometryFromText(), Convert_TZ(), GET_FORMAT().
+
+ Similar, fields of certain type, like DATE, TIME,
+ when you insert string data into them, expect in fact ASCII input.
+ If they get non-ASCII input, for example UTF32, they
+ convert input from UTF32 to ASCII, and then use ASCII
+ representation to do further processing.
+
+
+ 3. Now imagine we pass result of a data source of the first type
+ to a data destination of the second type.
+
+ What happens:
+ a. data source converts data from ASCII to UTF32, because
+ @@character_set_results wants so and passes the result to
+ data destination.
+ b. data destination gets UTF32 string.
+ c. data destination converts UTF32 string to ASCII,
+ because it needs ASCII representation to be able to handle data
+ correctly.
+
+ As a result we get two steps of unnecessary conversion:
+ From ASCII to UTF32, then from UTF32 to ASCII.
+
+ A better way to handle these situations is to pass ASCII
+ representation directly from the source to the destination.
+
+ This is why val_str_ascii() introduced.
+
+ RETURN
+ Similar to val_str()
+ */
+ virtual String *val_str_ascii(String *str);
+
/*
Return decimal representation of item with fixed point.
@@ -856,6 +960,16 @@ public:
static CHARSET_INFO *default_charset();
virtual CHARSET_INFO *compare_collation() { return NULL; }
+ /*
+ For backward compatibility, to make numeric
+ data types return "binary" charset in client-side metadata.
+ */
+ virtual CHARSET_INFO *charset_for_protocol(void) const
+ {
+ return result_type() == STRING_RESULT ? collation.collation :
+ &my_charset_bin;
+ };
+
virtual bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
return (this->*processor)(arg);
@@ -893,6 +1007,15 @@ public:
(*traverser)(this, arg);
}
+ /*
+ This is used to get the most recent version of any function in
+ an item tree. The version is the version where a MySQL function
+ was introduced in. So any function which is added should use
+ this function and set the int_arg to maximum of the input data
+ and their own version info.
+ */
+ virtual bool intro_version(uchar *int_arg) { return 0; }
+
virtual bool remove_dependence_processor(uchar * arg) { return 0; }
virtual bool remove_fixed(uchar * arg) { fixed= 0; return 0; }
virtual bool cleanup_processor(uchar *arg);
@@ -903,6 +1026,9 @@ public:
virtual bool is_expensive_processor(uchar *arg) { return 0; }
virtual bool find_item_processor(uchar *arg) { return this == (void *) arg; }
virtual bool register_field_in_read_map(uchar *arg) { return 0; }
+
+ virtual bool cache_const_expr_analyzer(uchar **arg);
+ virtual Item* cache_const_expr_transformer(uchar *arg);
/*
Check if a partition function is allowed
SYNOPSIS
@@ -1045,11 +1171,77 @@ public:
representation is more precise than the string one).
*/
virtual bool result_as_longlong() { return FALSE; }
- bool is_datetime();
+ inline bool is_datetime() const
+ {
+ switch (field_type())
+ {
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ return TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+ }
+ /**
+ Check whether this and the given item has compatible comparison context.
+ Used by the equality propagation. See Item_field::equal_fields_propagator.
+
+ @return
+ TRUE if the context is the same or if fields could be
+ compared as DATETIME values by the Arg_comparator.
+ FALSE otherwise.
+ */
+ inline bool has_compatible_context(Item *item) const
+ {
+ /* Same context. */
+ if (cmp_context == (Item_result)-1 || item->cmp_context == cmp_context)
+ return TRUE;
+ /* DATETIME comparison context. */
+ if (is_datetime())
+ return item->is_datetime() || item->cmp_context == STRING_RESULT;
+ if (item->is_datetime())
+ return is_datetime() || cmp_context == STRING_RESULT;
+ return FALSE;
+ }
virtual Field::geometry_type get_geometry_type() const
{ return Field::GEOM_GEOMETRY; };
String *check_well_formed_result(String *str, bool send_error= 0);
bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs);
+ uint32 max_char_length() const
+ { return max_length / collation.collation->mbmaxlen; }
+ void fix_length_and_charset(uint32 max_char_length_arg, CHARSET_INFO *cs)
+ {
+ max_length= char_to_byte_length_safe(max_char_length_arg, cs->mbmaxlen);
+ collation.collation= cs;
+ }
+ void fix_char_length(uint32 max_char_length_arg)
+ {
+ max_length= char_to_byte_length_safe(max_char_length_arg,
+ collation.collation->mbmaxlen);
+ }
+ void fix_char_length_ulonglong(ulonglong max_char_length_arg)
+ {
+ ulonglong max_result_length= max_char_length_arg *
+ collation.collation->mbmaxlen;
+ if (max_result_length >= MAX_BLOB_WIDTH)
+ {
+ max_length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
+ }
+ else
+ max_length= max_result_length;
+ }
+ void fix_length_and_charset_datetime(uint32 max_char_length_arg)
+ {
+ collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII);
+ fix_char_length(max_char_length_arg);
+ }
+ /*
+ Return TRUE if the item points to a column of an outer-joined table.
+ */
+ virtual bool is_outer_field() const { DBUG_ASSERT(fixed); return FALSE; }
};
@@ -1171,6 +1363,13 @@ class Item_splocal :public Item_sp_variable,
Item_result m_result_type;
enum_field_types m_field_type;
public:
+ /*
+ Is this variable a parameter in LIMIT clause.
+ Used only during NAME_CONST substitution, to not append
+ NAME_CONST to the resulting query and thus not break
+ the slave.
+ */
+ bool limit_clause_param;
/*
Position of this reference to SP variable in the statement (the
statement itself is in sp_instr_stmt::m_query).
@@ -1352,12 +1551,30 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
Item **args, uint nargs, uint flags, int item_sep);
bool agg_item_charsets(DTCollation &c, const char *name,
Item **items, uint nitems, uint flags, int item_sep);
-
+inline bool
+agg_item_charsets_for_string_result(DTCollation &c, const char *name,
+ Item **items, uint nitems,
+ int item_sep= 1)
+{
+ uint flags= MY_COLL_ALLOW_SUPERSET_CONV |
+ MY_COLL_ALLOW_COERCIBLE_CONV;
+ return agg_item_charsets(c, name, items, nitems, flags, item_sep);
+}
+inline bool
+agg_item_charsets_for_comparison(DTCollation &c, const char *name,
+ Item **items, uint nitems,
+ int item_sep= 1)
+{
+ uint flags= MY_COLL_ALLOW_SUPERSET_CONV |
+ MY_COLL_ALLOW_COERCIBLE_CONV |
+ MY_COLL_DISALLOW_NONE;
+ return agg_item_charsets(c, name, items, nitems, flags, item_sep);
+}
class Item_num: public Item_basic_constant
{
public:
- Item_num() {} /* Remove gcc warning */
+ Item_num() { collation.set_numeric(); } /* Remove gcc warning */
virtual Item_num *neg()= 0;
Item *safe_charset_converter(CHARSET_INFO *tocs);
bool check_partition_func_processor(uchar *int_arg) { return FALSE;}
@@ -1538,11 +1755,18 @@ public:
int fix_outer_field(THD *thd, Field **field, Item **reference);
virtual Item *update_value_transformer(uchar *select_arg);
virtual void print(String *str, enum_query_type query_type);
+ bool is_outer_field() const
+ {
+ 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();
}
+ CHARSET_INFO *charset_for_protocol(void) const
+ { return field->charset_for_protocol(); }
friend class Item_default_value;
friend class Item_insert_value;
friend class st_select_lex_unit;
@@ -1598,7 +1822,8 @@ public:
/* Item represents one placeholder ('?') of prepared statement */
-class Item_param :public Item
+class Item_param :public Item,
+ private Settable_routine_parameter
{
char cnvbuf[MAX_FIELD_WIDTH];
String cnvstr;
@@ -1686,6 +1911,7 @@ public:
void set_int(longlong i, uint32 max_length_arg);
void set_double(double i);
void set_decimal(const char *str, ulong length);
+ void set_decimal(const my_decimal *dv);
bool set_str(const char *str, ulong length);
bool set_longdata(const char *str, ulong length);
void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg);
@@ -1735,6 +1961,25 @@ public:
/** Item is a argument to a limit clause. */
bool limit_clause_param;
void set_param_type_and_swap_value(Item_param *from);
+
+private:
+ virtual inline Settable_routine_parameter *
+ get_settable_routine_parameter()
+ {
+ return this;
+ }
+
+ virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it);
+
+ virtual void set_out_param_info(Send_field *info);
+
+public:
+ virtual const Send_field *get_out_param_info() const;
+
+ virtual void make_field(Send_field *field);
+
+private:
+ Send_field *m_out_param_info;
};
@@ -2092,7 +2337,7 @@ public:
/**
Item_empty_string -- is a utility class to put an item into List<Item>
- which is then used in protocol.send_fields() when sending SHOW output to
+ which is then used in protocol.send_result_set_metadata() when sending SHOW output to
the client.
*/
@@ -2327,6 +2572,13 @@ public:
DBUG_ASSERT(fixed);
return (*ref)->get_time(ltime);
}
+ virtual bool basic_const_item() const { return ref && (*ref)->basic_const_item(); }
+ bool is_outer_field() const
+ {
+ DBUG_ASSERT(fixed);
+ DBUG_ASSERT(ref);
+ return (*ref)->is_outer_field();
+ }
};
@@ -2526,6 +2778,7 @@ public:
#include "item_timefunc.h"
#include "item_subselect.h"
#include "item_xmlfunc.h"
+#include "item_create.h"
#endif
/**
@@ -2583,6 +2836,8 @@ protected:
cached_field_type= item->field_type();
cached_result_type= item->result_type();
unsigned_flag= item->unsigned_flag;
+ fixed= item->fixed;
+ collation.set(item->collation);
}
public:
@@ -2859,18 +3114,6 @@ public:
};
-/*
- We need this two enums here instead of sql_lex.h because
- at least one of them is used by Item_trigger_field interface.
-
- Time when trigger is invoked (i.e. before or after row actually
- inserted/updated/deleted).
-*/
-enum trg_action_time_type
-{
- TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX
-};
-
class Table_triggers_list;
/*
@@ -2978,14 +3221,16 @@ protected:
bool value_cached;
public:
Item_cache():
- example(0), used_table_map(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING),
+ example(0), used_table_map(0), cached_field(0),
+ cached_field_type(MYSQL_TYPE_STRING),
value_cached(0)
{
fixed= 1;
null_value= 1;
}
Item_cache(enum_field_types field_type_arg):
- example(0), used_table_map(0), cached_field(0), cached_field_type(field_type_arg),
+ example(0), used_table_map(0), cached_field(0),
+ cached_field_type(field_type_arg),
value_cached(0)
{
fixed= 1;
@@ -3021,8 +3266,26 @@ public:
{
return this == item;
}
+ /**
+ Check if saved item has a non-NULL value.
+ Will cache value of saved item if not already done.
+ @return TRUE if cached value is non-NULL.
+ */
+ bool has_value()
+ {
+ return (value_cached || cache_value()) && !null_value;
+ }
virtual void store(Item *item);
virtual bool cache_value()= 0;
+ bool basic_const_item() const
+ { return test(example && example->basic_const_item());}
+ virtual void clear() { null_value= TRUE; value_cached= FALSE; }
+ Item_result result_type() const
+ {
+ if (!example)
+ return INT_RESULT;
+ return Field::result_merge_type(example->field_type());
+ }
};
@@ -3088,12 +3351,13 @@ class Item_cache_str: public Item_cache
public:
Item_cache_str(const Item *item) :
- Item_cache(), value(0),
+ Item_cache(item->field_type()), value(0),
is_varbinary(item->type() == FIELD_ITEM &&
- ((const Item_field *) item)->field->type() ==
- MYSQL_TYPE_VARCHAR &&
+ cached_field_type == MYSQL_TYPE_VARCHAR &&
!((const Item_field *) item)->field->has_charset())
- {}
+ {
+ collation.set(const_cast<DTCollation&>(item->collation));
+ }
double val_real();
longlong val_int();
String* val_str(String *);
@@ -3174,6 +3438,40 @@ public:
};
+class Item_cache_datetime: public Item_cache
+{
+protected:
+ String str_value;
+ ulonglong int_value;
+ bool str_value_cached;
+public:
+ Item_cache_datetime(enum_field_types field_type_arg):
+ Item_cache(field_type_arg), int_value(0), str_value_cached(0)
+ {
+ cmp_context= STRING_RESULT;
+ }
+
+ virtual void store(Item *item) { Item_cache::store(item); }
+ void store(Item *item, longlong val_arg);
+ double val_real();
+ longlong val_int();
+ String* val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
+ enum Item_result result_type() const { return STRING_RESULT; }
+ bool result_as_longlong() { return TRUE; }
+ /*
+ In order to avoid INT <-> STRING conversion of a DATETIME value
+ two cache_value functions are introduced. One (cache_value) caches STRING
+ value, another (cache_value_int) - INT value. Thus this cache item
+ completely relies on the ability of the underlying item to do the
+ correct conversion.
+ */
+ bool cache_value_int();
+ bool cache_value();
+ void clear() { Item_cache::clear(); str_value_cached= FALSE; }
+};
+
+
/*
Item_type_holder used to store type. name, length of Item for UNIONS &
derived tables.
@@ -3221,3 +3519,7 @@ extern Cached_item *new_Cached_item(THD *thd, Item *item);
extern Item_result item_cmp_type(Item_result a,Item_result b);
extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item);
extern int stored_field_cmp_to_item(THD *thd, Field *field, Item *item);
+
+extern const String my_null_string;
+
+#endif /* ITEM_INCLUDED */
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index 0ac4edb3656..87197c7d9b6 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -21,7 +21,14 @@
Buffers to save and compare item values
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" // THD
+#include "set_var.h" // Cached_item, Cached_item_field, ...
/**
Create right type of Cached_item for an item.
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 6987dd9e053..b04ec105468 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -25,9 +25,11 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
#include <m_ctype.h>
#include "sql_select.h"
+#include "sql_parse.h" // check_stack_overrun
+#include "sql_time.h" // make_truncated_value_warning
static bool convert_constant_item(THD *, Item_field *, Item **);
static longlong
@@ -404,7 +406,7 @@ static bool convert_constant_item(THD *thd, Item_field *field_item,
if (!(*item)->with_subselect && (*item)->const_item())
{
TABLE *table= field->table;
- ulong orig_sql_mode= thd->variables.sql_mode;
+ ulonglong orig_sql_mode= thd->variables.sql_mode;
enum_check_fields orig_count_cuted_fields= thd->count_cuted_fields;
my_bitmap_map *old_maps[2];
ulonglong UNINIT_VAR(orig_field_val); /* original field value if valid */
@@ -483,7 +485,7 @@ void Item_bool_func2::fix_length_and_dec()
DTCollation coll;
if (args[0]->result_type() == STRING_RESULT &&
args[1]->result_type() == STRING_RESULT &&
- agg_arg_charsets(coll, args, 2, MY_COLL_CMP_CONV, 1))
+ agg_arg_charsets_for_comparison(coll, args, 2))
return;
args[0]->cmp_context= args[1]->cmp_context=
@@ -867,14 +869,17 @@ get_time_value(THD *thd, Item ***item_arg, Item **cache_arg,
else
{
*is_null= item->get_time(&ltime);
- value= !*is_null ? (longlong) TIME_to_ulonglong_datetime(&ltime) : 0;
+ value= !*is_null ? (longlong) TIME_to_ulonglong_datetime(&ltime) *
+ (ltime.neg ? -1 : 1) : 0;
}
/*
Do not cache GET_USER_VAR() function as its const_item() may return TRUE
for the current thread but it still may change during the execution.
*/
- if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM ||
- ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC))
+ if (item->const_item() && cache_arg &&
+ item->type() != Item::CACHE_ITEM &&
+ (item->type() != Item::FUNC_ITEM ||
+ ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC))
{
Item_cache_int *cache= new Item_cache_int();
/* Mark the cache as non-const to prevent re-caching. */
@@ -933,6 +938,8 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
func= &Arg_comparator::compare_datetime;
get_value_a_func= &get_datetime_value;
get_value_b_func= &get_datetime_value;
+ cmp_collation.set(&my_charset_numeric);
+ set_cmp_context_for_datetime();
return 0;
}
else if (type == STRING_RESULT && (*a)->field_type() == MYSQL_TYPE_TIME &&
@@ -945,6 +952,7 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
func= &Arg_comparator::compare_datetime;
get_value_a_func= &get_time_value;
get_value_b_func= &get_time_value;
+ set_cmp_context_for_datetime();
return 0;
}
else if (type == STRING_RESULT &&
@@ -1001,6 +1009,7 @@ bool Arg_comparator::try_year_cmp_func(Item_result type)
is_nulls_eq= is_owner_equal_func();
func= &Arg_comparator::compare_datetime;
+ set_cmp_context_for_datetime();
return TRUE;
}
@@ -1054,6 +1063,7 @@ void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg,
func= &Arg_comparator::compare_datetime;
get_value_a_func= &get_datetime_value;
get_value_b_func= &get_datetime_value;
+ set_cmp_context_for_datetime();
}
@@ -1140,8 +1150,10 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
Do not cache GET_USER_VAR() function as its const_item() may return TRUE
for the current thread but it still may change during the execution.
*/
- if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM ||
- ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC))
+ if (item->const_item() && cache_arg &&
+ item->type() != Item::CACHE_ITEM &&
+ (item->type() != Item::FUNC_ITEM ||
+ ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC))
{
Item_cache_int *cache= new Item_cache_int(MYSQL_TYPE_DATETIME);
/* Mark the cache as non-const to prevent re-caching. */
@@ -2261,7 +2273,7 @@ void Item_func_between::fix_length_and_dec()
if ( agg_cmp_type(&cmp_type, args, 3))
return;
if (cmp_type == STRING_RESULT &&
- agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1))
+ agg_arg_charsets_for_comparison(cmp_collation, args, 3))
return;
/*
@@ -2442,6 +2454,7 @@ void Item_func_between::print(String *str, enum_query_type query_type)
void
Item_func_ifnull::fix_length_and_dec()
{
+ uint32 char_length;
agg_result_type(&hybrid_type, args, 2);
maybe_null=args[1]->maybe_null;
decimals= max(args[0]->decimals, args[1]->decimals);
@@ -2449,20 +2462,21 @@ Item_func_ifnull::fix_length_and_dec()
if (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT)
{
- int len0= args[0]->max_length - args[0]->decimals
+ int len0= args[0]->max_char_length() - args[0]->decimals
- (args[0]->unsigned_flag ? 0 : 1);
- int len1= args[1]->max_length - args[1]->decimals
+ int len1= args[1]->max_char_length() - args[1]->decimals
- (args[1]->unsigned_flag ? 0 : 1);
- max_length= max(len0, len1) + decimals + (unsigned_flag ? 0 : 1);
+ char_length= max(len0, len1) + decimals + (unsigned_flag ? 0 : 1);
}
else
- max_length= max(args[0]->max_length, args[1]->max_length);
+ char_length= max(args[0]->max_char_length(), args[1]->max_char_length());
switch (hybrid_type) {
case STRING_RESULT:
- agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1);
+ if (agg_arg_charsets_for_comparison(collation, args, arg_count))
+ return;
break;
case DECIMAL_RESULT:
case REAL_RESULT:
@@ -2474,6 +2488,7 @@ Item_func_ifnull::fix_length_and_dec()
default:
DBUG_ASSERT(0);
}
+ fix_char_length(char_length);
cached_field_type= agg_field_type(args, 2);
}
@@ -2625,28 +2640,32 @@ Item_func_if::fix_length_and_dec()
cached_result_type= arg2_type;
collation.set(args[2]->collation.collation);
cached_field_type= args[2]->field_type();
+ max_length= args[2]->max_length;
+ return;
}
- else if (null2)
+
+ if (null2)
{
cached_result_type= arg1_type;
collation.set(args[1]->collation.collation);
cached_field_type= args[1]->field_type();
+ max_length= args[1]->max_length;
+ return;
+ }
+
+ agg_result_type(&cached_result_type, args + 1, 2);
+ if (cached_result_type == STRING_RESULT)
+ {
+ if (agg_arg_charsets_for_string_result(collation, args + 1, 2))
+ return;
}
else
{
- agg_result_type(&cached_result_type, args+1, 2);
- if (cached_result_type == STRING_RESULT)
- {
- if (agg_arg_charsets(collation, args+1, 2, MY_COLL_ALLOW_CONV, 1))
- return;
- }
- else
- {
- collation.set(&my_charset_bin); // Number
- }
- cached_field_type= agg_field_type(args + 1, 2);
+ collation.set_numeric(); // Number
}
+ cached_field_type= agg_field_type(args + 1, 2);
+ uint32 char_length;
if ((cached_result_type == DECIMAL_RESULT )
|| (cached_result_type == INT_RESULT))
{
@@ -2656,10 +2675,11 @@ Item_func_if::fix_length_and_dec()
int len2= args[2]->max_length - args[2]->decimals
- (args[2]->unsigned_flag ? 0 : 1);
- max_length=max(len1, len2) + decimals + (unsigned_flag ? 0 : 1);
+ char_length= max(len1, len2) + decimals + (unsigned_flag ? 0 : 1);
}
else
- max_length= max(args[1]->max_length, args[2]->max_length);
+ char_length= max(args[1]->max_char_length(), args[2]->max_char_length());
+ fix_char_length(char_length);
}
@@ -2728,7 +2748,7 @@ Item_func_nullif::fix_length_and_dec()
unsigned_flag= args[0]->unsigned_flag;
cached_result_type= args[0]->result_type();
if (cached_result_type == STRING_RESULT &&
- agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1))
+ agg_arg_charsets_for_comparison(collation, args, arg_count))
return;
}
}
@@ -2955,9 +2975,7 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref)
buff should match stack usage from
Item_func_case::val_int() -> Item_func_case::find_item()
*/
-#ifndef EMBEDDED_LIBRARY
uchar buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2];
-#endif
bool res= Item_func::fix_fields(thd, ref);
/*
Call check_stack_overrun after fix_fields to be sure that stack variable
@@ -2971,7 +2989,7 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref)
void Item_func_case::agg_str_lengths(Item* arg)
{
- set_if_bigger(max_length, arg->max_length);
+ fix_char_length(max(max_char_length(), arg->max_char_length()));
set_if_bigger(decimals, arg->decimals);
unsigned_flag= unsigned_flag && arg->unsigned_flag;
}
@@ -3007,9 +3025,21 @@ void Item_func_case::fix_length_and_dec()
agg[nagg++]= args[else_expr_num];
agg_result_type(&cached_result_type, agg, nagg);
- if ((cached_result_type == STRING_RESULT) &&
- agg_arg_charsets(collation, agg, nagg, MY_COLL_ALLOW_CONV, 1))
- return;
+ if (cached_result_type == STRING_RESULT)
+ {
+ if (agg_arg_charsets_for_string_result(collation, agg, nagg))
+ return;
+ /*
+ Copy all THEN and ELSE items back to args[] array.
+ Some of the items might have been changed to Item_func_conv_charset.
+ */
+ for (nagg= 0 ; nagg < ncases / 2 ; nagg++)
+ args[nagg * 2 + 1]= agg[nagg];
+ if (else_expr_num != -1)
+ args[else_expr_num]= agg[nagg++];
+ }
+ else
+ collation.set_numeric();
cached_field_type= agg_field_type(agg, nagg);
/*
@@ -3034,7 +3064,7 @@ void Item_func_case::fix_length_and_dec()
{
DBUG_ASSERT((Item_result)i != ROW_RESULT);
if ((Item_result)i == STRING_RESULT &&
- agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1))
+ agg_arg_charsets_for_comparison(cmp_collation, agg, nagg))
return;
if (!(cmp_items[i]=
cmp_item::get_comparator((Item_result)i,
@@ -3195,9 +3225,10 @@ void Item_func_coalesce::fix_length_and_dec()
agg_result_type(&hybrid_type, args, arg_count);
switch (hybrid_type) {
case STRING_RESULT:
- count_only_length();
decimals= NOT_FIXED_DEC;
- agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1);
+ if (agg_arg_charsets_for_string_result(collation, args, arg_count))
+ return;
+ count_only_length();
break;
case DECIMAL_RESULT:
count_decimal_length();
@@ -3842,7 +3873,7 @@ void Item_func_in::fix_length_and_dec()
if (type_cnt == 1)
{
if (cmp_type == STRING_RESULT &&
- agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
+ agg_arg_charsets_for_comparison(cmp_collation, args, arg_count))
return;
arg_types_compatible= TRUE;
}
@@ -4020,8 +4051,7 @@ void Item_func_in::fix_length_and_dec()
if (found_types & (1 << i) && !cmp_items[i])
{
if ((Item_result)i == STRING_RESULT &&
- agg_arg_charsets(cmp_collation, args, arg_count,
- MY_COLL_CMP_CONV, 1))
+ agg_arg_charsets_for_comparison(cmp_collation, args, arg_count))
return;
if (!cmp_items[i] && !(cmp_items[i]=
cmp_item::get_comparator((Item_result)i,
@@ -4179,9 +4209,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
DBUG_ASSERT(fixed == 0);
List_iterator<Item> li(list);
Item *item;
-#ifndef EMBEDDED_LIBRARY
uchar buff[sizeof(char*)]; // Max local vars in function
-#endif
not_null_tables_cache= used_tables_cache= 0;
const_item_cache= 1;
/*
@@ -4451,7 +4479,7 @@ void Item_cond::neg_arguments(THD *thd)
if (!(new_item= new Item_func_not(item)))
return; // Fatal OEM error
}
- VOID(li.replace(new_item));
+ (void) li.replace(new_item);
}
}
@@ -4789,8 +4817,6 @@ void Item_func_like::cleanup()
Item_bool_func2::cleanup();
}
-#ifdef USE_REGEX
-
/**
@brief Compile regular expression.
@@ -4861,7 +4887,7 @@ Item_func_regex::fix_fields(THD *thd, Item **ref)
max_length= 1;
decimals= 0;
- if (agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1))
+ if (agg_arg_charsets_for_comparison(cmp_collation, args, 2))
return TRUE;
regex_lib_flags= (cmp_collation.collation->state &
@@ -4942,9 +4968,6 @@ void Item_func_regex::cleanup()
}
-#endif /* USE_REGEX */
-
-
#ifdef LIKE_CMP_TOUPPER
#define likeconv(cs,A) (uchar) (cs)->toupper(A)
#else
@@ -5554,7 +5577,21 @@ void Item_equal::update_const()
Item *item;
while ((item= it++))
{
- if (item->const_item())
+ if (item->const_item() &&
+ /*
+ Don't propagate constant status of outer-joined column.
+ Such a constant status here is a result of:
+ a) empty outer-joined table: in this case such a column has a
+ value of NULL; but at the same time other arguments of
+ Item_equal don't have to be NULLs and the value of the whole
+ multiple equivalence expression doesn't have to be NULL or FALSE
+ because of the outer join nature;
+ or
+ b) outer-joined table contains only 1 row: the result of
+ this column is equal to a row field value *or* NULL.
+ Both values are inacceptable as Item_equal constants.
+ */
+ !item->is_outer_field())
{
it.remove();
add(item);
@@ -5593,7 +5630,8 @@ void Item_equal::update_used_tables()
{
item->update_used_tables();
used_tables_cache|= item->used_tables();
- const_item_cache&= item->const_item();
+ /* see commentary at Item_equal::update_const() */
+ const_item_cache&= item->const_item() && !item->is_outer_field();
}
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 506de05f0ea..f9851011563 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1,3 +1,6 @@
+#ifndef ITEM_CMPFUNC_INCLUDED
+#define ITEM_CMPFUNC_INCLUDED
+
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
@@ -20,6 +23,10 @@
#pragma interface /* gcc class implementation */
#endif
+#include "thr_malloc.h" /* sql_calloc */
+#include "item_func.h" /* Item_int_func, Item_bool_func */
+#include "my_regex.h"
+
extern Item_result item_cmp_type(Item_result a,Item_result b);
class Item_bool_func2;
class Arg_comparator;
@@ -117,7 +124,17 @@ public:
delete [] comparators;
comparators= 0;
}
-
+ /*
+ Set correct cmp_context if items would be compared as INTs.
+ */
+ inline void set_cmp_context_for_datetime()
+ {
+ DBUG_ASSERT(func == &Arg_comparator::compare_datetime);
+ if ((*a)->result_as_longlong())
+ (*a)->cmp_context= INT_RESULT;
+ if ((*b)->result_as_longlong())
+ (*b)->cmp_context= INT_RESULT;
+ }
friend class Item_func;
};
@@ -252,7 +269,7 @@ protected:
my_bool result_for_null_param;
public:
Item_in_optimizer(Item *a, Item_in_subselect *b):
- Item_bool_func(a, my_reinterpret_cast(Item *)(b)), cache(0),
+ Item_bool_func(a, reinterpret_cast<Item *>(b)), cache(0),
save_cache(0), result_for_null_param(UNKNOWN)
{}
bool fix_fields(THD *, Item **);
@@ -644,6 +661,11 @@ public:
{
Item_func::print(str, query_type);
}
+ void fix_length_and_dec()
+ {
+ Item_bool_func2::fix_length_and_dec();
+ fix_char_length(2); // returns "1" or "0" or "-1"
+ }
};
@@ -1413,9 +1435,6 @@ public:
void cleanup();
};
-#ifdef USE_REGEX
-
-#include "my_regex.h"
class Item_func_regex :public Item_bool_func
{
@@ -1444,23 +1463,6 @@ public:
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
};
-#else
-
-class Item_func_regex :public Item_bool_func
-{
-public:
- Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b) {}
- longlong val_int() { return 0;}
- const char *func_name() const { return "regex"; }
-
- virtual inline void print(String *str, enum_query_type query_type)
- {
- print_op(str, query_type);
- }
-};
-
-#endif /* USE_REGEX */
-
typedef class Item COND;
@@ -1762,7 +1764,26 @@ inline Item *and_conds(Item *a, Item *b)
return new Item_cond_and(a, b);
}
+
Item *and_expressions(Item *a, Item *b, Item **org_item);
-bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type,
+longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
+ Item *warn_item, bool *is_null);
+
+
+bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type,
const char *warn_name, MYSQL_TIME *l_time);
+
+/*
+ These need definitions from this file but the variables are defined
+ in mysqld.h. The variables really belong in this component, but for
+ the time being we leave them in mysqld.cc to avoid merge problems.
+*/
+extern Eq_creator eq_creator;
+extern Ne_creator ne_creator;
+extern Gt_creator gt_creator;
+extern Lt_creator lt_creator;
+extern Ge_creator ge_creator;
+extern Le_creator le_creator;
+
+#endif /* ITEM_CMPFUNC_INCLUDED */
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 5726e987ef6..1ae65926013 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -20,8 +20,14 @@
Functions to create an item. Used by sql_yac.yy
*/
-#include "mysql_priv.h"
-#include "item_create.h"
+#include "sql_priv.h"
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" // set_var.h: THD
+#include "set_var.h"
#include "sp_head.h"
#include "sp.h"
@@ -927,10 +933,10 @@ protected:
};
-class Create_func_format : public Create_func_arg2
+class Create_func_format : public Create_native_func
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
static Create_func_format s_singleton;
@@ -1324,6 +1330,34 @@ protected:
};
+#ifndef DBUG_OFF
+class Create_func_like_range_min : public Create_func_arg2
+{
+public:
+ virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+
+ static Create_func_like_range_min s_singleton;
+
+protected:
+ Create_func_like_range_min() {}
+ virtual ~Create_func_like_range_min() {}
+};
+
+
+class Create_func_like_range_max : public Create_func_arg2
+{
+public:
+ virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+
+ static Create_func_like_range_max s_singleton;
+
+protected:
+ Create_func_like_range_max() {}
+ virtual ~Create_func_like_range_max() {}
+};
+#endif
+
+
class Create_func_ln : public Create_func_arg1
{
public:
@@ -1828,6 +1862,19 @@ protected:
};
+class Create_func_sha2 : public Create_func_arg2
+{
+public:
+ virtual Item* create(THD *thd, Item *arg1, Item *arg2);
+
+ static Create_func_sha2 s_singleton;
+
+protected:
+ Create_func_sha2() {}
+ virtual ~Create_func_sha2() {}
+};
+
+
class Create_func_sign : public Create_func_arg1
{
public:
@@ -2052,6 +2099,18 @@ protected:
virtual ~Create_func_to_days() {}
};
+class Create_func_to_seconds : public Create_func_arg1
+{
+public:
+ virtual Item* create(THD *thd, Item *arg1);
+
+ static Create_func_to_seconds s_singleton;
+
+protected:
+ Create_func_to_seconds() {}
+ virtual ~Create_func_to_seconds() {}
+};
+
#ifdef HAVE_SPATIAL
class Create_func_touches : public Create_func_arg2
@@ -2375,10 +2434,11 @@ Create_udf_func::create(THD *thd, udf_func *udf, List<Item> *item_list)
Item *func= NULL;
int arg_count= 0;
+ DBUG_ENTER("Create_udf_func::create");
if (item_list != NULL)
arg_count= item_list->elements;
- thd->lex->set_stmt_unsafe();
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_UDF);
DBUG_ASSERT( (udf->type == UDFTYPE_FUNCTION)
|| (udf->type == UDFTYPE_AGGREGATE));
@@ -2462,7 +2522,7 @@ Create_udf_func::create(THD *thd, udf_func *udf, List<Item> *item_list)
}
}
thd->lex->safe_to_cache_query= 0;
- return func;
+ DBUG_RETURN(func);
}
#endif
@@ -2933,9 +2993,7 @@ Create_func_cot Create_func_cot::s_singleton;
Item*
Create_func_cot::create(THD *thd, Item *arg1)
{
- Item *i1= new (thd->mem_root) Item_int((char*) "1", 1, 1);
- Item *i2= new (thd->mem_root) Item_func_tan(arg1);
- return new (thd->mem_root) Item_func_div(i1, i2);
+ return new (thd->mem_root) Item_func_cot(arg1);
}
@@ -3352,9 +3410,34 @@ Create_func_floor::create(THD *thd, Item *arg1)
Create_func_format Create_func_format::s_singleton;
Item*
-Create_func_format::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_format::create_native(THD *thd, LEX_STRING name,
+ List<Item> *item_list)
{
- return new (thd->mem_root) Item_func_format(arg1, arg2);
+ Item *func= NULL;
+ int arg_count= item_list ? item_list->elements : 0;
+
+ switch (arg_count) {
+ case 2:
+ {
+ Item *param_1= item_list->pop();
+ Item *param_2= item_list->pop();
+ func= new (thd->mem_root) Item_func_format(param_1, param_2);
+ break;
+ }
+ case 3:
+ {
+ Item *param_1= item_list->pop();
+ Item *param_2= item_list->pop();
+ Item *param_3= item_list->pop();
+ func= new (thd->mem_root) Item_func_format(param_1, param_2, param_3);
+ break;
+ }
+ default:
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
+ break;
+ }
+
+ return func;
}
@@ -3363,9 +3446,10 @@ Create_func_found_rows Create_func_found_rows::s_singleton;
Item*
Create_func_found_rows::create(THD *thd)
{
- thd->lex->set_stmt_unsafe();
+ DBUG_ENTER("Create_func_found_rows::create");
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
thd->lex->safe_to_cache_query= 0;
- return new (thd->mem_root) Item_func_found_rows();
+ DBUG_RETURN(new (thd->mem_root) Item_func_found_rows());
}
@@ -3524,7 +3608,7 @@ Create_func_get_lock Create_func_get_lock::s_singleton;
Item*
Create_func_get_lock::create(THD *thd, Item *arg1, Item *arg2)
{
- thd->lex->set_stmt_unsafe();
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
return new (thd->mem_root) Item_func_get_lock(arg1, arg2);
}
@@ -3636,7 +3720,7 @@ Create_func_is_free_lock Create_func_is_free_lock::s_singleton;
Item*
Create_func_is_free_lock::create(THD *thd, Item *arg1)
{
- thd->lex->set_stmt_unsafe();
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
return new (thd->mem_root) Item_func_is_free_lock(arg1);
}
@@ -3647,7 +3731,7 @@ Create_func_is_used_lock Create_func_is_used_lock::s_singleton;
Item*
Create_func_is_used_lock::create(THD *thd, Item *arg1)
{
- thd->lex->set_stmt_unsafe();
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
return new (thd->mem_root) Item_func_is_used_lock(arg1);
}
@@ -3780,6 +3864,26 @@ Create_func_length::create(THD *thd, Item *arg1)
}
+#ifndef DBUG_OFF
+Create_func_like_range_min Create_func_like_range_min::s_singleton;
+
+Item*
+Create_func_like_range_min::create(THD *thd, Item *arg1, Item *arg2)
+{
+ return new (thd->mem_root) Item_func_like_range_min(arg1, arg2);
+}
+
+
+Create_func_like_range_max Create_func_like_range_max::s_singleton;
+
+Item*
+Create_func_like_range_max::create(THD *thd, Item *arg1, Item *arg2)
+{
+ return new (thd->mem_root) Item_func_like_range_max(arg1, arg2);
+}
+#endif
+
+
Create_func_ln Create_func_ln::s_singleton;
Item*
@@ -3794,9 +3898,10 @@ Create_func_load_file Create_func_load_file::s_singleton;
Item*
Create_func_load_file::create(THD *thd, Item *arg1)
{
- thd->lex->set_stmt_unsafe();
+ DBUG_ENTER("Create_func_load_file::create");
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- return new (thd->mem_root) Item_load_file(arg1);
+ DBUG_RETURN(new (thd->mem_root) Item_load_file(arg1));
}
@@ -3964,7 +4069,7 @@ Create_func_master_pos_wait::create_native(THD *thd, LEX_STRING name,
Item *func= NULL;
int arg_count= 0;
- thd->lex->set_stmt_unsafe();
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
if (item_list != NULL)
arg_count= item_list->elements;
@@ -4186,7 +4291,7 @@ Create_func_rand::create_native(THD *thd, LEX_STRING name,
between master and slave, because the order is undefined. Hence,
the statement is unsafe to log in statement format.
*/
- thd->lex->set_stmt_unsafe();
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
switch (arg_count) {
case 0:
@@ -4218,7 +4323,7 @@ Create_func_release_lock Create_func_release_lock::s_singleton;
Item*
Create_func_release_lock::create(THD *thd, Item *arg1)
{
- thd->lex->set_stmt_unsafe();
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
return new (thd->mem_root) Item_func_release_lock(arg1);
}
@@ -4276,9 +4381,10 @@ Create_func_row_count Create_func_row_count::s_singleton;
Item*
Create_func_row_count::create(THD *thd)
{
- thd->lex->set_stmt_unsafe();
+ DBUG_ENTER("Create_func_row_count::create");
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
thd->lex->safe_to_cache_query= 0;
- return new (thd->mem_root) Item_func_row_count();
+ DBUG_RETURN(new (thd->mem_root) Item_func_row_count());
}
@@ -4318,6 +4424,15 @@ Create_func_sha::create(THD *thd, Item *arg1)
}
+Create_func_sha2 Create_func_sha2::s_singleton;
+
+Item*
+Create_func_sha2::create(THD *thd, Item *arg1, Item *arg2)
+{
+ return new (thd->mem_root) Item_func_sha2(arg1, arg2);
+}
+
+
Create_func_sign Create_func_sign::s_singleton;
Item*
@@ -4341,7 +4456,7 @@ Create_func_sleep Create_func_sleep::s_singleton;
Item*
Create_func_sleep::create(THD *thd, Item *arg1)
{
- thd->lex->set_stmt_unsafe();
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
return new (thd->mem_root) Item_func_sleep(arg1);
}
@@ -4497,6 +4612,15 @@ Create_func_to_days::create(THD *thd, Item *arg1)
}
+Create_func_to_seconds Create_func_to_seconds::s_singleton;
+
+Item*
+Create_func_to_seconds::create(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_to_seconds(arg1);
+}
+
+
#ifdef HAVE_SPATIAL
Create_func_touches Create_func_touches::s_singleton;
@@ -4586,9 +4710,10 @@ Create_func_uuid Create_func_uuid::s_singleton;
Item*
Create_func_uuid::create(THD *thd)
{
- thd->lex->set_stmt_unsafe();
+ DBUG_ENTER("Create_func_uuid::create");
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
thd->lex->safe_to_cache_query= 0;
- return new (thd->mem_root) Item_func_uuid();
+ DBUG_RETURN(new (thd->mem_root) Item_func_uuid());
}
@@ -4597,9 +4722,10 @@ Create_func_uuid_short Create_func_uuid_short::s_singleton;
Item*
Create_func_uuid_short::create(THD *thd)
{
- thd->lex->set_stmt_unsafe();
+ DBUG_ENTER("Create_func_uuid_short::create");
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
thd->lex->safe_to_cache_query= 0;
- return new (thd->mem_root) Item_func_uuid_short();
+ DBUG_RETURN(new (thd->mem_root) Item_func_uuid_short());
}
@@ -4608,7 +4734,7 @@ Create_func_version Create_func_version::s_singleton;
Item*
Create_func_version::create(THD *thd)
{
- thd->lex->set_stmt_unsafe();
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
return new (thd->mem_root) Item_static_string_func("version()",
server_version,
(uint) strlen(server_version),
@@ -4846,6 +4972,10 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("LCASE") }, BUILDER(Create_func_lcase)},
{ { C_STRING_WITH_LEN("LEAST") }, BUILDER(Create_func_least)},
{ { C_STRING_WITH_LEN("LENGTH") }, BUILDER(Create_func_length)},
+#ifndef DBUG_OFF
+ { { C_STRING_WITH_LEN("LIKE_RANGE_MIN") }, BUILDER(Create_func_like_range_min)},
+ { { C_STRING_WITH_LEN("LIKE_RANGE_MAX") }, BUILDER(Create_func_like_range_max)},
+#endif
{ { C_STRING_WITH_LEN("LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { C_STRING_WITH_LEN("LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
@@ -4917,6 +5047,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("SEC_TO_TIME") }, BUILDER(Create_func_sec_to_time)},
{ { C_STRING_WITH_LEN("SHA") }, BUILDER(Create_func_sha)},
{ { C_STRING_WITH_LEN("SHA1") }, BUILDER(Create_func_sha)},
+ { { C_STRING_WITH_LEN("SHA2") }, BUILDER(Create_func_sha2)},
{ { C_STRING_WITH_LEN("SIGN") }, BUILDER(Create_func_sign)},
{ { C_STRING_WITH_LEN("SIN") }, BUILDER(Create_func_sin)},
{ { C_STRING_WITH_LEN("SLEEP") }, BUILDER(Create_func_sleep)},
@@ -4935,6 +5066,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("TIME_TO_SEC") }, BUILDER(Create_func_time_to_sec)},
{ { C_STRING_WITH_LEN("TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
{ { C_STRING_WITH_LEN("TO_DAYS") }, BUILDER(Create_func_to_days)},
+ { { C_STRING_WITH_LEN("TO_SECONDS") }, BUILDER(Create_func_to_seconds)},
{ { C_STRING_WITH_LEN("UCASE") }, BUILDER(Create_func_ucase)},
{ { C_STRING_WITH_LEN("UNCOMPRESS") }, BUILDER(Create_func_uncompress)},
{ { C_STRING_WITH_LEN("UNCOMPRESSED_LENGTH") }, BUILDER(Create_func_uncompressed_length)},
@@ -4978,14 +5110,14 @@ int item_create_init()
DBUG_ENTER("item_create_init");
- if (hash_init(& native_functions_hash,
- system_charset_info,
- array_elements(func_array),
- 0,
- 0,
- (hash_get_key) get_native_fct_hash_key,
- NULL, /* Nothing to free */
- MYF(0)))
+ if (my_hash_init(& native_functions_hash,
+ system_charset_info,
+ array_elements(func_array),
+ 0,
+ 0,
+ (my_hash_get_key) get_native_fct_hash_key,
+ NULL, /* Nothing to free */
+ MYF(0)))
DBUG_RETURN(1);
for (func= func_array; func->builder != NULL; func++)
@@ -4997,7 +5129,7 @@ int item_create_init()
#ifndef DBUG_OFF
for (uint i=0 ; i < native_functions_hash.records ; i++)
{
- func= (Native_func_registry*) hash_element(& native_functions_hash, i);
+ func= (Native_func_registry*) my_hash_element(& native_functions_hash, i);
DBUG_PRINT("info", ("native function: %s length: %u",
func->name.str, (uint) func->name.length));
}
@@ -5015,7 +5147,7 @@ int item_create_init()
void item_create_cleanup()
{
DBUG_ENTER("item_create_cleanup");
- hash_free(& native_functions_hash);
+ my_hash_free(& native_functions_hash);
DBUG_VOID_RETURN;
}
@@ -5026,9 +5158,9 @@ find_native_function_builder(THD *thd, LEX_STRING name)
Create_func *builder= NULL;
/* Thread safe */
- func= (Native_func_registry*) hash_search(& native_functions_hash,
- (uchar*) name.str,
- name.length);
+ func= (Native_func_registry*) my_hash_search(& native_functions_hash,
+ (uchar*) name.str,
+ name.length);
if (func)
{
diff --git a/sql/item_create.h b/sql/item_create.h
index d84c764a3d9..fc21e0a4d33 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -18,6 +18,8 @@
#ifndef ITEM_CREATE_H
#define ITEM_CREATE_H
+typedef struct st_udf_func udf_func;
+
/**
Public function builder interface.
The parser (sql/sql_yacc.yy) uses a factory / builder pattern to
@@ -163,5 +165,9 @@ Item *
create_func_cast(THD *thd, Item *a, Cast_target cast_type,
const char *len, const char *dec,
CHARSET_INFO *cs);
+
+int item_create_init();
+void item_create_cleanup();
+
#endif
diff --git a/sql/item_func.cc b/sql/item_func.cc
index b542969cfb0..92b80e274f4 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -25,8 +25,21 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" // set_var.h: THD
+#include "set_var.h"
#include "slave.h" // for wait_for_master_pos
+#include "sql_show.h" // append_identifier
+#include "strfunc.h" // find_type
+#include "sql_parse.h" // is_update_query
+#include "sql_acl.h" // EXECUTE_ACL
+#include "mysqld.h" // LOCK_uuid_generator
#include "rpl_mi.h"
#include <m_ctype.h>
#include <hash.h>
@@ -37,6 +50,8 @@
#include "sp_head.h"
#include "sp_rcontext.h"
#include "sp.h"
+#include "set_var.h"
+#include "debug_sync.h"
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define sp_restore_security_context(A,B) while (0) {}
@@ -64,6 +79,14 @@ eval_const_cond(COND *cond)
}
+/**
+ Test if the sum of arguments overflows the ulonglong range.
+*/
+static inline bool test_if_sum_overflows_ull(ulonglong arg1, ulonglong arg2)
+{
+ return ULONGLONG_MAX - arg1 < arg2;
+}
+
void Item_func::set_arguments(List<Item> &list)
{
allowed_arg_cols= 1;
@@ -150,9 +173,7 @@ Item_func::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
Item **arg,**arg_end;
-#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
uchar buff[STACK_BUFF_ALLOC]; // Max argument in function
-#endif
used_tables_cache= not_null_tables_cache= 0;
const_item_cache=1;
@@ -446,13 +467,15 @@ Field *Item_func::tmp_table_field(TABLE *table)
switch (result_type()) {
case INT_RESULT:
- if (max_length > MY_INT32_NUM_DECIMAL_DIGITS)
- field= new Field_longlong(max_length, maybe_null, name, unsigned_flag);
+ if (max_char_length() > MY_INT32_NUM_DECIMAL_DIGITS)
+ field= new Field_longlong(max_char_length(), maybe_null, name,
+ unsigned_flag);
else
- field= new Field_long(max_length, maybe_null, name, unsigned_flag);
+ field= new Field_long(max_char_length(), maybe_null, name,
+ unsigned_flag);
break;
case REAL_RESULT:
- field= new Field_double(max_length, maybe_null, name, decimals);
+ field= new Field_double(max_char_length(), maybe_null, name, decimals);
break;
case STRING_RESULT:
return make_string_field(table);
@@ -493,7 +516,7 @@ String *Item_real_func::val_str(String *str)
double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
- str->set_real(nr,decimals, &my_charset_bin);
+ str->set_real(nr, decimals, collation.collation);
return str;
}
@@ -548,8 +571,9 @@ void Item_func::count_decimal_length()
set_if_smaller(unsigned_flag, args[i]->unsigned_flag);
}
int precision= min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
- max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
- unsigned_flag);
+ fix_char_length(my_decimal_precision_to_length_no_truncation(precision,
+ decimals,
+ unsigned_flag));
}
@@ -559,13 +583,14 @@ void Item_func::count_decimal_length()
void Item_func::count_only_length()
{
- max_length= 0;
+ uint32 char_length= 0;
unsigned_flag= 0;
for (uint i=0 ; i < arg_count ; i++)
{
- set_if_bigger(max_length, args[i]->max_length);
+ set_if_bigger(char_length, args[i]->max_char_length());
set_if_bigger(unsigned_flag, args[i]->unsigned_flag);
}
+ fix_char_length(char_length);
}
@@ -605,7 +630,7 @@ void Item_func::signal_divide_by_null()
{
THD *thd= current_thd;
if (thd->variables.sql_mode & MODE_ERROR_FOR_DIVISION_BY_ZERO)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DIVISION_BY_ZERO,
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_DIVISION_BY_ZERO,
ER(ER_DIVISION_BY_ZERO));
null_value= 1;
}
@@ -632,7 +657,7 @@ String *Item_int_func::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- str->set_int(nr, unsigned_flag, &my_charset_bin);
+ str->set_int(nr, unsigned_flag, collation.collation);
return str;
}
@@ -752,6 +777,7 @@ String *Item_func_numhybrid::val_str(String *str)
if (!(val= decimal_op(&decimal_value)))
return 0; // null is set
my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
+ str->set_charset(collation.collation);
my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str);
break;
}
@@ -760,7 +786,7 @@ String *Item_func_numhybrid::val_str(String *str)
longlong nr= int_op();
if (null_value)
return 0; /* purecov: inspected */
- str->set_int(nr, unsigned_flag, &my_charset_bin);
+ str->set_int(nr, unsigned_flag, collation.collation);
break;
}
case REAL_RESULT:
@@ -768,7 +794,7 @@ String *Item_func_numhybrid::val_str(String *str)
double nr= real_op();
if (null_value)
return 0; /* purecov: inspected */
- str->set_real(nr,decimals,&my_charset_bin);
+ str->set_real(nr, decimals, collation.collation);
break;
}
case STRING_RESULT:
@@ -903,6 +929,7 @@ longlong Item_func_signed::val_int_from_str(int *error)
uint32 length;
String tmp(buff,sizeof(buff), &my_charset_bin), *res;
longlong value;
+ CHARSET_INFO *cs;
/*
For a string result, we must first get the string and then convert it
@@ -918,9 +945,10 @@ longlong Item_func_signed::val_int_from_str(int *error)
null_value= 0;
start= (char *)res->ptr();
length= res->length();
+ cs= res->charset();
end= start + length;
- value= my_strtoll10(start, &end, error);
+ value= cs->cset->strtoll10(cs, start, &end, error);
if (*error > 0 || end != start+ length)
{
char err_buff[128];
@@ -1060,7 +1088,7 @@ my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec)
return dec;
err:
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
ER(ER_WARN_DATA_OUT_OF_RANGE),
name, 1);
@@ -1097,16 +1125,68 @@ double Item_func_plus::real_op()
double value= args[0]->val_real() + args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
- return fix_result(value);
+ return check_float_overflow(value);
}
longlong Item_func_plus::int_op()
{
- longlong value=args[0]->val_int()+args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
+ longlong val0= args[0]->val_int();
+ longlong val1= args[1]->val_int();
+ longlong res= val0 + val1;
+ bool res_unsigned= FALSE;
+
+ if ((null_value= args[0]->null_value || args[1]->null_value))
return 0;
- return value;
+
+ /*
+ First check whether the result can be represented as a
+ (bool unsigned_flag, longlong value) pair, then check if it is compatible
+ with this Item's unsigned_flag by calling check_integer_overflow().
+ */
+ if (args[0]->unsigned_flag)
+ {
+ if (args[1]->unsigned_flag || val1 >= 0)
+ {
+ if (test_if_sum_overflows_ull((ulonglong) val0, (ulonglong) val1))
+ goto err;
+ res_unsigned= TRUE;
+ }
+ else
+ {
+ /* val1 is negative */
+ if ((ulonglong) val0 > (ulonglong) LONGLONG_MAX)
+ res_unsigned= TRUE;
+ }
+ }
+ else
+ {
+ if (args[1]->unsigned_flag)
+ {
+ if (val0 >= 0)
+ {
+ if (test_if_sum_overflows_ull((ulonglong) val0, (ulonglong) val1))
+ goto err;
+ res_unsigned= TRUE;
+ }
+ else
+ {
+ if ((ulonglong) val1 > (ulonglong) LONGLONG_MAX)
+ res_unsigned= TRUE;
+ }
+ }
+ else
+ {
+ if (val0 >=0 && val1 >= 0)
+ res_unsigned= TRUE;
+ else if (val0 < 0 && val1 < 0 && res >= 0)
+ goto err;
+ }
+ }
+ return check_integer_overflow(res, res_unsigned);
+
+err:
+ return raise_integer_overflow();
}
@@ -1130,8 +1210,10 @@ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value)
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
- (my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 3))))
+ check_decimal_overflow(my_decimal_add(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW,
+ decimal_value,
+ val1, val2)) > 3)))
return decimal_value;
return 0;
}
@@ -1175,16 +1257,71 @@ double Item_func_minus::real_op()
double value= args[0]->val_real() - args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
- return fix_result(value);
+ return check_float_overflow(value);
}
longlong Item_func_minus::int_op()
{
- longlong value=args[0]->val_int() - args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
+ longlong val0= args[0]->val_int();
+ longlong val1= args[1]->val_int();
+ longlong res= val0 - val1;
+ bool res_unsigned= FALSE;
+
+ if ((null_value= args[0]->null_value || args[1]->null_value))
return 0;
- return value;
+
+ /*
+ First check whether the result can be represented as a
+ (bool unsigned_flag, longlong value) pair, then check if it is compatible
+ with this Item's unsigned_flag by calling check_integer_overflow().
+ */
+ if (args[0]->unsigned_flag)
+ {
+ if (args[1]->unsigned_flag)
+ {
+ if ((ulonglong) val0 < (ulonglong) val1)
+ {
+ if (res >= 0)
+ goto err;
+ }
+ else
+ res_unsigned= TRUE;
+ }
+ else
+ {
+ if (val1 >= 0)
+ {
+ if ((ulonglong) val0 > (ulonglong) val1)
+ res_unsigned= TRUE;
+ }
+ else
+ {
+ if (test_if_sum_overflows_ull((ulonglong) val0, (ulonglong) -val1))
+ goto err;
+ res_unsigned= TRUE;
+ }
+ }
+ }
+ else
+ {
+ if (args[1]->unsigned_flag)
+ {
+ if ((ulonglong) (val0 - LONGLONG_MIN) < (ulonglong) val1)
+ goto err;
+ }
+ else
+ {
+ if (val0 > 0 && val1 < 0)
+ res_unsigned= TRUE;
+ else if (val0 < 0 && val1 > 0 && res >= 0)
+ goto err;
+ }
+ }
+ return check_integer_overflow(res, res_unsigned);
+
+err:
+ return raise_integer_overflow();
}
@@ -1202,8 +1339,10 @@ my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value)
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
- (my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 3))))
+ (check_decimal_overflow(my_decimal_sub(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW,
+ decimal_value, val1,
+ val2)) > 3))))
return decimal_value;
return 0;
}
@@ -1215,17 +1354,86 @@ double Item_func_mul::real_op()
double value= args[0]->val_real() * args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
- return fix_result(value);
+ return check_float_overflow(value);
}
longlong Item_func_mul::int_op()
{
DBUG_ASSERT(fixed == 1);
- longlong value=args[0]->val_int()*args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
+ longlong a= args[0]->val_int();
+ longlong b= args[1]->val_int();
+ longlong res;
+ ulonglong res0, res1;
+ ulong a0, a1, b0, b1;
+ bool res_unsigned= FALSE;
+ bool a_negative= FALSE, b_negative= FALSE;
+
+ if ((null_value= args[0]->null_value || args[1]->null_value))
return 0;
- return value;
+
+ /*
+ First check whether the result can be represented as a
+ (bool unsigned_flag, longlong value) pair, then check if it is compatible
+ with this Item's unsigned_flag by calling check_integer_overflow().
+
+ Let a = a1 * 2^32 + a0 and b = b1 * 2^32 + b0. Then
+ a * b = (a1 * 2^32 + a0) * (b1 * 2^32 + b0) = a1 * b1 * 2^64 +
+ + (a1 * b0 + a0 * b1) * 2^32 + a0 * b0;
+ We can determine if the above sum overflows the ulonglong range by
+ sequentially checking the following conditions:
+ 1. If both a1 and b1 are non-zero.
+ 2. Otherwise, if (a1 * b0 + a0 * b1) is greater than ULONG_MAX.
+ 3. Otherwise, if (a1 * b0 + a0 * b1) * 2^32 + a0 * b0 is greater than
+ ULONGLONG_MAX.
+
+ Since we also have to take the unsigned_flag for a and b into account,
+ it is easier to first work with absolute values and set the
+ correct sign later.
+ */
+ if (!args[0]->unsigned_flag && a < 0)
+ {
+ a_negative= TRUE;
+ a= -a;
+ }
+ if (!args[1]->unsigned_flag && b < 0)
+ {
+ b_negative= TRUE;
+ b= -b;
+ }
+
+ a0= 0xFFFFFFFFUL & a;
+ a1= ((ulonglong) a) >> 32;
+ b0= 0xFFFFFFFFUL & b;
+ b1= ((ulonglong) b) >> 32;
+
+ if (a1 && b1)
+ goto err;
+
+ res1= (ulonglong) a1 * b0 + (ulonglong) a0 * b1;
+ if (res1 > 0xFFFFFFFFUL)
+ goto err;
+
+ res1= res1 << 32;
+ res0= (ulonglong) a0 * b0;
+
+ if (test_if_sum_overflows_ull(res1, res0))
+ goto err;
+ res= res1 + res0;
+
+ if (a_negative != b_negative)
+ {
+ if ((ulonglong) res > (ulonglong) LONGLONG_MIN + 1)
+ goto err;
+ res= -res;
+ }
+ else
+ res_unsigned= TRUE;
+
+ return check_integer_overflow(res, res_unsigned);
+
+err:
+ return raise_integer_overflow();
}
@@ -1240,8 +1448,10 @@ my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value)
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
- (my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 3))))
+ (check_decimal_overflow(my_decimal_mul(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW,
+ decimal_value, val1,
+ val2)) > 3))))
return decimal_value;
return 0;
}
@@ -1274,7 +1484,7 @@ double Item_func_div::real_op()
signal_divide_by_null();
return 0.0;
}
- return fix_result(value/val2);
+ return check_float_overflow(value/val2);
}
@@ -1290,8 +1500,12 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
val2= args[1]->val_decimal(&value2);
if ((null_value= args[1]->null_value))
return 0;
- if ((err= my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value,
- val1, val2, prec_increment)) > 3)
+ if ((err= check_decimal_overflow(my_decimal_div(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW &
+ ~E_DEC_DIV_ZERO,
+ decimal_value,
+ val1, val2,
+ prec_increment))) > 3)
{
if (err == E_DEC_DIV_ZERO)
signal_divide_by_null();
@@ -1354,22 +1568,63 @@ void Item_func_div::fix_length_and_dec()
longlong Item_func_int_div::val_int()
{
DBUG_ASSERT(fixed == 1);
- longlong value=args[0]->val_int();
- longlong val2=args[1]->val_int();
+
+ /*
+ Perform division using DECIMAL math if either of the operands has a
+ non-integer type
+ */
+ if (args[0]->result_type() != INT_RESULT ||
+ args[1]->result_type() != INT_RESULT)
+ {
+ my_decimal value0, value1, tmp;
+ my_decimal *val0, *val1;
+ longlong res;
+ int err;
+
+ val0= args[0]->val_decimal(&value0);
+ val1= args[1]->val_decimal(&value1);
+ if ((null_value= (args[0]->null_value || args[1]->null_value)))
+ return 0;
+
+ if ((err= my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, &tmp,
+ val0, val1, 0)) > 3)
+ {
+ if (err == E_DEC_DIV_ZERO)
+ signal_divide_by_null();
+ return 0;
+ }
+
+ if (my_decimal2int(E_DEC_FATAL_ERROR, &tmp, unsigned_flag, &res) &
+ E_DEC_OVERFLOW)
+ raise_integer_overflow();
+ return res;
+ }
+
+ longlong val0=args[0]->val_int();
+ longlong val1=args[1]->val_int();
+ bool val0_negative, val1_negative, res_negative;
+ ulonglong uval0, uval1, res;
if ((null_value= (args[0]->null_value || args[1]->null_value)))
return 0;
- if (val2 == 0)
+ if (val1 == 0)
{
signal_divide_by_null();
return 0;
}
- if (unsigned_flag)
- return ((ulonglong) value / (ulonglong) val2);
- else if (value == LONGLONG_MIN && val2 == -1)
- return LONGLONG_MIN;
- else
- return value / val2;
+ val0_negative= !args[0]->unsigned_flag && val0 < 0;
+ val1_negative= !args[1]->unsigned_flag && val1 < 0;
+ res_negative= val0_negative != val1_negative;
+ uval0= (ulonglong) (val0_negative ? -val0 : val0);
+ uval1= (ulonglong) (val1_negative ? -val1 : val1);
+ res= uval0 / uval1;
+ if (res_negative)
+ {
+ if (res > (ulonglong) LONGLONG_MAX)
+ return raise_integer_overflow();
+ res= (ulonglong) (-(longlong) res);
+ }
+ return check_integer_overflow(res, !res_negative);
}
@@ -1388,26 +1643,32 @@ void Item_func_int_div::fix_length_and_dec()
longlong Item_func_mod::int_op()
{
DBUG_ASSERT(fixed == 1);
- longlong value= args[0]->val_int();
- longlong val2= args[1]->val_int();
- longlong result;
+ longlong val0= args[0]->val_int();
+ longlong val1= args[1]->val_int();
+ bool val0_negative, val1_negative;
+ ulonglong uval0, uval1;
+ ulonglong res;
if ((null_value= args[0]->null_value || args[1]->null_value))
return 0; /* purecov: inspected */
- if (val2 == 0)
+ if (val1 == 0)
{
signal_divide_by_null();
return 0;
}
- if (args[0]->unsigned_flag)
- result= args[1]->unsigned_flag ?
- ((ulonglong) value) % ((ulonglong) val2) : ((ulonglong) value) % val2;
- else result= args[1]->unsigned_flag ?
- value % ((ulonglong) val2) :
- (val2 == -1) ? 0 : value % val2;
-
- return result;
+ /*
+ '%' is calculated by integer division internally. Since dividing
+ LONGLONG_MIN by -1 generates SIGFPE, we calculate using unsigned values and
+ then adjust the sign appropriately.
+ */
+ val0_negative= !args[0]->unsigned_flag && val0 < 0;
+ val1_negative= !args[1]->unsigned_flag && val1 < 0;
+ uval0= (ulonglong) (val0_negative ? -val0 : val0);
+ uval1= (ulonglong) (val1_negative ? -val1 : val1);
+ res= uval0 % uval1;
+ return check_integer_overflow(val0_negative ? -(longlong) res : res,
+ !val0_negative);
}
double Item_func_mod::real_op()
@@ -1477,8 +1738,12 @@ double Item_func_neg::real_op()
longlong Item_func_neg::int_op()
{
longlong value= args[0]->val_int();
- null_value= args[0]->null_value;
- return -value;
+ if ((null_value= args[0]->null_value))
+ return 0;
+ if (args[0]->unsigned_flag &&
+ (ulonglong) value > (ulonglong) LONGLONG_MAX + 1)
+ return raise_integer_overflow();
+ return check_integer_overflow(-value, !args[0]->unsigned_flag && value < 0);
}
@@ -1547,7 +1812,12 @@ longlong Item_func_abs::int_op()
longlong value= args[0]->val_int();
if ((null_value= args[0]->null_value))
return 0;
- return (value >= 0) || unsigned_flag ? value : -value;
+ if (unsigned_flag)
+ return value;
+ /* -LONGLONG_MIN = LONGLONG_MAX + 1 => outside of signed longlong range */
+ if (value == LONGLONG_MIN)
+ return raise_integer_overflow();
+ return (value >= 0) ? value : -value;
}
@@ -1654,7 +1924,7 @@ double Item_func_exp::val_real()
double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0.0; /* purecov: inspected */
- return fix_result(exp(value));
+ return check_float_overflow(exp(value));
}
double Item_func_sqrt::val_real()
@@ -1673,7 +1943,7 @@ double Item_func_pow::val_real()
double val2= args[1]->val_real();
if ((null_value=(args[0]->null_value || args[1]->null_value)))
return 0.0; /* purecov: inspected */
- return fix_result(pow(value,val2));
+ return check_float_overflow(pow(value,val2));
}
// Trigonometric functions
@@ -1681,6 +1951,8 @@ double Item_func_pow::val_real()
double Item_func_acos::val_real()
{
DBUG_ASSERT(fixed == 1);
+ /* One can use this to defer SELECT processing. */
+ DEBUG_SYNC(current_thd, "before_acos_function");
// the volatile's for BUG #2338 to calm optimizer down (because of gcc's bug)
volatile double value= args[0]->val_real();
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
@@ -1709,7 +1981,7 @@ double Item_func_atan::val_real()
double val2= args[1]->val_real();
if ((null_value=args[1]->null_value))
return 0.0;
- return fix_result(atan2(value,val2));
+ return check_float_overflow(atan2(value,val2));
}
return atan(value);
}
@@ -1738,7 +2010,17 @@ double Item_func_tan::val_real()
double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0.0;
- return fix_result(tan(value));
+ return check_float_overflow(tan(value));
+}
+
+
+double Item_func_cot::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+ double value= args[0]->val_real();
+ if ((null_value=args[0]->null_value))
+ return 0.0;
+ return check_float_overflow(1.0 / tan(value));
}
@@ -2213,7 +2495,7 @@ double Item_func_units::val_real()
double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0;
- return value*mul+add;
+ return check_float_overflow(value * mul + add);
}
@@ -2243,7 +2525,7 @@ void Item_func_min_max::fix_length_and_dec()
}
if (cmp_type == STRING_RESULT)
{
- agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1);
+ agg_arg_charsets_for_comparison(collation, args, arg_count);
if (datetime_found)
{
thd= current_thd;
@@ -2251,11 +2533,15 @@ void Item_func_min_max::fix_length_and_dec()
}
}
else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
- max_length= my_decimal_precision_to_length_no_truncation(max_int_part +
- decimals, decimals,
- unsigned_flag);
+ {
+ collation.set_numeric();
+ fix_char_length(my_decimal_precision_to_length_no_truncation(max_int_part +
+ decimals,
+ decimals,
+ unsigned_flag));
+ }
else if (cmp_type == REAL_RESULT)
- max_length= float_length(decimals);
+ fix_char_length(float_length(decimals));
cached_field_type= agg_field_type(args, arg_count);
}
@@ -2339,7 +2625,7 @@ String *Item_func_min_max::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- str->set_int(nr, unsigned_flag, &my_charset_bin);
+ str->set_int(nr, unsigned_flag, collation.collation);
return str;
}
case DECIMAL_RESULT:
@@ -2355,7 +2641,7 @@ String *Item_func_min_max::val_str(String *str)
double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
- str->set_real(nr,decimals,&my_charset_bin);
+ str->set_real(nr, decimals, collation.collation);
return str;
}
case STRING_RESULT:
@@ -2526,7 +2812,7 @@ longlong Item_func_coercibility::val_int()
void Item_func_locate::fix_length_and_dec()
{
max_length= MY_INT32_NUM_DECIMAL_DIGITS;
- agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1);
+ agg_arg_charsets_for_comparison(cmp_collation, args, 2);
}
@@ -2650,7 +2936,7 @@ void Item_func_field::fix_length_and_dec()
for (uint i=1; i < arg_count ; i++)
cmp_type= item_cmp_type(cmp_type, args[i]->result_type());
if (cmp_type == STRING_RESULT)
- agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1);
+ agg_arg_charsets_for_comparison(cmp_collation, args, arg_count);
}
@@ -2717,7 +3003,7 @@ void Item_func_find_in_set::fix_length_and_dec()
}
}
}
- agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1);
+ agg_arg_charsets_for_comparison(cmp_collation, args, 2);
}
static const char separator=',';
@@ -2833,9 +3119,7 @@ bool
udf_handler::fix_fields(THD *thd, Item_result_field *func,
uint arg_count, Item **arguments)
{
-#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
uchar buff[STACK_BUFF_ALLOC]; // Max argument in function
-#endif
DBUG_ENTER("Item_udf_func::fix_fields");
if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
@@ -2947,7 +3231,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
String *res= arguments[i]->val_str(&buffers[i]);
if (arguments[i]->null_value)
continue;
- f_args.args[i]= (char*) res->c_ptr();
+ f_args.args[i]= (char*) res->c_ptr_safe();
f_args.lengths[i]= res->length();
break;
}
@@ -3085,7 +3369,7 @@ String *udf_handler::val_str(String *str,String *save_str)
if (res == str->ptr())
{
str->length(res_length);
- DBUG_PRINT("exit", ("str: %s", str->ptr()));
+ DBUG_PRINT("exit", ("str: %*.s", (int) str->length(), str->ptr()));
DBUG_RETURN(str);
}
save_str->set(res, res_length, str->charset());
@@ -3277,7 +3561,7 @@ bool udf_handler::get_arguments() { return 0; }
** User level locks
*/
-pthread_mutex_t LOCK_user_locks;
+mysql_mutex_t LOCK_user_locks;
static HASH hash_user_locks;
class User_level_lock
@@ -3288,7 +3572,7 @@ class User_level_lock
public:
int count;
bool locked;
- pthread_cond_t cond;
+ mysql_cond_t cond;
my_thread_id thread_id;
void set_thread(THD *thd) { thread_id= thd->thread_id; }
@@ -3296,12 +3580,12 @@ public:
:key_length(length),count(1),locked(1), thread_id(id)
{
key= (uchar*) my_memdup(key_arg,length,MYF(0));
- pthread_cond_init(&cond,NULL);
+ mysql_cond_init(key_user_level_lock_cond, &cond, NULL);
if (key)
{
if (my_hash_insert(&hash_user_locks,(uchar*) this))
{
- my_free(key,MYF(0));
+ my_free(key);
key=0;
}
}
@@ -3310,10 +3594,10 @@ public:
{
if (key)
{
- hash_delete(&hash_user_locks,(uchar*) this);
- my_free(key, MYF(0));
+ my_hash_delete(&hash_user_locks,(uchar*) this);
+ my_free(key);
}
- pthread_cond_destroy(&cond);
+ mysql_cond_destroy(&cond);
}
inline bool initialized() { return key != 0; }
friend void item_user_lock_release(User_level_lock *ull);
@@ -3328,14 +3612,38 @@ uchar *ull_get_key(const User_level_lock *ull, size_t *length,
return ull->key;
}
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_LOCK_user_locks;
+
+static PSI_mutex_info all_user_mutexes[]=
+{
+ { &key_LOCK_user_locks, "LOCK_user_locks", PSI_FLAG_GLOBAL}
+};
+
+static void init_user_lock_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_user_mutexes);
+ PSI_server->register_mutex(category, all_user_mutexes, count);
+}
+#endif
static bool item_user_lock_inited= 0;
void item_user_lock_init(void)
{
- pthread_mutex_init(&LOCK_user_locks,MY_MUTEX_INIT_SLOW);
- hash_init(&hash_user_locks,system_charset_info,
- 16,0,0,(hash_get_key) ull_get_key,NULL,0);
+#ifdef HAVE_PSI_INTERFACE
+ init_user_lock_psi_keys();
+#endif
+
+ mysql_mutex_init(key_LOCK_user_locks, &LOCK_user_locks, MY_MUTEX_INIT_SLOW);
+ my_hash_init(&hash_user_locks,system_charset_info,
+ 16,0,0,(my_hash_get_key) ull_get_key,NULL,0);
item_user_lock_inited= 1;
}
@@ -3344,8 +3652,8 @@ void item_user_lock_free(void)
if (item_user_lock_inited)
{
item_user_lock_inited= 0;
- hash_free(&hash_user_locks);
- pthread_mutex_destroy(&LOCK_user_locks);
+ my_hash_free(&hash_user_locks);
+ mysql_mutex_destroy(&LOCK_user_locks);
}
}
@@ -3354,7 +3662,7 @@ void item_user_lock_release(User_level_lock *ull)
ull->locked=0;
ull->thread_id= 0;
if (--ull->count)
- pthread_cond_signal(&ull->cond);
+ mysql_cond_signal(&ull->cond);
else
delete ull;
}
@@ -3391,6 +3699,92 @@ longlong Item_master_pos_wait::val_int()
/**
+ Enables a session to wait on a condition until a timeout or a network
+ disconnect occurs.
+
+ @remark The connection is polled every m_interrupt_interval nanoseconds.
+*/
+
+class Interruptible_wait
+{
+ THD *m_thd;
+ struct timespec m_abs_timeout;
+ static const ulonglong m_interrupt_interval;
+
+ public:
+ Interruptible_wait(THD *thd)
+ : m_thd(thd) {}
+
+ ~Interruptible_wait() {}
+
+ public:
+ /**
+ Set the absolute timeout.
+
+ @param timeout The amount of time in nanoseconds to wait
+ */
+ void set_timeout(ulonglong timeout)
+ {
+ /*
+ Calculate the absolute system time at the start so it can
+ be controlled in slices. It relies on the fact that once
+ the absolute time passes, the timed wait call will fail
+ automatically with a timeout error.
+ */
+ set_timespec_nsec(m_abs_timeout, timeout);
+ }
+
+ /** The timed wait. */
+ int wait(mysql_cond_t *, mysql_mutex_t *);
+};
+
+
+/** Time to wait before polling the connection status. */
+const ulonglong Interruptible_wait::m_interrupt_interval= 5 * ULL(1000000000);
+
+
+/**
+ Wait for a given condition to be signaled.
+
+ @param cond The condition variable to wait on.
+ @param mutex The associated mutex.
+
+ @remark The absolute timeout is preserved across calls.
+
+ @retval return value from mysql_cond_timedwait
+*/
+
+int Interruptible_wait::wait(mysql_cond_t *cond, mysql_mutex_t *mutex)
+{
+ int error;
+ struct timespec timeout;
+
+ while (1)
+ {
+ /* Wait for a fixed interval. */
+ set_timespec_nsec(timeout, m_interrupt_interval);
+
+ /* But only if not past the absolute timeout. */
+ if (cmp_timespec(timeout, m_abs_timeout) > 0)
+ timeout= m_abs_timeout;
+
+ error= mysql_cond_timedwait(cond, mutex, &timeout);
+ if (error == ETIMEDOUT || error == ETIME)
+ {
+ /* Return error if timed out or connection is broken. */
+ if (!cmp_timespec(timeout, m_abs_timeout) || !m_thd->is_connected())
+ break;
+ }
+ /* Otherwise, propagate status to the caller. */
+ else
+ break;
+ }
+
+ return error;
+}
+
+
+/**
Get a user level lock. If the thread has an old lock this is first released.
@retval
@@ -3405,11 +3799,11 @@ longlong Item_func_get_lock::val_int()
{
DBUG_ASSERT(fixed == 1);
String *res=args[0]->val_str(&value);
- longlong timeout=args[1]->val_int();
- struct timespec abstime;
+ ulonglong timeout= args[1]->val_int();
THD *thd=current_thd;
User_level_lock *ull;
int error;
+ Interruptible_wait timed_cond(thd);
DBUG_ENTER("Item_func_get_lock::val_int");
/*
@@ -3422,11 +3816,11 @@ longlong Item_func_get_lock::val_int()
if (thd->slave_thread)
DBUG_RETURN(1);
- pthread_mutex_lock(&LOCK_user_locks);
+ mysql_mutex_lock(&LOCK_user_locks);
if (!res || !res->length())
{
- pthread_mutex_unlock(&LOCK_user_locks);
+ mysql_mutex_unlock(&LOCK_user_locks);
null_value=1;
DBUG_RETURN(0);
}
@@ -3440,22 +3834,22 @@ longlong Item_func_get_lock::val_int()
thd->ull=0;
}
- if (!(ull= ((User_level_lock *) hash_search(&hash_user_locks,
- (uchar*) res->ptr(),
- (size_t) res->length()))))
+ if (!(ull= ((User_level_lock *) my_hash_search(&hash_user_locks,
+ (uchar*) res->ptr(),
+ (size_t) res->length()))))
{
ull= new User_level_lock((uchar*) res->ptr(), (size_t) res->length(),
thd->thread_id);
if (!ull || !ull->initialized())
{
delete ull;
- pthread_mutex_unlock(&LOCK_user_locks);
+ mysql_mutex_unlock(&LOCK_user_locks);
null_value=1; // Probably out of memory
DBUG_RETURN(0);
}
ull->set_thread(thd);
thd->ull=ull;
- pthread_mutex_unlock(&LOCK_user_locks);
+ mysql_mutex_unlock(&LOCK_user_locks);
DBUG_PRINT("info", ("made new lock"));
DBUG_RETURN(1); // Got new lock
}
@@ -3470,12 +3864,13 @@ longlong Item_func_get_lock::val_int()
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
- set_timespec(abstime,timeout);
+ timed_cond.set_timeout(timeout * ULL(1000000000));
+
error= 0;
while (ull->locked && !thd->killed)
{
DBUG_PRINT("info", ("waiting on lock"));
- error= pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime);
+ error= timed_cond.wait(&ull->cond, &LOCK_user_locks);
if (error == ETIMEDOUT || error == ETIME)
{
DBUG_PRINT("info", ("lock wait timeout"));
@@ -3506,13 +3901,13 @@ longlong Item_func_get_lock::val_int()
error=0;
DBUG_PRINT("info", ("got the lock"));
}
- pthread_mutex_unlock(&LOCK_user_locks);
+ mysql_mutex_unlock(&LOCK_user_locks);
- pthread_mutex_lock(&thd->mysys_var->mutex);
+ mysql_mutex_lock(&thd->mysys_var->mutex);
thd_proc_info(thd, 0);
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
- pthread_mutex_unlock(&thd->mysys_var->mutex);
+ mysql_mutex_unlock(&thd->mysys_var->mutex);
DBUG_RETURN(!error ? 1 : 0);
}
@@ -3543,10 +3938,10 @@ longlong Item_func_release_lock::val_int()
null_value=0;
result=0;
- pthread_mutex_lock(&LOCK_user_locks);
- if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks,
- (const uchar*) res->ptr(),
- (size_t) res->length()))))
+ mysql_mutex_lock(&LOCK_user_locks);
+ if (!(ull= ((User_level_lock*) my_hash_search(&hash_user_locks,
+ (const uchar*) res->ptr(),
+ (size_t) res->length()))))
{
null_value=1;
}
@@ -3564,7 +3959,7 @@ longlong Item_func_release_lock::val_int()
thd->ull=0;
}
}
- pthread_mutex_unlock(&LOCK_user_locks);
+ mysql_mutex_unlock(&LOCK_user_locks);
DBUG_RETURN(result);
}
@@ -3619,7 +4014,7 @@ longlong Item_func_benchmark::val_int()
{
char buff[22];
llstr(((longlong) loop_count), buff);
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE),
"count", buff, "benchmark");
}
@@ -3670,29 +4065,30 @@ void Item_func_benchmark::print(String *str, enum_query_type query_type)
longlong Item_func_sleep::val_int()
{
THD *thd= current_thd;
- struct timespec abstime;
- pthread_cond_t cond;
+ Interruptible_wait timed_cond(thd);
+ mysql_cond_t cond;
+ double timeout;
int error;
DBUG_ASSERT(fixed == 1);
- double time= args[0]->val_real();
+ timeout= args[0]->val_real();
/*
- On 64-bit OSX pthread_cond_timedwait() waits forever
+ On 64-bit OSX mysql_cond_timedwait() waits forever
if passed abstime time has already been exceeded by
the system time.
When given a very short timeout (< 10 mcs) just return
immediately.
We assume that the lines between this test and the call
- to pthread_cond_timedwait() will be executed in less than 0.00001 sec.
+ to mysql_cond_timedwait() will be executed in less than 0.00001 sec.
*/
- if (time < 0.00001)
+ if (timeout < 0.00001)
return 0;
-
- set_timespec_nsec(abstime, (ulonglong)(time * ULL(1000000000)));
- pthread_cond_init(&cond, NULL);
- pthread_mutex_lock(&LOCK_user_locks);
+ timed_cond.set_timeout((ulonglong) (timeout * 1000000000.0));
+
+ mysql_cond_init(key_item_func_sleep_cond, &cond, NULL);
+ mysql_mutex_lock(&LOCK_user_locks);
thd_proc_info(thd, "User sleep");
thd->mysys_var->current_mutex= &LOCK_user_locks;
@@ -3701,19 +4097,19 @@ longlong Item_func_sleep::val_int()
error= 0;
while (!thd->killed)
{
- error= pthread_cond_timedwait(&cond, &LOCK_user_locks, &abstime);
+ error= timed_cond.wait(&cond, &LOCK_user_locks);
if (error == ETIMEDOUT || error == ETIME)
break;
error= 0;
}
thd_proc_info(thd, 0);
- pthread_mutex_unlock(&LOCK_user_locks);
- pthread_mutex_lock(&thd->mysys_var->mutex);
+ mysql_mutex_unlock(&LOCK_user_locks);
+ mysql_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
- pthread_mutex_unlock(&thd->mysys_var->mutex);
+ mysql_mutex_unlock(&thd->mysys_var->mutex);
- pthread_cond_destroy(&cond);
+ mysql_cond_destroy(&cond);
return test(!error); // Return 1 killed
}
@@ -3726,14 +4122,14 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
{
user_var_entry *entry;
- if (!(entry = (user_var_entry*) hash_search(hash, (uchar*) name.str,
- name.length)) &&
+ if (!(entry = (user_var_entry*) my_hash_search(hash, (uchar*) name.str,
+ name.length)) &&
create_if_not_exists)
{
uint size=ALIGN_SIZE(sizeof(user_var_entry))+name.length+1+extra_size;
- if (!hash_inited(hash))
+ if (!my_hash_inited(hash))
return 0;
- if (!(entry = (user_var_entry*) my_malloc(size,MYF(MY_WME))))
+ if (!(entry = (user_var_entry*) my_malloc(size,MYF(MY_WME | ME_FATALERROR))))
return 0;
entry->name.str=(char*) entry+ ALIGN_SIZE(sizeof(user_var_entry))+
extra_size;
@@ -3758,7 +4154,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
memcpy(entry->name.str, name.str, name.length+1);
if (my_hash_insert(hash,(uchar*) entry))
{
- my_free((char*) entry,MYF(0));
+ my_free(entry);
return 0;
}
}
@@ -3822,7 +4218,9 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref)
*/
null_item= (args[0]->type() == NULL_ITEM);
if (!entry->collation.collation || !null_item)
- entry->collation.set(args[0]->collation.collation, DERIVATION_IMPLICIT);
+ entry->collation.set(args[0]->collation.derivation == DERIVATION_NUMERIC ?
+ default_charset() : args[0]->collation.collation,
+ DERIVATION_IMPLICIT);
collation.set(entry->collation.collation, DERIVATION_IMPLICIT);
cached_result_type= args[0]->result_type();
return FALSE;
@@ -3833,9 +4231,15 @@ void
Item_func_set_user_var::fix_length_and_dec()
{
maybe_null=args[0]->maybe_null;
- max_length=args[0]->max_length;
decimals=args[0]->decimals;
- collation.set(args[0]->collation.collation, DERIVATION_IMPLICIT);
+ collation.set(DERIVATION_IMPLICIT);
+ if (args[0]->collation.derivation == DERIVATION_NUMERIC)
+ fix_length_and_charset(args[0]->max_char_length(), default_charset());
+ else
+ {
+ fix_length_and_charset(args[0]->max_char_length(),
+ args[0]->collation.collation);
+ }
}
@@ -3871,6 +4275,8 @@ bool Item_func_set_user_var::register_field_in_read_map(uchar *arg)
@param dv derivation for new value
@param unsigned_arg indiates if a value of type INT_RESULT is unsigned
+ @note Sets error and fatal error if allocation fails.
+
@retval
false success
@retval
@@ -3886,7 +4292,7 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
{
char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
if (entry->value && entry->value != pos)
- my_free(entry->value,MYF(0));
+ my_free(entry->value);
entry->value= 0;
entry->length= 0;
}
@@ -3901,7 +4307,7 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
if (entry->value != pos)
{
if (entry->value)
- my_free(entry->value,MYF(0));
+ my_free(entry->value);
entry->value=pos;
}
}
@@ -3914,7 +4320,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
if (entry->value == pos)
entry->value=0;
entry->value= (char*) my_realloc(entry->value, length,
- MYF(MY_ALLOW_ZERO_PTR | MY_WME));
+ MYF(MY_ALLOW_ZERO_PTR | MY_WME |
+ ME_FATALERROR));
if (!entry->value)
return 1;
}
@@ -3951,7 +4358,6 @@ Item_func_set_user_var::update_hash(void *ptr, uint length,
if (::update_hash(entry, (null_value= args[0]->null_value),
ptr, length, res_type, cs, dv, unsigned_arg))
{
- current_thd->fatal_error(); // Probably end of memory
null_value= 1;
return 1;
}
@@ -4028,16 +4434,16 @@ String *user_var_entry::val_str(my_bool *null_value, String *str,
switch (type) {
case REAL_RESULT:
- str->set_real(*(double*) value, decimals, &my_charset_bin);
+ str->set_real(*(double*) value, decimals, collation.collation);
break;
case INT_RESULT:
if (!unsigned_flag)
- str->set(*(longlong*) value, &my_charset_bin);
+ str->set(*(longlong*) value, collation.collation);
else
- str->set(*(ulonglong*) value, &my_charset_bin);
+ str->set(*(ulonglong*) value, collation.collation);
break;
case DECIMAL_RESULT:
- my_decimal2string(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, 0, 0, str);
+ str_set_decimal((my_decimal *) value, str, collation.collation);
break;
case STRING_RESULT:
if (str->copy(value, length, collation.collation))
@@ -4195,13 +4601,13 @@ Item_func_set_user_var::update()
case REAL_RESULT:
{
res= update_hash((void*) &save_result.vreal,sizeof(save_result.vreal),
- REAL_RESULT, &my_charset_bin, DERIVATION_IMPLICIT, 0);
+ REAL_RESULT, default_charset(), DERIVATION_IMPLICIT, 0);
break;
}
case INT_RESULT:
{
res= update_hash((void*) &save_result.vint, sizeof(save_result.vint),
- INT_RESULT, &my_charset_bin, DERIVATION_IMPLICIT,
+ INT_RESULT, default_charset(), DERIVATION_IMPLICIT,
unsigned_flag);
break;
}
@@ -4225,7 +4631,7 @@ Item_func_set_user_var::update()
else
res= update_hash((void*) save_result.vdec,
sizeof(my_decimal), DECIMAL_RESULT,
- &my_charset_bin, DERIVATION_IMPLICIT, 0);
+ default_charset(), DERIVATION_IMPLICIT, 0);
break;
}
case ROW_RESULT:
@@ -4617,6 +5023,7 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
user_var_event->user_var_event= var_entry;
user_var_event->type= var_entry->type;
user_var_event->charset_number= var_entry->collation.collation->number;
+ user_var_event->unsigned_flag= var_entry->unsigned_flag;
if (!var_entry->value)
{
/* NULL value*/
@@ -4666,17 +5073,17 @@ void Item_func_get_user_var::fix_length_and_dec()
collation.set(var_entry->collation);
switch(m_cached_result_type) {
case REAL_RESULT:
- max_length= DBL_DIG + 8;
+ fix_char_length(DBL_DIG + 8);
break;
case INT_RESULT:
- max_length= MAX_BIGINT_WIDTH;
+ fix_char_length(MAX_BIGINT_WIDTH);
decimals=0;
break;
case STRING_RESULT:
max_length= MAX_BLOB_WIDTH - 1;
break;
case DECIMAL_RESULT:
- max_length= DECIMAL_MAX_STR_LENGTH;
+ fix_char_length(DECIMAL_MAX_STR_LENGTH);
decimals= DECIMAL_MAX_SCALE;
break;
case ROW_RESULT: // Keep compiler happy
@@ -4692,11 +5099,6 @@ void Item_func_get_user_var::fix_length_and_dec()
m_cached_result_type= STRING_RESULT;
max_length= MAX_BLOB_WIDTH;
}
-
- if (error)
- thd->fatal_error();
-
- return;
}
@@ -4770,18 +5172,16 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref)
void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs)
{
- if (::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs,
- DERIVATION_IMPLICIT, 0 /* unsigned_arg */))
- current_thd->fatal_error(); // Probably end of memory
+ ::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs,
+ DERIVATION_IMPLICIT, 0 /* unsigned_arg */);
}
void Item_user_var_as_out_param::set_value(const char *str, uint length,
CHARSET_INFO* cs)
{
- if (::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs,
- DERIVATION_IMPLICIT, 0 /* unsigned_arg */))
- current_thd->fatal_error(); // Probably end of memory
+ ::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs,
+ DERIVATION_IMPLICIT, 0 /* unsigned_arg */);
}
@@ -4859,7 +5259,7 @@ void Item_func_get_system_var::fix_length_and_dec()
if (var_type != OPT_DEFAULT)
{
my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0),
- var->name, var_type == OPT_GLOBAL ? "SESSION" : "GLOBAL");
+ var->name.str, var_type == OPT_GLOBAL ? "SESSION" : "GLOBAL");
return;
}
/* As there was no local variable, return the global value */
@@ -4872,39 +5272,59 @@ void Item_func_get_system_var::fix_length_and_dec()
case SHOW_INT:
case SHOW_HA_ROWS:
unsigned_flag= TRUE;
- max_length= MY_INT64_NUM_DECIMAL_DIGITS;
+ collation.set_numeric();
+ fix_char_length(MY_INT64_NUM_DECIMAL_DIGITS);
decimals=0;
break;
case SHOW_LONGLONG:
unsigned_flag= TRUE;
- max_length= MY_INT64_NUM_DECIMAL_DIGITS;
+ collation.set_numeric();
+ fix_char_length(MY_INT64_NUM_DECIMAL_DIGITS);
decimals=0;
break;
case SHOW_CHAR:
case SHOW_CHAR_PTR:
- pthread_mutex_lock(&LOCK_global_system_variables);
- cptr= var->show_type() == SHOW_CHAR_PTR ?
- *(char**) var->value_ptr(current_thd, var_type, &component) :
- (char*) var->value_ptr(current_thd, var_type, &component);
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ cptr= var->show_type() == SHOW_CHAR ?
+ (char*) var->value_ptr(current_thd, var_type, &component) :
+ *(char**) var->value_ptr(current_thd, var_type, &component);
if (cptr)
- max_length= strlen(cptr) * system_charset_info->mbmaxlen;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ max_length= system_charset_info->cset->numchars(system_charset_info,
+ cptr,
+ cptr + strlen(cptr));
+ mysql_mutex_unlock(&LOCK_global_system_variables);
collation.set(system_charset_info, DERIVATION_SYSCONST);
+ max_length*= system_charset_info->mbmaxlen;
decimals=NOT_FIXED_DEC;
break;
+ case SHOW_LEX_STRING:
+ {
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ LEX_STRING *ls= ((LEX_STRING*)var->value_ptr(current_thd, var_type, &component));
+ max_length= system_charset_info->cset->numchars(system_charset_info,
+ ls->str,
+ ls->str + ls->length);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ collation.set(system_charset_info, DERIVATION_SYSCONST);
+ max_length*= system_charset_info->mbmaxlen;
+ decimals=NOT_FIXED_DEC;
+ }
+ break;
case SHOW_BOOL:
case SHOW_MY_BOOL:
unsigned_flag= FALSE;
- max_length= 1;
+ collation.set_numeric();
+ fix_char_length(1);
decimals=0;
break;
case SHOW_DOUBLE:
unsigned_flag= FALSE;
decimals= 6;
- max_length= DBL_DIG + 6;
+ collation.set_numeric();
+ fix_char_length(DBL_DIG + 6);
break;
default:
- my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name.str);
break;
}
}
@@ -4929,11 +5349,12 @@ enum Item_result Item_func_get_system_var::result_type() const
return INT_RESULT;
case SHOW_CHAR:
case SHOW_CHAR_PTR:
+ case SHOW_LEX_STRING:
return STRING_RESULT;
case SHOW_DOUBLE:
return REAL_RESULT;
default:
- my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name.str);
return STRING_RESULT; // keep the compiler happy
}
}
@@ -4952,11 +5373,12 @@ enum_field_types Item_func_get_system_var::field_type() const
return MYSQL_TYPE_LONGLONG;
case SHOW_CHAR:
case SHOW_CHAR_PTR:
+ case SHOW_LEX_STRING:
return MYSQL_TYPE_VARCHAR;
case SHOW_DOUBLE:
return MYSQL_TYPE_DOUBLE;
default:
- my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name.str);
return MYSQL_TYPE_VARCHAR; // keep the compiler happy
}
}
@@ -4969,9 +5391,9 @@ enum_field_types Item_func_get_system_var::field_type() const
#define get_sys_var_safe(type) \
do { \
type value; \
- pthread_mutex_lock(&LOCK_global_system_variables); \
+ mysql_mutex_lock(&LOCK_global_system_variables); \
value= *(type*) var->value_ptr(thd, var_type, &component); \
- pthread_mutex_unlock(&LOCK_global_system_variables); \
+ mysql_mutex_unlock(&LOCK_global_system_variables); \
cache_present |= GET_SYS_VAR_CACHE_LONG; \
used_query_id= thd->query_id; \
cached_llval= null_value ? 0 : (longlong) value; \
@@ -5032,6 +5454,7 @@ longlong Item_func_get_system_var::val_int()
}
case SHOW_CHAR:
case SHOW_CHAR_PTR:
+ case SHOW_LEX_STRING:
{
String *str_val= val_str(NULL);
@@ -5051,7 +5474,7 @@ longlong Item_func_get_system_var::val_int()
}
default:
- my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name.str);
return 0; // keep the compiler happy
}
}
@@ -5091,14 +5514,18 @@ String* Item_func_get_system_var::val_str(String* str)
{
case SHOW_CHAR:
case SHOW_CHAR_PTR:
+ case SHOW_LEX_STRING:
{
- pthread_mutex_lock(&LOCK_global_system_variables);
- char *cptr= var->show_type() == SHOW_CHAR_PTR ?
- *(char**) var->value_ptr(thd, var_type, &component) :
- (char*) var->value_ptr(thd, var_type, &component);
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ char *cptr= var->show_type() == SHOW_CHAR ?
+ (char*) var->value_ptr(thd, var_type, &component) :
+ *(char**) var->value_ptr(thd, var_type, &component);
if (cptr)
{
- if (str->copy(cptr, strlen(cptr), collation.collation))
+ size_t len= var->show_type() == SHOW_LEX_STRING ?
+ ((LEX_STRING*)(var->value_ptr(thd, var_type, &component)))->length :
+ strlen(cptr);
+ if (str->copy(cptr, len, collation.collation))
{
null_value= TRUE;
str= NULL;
@@ -5109,7 +5536,7 @@ String* Item_func_get_system_var::val_str(String* str)
null_value= TRUE;
str= NULL;
}
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
break;
}
@@ -5126,7 +5553,7 @@ String* Item_func_get_system_var::val_str(String* str)
break;
default:
- my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name.str);
str= NULL;
break;
}
@@ -5174,9 +5601,9 @@ double Item_func_get_system_var::val_real()
switch (var->show_type())
{
case SHOW_DOUBLE:
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
cached_dval= *(double*) var->value_ptr(thd, var_type, &component);
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
used_query_id= thd->query_id;
cached_null_value= null_value;
if (null_value)
@@ -5184,12 +5611,11 @@ double Item_func_get_system_var::val_real()
cache_present|= GET_SYS_VAR_CACHE_DOUBLE;
return cached_dval;
case SHOW_CHAR:
+ case SHOW_LEX_STRING:
case SHOW_CHAR_PTR:
{
- char *cptr;
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- cptr= var->show_type() == SHOW_CHAR ?
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ char *cptr= var->show_type() == SHOW_CHAR ?
(char*) var->value_ptr(thd, var_type, &component) :
*(char**) var->value_ptr(thd, var_type, &component);
if (cptr)
@@ -5200,7 +5626,7 @@ double Item_func_get_system_var::val_real()
null_value= TRUE;
cached_dval= 0;
}
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
used_query_id= thd->query_id;
cached_null_value= null_value;
cache_present|= GET_SYS_VAR_CACHE_DOUBLE;
@@ -5218,7 +5644,7 @@ double Item_func_get_system_var::val_real()
cached_null_value= null_value;
return cached_dval;
default:
- my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name);
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name.str);
return 0;
}
}
@@ -5257,8 +5683,8 @@ longlong Item_func_inet_aton::val_int()
char buff[36];
int dot_count= 0;
- String *s,tmp(buff,sizeof(buff),&my_charset_bin);
- if (!(s = args[0]->val_str(&tmp))) // If null value
+ String *s, tmp(buff, sizeof(buff), &my_charset_latin1);
+ if (!(s = args[0]->val_str_ascii(&tmp))) // If null value
goto err;
null_value=0;
@@ -5266,7 +5692,7 @@ longlong Item_func_inet_aton::val_int()
while (p < end)
{
c = *p++;
- int digit = (int) (c - '0'); // Assume ascii
+ int digit = (int) (c - '0');
if (digit >= 0 && digit <= 9)
{
if ((byte_result = byte_result * 10 + digit) > 255)
@@ -5426,8 +5852,8 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref)
return 1;
}
table->fulltext_searched=1;
- return agg_arg_collations_for_comparison(cmp_collation,
- args+1, arg_count-1, 0);
+ return agg_item_collations_for_comparison(cmp_collation, func_name(),
+ args+1, arg_count-1, 0);
}
bool Item_func_match::fix_index()
@@ -5667,10 +6093,10 @@ longlong Item_func_is_free_lock::val_int()
return 0;
}
- pthread_mutex_lock(&LOCK_user_locks);
- ull= (User_level_lock *) hash_search(&hash_user_locks, (uchar*) res->ptr(),
- (size_t) res->length());
- pthread_mutex_unlock(&LOCK_user_locks);
+ mysql_mutex_lock(&LOCK_user_locks);
+ ull= (User_level_lock *) my_hash_search(&hash_user_locks, (uchar*) res->ptr(),
+ (size_t) res->length());
+ mysql_mutex_unlock(&LOCK_user_locks);
if (!ull || !ull->locked)
return 1;
return 0;
@@ -5686,10 +6112,10 @@ longlong Item_func_is_used_lock::val_int()
if (!res || !res->length())
return 0;
- pthread_mutex_lock(&LOCK_user_locks);
- ull= (User_level_lock *) hash_search(&hash_user_locks, (uchar*) res->ptr(),
- (size_t) res->length());
- pthread_mutex_unlock(&LOCK_user_locks);
+ mysql_mutex_lock(&LOCK_user_locks);
+ ull= (User_level_lock *) my_hash_search(&hash_user_locks, (uchar*) res->ptr(),
+ (size_t) res->length());
+ mysql_mutex_unlock(&LOCK_user_locks);
if (!ull || !ull->locked)
return 0;
@@ -5703,7 +6129,7 @@ longlong Item_func_row_count::val_int()
DBUG_ASSERT(fixed == 1);
THD *thd= current_thd;
- return thd->row_count_func;
+ return thd->get_row_count_func();
}
@@ -5769,12 +6195,12 @@ Item_func_sp::func_name() const
}
-int my_missing_function_error(const LEX_STRING &token, const char *func_name)
+void my_missing_function_error(const LEX_STRING &token, const char *func_name)
{
if (token.length && is_lex_native_function (&token))
- return my_error(ER_FUNC_INEXISTENT_NAME_COLLISION, MYF(0), func_name);
+ my_error(ER_FUNC_INEXISTENT_NAME_COLLISION, MYF(0), func_name);
else
- return my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", func_name);
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", func_name);
}
@@ -6143,8 +6569,8 @@ void uuid_short_init()
longlong Item_func_uuid_short::val_int()
{
ulonglong val;
- pthread_mutex_lock(&LOCK_uuid_generator);
+ mysql_mutex_lock(&LOCK_uuid_generator);
val= uuid_value++;
- pthread_mutex_unlock(&LOCK_uuid_generator);
+ mysql_mutex_unlock(&LOCK_uuid_generator);
return (longlong) val;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 26a7e033692..63662d97019 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1,3 +1,6 @@
+#ifndef ITEM_FUNC_INCLUDED
+#define ITEM_FUNC_INCLUDED
+
/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
@@ -157,22 +160,24 @@ public:
my_decimal *val_decimal(my_decimal *);
- bool agg_arg_collations(DTCollation &c, Item **items, uint nitems,
- uint flags)
+ bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems,
+ uint flags, int item_sep)
{
- return agg_item_collations(c, func_name(), items, nitems, flags, 1);
+ return agg_item_charsets(c, func_name(), items, nitems, flags, item_sep);
}
- bool agg_arg_collations_for_comparison(DTCollation &c,
- Item **items, uint nitems,
- uint flags)
+ bool agg_arg_charsets_for_string_result(DTCollation &c,
+ Item **items, uint nitems,
+ int item_sep= 1)
{
- return agg_item_collations_for_comparison(c, func_name(),
- items, nitems, flags);
+ return agg_item_charsets_for_string_result(c, func_name(),
+ items, nitems, item_sep);
}
- bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems,
- uint flags, int item_sep)
+ bool agg_arg_charsets_for_comparison(DTCollation &c,
+ Item **items, uint nitems,
+ int item_sep= 1)
{
- return agg_item_charsets(c, func_name(), items, nitems, flags, item_sep);
+ return agg_item_charsets_for_comparison(c, func_name(),
+ items, nitems, item_sep);
}
bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
Item *transform(Item_transformer transformer, uchar *arg);
@@ -182,13 +187,56 @@ public:
void * arg, traverse_order order);
bool is_expensive_processor(uchar *arg);
virtual bool is_expensive() { return 0; }
- inline double fix_result(double value)
+ inline void raise_numeric_overflow(const char *type_name)
+ {
+ char buf[256];
+ String str(buf, sizeof(buf), system_charset_info);
+ str.length(0);
+ print(&str, QT_ORDINARY);
+ my_error(ER_DATA_OUT_OF_RANGE, MYF(0), type_name, str.c_ptr_safe());
+ }
+ inline double raise_float_overflow()
{
- if (isfinite(value))
- return value;
- null_value=1;
+ raise_numeric_overflow("DOUBLE");
return 0.0;
}
+ inline longlong raise_integer_overflow()
+ {
+ raise_numeric_overflow(unsigned_flag ? "BIGINT UNSIGNED": "BIGINT");
+ return 0;
+ }
+ inline int raise_decimal_overflow()
+ {
+ raise_numeric_overflow("DECIMAL");
+ return E_DEC_OVERFLOW;
+ }
+ /**
+ Throw an error if the input double number is not finite, i.e. is either
+ +/-INF or NAN.
+ */
+ inline double check_float_overflow(double value)
+ {
+ return isfinite(value) ? value : raise_float_overflow();
+ }
+ /**
+ Throw an error if the input BIGINT value represented by the
+ (longlong value, bool unsigned flag) pair cannot be returned by the
+ function, i.e. is not compatible with this Item's unsigned_flag.
+ */
+ inline longlong check_integer_overflow(longlong value, bool val_unsigned)
+ {
+ if ((unsigned_flag && !val_unsigned && value < 0) ||
+ (!unsigned_flag && val_unsigned && (ulonglong) value > LONGLONG_MAX))
+ return raise_integer_overflow();
+ return value;
+ }
+ /**
+ Throw an error if the error code of a DECIMAL operation is E_DEC_OVERFLOW.
+ */
+ inline int check_decimal_overflow(int error)
+ {
+ return (error == E_DEC_OVERFLOW) ? raise_decimal_overflow() : error;
+ }
bool has_timestamp_args()
{
DBUG_ASSERT(fixed == TRUE);
@@ -223,10 +271,10 @@ public:
class Item_real_func :public Item_func
{
public:
- Item_real_func() :Item_func() {}
- Item_real_func(Item *a) :Item_func(a) {}
- Item_real_func(Item *a,Item *b) :Item_func(a,b) {}
- Item_real_func(List<Item> &list) :Item_func(list) {}
+ Item_real_func() :Item_func() { collation.set_numeric(); }
+ Item_real_func(Item *a) :Item_func(a) { collation.set_numeric(); }
+ Item_real_func(Item *a,Item *b) :Item_func(a,b) { collation.set_numeric(); }
+ Item_real_func(List<Item> &list) :Item_func(list) { collation.set_numeric(); }
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *decimal_value);
longlong val_int()
@@ -243,13 +291,13 @@ protected:
Item_result hybrid_type;
public:
Item_func_numhybrid(Item *a) :Item_func(a), hybrid_type(REAL_RESULT)
- {}
+ { collation.set_numeric(); }
Item_func_numhybrid(Item *a,Item *b)
:Item_func(a,b), hybrid_type(REAL_RESULT)
- {}
+ { collation.set_numeric(); }
Item_func_numhybrid(List<Item> &list)
:Item_func(list), hybrid_type(REAL_RESULT)
- {}
+ { collation.set_numeric(); }
enum Item_result result_type () const { return hybrid_type; }
void fix_length_and_dec();
@@ -332,13 +380,18 @@ class Item_num_op :public Item_func_numhybrid
class Item_int_func :public Item_func
{
public:
- Item_int_func() :Item_func() { max_length= 21; }
- Item_int_func(Item *a) :Item_func(a) { max_length= 21; }
- Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length= 21; }
+ Item_int_func() :Item_func()
+ { collation.set_numeric(); fix_char_length(21); }
+ Item_int_func(Item *a) :Item_func(a)
+ { collation.set_numeric(); fix_char_length(21); }
+ Item_int_func(Item *a,Item *b) :Item_func(a,b)
+ { collation.set_numeric(); fix_char_length(21); }
Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c)
- { max_length= 21; }
- Item_int_func(List<Item> &list) :Item_func(list) { max_length= 21; }
- Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) {}
+ { collation.set_numeric(); fix_char_length(21); }
+ Item_int_func(List<Item> &list) :Item_func(list)
+ { collation.set_numeric(); fix_char_length(21); }
+ Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item)
+ { collation.set_numeric(); }
double val_real();
String *val_str(String*str);
enum Item_result result_type () const { return INT_RESULT; }
@@ -367,7 +420,7 @@ public:
longlong val_int();
longlong val_int_from_str(int *error);
void fix_length_and_dec()
- { max_length=args[0]->max_length; unsigned_flag=0; }
+ { fix_char_length(args[0]->max_char_length()); unsigned_flag=0; }
virtual void print(String *str, enum_query_type query_type);
uint decimal_precision() const { return args[0]->decimal_precision(); }
};
@@ -380,7 +433,8 @@ public:
const char *func_name() const { return "cast_as_unsigned"; }
void fix_length_and_dec()
{
- max_length= min(args[0]->max_length, DECIMAL_MAX_PRECISION + 2);
+ fix_char_length(min(args[0]->max_char_length(),
+ DECIMAL_MAX_PRECISION + 2));
unsigned_flag=1;
}
longlong val_int();
@@ -395,8 +449,9 @@ public:
Item_decimal_typecast(Item *a, int len, int dec) :Item_func(a)
{
decimals= dec;
- max_length= my_decimal_precision_to_length_no_truncation(len, dec,
- unsigned_flag);
+ collation.set_numeric();
+ fix_char_length(my_decimal_precision_to_length_no_truncation(len, dec,
+ unsigned_flag));
}
String *val_str(String *str);
double val_real();
@@ -655,6 +710,14 @@ public:
const char *func_name() const { return "tan"; }
};
+class Item_func_cot :public Item_dec_func
+{
+public:
+ Item_func_cot(Item *a) :Item_dec_func(a) {}
+ double val_real();
+ const char *func_name() const { return "cot"; }
+};
+
class Item_func_integer :public Item_int_func
{
public:
@@ -1436,7 +1499,8 @@ class Item_user_var_as_out_param :public Item
LEX_STRING name;
user_var_entry *entry;
public:
- Item_user_var_as_out_param(LEX_STRING a) : name(a) {}
+ Item_user_var_as_out_param(LEX_STRING a) : name(a)
+ { set_name(a.str, 0, system_charset_info); }
/* We should return something different from FIELD_ITEM here */
enum Type type() const { return STRING_ITEM;}
double val_real();
@@ -1735,3 +1799,14 @@ public:
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
+Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
+ LEX_STRING component);
+extern bool check_reserved_words(LEX_STRING *name);
+extern enum_field_types agg_field_type(Item **items, uint nitems);
+double my_double_round(double value, longlong dec, bool dec_unsigned,
+ bool truncate);
+bool eval_const_cond(COND *cond);
+
+extern bool volatile mqh_used;
+
+#endif /* ITEM_FUNC_INCLUDED */
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 8c38cb2a859..d734b55a970 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -25,7 +25,14 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" // THD, set_var.h: THD
+#include "set_var.h"
#ifdef HAVE_SPATIAL
#include <m_ctype.h>
@@ -42,7 +49,7 @@ void Item_geometry_func::fix_length_and_dec()
{
collation.set(&my_charset_bin);
decimals=0;
- max_length= max_field_size;
+ max_length= (uint32) 4294967295U;
maybe_null= 1;
}
@@ -52,7 +59,7 @@ String *Item_func_geometry_from_text::val_str(String *str)
DBUG_ASSERT(fixed == 1);
Geometry_buffer buffer;
String arg_val;
- String *wkt= args[0]->val_str(&arg_val);
+ String *wkt= args[0]->val_str_ascii(&arg_val);
if ((null_value= args[0]->null_value))
return 0;
@@ -110,7 +117,7 @@ String *Item_func_geometry_from_wkb::val_str(String *str)
}
-String *Item_func_as_wkt::val_str(String *str)
+String *Item_func_as_wkt::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
String arg_val;
@@ -134,6 +141,7 @@ String *Item_func_as_wkt::val_str(String *str)
void Item_func_as_wkt::fix_length_and_dec()
{
+ collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
max_length=MAX_BLOB_WIDTH;
maybe_null= 1;
}
@@ -157,7 +165,7 @@ String *Item_func_as_wkb::val_str(String *str)
}
-String *Item_func_geometry_type::val_str(String *str)
+String *Item_func_geometry_type::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
String *swkb= args[0]->val_str(str);
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index b3ecbc39933..84034841ad5 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -1,3 +1,6 @@
+#ifndef ITEM_GEOFUNC_INCLUDED
+#define ITEM_GEOFUNC_INCLUDED
+
/* Copyright (C) 2000-2003 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -54,12 +57,12 @@ public:
String *val_str(String *);
};
-class Item_func_as_wkt: public Item_str_func
+class Item_func_as_wkt: public Item_str_ascii_func
{
public:
- Item_func_as_wkt(Item *a): Item_str_func(a) {}
+ Item_func_as_wkt(Item *a): Item_str_ascii_func(a) {}
const char *func_name() const { return "astext"; }
- String *val_str(String *);
+ String *val_str_ascii(String *);
void fix_length_and_dec();
};
@@ -72,16 +75,17 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
};
-class Item_func_geometry_type: public Item_str_func
+class Item_func_geometry_type: public Item_str_ascii_func
{
public:
- Item_func_geometry_type(Item *a): Item_str_func(a) {}
- String *val_str(String *);
+ Item_func_geometry_type(Item *a): Item_str_ascii_func(a) {}
+ String *val_str_ascii(String *);
const char *func_name() const { return "geometrytype"; }
void fix_length_and_dec()
{
- max_length=20; // "GeometryCollection" is the most long
- maybe_null= 1;
+ // "GeometryCollection" is the longest
+ fix_length_and_charset(20, default_charset());
+ maybe_null= 1;
};
};
@@ -401,3 +405,4 @@ public:
#endif
+#endif /* ITEM_GEOFUNC_INCLUDED */
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 7535c1fa80b..2fbf0c12499 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -13,7 +13,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" // THD, set_var.h: THD
+#include "set_var.h"
/**
Row items used for comparing rows and IN operations on rows:
diff --git a/sql/item_row.h b/sql/item_row.h
index 76d1c875e7d..87988e718ca 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -1,3 +1,6 @@
+#ifndef ITEM_ROW_INCLUDED
+#define ITEM_ROW_INCLUDED
+
/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -79,3 +82,5 @@ public:
bool null_inside() { return with_null; };
void bring_value();
};
+
+#endif /* ITEM_ROW_INCLUDED */
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 8fda281bd9e..3c92c829144 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2006 MySQL AB
+/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -29,7 +29,24 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+/* May include caustic 3rd-party defs. Use early, so it can override nothing. */
+#include "sha2.h"
+#include "my_global.h" // HAVE_*
+
+
+#include "sql_priv.h"
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" // set_var.h: THD
+#include "set_var.h"
+#include "mysqld.h" // LOCK_uuid_generator
+#include "sql_acl.h" // SUPER_ACL
+#include "des_key_file.h" // st_des_keyschedule, st_des_keyblock
+#include "password.h" // my_make_scrambled_password,
+ // my_make_scrambled_password_323
#include <m_ctype.h>
#include "my_md5.h"
#include "sha1.h"
@@ -41,15 +58,52 @@ C_MODE_END
String my_empty_string("",default_charset_info);
+/*
+ For the Items which have only val_str_ascii() method
+ and don't have their own "native" val_str(),
+ we provide a "wrapper" method to convert from ASCII
+ to Item character set when it's necessary.
+ Conversion happens only in case of "tricky" Item character set (e.g. UCS2).
+ Normally conversion does not happen, and val_str_ascii() is immediately
+ returned instead.
+*/
+String *Item_str_ascii_func::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+
+ if (!(collation.collation->state & MY_CS_NONASCII))
+ {
+ String *res= val_str_ascii(str);
+ if (res)
+ res->set_charset(collation.collation);
+ return res;
+ }
+
+ DBUG_ASSERT(str != &ascii_buf);
+
+ uint errors;
+ String *res= val_str_ascii(&ascii_buf);
+ if (!res)
+ return 0;
+
+ if ((null_value= str->copy(res->ptr(), res->length(),
+ &my_charset_latin1, collation.collation,
+ &errors)))
+ return 0;
+
+ return str;
+}
+
+
/*
Convert an array of bytes to a hexadecimal representation.
Used to generate a hexadecimal representation of a message digest.
*/
-static void array_to_hex(char *to, const char *str, uint len)
+static void array_to_hex(char *to, const unsigned char *str, uint len)
{
- const char *str_end= str + len;
+ const unsigned char *str_end= str + len;
for (; str != str_end; ++str)
{
*to++= _dig_vec_lower[((uchar) *str) >> 4];
@@ -112,7 +166,7 @@ longlong Item_str_func::val_int()
}
-String *Item_func_md5::val_str(String *str)
+String *Item_func_md5::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
String * sptr= args[0]->val_str(str);
@@ -128,7 +182,7 @@ String *Item_func_md5::val_str(String *str)
null_value=1;
return 0;
}
- array_to_hex((char *) str->ptr(), (const char*) digest, 16);
+ array_to_hex((char *) str->ptr(), digest, 16);
str->length((uint) 32);
return str;
}
@@ -139,7 +193,6 @@ String *Item_func_md5::val_str(String *str)
void Item_func_md5::fix_length_and_dec()
{
- max_length=32;
/*
The MD5() function treats its parameter as being a case sensitive. Thus
we set binary collation on it so different instances of MD5() will be
@@ -148,10 +201,11 @@ void Item_func_md5::fix_length_and_dec()
args[0]->collation.set(
get_charset_by_csname(args[0]->collation.collation->csname,
MY_CS_BINSORT,MYF(0)), DERIVATION_COERCIBLE);
+ fix_length_and_charset(32, default_charset());
}
-String *Item_func_sha::val_str(String *str)
+String *Item_func_sha::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
String * sptr= args[0]->val_str(str);
@@ -169,7 +223,7 @@ String *Item_func_sha::val_str(String *str)
if (!( str->alloc(SHA1_HASH_SIZE*2) ||
(mysql_sha1_result(&context,digest))))
{
- array_to_hex((char *) str->ptr(), (const char*) digest, SHA1_HASH_SIZE);
+ array_to_hex((char *) str->ptr(), digest, SHA1_HASH_SIZE);
str->length((uint) SHA1_HASH_SIZE*2);
null_value=0;
return str;
@@ -181,7 +235,6 @@ String *Item_func_sha::val_str(String *str)
void Item_func_sha::fix_length_and_dec()
{
- max_length=SHA1_HASH_SIZE*2; // size of hex representation of hash
/*
The SHA() function treats its parameter as being a case sensitive. Thus
we set binary collation on it so different instances of MD5() will be
@@ -190,8 +243,148 @@ void Item_func_sha::fix_length_and_dec()
args[0]->collation.set(
get_charset_by_csname(args[0]->collation.collation->csname,
MY_CS_BINSORT,MYF(0)), DERIVATION_COERCIBLE);
+ // size of hex representation of hash
+ fix_length_and_charset(SHA1_HASH_SIZE * 2, default_charset());
}
+String *Item_func_sha2::val_str_ascii(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
+ unsigned char digest_buf[SHA512_DIGEST_LENGTH];
+ String *input_string;
+ unsigned char *input_ptr;
+ size_t input_len;
+ uint digest_length= 0;
+
+ str->set_charset(&my_charset_bin);
+
+ input_string= args[0]->val_str(str);
+ if (input_string == NULL)
+ {
+ null_value= TRUE;
+ return (String *) NULL;
+ }
+
+ null_value= args[0]->null_value;
+ if (null_value)
+ return (String *) NULL;
+
+ input_ptr= (unsigned char *) input_string->ptr();
+ input_len= input_string->length();
+
+ switch ((uint) args[1]->val_int()) {
+#ifndef OPENSSL_NO_SHA512
+ case 512:
+ digest_length= SHA512_DIGEST_LENGTH;
+ (void) SHA512(input_ptr, input_len, digest_buf);
+ break;
+ case 384:
+ digest_length= SHA384_DIGEST_LENGTH;
+ (void) SHA384(input_ptr, input_len, digest_buf);
+ break;
+#endif
+#ifndef OPENSSL_NO_SHA256
+ case 224:
+ digest_length= SHA224_DIGEST_LENGTH;
+ (void) SHA224(input_ptr, input_len, digest_buf);
+ break;
+ case 256:
+ case 0: // SHA-256 is the default
+ digest_length= SHA256_DIGEST_LENGTH;
+ (void) SHA256(input_ptr, input_len, digest_buf);
+ break;
+#endif
+ default:
+ if (!args[1]->const_item())
+ push_warning_printf(current_thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WRONG_PARAMETERS_TO_NATIVE_FCT,
+ ER(ER_WRONG_PARAMETERS_TO_NATIVE_FCT), "sha2");
+ null_value= TRUE;
+ return NULL;
+ }
+
+ /*
+ Since we're subverting the usual String methods, we must make sure that
+ the destination has space for the bytes we're about to write.
+ */
+ str->realloc((uint) digest_length*2 + 1); /* Each byte as two nybbles */
+
+ /* Convert the large number to a string-hex representation. */
+ array_to_hex((char *) str->ptr(), digest_buf, digest_length);
+
+ /* We poked raw bytes in. We must inform the the String of its length. */
+ str->length((uint) digest_length*2); /* Each byte as two nybbles */
+
+ null_value= FALSE;
+ return str;
+
+#else
+ push_warning_printf(current_thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_FEATURE_DISABLED,
+ ER(ER_FEATURE_DISABLED),
+ "sha2", "--with-ssl");
+ null_value= TRUE;
+ return (String *) NULL;
+#endif /* defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) */
+}
+
+
+void Item_func_sha2::fix_length_and_dec()
+{
+ maybe_null = 1;
+ max_length = 0;
+
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
+ int sha_variant= args[1]->const_item() ? args[1]->val_int() : 512;
+
+ switch (sha_variant) {
+#ifndef OPENSSL_NO_SHA512
+ case 512:
+ fix_length_and_charset(SHA512_DIGEST_LENGTH * 2, default_charset());
+ break;
+ case 384:
+ fix_length_and_charset(SHA384_DIGEST_LENGTH * 2, default_charset());
+ break;
+#endif
+#ifndef OPENSSL_NO_SHA256
+ case 256:
+ case 0: // SHA-256 is the default
+ fix_length_and_charset(SHA256_DIGEST_LENGTH * 2, default_charset());
+ break;
+ case 224:
+ fix_length_and_charset(SHA224_DIGEST_LENGTH * 2, default_charset());
+ break;
+#endif
+ default:
+ push_warning_printf(current_thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WRONG_PARAMETERS_TO_NATIVE_FCT,
+ ER(ER_WRONG_PARAMETERS_TO_NATIVE_FCT), "sha2");
+ }
+
+ /*
+ The SHA2() function treats its parameter as being a case sensitive.
+ Thus we set binary collation on it so different instances of SHA2()
+ will be compared properly.
+ */
+
+ args[0]->collation.set(
+ get_charset_by_csname(
+ args[0]->collation.collation->csname,
+ MY_CS_BINSORT,
+ MYF(0)),
+ DERIVATION_COERCIBLE);
+#else
+ push_warning_printf(current_thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_FEATURE_DISABLED,
+ ER(ER_FEATURE_DISABLED),
+ "sha2", "--with-ssl");
+#endif /* defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) */
+}
/* Implementation of AES encryption routines */
@@ -412,27 +605,15 @@ null:
void Item_func_concat::fix_length_and_dec()
{
- ulonglong max_result_length= 0;
+ ulonglong char_length= 0;
- if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1))
+ if (agg_arg_charsets_for_string_result(collation, args, arg_count))
return;
for (uint i=0 ; i < arg_count ; i++)
- {
- if (args[i]->collation.collation->mbmaxlen != collation.collation->mbmaxlen)
- max_result_length+= (args[i]->max_length /
- args[i]->collation.collation->mbmaxlen) *
- collation.collation->mbmaxlen;
- else
- max_result_length+= args[i]->max_length;
- }
+ char_length+= args[i]->max_char_length();
- if (max_result_length >= MAX_BLOB_WIDTH)
- {
- max_result_length= MAX_BLOB_WIDTH;
- maybe_null= 1;
- }
- max_length= (ulong) max_result_length;
+ fix_char_length_ulonglong(char_length);
}
/**
@@ -449,7 +630,7 @@ void Item_func_concat::fix_length_and_dec()
String *Item_func_des_encrypt::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
uint code= ER_WRONG_PARAMETERS_TO_PROCEDURE;
DES_cblock ivec;
struct st_des_keyblock keyblock;
@@ -462,22 +643,21 @@ String *Item_func_des_encrypt::val_str(String *str)
return 0; // ENCRYPT(NULL) == NULL
if ((res_length=res->length()) == 0)
return &my_empty_string;
-
if (arg_count == 1)
{
/* Protect against someone doing FLUSH DES_KEY_FILE */
- VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ mysql_mutex_lock(&LOCK_des_key_file);
keyschedule= des_keyschedule[key_number=des_default_key];
- VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ mysql_mutex_unlock(&LOCK_des_key_file);
}
else if (args[1]->result_type() == INT_RESULT)
{
key_number= (uint) args[1]->val_int();
if (key_number > 9)
goto error;
- VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ mysql_mutex_lock(&LOCK_des_key_file);
keyschedule= des_keyschedule[key_number];
- VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ mysql_mutex_unlock(&LOCK_des_key_file);
}
else
{
@@ -529,14 +709,14 @@ String *Item_func_des_encrypt::val_str(String *str)
return &tmp_value;
error:
- push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN,
code, ER(code),
"des_encrypt");
#else
- push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN,
ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED),
- "des_encrypt","--with-openssl");
-#endif /* HAVE_OPENSSL */
+ "des_encrypt", "--with-ssl");
+#endif /* defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) */
null_value=1;
return 0;
}
@@ -545,7 +725,7 @@ error:
String *Item_func_des_decrypt::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
uint code= ER_WRONG_PARAMETERS_TO_PROCEDURE;
DES_cblock ivec;
struct st_des_keyblock keyblock;
@@ -567,9 +747,9 @@ String *Item_func_des_decrypt::val_str(String *str)
key_number > 9)
goto error;
- VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ mysql_mutex_lock(&LOCK_des_key_file);
keyschedule= des_keyschedule[key_number];
- VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ mysql_mutex_unlock(&LOCK_des_key_file);
}
else
{
@@ -606,15 +786,15 @@ String *Item_func_des_decrypt::val_str(String *str)
return &tmp_value;
error:
- push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN,
code, ER(code),
"des_decrypt");
wrong_key:
#else
- push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN,
ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED),
- "des_decrypt","--with-openssl");
-#endif /* HAVE_OPENSSL */
+ "des_decrypt", "--with-ssl");
+#endif /* defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) */
null_value=1;
return 0;
}
@@ -770,9 +950,9 @@ null:
void Item_func_concat_ws::fix_length_and_dec()
{
- ulonglong max_result_length;
+ ulonglong char_length;
- if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1))
+ if (agg_arg_charsets_for_string_result(collation, args, arg_count))
return;
/*
@@ -780,16 +960,11 @@ void Item_func_concat_ws::fix_length_and_dec()
it is done on parser level in sql_yacc.yy
so, (arg_count - 2) is safe here.
*/
- max_result_length= (ulonglong) args[0]->max_length * (arg_count - 2);
+ char_length= (ulonglong) args[0]->max_char_length() * (arg_count - 2);
for (uint i=1 ; i < arg_count ; i++)
- max_result_length+=args[i]->max_length;
+ char_length+= args[i]->max_char_length();
- if (max_result_length >= MAX_BLOB_WIDTH)
- {
- max_result_length= MAX_BLOB_WIDTH;
- maybe_null= 1;
- }
- max_length= (ulong) max_result_length;
+ fix_char_length_ulonglong(char_length);
}
@@ -843,8 +1018,9 @@ String *Item_func_reverse::val_str(String *str)
void Item_func_reverse::fix_length_and_dec()
{
- collation.set(args[0]->collation);
- max_length = args[0]->max_length;
+ agg_arg_charsets_for_string_result(collation, args, 1);
+ DBUG_ASSERT(collation.collation != NULL);
+ fix_char_length(args[0]->max_char_length());
}
/**
@@ -973,22 +1149,17 @@ null:
void Item_func_replace::fix_length_and_dec()
{
- ulonglong max_result_length= args[0]->max_length;
- int diff=(int) (args[2]->max_length - args[1]->max_length);
- if (diff > 0 && args[1]->max_length)
+ ulonglong char_length= (ulonglong) args[0]->max_char_length();
+ int diff=(int) (args[2]->max_char_length() - args[1]->max_char_length());
+ if (diff > 0 && args[1]->max_char_length())
{ // Calculate of maxreplaces
- ulonglong max_substrs= max_result_length/args[1]->max_length;
- max_result_length+= max_substrs * (uint) diff;
- }
- if (max_result_length >= MAX_BLOB_WIDTH)
- {
- max_result_length= MAX_BLOB_WIDTH;
- maybe_null= 1;
+ ulonglong max_substrs= char_length / args[1]->max_char_length();
+ char_length+= max_substrs * (uint) diff;
}
- max_length= (ulong) max_result_length;
-
- if (agg_arg_charsets(collation, args, 3, MY_COLL_CMP_CONV, 1))
+
+ if (agg_arg_charsets_for_comparison(collation, args, 3))
return;
+ fix_char_length_ulonglong(char_length);
}
@@ -1057,19 +1228,14 @@ null:
void Item_func_insert::fix_length_and_dec()
{
- ulonglong max_result_length;
+ ulonglong char_length;
// Handle character set for args[0] and args[3].
- if (agg_arg_charsets(collation, &args[0], 2, MY_COLL_ALLOW_CONV, 3))
+ if (agg_arg_charsets_for_string_result(collation, args, 2, 3))
return;
- max_result_length= ((ulonglong) args[0]->max_length+
- (ulonglong) args[3]->max_length);
- if (max_result_length >= MAX_BLOB_WIDTH)
- {
- max_result_length= MAX_BLOB_WIDTH;
- maybe_null= 1;
- }
- max_length= (ulong) max_result_length;
+ char_length= ((ulonglong) args[0]->max_char_length() +
+ (ulonglong) args[3]->max_char_length());
+ fix_char_length_ulonglong(char_length);
}
@@ -1108,18 +1274,20 @@ String *Item_str_conv::val_str(String *str)
void Item_func_lcase::fix_length_and_dec()
{
- collation.set(args[0]->collation);
+ agg_arg_charsets_for_string_result(collation, args, 1);
+ DBUG_ASSERT(collation.collation != NULL);
multiply= collation.collation->casedn_multiply;
converter= collation.collation->cset->casedn;
- max_length= args[0]->max_length * multiply;
+ fix_char_length_ulonglong((ulonglong) args[0]->max_char_length() * multiply);
}
void Item_func_ucase::fix_length_and_dec()
{
- collation.set(args[0]->collation);
+ agg_arg_charsets_for_string_result(collation, args, 1);
+ DBUG_ASSERT(collation.collation != NULL);
multiply= collation.collation->caseup_multiply;
converter= collation.collation->cset->caseup;
- max_length= args[0]->max_length * multiply;
+ fix_char_length_ulonglong((ulonglong) args[0]->max_char_length() * multiply);
}
@@ -1150,21 +1318,23 @@ String *Item_func_left::val_str(String *str)
void Item_str_func::left_right_max_length()
{
- max_length=args[0]->max_length;
+ uint32 char_length= args[0]->max_char_length();
if (args[1]->const_item())
{
- int length=(int) args[1]->val_int()*collation.collation->mbmaxlen;
+ int length= (int) args[1]->val_int();
if (length <= 0)
- max_length=0;
+ char_length=0;
else
- set_if_smaller(max_length,(uint) length);
+ set_if_smaller(char_length, (uint) length);
}
+ fix_char_length(char_length);
}
void Item_func_left::fix_length_and_dec()
{
- collation.set(args[0]->collation);
+ agg_arg_charsets_for_string_result(collation, args, 1);
+ DBUG_ASSERT(collation.collation != NULL);
left_right_max_length();
}
@@ -1197,7 +1367,8 @@ String *Item_func_right::val_str(String *str)
void Item_func_right::fix_length_and_dec()
{
- collation.set(args[0]->collation);
+ agg_arg_charsets_for_string_result(collation, args, 1);
+ DBUG_ASSERT(collation.collation != NULL);
left_right_max_length();
}
@@ -1253,7 +1424,8 @@ void Item_func_substr::fix_length_and_dec()
{
max_length=args[0]->max_length;
- collation.set(args[0]->collation);
+ agg_arg_charsets_for_string_result(collation, args, 1);
+ DBUG_ASSERT(collation.collation != NULL);
if (args[1]->const_item())
{
int32 start= (int32) args[1]->val_int();
@@ -1276,10 +1448,9 @@ void Item_func_substr::fix_length_and_dec()
void Item_func_substr_index::fix_length_and_dec()
{
- max_length= args[0]->max_length;
-
- if (agg_arg_charsets(collation, args, 2, MY_COLL_CMP_CONV, 1))
+ if (agg_arg_charsets_for_comparison(collation, args, 2))
return;
+ fix_char_length(args[0]->max_char_length());
}
@@ -1605,10 +1776,10 @@ String *Item_func_trim::val_str(String *str)
void Item_func_trim::fix_length_and_dec()
{
- max_length= args[0]->max_length;
if (arg_count == 1)
{
- collation.set(args[0]->collation);
+ agg_arg_charsets_for_string_result(collation, args, 1);
+ DBUG_ASSERT(collation.collation != NULL);
remove.set_charset(collation.collation);
remove.set_ascii(" ",1);
}
@@ -1616,9 +1787,10 @@ void Item_func_trim::fix_length_and_dec()
{
// Handle character set for args[1] and args[0].
// Note that we pass args[1] as the first item, and args[0] as the second.
- if (agg_arg_charsets(collation, &args[1], 2, MY_COLL_CMP_CONV, -1))
+ if (agg_arg_charsets_for_comparison(collation, &args[1], 2, -1))
return;
}
+ fix_char_length(args[0]->max_char_length());
}
void Item_func_trim::print(String *str, enum_query_type query_type)
@@ -1641,7 +1813,7 @@ void Item_func_trim::print(String *str, enum_query_type query_type)
/* Item_func_password */
-String *Item_func_password::val_str(String *str)
+String *Item_func_password::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res= args[0]->val_str(str);
@@ -1650,7 +1822,7 @@ String *Item_func_password::val_str(String *str)
if (res->length() == 0)
return &my_empty_string;
my_make_scrambled_password(tmp_value, res->ptr(), res->length());
- str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, res->charset());
+ str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1);
return str;
}
@@ -1665,7 +1837,7 @@ char *Item_func_password::alloc(THD *thd, const char *password,
/* Item_func_old_password */
-String *Item_func_old_password::val_str(String *str)
+String *Item_func_old_password::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res= args[0]->val_str(str);
@@ -1674,7 +1846,7 @@ String *Item_func_old_password::val_str(String *str)
if (res->length() == 0)
return &my_empty_string;
my_make_scrambled_password_323(tmp_value, res->ptr(), res->length());
- str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, res->charset());
+ str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1);
return str;
}
@@ -1717,17 +1889,17 @@ String *Item_func_encrypt::val_str(String *str)
return 0;
salt_ptr= salt_str->c_ptr_safe();
}
- pthread_mutex_lock(&LOCK_crypt);
+ mysql_mutex_lock(&LOCK_crypt);
char *tmp= crypt(res->c_ptr_safe(),salt_ptr);
if (!tmp)
{
- pthread_mutex_unlock(&LOCK_crypt);
+ mysql_mutex_unlock(&LOCK_crypt);
null_value= 1;
return 0;
}
str->set(tmp, (uint) strlen(tmp), &my_charset_bin);
str->copy();
- pthread_mutex_unlock(&LOCK_crypt);
+ mysql_mutex_unlock(&LOCK_crypt);
return str;
#else
null_value=1;
@@ -1894,9 +2066,11 @@ bool Item_func_current_user::fix_fields(THD *thd, Item **ref)
void Item_func_soundex::fix_length_and_dec()
{
- collation.set(args[0]->collation);
- max_length=args[0]->max_length;
- set_if_bigger(max_length, 4 * collation.collation->mbminlen);
+ uint32 char_length= args[0]->max_char_length();
+ agg_arg_charsets_for_string_result(collation, args, 1);
+ DBUG_ASSERT(collation.collation != NULL);
+ set_if_bigger(char_length, 4);
+ fix_char_length(char_length);
tmp_value.set_charset(collation.collation);
}
@@ -2053,18 +2227,34 @@ String *Item_func_soundex::val_str(String *str)
const int FORMAT_MAX_DECIMALS= 30;
-Item_func_format::Item_func_format(Item *org, Item *dec)
-: Item_str_func(org, dec)
+
+MY_LOCALE *Item_func_format::get_locale(Item *item)
{
+ DBUG_ASSERT(arg_count == 3);
+ String tmp, *locale_name= args[2]->val_str_ascii(&tmp);
+ MY_LOCALE *lc;
+ if (!locale_name ||
+ !(lc= my_locale_by_name(locale_name->c_ptr_safe())))
+ {
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_UNKNOWN_LOCALE,
+ ER(ER_UNKNOWN_LOCALE),
+ locale_name ? locale_name->c_ptr_safe() : "NULL");
+ lc= &my_locale_en_US;
+ }
+ return lc;
}
void Item_func_format::fix_length_and_dec()
{
- uint char_length= args[0]->max_length/args[0]->collation.collation->mbmaxlen;
- uint max_sep_count= char_length/3 + (decimals ? 1 : 0) + /*sign*/1;
+ uint32 char_length= args[0]->max_char_length();
+ uint32 max_sep_count= (char_length / 3) + (decimals ? 1 : 0) + /*sign*/1;
collation.set(default_charset());
- max_length= (char_length + max_sep_count + decimals) *
- collation.collation->mbmaxlen;
+ fix_char_length(char_length + max_sep_count + decimals);
+ if (arg_count == 3)
+ locale= args[2]->basic_const_item() ? get_locale(args[2]) : NULL;
+ else
+ locale= &my_locale_en_US; /* Two arguments */
}
@@ -2074,15 +2264,14 @@ void Item_func_format::fix_length_and_dec()
are stored in more than one byte
*/
-String *Item_func_format::val_str(String *str)
+String *Item_func_format::val_str_ascii(String *str)
{
- uint32 length;
uint32 str_length;
/* Number of decimal digits */
int dec;
/* Number of characters used to represent the decimals, including '.' */
uint32 dec_length;
- int diff;
+ MY_LOCALE *lc;
DBUG_ASSERT(fixed == 1);
dec= (int) args[1]->val_int();
@@ -2092,6 +2281,8 @@ String *Item_func_format::val_str(String *str)
return NULL;
}
+ lc= locale ? locale : get_locale(args[2]);
+
dec= set_zone(dec, 0, FORMAT_MAX_DECIMALS);
dec_length= dec ? dec+1 : 0;
null_value=0;
@@ -2106,8 +2297,6 @@ String *Item_func_format::val_str(String *str)
my_decimal_round(E_DEC_FATAL_ERROR, res, dec, false, &rnd_dec);
my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str);
str_length= str->length();
- if (rnd_dec.sign())
- str_length--;
}
else
{
@@ -2115,36 +2304,64 @@ String *Item_func_format::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
nr= my_double_round(nr, (longlong) dec, FALSE, FALSE);
- /* Here default_charset() is right as this is not an automatic conversion */
- str->set_real(nr, dec, default_charset());
+ str->set_real(nr, dec, &my_charset_numeric);
if (isnan(nr))
return str;
str_length=str->length();
- if (nr < 0)
- str_length--; // Don't count sign
- }
- /* We need this test to handle 'nan' values */
- if (str_length >= dec_length+4)
- {
- char *tmp,*pos;
- length= str->length()+(diff=((int)(str_length- dec_length-1))/3);
- str= copy_if_not_alloced(&tmp_str,str,length);
- str->length(length);
- tmp= (char*) str->ptr()+length - dec_length-1;
- for (pos= (char*) str->ptr()+length-1; pos != tmp; pos--)
- pos[0]= pos[-diff];
- while (diff)
+ }
+ /* We need this test to handle 'nan' and short values */
+ if (lc->grouping[0] > 0 &&
+ str_length >= dec_length + 1 + lc->grouping[0])
+ {
+ /* We need space for ',' between each group of digits as well. */
+ char buf[2 * FLOATING_POINT_BUFFER];
+ int count;
+ const char *grouping= lc->grouping;
+ char sign_length= *str->ptr() == '-' ? 1 : 0;
+ const char *src= str->ptr() + str_length - dec_length - 1;
+ const char *src_begin= str->ptr() + sign_length;
+ char *dst= buf + sizeof(buf);
+
+ /* Put the fractional part */
+ if (dec)
{
- *pos= *(pos - diff);
- pos--;
- *pos= *(pos - diff);
- pos--;
- *pos= *(pos - diff);
- pos--;
- pos[0]=',';
- pos--;
- diff--;
+ dst-= (dec + 1);
+ *dst= lc->decimal_point;
+ memcpy(dst + 1, src + 2, dec);
}
+
+ /* Put the integer part with grouping */
+ for (count= *grouping; src >= src_begin; count--)
+ {
+ /*
+ When *grouping==0x80 (which means "end of grouping")
+ count will be initialized to -1 and
+ we'll never get into this "if" anymore.
+ */
+ if (count == 0)
+ {
+ *--dst= lc->thousand_sep;
+ if (grouping[1])
+ grouping++;
+ count= *grouping;
+ }
+ DBUG_ASSERT(dst > buf);
+ *--dst= *src--;
+ }
+
+ if (sign_length) /* Put '-' */
+ *--dst= *str->ptr();
+
+ /* Put the rest of the integer part without grouping */
+ str->copy(dst, buf + sizeof(buf) - dst, &my_charset_latin1);
+ }
+ else if (dec_length && lc->decimal_point != '.')
+ {
+ /*
+ For short values without thousands (<1000)
+ replace decimal point to localized value.
+ */
+ ((char*) str->ptr())[str_length - dec_length]= lc->decimal_point;
}
return str;
}
@@ -2161,17 +2378,18 @@ void Item_func_format::print(String *str, enum_query_type query_type)
void Item_func_elt::fix_length_and_dec()
{
- max_length=0;
+ uint32 char_length= 0;
decimals=0;
- if (agg_arg_charsets(collation, args+1, arg_count-1, MY_COLL_ALLOW_CONV, 1))
+ if (agg_arg_charsets_for_string_result(collation, args + 1, arg_count - 1))
return;
for (uint i= 1 ; i < arg_count ; i++)
{
- set_if_bigger(max_length,args[i]->max_length);
+ set_if_bigger(char_length, args[i]->max_char_length());
set_if_bigger(decimals,args[i]->decimals);
}
+ fix_char_length(char_length);
maybe_null=1; // NULL if wrong first arg
}
@@ -2229,14 +2447,14 @@ void Item_func_make_set::split_sum_func(THD *thd, Item **ref_pointer_array,
void Item_func_make_set::fix_length_and_dec()
{
- max_length=arg_count-1;
+ uint32 char_length= arg_count - 1; /* Separators */
- if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1))
+ if (agg_arg_charsets_for_string_result(collation, args, arg_count))
return;
for (uint i=0 ; i < arg_count ; i++)
- max_length+=args[i]->max_length;
-
+ char_length+= args[i]->max_char_length();
+ fix_char_length(char_length);
used_tables_cache|= item->used_tables();
not_null_tables_cache&= item->not_null_tables();
const_item_cache&= item->const_item();
@@ -2349,17 +2567,27 @@ String *Item_func_char::val_str(String *str)
int32 num=(int32) args[i]->val_int();
if (!args[i]->null_value)
{
- char char_num= (char) num;
- if (num&0xFF000000L) {
- str->append((char)(num>>24));
- goto b2;
- } else if (num&0xFF0000L) {
- b2: str->append((char)(num>>16));
- goto b1;
- } else if (num&0xFF00L) {
- b1: str->append((char)(num>>8));
+ char tmp[4];
+ if (num & 0xFF000000L)
+ {
+ mi_int4store(tmp, num);
+ str->append(tmp, 4, &my_charset_bin);
+ }
+ else if (num & 0xFF0000L)
+ {
+ mi_int3store(tmp, num);
+ str->append(tmp, 3, &my_charset_bin);
+ }
+ else if (num & 0xFF00L)
+ {
+ mi_int2store(tmp, num);
+ str->append(tmp, 2, &my_charset_bin);
+ }
+ else
+ {
+ tmp[0]= (char) num;
+ str->append(tmp, 1, &my_charset_bin);
}
- str->append(&char_num, 1);
}
}
str->realloc(str->length()); // Add end 0 (for Purify)
@@ -2391,7 +2619,8 @@ inline String* alloc_buffer(String *res,String *str,String *tmp_value,
void Item_func_repeat::fix_length_and_dec()
{
- collation.set(args[0]->collation);
+ agg_arg_charsets_for_string_result(collation, args, 1);
+ DBUG_ASSERT(collation.collation != NULL);
if (args[1]->const_item())
{
/* must be longlong to avoid truncation */
@@ -2402,13 +2631,8 @@ void Item_func_repeat::fix_length_and_dec()
if (count > INT_MAX32)
count= INT_MAX32;
- ulonglong max_result_length= (ulonglong) args[0]->max_length * count;
- if (max_result_length >= MAX_BLOB_WIDTH)
- {
- max_result_length= MAX_BLOB_WIDTH;
- maybe_null= 1;
- }
- max_length= (ulong) max_result_length;
+ ulonglong char_length= (ulonglong) args[0]->max_char_length() * count;
+ fix_char_length_ulonglong(char_length);
}
else
{
@@ -2475,30 +2699,17 @@ err:
void Item_func_rpad::fix_length_and_dec()
{
// Handle character set for args[0] and args[2].
- if (agg_arg_charsets(collation, &args[0], 2, MY_COLL_ALLOW_CONV, 2))
+ if (agg_arg_charsets_for_string_result(collation, &args[0], 2, 2))
return;
if (args[1]->const_item())
{
- ulonglong length= 0;
-
- if (collation.collation->mbmaxlen > 0)
- {
- ulonglong temp= (ulonglong) args[1]->val_int();
-
- /* Assumes that the maximum length of a String is < INT_MAX32. */
- /* Set here so that rest of code sees out-of-bound value as such. */
- if (temp > INT_MAX32)
- temp = INT_MAX32;
-
- length= temp * collation.collation->mbmaxlen;
- }
-
- if (length >= MAX_BLOB_WIDTH)
- {
- length= MAX_BLOB_WIDTH;
- maybe_null= 1;
- }
- max_length= (ulong) length;
+ ulonglong char_length= (ulonglong) args[1]->val_int();
+ DBUG_ASSERT(collation.collation->mbmaxlen > 0);
+ /* Assumes that the maximum length of a String is < INT_MAX32. */
+ /* Set here so that rest of code sees out-of-bound value as such. */
+ if (char_length > INT_MAX32)
+ char_length= INT_MAX32;
+ fix_char_length_ulonglong(char_length);
}
else
{
@@ -2591,31 +2802,18 @@ String *Item_func_rpad::val_str(String *str)
void Item_func_lpad::fix_length_and_dec()
{
// Handle character set for args[0] and args[2].
- if (agg_arg_charsets(collation, &args[0], 2, MY_COLL_ALLOW_CONV, 2))
+ if (agg_arg_charsets_for_string_result(collation, &args[0], 2, 2))
return;
if (args[1]->const_item())
{
- ulonglong length= 0;
-
- if (collation.collation->mbmaxlen > 0)
- {
- ulonglong temp= (ulonglong) args[1]->val_int();
-
- /* Assumes that the maximum length of a String is < INT_MAX32. */
- /* Set here so that rest of code sees out-of-bound value as such. */
- if (temp > INT_MAX32)
- temp= INT_MAX32;
-
- length= temp * collation.collation->mbmaxlen;
- }
-
- if (length >= MAX_BLOB_WIDTH)
- {
- length= MAX_BLOB_WIDTH;
- maybe_null= 1;
- }
- max_length= (ulong) length;
+ ulonglong char_length= (ulonglong) args[1]->val_int();
+ DBUG_ASSERT(collation.collation->mbmaxlen > 0);
+ /* Assumes that the maximum length of a String is < INT_MAX32. */
+ /* Set here so that rest of code sees out-of-bound value as such. */
+ if (char_length > INT_MAX32)
+ char_length= INT_MAX32;
+ fix_char_length_ulonglong(char_length);
}
else
{
@@ -2775,7 +2973,7 @@ String *Item_func_conv_charset::val_str(String *str)
void Item_func_conv_charset::fix_length_and_dec()
{
collation.set(conv_charset, DERIVATION_IMPLICIT);
- max_length = args[0]->max_length*conv_charset->mbmaxlen;
+ fix_char_length(args[0]->max_char_length());
}
void Item_func_conv_charset::print(String *str, enum_query_type query_type)
@@ -2865,7 +3063,7 @@ String *Item_func_charset::val_str(String *str)
DBUG_ASSERT(fixed == 1);
uint dummy_errors;
- CHARSET_INFO *cs= args[0]->collation.collation;
+ CHARSET_INFO *cs= args[0]->charset_for_protocol();
null_value= 0;
str->copy(cs->csname, (uint) strlen(cs->csname),
&my_charset_latin1, collation.collation, &dummy_errors);
@@ -2876,7 +3074,7 @@ String *Item_func_collation::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
uint dummy_errors;
- CHARSET_INFO *cs= args[0]->collation.collation;
+ CHARSET_INFO *cs= args[0]->charset_for_protocol();
null_value= 0;
str->copy(cs->name, (uint) strlen(cs->name),
@@ -2885,7 +3083,7 @@ String *Item_func_collation::val_str(String *str)
}
-String *Item_func_hex::val_str(String *str)
+String *Item_func_hex::val_str_ascii(String *str)
{
String *res;
DBUG_ASSERT(fixed == 1);
@@ -2910,7 +3108,7 @@ String *Item_func_hex::val_str(String *str)
if ((null_value= args[0]->null_value))
return 0;
ptr= longlong2str(dec,ans,16);
- if (str->copy(ans,(uint32) (ptr-ans),default_charset()))
+ if (str->copy(ans,(uint32) (ptr-ans), &my_charset_numeric))
return &my_empty_string; // End of memory
return str;
}
@@ -2924,6 +3122,7 @@ String *Item_func_hex::val_str(String *str)
}
null_value=0;
tmp_value.length(res->length()*2);
+ tmp_value.set_charset(&my_charset_latin1);
octet2hex((char*) tmp_value.ptr(), res->ptr(), res->length());
return &tmp_value;
@@ -2971,6 +3170,41 @@ String *Item_func_unhex::val_str(String *str)
}
+#ifndef DBUG_OFF
+String *Item_func_like_range::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ longlong nbytes= args[1]->val_int();
+ String *res= args[0]->val_str(str);
+ size_t min_len, max_len;
+ CHARSET_INFO *cs= collation.collation;
+
+ if (!res || args[0]->null_value || args[1]->null_value ||
+ nbytes < 0 || nbytes > MAX_BLOB_WIDTH ||
+ min_str.alloc(nbytes) || max_str.alloc(nbytes))
+ goto err;
+ null_value=0;
+
+ if (cs->coll->like_range(cs, res->ptr(), res->length(),
+ '\\', '_', '%', nbytes,
+ (char*) min_str.ptr(), (char*) max_str.ptr(),
+ &min_len, &max_len))
+ goto err;
+
+ min_str.set_charset(collation.collation);
+ max_str.set_charset(collation.collation);
+ min_str.length(min_len);
+ max_str.length(max_len);
+
+ return is_min ? &min_str : &max_str;
+
+err:
+ null_value= 1;
+ return 0;
+}
+#endif
+
+
void Item_func_binary::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("cast("));
@@ -3004,7 +3238,7 @@ String *Item_load_file::val_str(String *str)
if (!is_secure_file_path(path))
goto err;
- if (!my_stat(path, &stat_info, MYF(0)))
+ if (!mysql_file_stat(key_file_loadfile, path, &stat_info, MYF(0)))
goto err;
if (!(stat_info.st_mode & S_IROTH))
@@ -3022,15 +3256,17 @@ String *Item_load_file::val_str(String *str)
}
if (tmp_value.alloc(stat_info.st_size))
goto err;
- if ((file = my_open(file_name->ptr(), O_RDONLY, MYF(0))) < 0)
+ if ((file= mysql_file_open(key_file_loadfile,
+ file_name->ptr(), O_RDONLY, MYF(0))) < 0)
goto err;
- if (my_read(file, (uchar*) tmp_value.ptr(), stat_info.st_size, MYF(MY_NABP)))
+ if (mysql_file_read(file, (uchar*) tmp_value.ptr(), stat_info.st_size,
+ MYF(MY_NABP)))
{
- my_close(file, MYF(0));
+ mysql_file_close(file, MYF(0));
goto err;
}
tmp_value.length(stat_info.st_size);
- my_close(file, MYF(0));
+ mysql_file_close(file, MYF(0));
null_value = 0;
DBUG_RETURN(&tmp_value);
@@ -3110,13 +3346,13 @@ String* Item_func_export_set::val_str(String* str)
void Item_func_export_set::fix_length_and_dec()
{
- uint length=max(args[1]->max_length,args[2]->max_length);
- uint sep_length=(arg_count > 3 ? args[3]->max_length : 1);
- max_length=length*64+sep_length*63;
+ uint32 length= max(args[1]->max_char_length(), args[2]->max_char_length());
+ uint32 sep_length= (arg_count > 3 ? args[3]->max_char_length() : 1);
- if (agg_arg_charsets(collation, args+1, min(4,arg_count)-1,
- MY_COLL_ALLOW_CONV, 1))
+ if (agg_arg_charsets_for_string_result(collation,
+ args + 1, min(4, arg_count) - 1))
return;
+ fix_char_length(length * 64 + sep_length * 63);
}
String* Item_func_inet_ntoa::val_str(String* str)
@@ -3153,11 +3389,11 @@ String* Item_func_inet_ntoa::val_str(String* str)
num[0]=(char) n1+'0';
num[1]=(char) n2+'0';
num[2]=(char) c+'0';
- uint length=(n1 ? 4 : n2 ? 3 : 2); // Remove pre-zero
-
- (void) str->append(num+4-length,length);
+ uint length= (n1 ? 4 : n2 ? 3 : 2); // Remove pre-zero
+ uint dot_length= (p <= buf) ? 1 : 0;
+ (void) str->append(num + 4 - length, length - dot_length,
+ &my_charset_latin1);
}
- str->length(str->length()-1); // Remove last '.';
return str;
}
@@ -3278,7 +3514,7 @@ longlong Item_func_uncompressed_length::val_int()
*/
if (res->length() <= 4)
{
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ZLIB_Z_DATA_ERROR,
ER(ER_ZLIB_Z_DATA_ERROR));
null_value= 1;
@@ -3355,7 +3591,7 @@ String *Item_func_compress::val_str(String *str)
(const Bytef*)res->ptr(), res->length())) != Z_OK)
{
code= err==Z_MEM_ERROR ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_BUF_ERROR;
- push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code));
+ push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN,code,ER(code));
null_value= 1;
return 0;
}
@@ -3393,7 +3629,7 @@ String *Item_func_uncompress::val_str(String *str)
/* If length is less than 4 bytes, data is corrupt */
if (res->length() <= 4)
{
- push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ZLIB_Z_DATA_ERROR,
ER(ER_ZLIB_Z_DATA_ERROR));
goto err;
@@ -3403,7 +3639,7 @@ String *Item_func_uncompress::val_str(String *str)
new_size= uint4korr(res->ptr()) & 0x3FFFFFFF;
if (new_size > current_thd->variables.max_allowed_packet)
{
- push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TOO_BIG_FOR_UNCOMPRESS,
ER(ER_TOO_BIG_FOR_UNCOMPRESS),
current_thd->variables.max_allowed_packet);
@@ -3421,7 +3657,7 @@ String *Item_func_uncompress::val_str(String *str)
code= ((err == Z_BUF_ERROR) ? ER_ZLIB_Z_BUF_ERROR :
((err == Z_MEM_ERROR) ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_DATA_ERROR));
- push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code));
+ push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN,code,ER(code));
err:
null_value= 1;
@@ -3475,7 +3711,7 @@ String *Item_func_uuid::val_str(String *str)
char *s;
THD *thd= current_thd;
- pthread_mutex_lock(&LOCK_uuid_generator);
+ mysql_mutex_lock(&LOCK_uuid_generator);
if (! uuid_time) /* first UUID() call. initializing data */
{
ulong tmp=sql_rnd_with_mutex();
@@ -3565,7 +3801,7 @@ String *Item_func_uuid::val_str(String *str)
}
uuid_time=tv;
- pthread_mutex_unlock(&LOCK_uuid_generator);
+ mysql_mutex_unlock(&LOCK_uuid_generator);
uint32 time_low= (uint32) (tv & 0xFFFFFFFF);
uint16 time_mid= (uint16) ((tv >> 32) & 0xFFFF);
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index ab2bf006032..d76e139883c 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -1,3 +1,6 @@
+#ifndef ITEM_STRFUNC_INCLUDED
+#define ITEM_STRFUNC_INCLUDED
+
/* Copyright (C) 2000-2003 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -20,6 +23,8 @@
#pragma interface /* gcc class implementation */
#endif
+class MY_LOCALE;
+
class Item_str_func :public Item_func
{
public:
@@ -38,32 +43,54 @@ public:
bool fix_fields(THD *thd, Item **ref);
};
-class Item_func_md5 :public Item_str_func
+
+
+/*
+ Functions that return values with ASCII repertoire
+*/
+class Item_str_ascii_func :public Item_str_func
+{
+ String ascii_buf;
+public:
+ Item_str_ascii_func() :Item_str_func() {}
+ Item_str_ascii_func(Item *a) :Item_str_func(a) {}
+ Item_str_ascii_func(Item *a,Item *b) :Item_str_func(a,b) {}
+ Item_str_ascii_func(Item *a,Item *b,Item *c) :Item_str_func(a,b,c) {}
+ String *val_str_convert_from_ascii(String *str, String *ascii_buf);
+ String *val_str(String *str);
+ virtual String *val_str_ascii(String *)= 0;
+};
+
+
+class Item_func_md5 :public Item_str_ascii_func
{
String tmp_value;
public:
- Item_func_md5(Item *a) :Item_str_func(a)
- {
- collation.set(&my_charset_bin);
- }
- String *val_str(String *);
+ Item_func_md5(Item *a) :Item_str_ascii_func(a) {}
+ String *val_str_ascii(String *);
void fix_length_and_dec();
const char *func_name() const { return "md5"; }
};
-class Item_func_sha :public Item_str_func
+class Item_func_sha :public Item_str_ascii_func
{
public:
- Item_func_sha(Item *a) :Item_str_func(a)
- {
- collation.set(&my_charset_bin);
- }
- String *val_str(String *);
+ Item_func_sha(Item *a) :Item_str_ascii_func(a) {}
+ String *val_str_ascii(String *);
void fix_length_and_dec();
const char *func_name() const { return "sha"; }
};
+class Item_func_sha2 :public Item_str_ascii_func
+{
+public:
+ Item_func_sha2(Item *a, Item *b) :Item_str_ascii_func(a, b) {}
+ String *val_str_ascii(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "sha2"; }
+};
+
class Item_func_aes_encrypt :public Item_str_func
{
public:
@@ -260,13 +287,16 @@ public:
authentication procedure works, see comments in password.c.
*/
-class Item_func_password :public Item_str_func
+class Item_func_password :public Item_str_ascii_func
{
char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
public:
- Item_func_password(Item *a) :Item_str_func(a) {}
- String *val_str(String *str);
- void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; }
+ Item_func_password(Item *a) :Item_str_ascii_func(a) {}
+ String *val_str_ascii(String *str);
+ void fix_length_and_dec()
+ {
+ fix_length_and_charset(SCRAMBLED_PASSWORD_CHAR_LENGTH, default_charset());
+ }
const char *func_name() const { return "password"; }
static char *alloc(THD *thd, const char *password, size_t pass_len);
};
@@ -279,13 +309,16 @@ public:
function.
*/
-class Item_func_old_password :public Item_str_func
+class Item_func_old_password :public Item_str_ascii_func
{
char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1];
public:
- Item_func_old_password(Item *a) :Item_str_func(a) {}
- String *val_str(String *str);
- void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; }
+ Item_func_old_password(Item *a) :Item_str_ascii_func(a) {}
+ String *val_str_ascii(String *str);
+ void fix_length_and_dec()
+ {
+ fix_length_and_charset(SCRAMBLED_PASSWORD_CHAR_LENGTH_323, default_charset());
+ }
const char *func_name() const { return "old_password"; }
static char *alloc(THD *thd, const char *password, size_t pass_len);
};
@@ -506,12 +539,17 @@ public:
};
-class Item_func_format :public Item_str_func
+class Item_func_format :public Item_str_ascii_func
{
String tmp_str;
-public:
- Item_func_format(Item *org, Item *dec);
- String *val_str(String *);
+ MY_LOCALE *locale;
+public:
+ Item_func_format(Item *org, Item *dec): Item_str_ascii_func(org, dec) {}
+ Item_func_format(Item *org, Item *dec, Item *lang):
+ Item_str_ascii_func(org, dec, lang) {}
+
+ MY_LOCALE *get_locale(Item *item);
+ String *val_str_ascii(String *);
void fix_length_and_dec();
const char *func_name() const { return "format"; }
virtual void print(String *str, enum_query_type query_type);
@@ -584,18 +622,18 @@ public:
};
-class Item_func_hex :public Item_str_func
+class Item_func_hex :public Item_str_ascii_func
{
String tmp_value;
public:
- Item_func_hex(Item *a) :Item_str_func(a) {}
+ Item_func_hex(Item *a) :Item_str_ascii_func(a) {}
const char *func_name() const { return "hex"; }
- String *val_str(String *);
+ String *val_str_ascii(String *);
void fix_length_and_dec()
{
collation.set(default_charset());
decimals=0;
- max_length=args[0]->max_length*2*collation.collation->mbmaxlen;
+ fix_char_length(args[0]->max_length * 2);
}
};
@@ -619,6 +657,46 @@ public:
};
+#ifndef DBUG_OFF
+class Item_func_like_range :public Item_str_func
+{
+protected:
+ String min_str;
+ String max_str;
+ const bool is_min;
+public:
+ Item_func_like_range(Item *a, Item *b, bool is_min_arg)
+ :Item_str_func(a, b), is_min(is_min_arg)
+ { maybe_null= 1; }
+ String *val_str(String *);
+ void fix_length_and_dec()
+ {
+ collation.set(args[0]->collation);
+ decimals=0;
+ max_length= MAX_BLOB_WIDTH;
+ }
+};
+
+
+class Item_func_like_range_min :public Item_func_like_range
+{
+public:
+ Item_func_like_range_min(Item *a, Item *b)
+ :Item_func_like_range(a, b, true) { }
+ const char *func_name() const { return "like_range_min"; }
+};
+
+
+class Item_func_like_range_max :public Item_func_like_range
+{
+public:
+ Item_func_like_range_max(Item *a, Item *b)
+ :Item_func_like_range(a, b, false) { }
+ const char *func_name() const { return "like_range_max"; }
+};
+#endif
+
+
class Item_func_binary :public Item_str_func
{
public:
@@ -680,7 +758,7 @@ public:
void fix_length_and_dec()
{
decimals= 0;
- max_length= 3 * 8 + 7;
+ fix_length_and_charset(3 * 8 + 7, default_charset());
maybe_null= 1;
}
};
@@ -841,16 +919,16 @@ class Item_func_uuid: public Item_str_func
{
public:
Item_func_uuid(): Item_str_func() {}
- void fix_length_and_dec() {
- collation.set(system_charset_info);
- /*
- NOTE! uuid() should be changed to use 'ascii'
- charset when hex(), format(), md5(), etc, and implicit
- number-to-string conversion will use 'ascii'
- */
- max_length= UUID_LENGTH * system_charset_info->mbmaxlen;
+ void fix_length_and_dec()
+ {
+ collation.set(system_charset_info,
+ DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
+ fix_char_length(UUID_LENGTH);
}
const char *func_name() const{ return "uuid"; }
String *val_str(String *);
};
+extern String my_empty_string;
+
+#endif /* ITEM_STRFUNC_INCLUDED */
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index d521ad0b4e8..c1b1f47e5e9 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -28,8 +28,16 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" // set_var.h: THD
+#include "set_var.h"
#include "sql_select.h"
+#include "sql_parse.h" // check_stack_overrun
inline Item * and_items(Item* cond, Item *item)
{
@@ -1753,8 +1761,6 @@ subselect_union_engine::subselect_union_engine(st_select_lex_unit *u,
:subselect_engine(item_arg, result_arg)
{
unit= u;
- if (!result_arg) //out of memory
- current_thd->fatal_error();
unit->item= item_arg;
}
@@ -1766,10 +1772,7 @@ int subselect_single_select_engine::prepare()
join= new JOIN(thd, select_lex->item_list,
select_lex->options | SELECT_NO_UNLOCK, result);
if (!join || !result)
- {
- thd->fatal_error(); //out of memory
- return 1;
- }
+ return 1; /* Fatal error is set already. */
prepared= 1;
SELECT_LEX *save_select= thd->lex->current_select;
thd->lex->current_select= select_lex;
@@ -1882,7 +1885,8 @@ void subselect_uniquesubquery_engine::fix_length_and_dec(Item_cache **row)
DBUG_ASSERT(0);
}
-int init_read_record_seq(JOIN_TAB *tab);
+int read_first_record_seq(JOIN_TAB *tab);
+int rr_sequential(READ_RECORD *info);
int join_read_always_key_or_null(JOIN_TAB *tab);
int join_read_next_same_or_null(READ_RECORD *info);
@@ -1973,7 +1977,8 @@ int subselect_single_select_engine::exec()
/* Change the access method to full table scan */
tab->save_read_first_record= tab->read_first_record;
tab->save_read_record= tab->read_record.read_record;
- tab->read_first_record= init_read_record_seq;
+ tab->read_record.read_record= rr_sequential;
+ tab->read_first_record= read_first_record_seq;
tab->read_record.record= tab->table->record[0];
tab->read_record.thd= join->thd;
tab->read_record.ref_length= tab->table->file->ref_length;
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 3806e68e377..d8d18fd8ef6 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -1,3 +1,6 @@
+#ifndef ITEM_SUBSELECT_INCLUDED
+#define ITEM_SUBSELECT_INCLUDED
+
/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -25,6 +28,15 @@ class JOIN;
class select_subselect;
class subselect_engine;
class Item_bool_func2;
+class Comp_creator;
+
+typedef class st_select_lex SELECT_LEX;
+
+/**
+ Convenience typedef used in this file, and further used by any files
+ including this file.
+*/
+typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
/* base class for subselects */
@@ -172,7 +184,7 @@ public:
void fix_length_and_dec();
uint cols();
- Item* element_index(uint i) { return my_reinterpret_cast(Item*)(row[i]); }
+ Item* element_index(uint i) { return reinterpret_cast<Item*>(row[i]); }
Item** addr(uint i) { return (Item**)row + i; }
bool check_cols(uint c);
bool null_inside();
@@ -570,6 +582,15 @@ public:
virtual void print (String *str, enum_query_type query_type);
};
+/*
+ This function is actually defined in sql_parse.cc, but it depends on
+ chooser_compare_func_creator defined in this file.
+ */
+Item * all_any_subquery_creator(Item *left_expr,
+ chooser_compare_func_creator cmp,
+ bool all,
+ SELECT_LEX *select_lex);
+
inline bool Item_subselect::is_evaluated() const
{
@@ -581,4 +602,4 @@ inline bool Item_subselect::is_uncacheable() const
return engine->uncacheable();
}
-
+#endif /* ITEM_SUBSELECT_INCLUDED */
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 65f8222d38b..8cd8e1bb222 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -25,10 +25,22 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
#include "sql_select.h"
/**
+ Calculate the affordable RAM limit for structures like TREE or Unique
+ used in Item_sum_*
+*/
+
+ulonglong Item_sum::ram_limitation(THD *thd)
+{
+ return min(thd->variables.tmp_table_size,
+ thd->variables.max_heap_table_size);
+}
+
+
+/**
Prepare an aggregate function item for checking context conditions.
The function initializes the members of the Item_sum object created
@@ -374,6 +386,7 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements),
args= NULL;
}
mark_as_sum_func();
+ init_aggregator();
list.empty(); // Fields are used
}
@@ -405,6 +418,10 @@ Item_sum::Item_sum(THD *thd, Item_sum *item):
}
memcpy(args, item->args, sizeof(Item*)*arg_count);
memcpy(orig_args, item->orig_args, sizeof(Item*)*arg_count);
+ init_aggregator();
+ with_distinct= item->with_distinct;
+ if (item->aggr)
+ set_aggregator(item->aggr->Aggrtype());
}
@@ -530,13 +547,526 @@ void Item_sum::update_used_tables ()
}
-Item *Item_sum::set_arg(int i, THD *thd, Item *new_val)
+Item *Item_sum::set_arg(uint i, THD *thd, Item *new_val)
{
thd->change_item_tree(args + i, new_val);
return new_val;
}
+int Item_sum::set_aggregator(Aggregator::Aggregator_type aggregator)
+{
+ if (aggr)
+ {
+ /*
+ Dependent subselects may be executed multiple times, making
+ set_aggregator to be called multiple times. The aggregator type
+ will be the same, but it needs to be reset so that it is
+ reevaluated with the new dependent data.
+ */
+ DBUG_ASSERT(aggregator == aggr->Aggrtype());
+ aggr->clear();
+ return FALSE;
+ }
+ switch (aggregator)
+ {
+ case Aggregator::DISTINCT_AGGREGATOR:
+ aggr= new Aggregator_distinct(this);
+ break;
+
+ case Aggregator::SIMPLE_AGGREGATOR:
+ aggr= new Aggregator_simple(this);
+ break;
+ };
+ return aggr ? FALSE : TRUE;
+}
+
+
+void Item_sum::cleanup()
+{
+ if (aggr)
+ {
+ delete aggr;
+ aggr= NULL;
+ }
+ Item_result_field::cleanup();
+ forced_const= FALSE;
+}
+
+
+/**
+ Compare keys consisting of single field that cannot be compared as binary.
+
+ Used by the Unique class to compare keys. Will do correct comparisons
+ for all field types.
+
+ @param arg Pointer to the relevant Field class instance
+ @param key1 left key image
+ @param key2 right key image
+ @return comparison result
+ @retval < 0 if key1 < key2
+ @retval = 0 if key1 = key2
+ @retval > 0 if key1 > key2
+*/
+
+static int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2)
+{
+ Field *f= (Field*) arg;
+ return f->cmp(key1, key2);
+}
+
+
+/**
+ Correctly compare composite keys.
+
+ Used by the Unique class to compare keys. Will do correct comparisons
+ for composite keys with various field types.
+
+ @param arg Pointer to the relevant Aggregator_distinct instance
+ @param key1 left key image
+ @param key2 right key image
+ @return comparison result
+ @retval <0 if key1 < key2
+ @retval =0 if key1 = key2
+ @retval >0 if key1 > key2
+*/
+
+int Aggregator_distinct::composite_key_cmp(void* arg, uchar* key1, uchar* key2)
+{
+ Aggregator_distinct *aggr= (Aggregator_distinct *) arg;
+ Field **field = aggr->table->field;
+ Field **field_end= field + aggr->table->s->fields;
+ uint32 *lengths=aggr->field_lengths;
+ for (; field < field_end; ++field)
+ {
+ Field* f = *field;
+ int len = *lengths++;
+ int res = f->cmp(key1, key2);
+ if (res)
+ return res;
+ key1 += len;
+ key2 += len;
+ }
+ return 0;
+}
+
+
+static enum enum_field_types
+calc_tmp_field_type(enum enum_field_types table_field_type,
+ Item_result result_type)
+{
+ /* Adjust tmp table type according to the chosen aggregation type */
+ switch (result_type) {
+ case STRING_RESULT:
+ case REAL_RESULT:
+ if (table_field_type != MYSQL_TYPE_FLOAT)
+ table_field_type= MYSQL_TYPE_DOUBLE;
+ break;
+ case INT_RESULT:
+ table_field_type= MYSQL_TYPE_LONGLONG;
+ /* fallthrough */
+ case DECIMAL_RESULT:
+ if (table_field_type != MYSQL_TYPE_LONGLONG)
+ table_field_type= MYSQL_TYPE_NEWDECIMAL;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ return table_field_type;
+}
+
+
+/***************************************************************************/
+
+C_MODE_START
+
+/* Declarations for auxilary C-callbacks */
+
+static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
+{
+ return memcmp(key1, key2, *(uint *) arg);
+}
+
+
+static int item_sum_distinct_walk(void *element, element_count num_of_dups,
+ void *item)
+{
+ return ((Aggregator_distinct*) (item))->unique_walk_function(element);
+}
+
+C_MODE_END
+
+/***************************************************************************/
+/**
+ Called before feeding the first row. Used to allocate/setup
+ the internal structures used for aggregation.
+
+ @param thd Thread descriptor
+ @return status
+ @retval FALSE success
+ @retval TRUE faliure
+
+ Prepares Aggregator_distinct to process the incoming stream.
+ Creates the temporary table and the Unique class if needed.
+ Called by Item_sum::aggregator_setup()
+*/
+
+bool Aggregator_distinct::setup(THD *thd)
+{
+ endup_done= FALSE;
+ /*
+ Setup can be called twice for ROLLUP items. This is a bug.
+ Please add DBUG_ASSERT(tree == 0) here when it's fixed.
+ */
+ if (tree || table || tmp_table_param)
+ return FALSE;
+
+ if (item_sum->setup(thd))
+ return TRUE;
+ if (item_sum->sum_func() == Item_sum::COUNT_FUNC ||
+ item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC)
+ {
+ List<Item> list;
+ SELECT_LEX *select_lex= thd->lex->current_select;
+
+ if (!(tmp_table_param= new TMP_TABLE_PARAM))
+ return TRUE;
+
+ /* Create a table with an unique key over all parameters */
+ for (uint i=0; i < item_sum->get_arg_count() ; i++)
+ {
+ Item *item=item_sum->get_arg(i);
+ if (list.push_back(item))
+ return TRUE; // End of memory
+ if (item->const_item() && item->is_null())
+ always_null= true;
+ }
+ if (always_null)
+ return FALSE;
+ count_field_types(select_lex, tmp_table_param, list, 0);
+ tmp_table_param->force_copy_fields= item_sum->has_force_copy_fields();
+ DBUG_ASSERT(table == 0);
+ /*
+ Make create_tmp_table() convert BIT columns to BIGINT.
+ This is needed because BIT fields store parts of their data in table's
+ null bits, and we don't have methods to compare two table records, which
+ is needed by Unique which is used when HEAP table is used.
+ */
+ {
+ List_iterator_fast<Item> li(list);
+ Item *item;
+ while ((item= li++))
+ {
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*)item)->field->type() == FIELD_TYPE_BIT)
+ item->marker=4;
+ }
+ }
+ if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
+ 0,
+ (select_lex->options | thd->variables.option_bits),
+ HA_POS_ERROR, "")))
+ return TRUE;
+ table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
+ table->no_rows=1;
+
+ if (table->s->db_type() == heap_hton)
+ {
+ /*
+ No blobs, otherwise it would have been MyISAM: set up a compare
+ function and its arguments to use with Unique.
+ */
+ qsort_cmp2 compare_key;
+ void* cmp_arg;
+ Field **field= table->field;
+ Field **field_end= field + table->s->fields;
+ bool all_binary= TRUE;
+
+ for (tree_key_length= 0; field < field_end; ++field)
+ {
+ Field *f= *field;
+ enum enum_field_types type= f->type();
+ tree_key_length+= f->pack_length();
+ if ((type == MYSQL_TYPE_VARCHAR) ||
+ (!f->binary() && (type == MYSQL_TYPE_STRING ||
+ type == MYSQL_TYPE_VAR_STRING)))
+ {
+ all_binary= FALSE;
+ break;
+ }
+ }
+ if (all_binary)
+ {
+ cmp_arg= (void*) &tree_key_length;
+ compare_key= (qsort_cmp2) simple_raw_key_cmp;
+ }
+ else
+ {
+ if (table->s->fields == 1)
+ {
+ /*
+ If we have only one field, which is the most common use of
+ count(distinct), it is much faster to use a simpler key
+ compare method that can take advantage of not having to worry
+ about other fields.
+ */
+ compare_key= (qsort_cmp2) simple_str_key_cmp;
+ cmp_arg= (void*) table->field[0];
+ /* tree_key_length has been set already */
+ }
+ else
+ {
+ uint32 *length;
+ compare_key= (qsort_cmp2) composite_key_cmp;
+ cmp_arg= (void*) this;
+ field_lengths= (uint32*) thd->alloc(table->s->fields * sizeof(uint32));
+ for (tree_key_length= 0, length= field_lengths, field= table->field;
+ field < field_end; ++field, ++length)
+ {
+ *length= (*field)->pack_length();
+ tree_key_length+= *length;
+ }
+ }
+ }
+ DBUG_ASSERT(tree == 0);
+ tree= new Unique(compare_key, cmp_arg, tree_key_length,
+ item_sum->ram_limitation(thd));
+ /*
+ The only time tree_key_length could be 0 is if someone does
+ count(distinct) on a char(0) field - stupid thing to do,
+ but this has to be handled - otherwise someone can crash
+ the server with a DoS attack
+ */
+ if (! tree)
+ return TRUE;
+ }
+ return FALSE;
+ }
+ else
+ {
+ List<Create_field> field_list;
+ Create_field field_def; /* field definition */
+ Item *arg;
+ DBUG_ENTER("Aggregator_distinct::setup");
+ /* It's legal to call setup() more than once when in a subquery */
+ if (tree)
+ DBUG_RETURN(FALSE);
+
+ /*
+ Virtual table and the tree are created anew on each re-execution of
+ PS/SP. Hence all further allocations are performed in the runtime
+ mem_root.
+ */
+ if (field_list.push_back(&field_def))
+ DBUG_RETURN(TRUE);
+
+ item_sum->null_value= item_sum->maybe_null= 1;
+ item_sum->quick_group= 0;
+
+ DBUG_ASSERT(item_sum->get_arg(0)->fixed);
+
+ arg= item_sum->get_arg(0);
+ if (arg->const_item())
+ {
+ (void) arg->val_int();
+ if (arg->null_value)
+ always_null= true;
+ }
+
+ if (always_null)
+ DBUG_RETURN(FALSE);
+
+ enum enum_field_types field_type;
+
+ field_type= calc_tmp_field_type(arg->field_type(),
+ arg->result_type());
+ field_def.init_for_tmp_table(field_type,
+ arg->max_length,
+ arg->decimals,
+ arg->maybe_null,
+ arg->unsigned_flag);
+
+ if (! (table= create_virtual_tmp_table(thd, field_list)))
+ DBUG_RETURN(TRUE);
+
+ /* XXX: check that the case of CHAR(0) works OK */
+ tree_key_length= table->s->reclength - table->s->null_bytes;
+
+ /*
+ Unique handles all unique elements in a tree until they can't fit
+ in. Then the tree is dumped to the temporary file. We can use
+ simple_raw_key_cmp because the table contains numbers only; decimals
+ are converted to binary representation as well.
+ */
+ tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length,
+ item_sum->ram_limitation(thd));
+
+ DBUG_RETURN(tree == 0);
+ }
+}
+
+
+/**
+ Invalidate calculated value and clear the distinct rows.
+
+ Frees space used by the internal data structures.
+ Removes the accumulated distinct rows. Invalidates the calculated result.
+*/
+
+void Aggregator_distinct::clear()
+{
+ endup_done= FALSE;
+ item_sum->clear();
+ if (tree)
+ tree->reset();
+ /* tree and table can be both null only if always_null */
+ if (item_sum->sum_func() == Item_sum::COUNT_FUNC ||
+ item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC)
+ {
+ if (!tree && table)
+ {
+ table->file->extra(HA_EXTRA_NO_CACHE);
+ table->file->ha_delete_all_rows();
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ }
+ }
+ else
+ {
+ item_sum->null_value= 1;
+ }
+}
+
+
+/**
+ Process incoming row.
+
+ Add it to Unique/temp hash table if it's unique. Skip the row if
+ not unique.
+ Prepare Aggregator_distinct to process the incoming stream.
+ Create the temporary table and the Unique class if needed.
+ Called by Item_sum::aggregator_add().
+ To actually get the result value in item_sum's buffers
+ Aggregator_distinct::endup() must be called.
+
+ @return status
+ @retval FALSE success
+ @retval TRUE failure
+*/
+
+bool Aggregator_distinct::add()
+{
+ if (always_null)
+ return 0;
+
+ if (item_sum->sum_func() == Item_sum::COUNT_FUNC ||
+ item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC)
+ {
+ int error;
+ copy_fields(tmp_table_param);
+ if (copy_funcs(tmp_table_param->items_to_copy, table->in_use))
+ return TRUE;
+
+ for (Field **field=table->field ; *field ; field++)
+ if ((*field)->is_real_null(0))
+ return 0; // Don't count NULL
+
+ if (tree)
+ {
+ /*
+ The first few bytes of record (at least one) are just markers
+ for deleted and NULLs. We want to skip them since they will
+ bloat the tree without providing any valuable info. Besides,
+ key_length used to initialize the tree didn't include space for them.
+ */
+ return tree->unique_add(table->record[0] + table->s->null_bytes);
+ }
+ if ((error= table->file->ha_write_row(table->record[0])) &&
+ table->file->is_fatal_error(error, HA_CHECK_DUP))
+ return TRUE;
+ return FALSE;
+ }
+ else
+ {
+ item_sum->get_arg(0)->save_in_field(table->field[0], FALSE);
+ if (table->field[0]->is_null())
+ return 0;
+ DBUG_ASSERT(tree);
+ item_sum->null_value= 0;
+ /*
+ '0' values are also stored in the tree. This doesn't matter
+ for SUM(DISTINCT), but is important for AVG(DISTINCT)
+ */
+ return tree->unique_add(table->field[0]->ptr);
+ }
+}
+
+
+/**
+ Calculate the aggregate function value.
+
+ Since Distinct_aggregator::add() just collects the distinct rows,
+ we must go over the distinct rows and feed them to the aggregation
+ function before returning its value.
+ This is what endup () does. It also sets the result validity flag
+ endup_done to TRUE so it will not recalculate the aggregate value
+ again if the Item_sum hasn't been reset.
+*/
+
+void Aggregator_distinct::endup()
+{
+ /* prevent consecutive recalculations */
+ if (endup_done)
+ return;
+
+ /* we are going to calculate the aggregate value afresh */
+ item_sum->clear();
+
+ /* The result will definitely be null : no more calculations needed */
+ if (always_null)
+ return;
+
+ if (item_sum->sum_func() == Item_sum::COUNT_FUNC ||
+ item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC)
+ {
+ DBUG_ASSERT(item_sum->fixed == 1);
+ Item_sum_count *sum= (Item_sum_count *)item_sum;
+ if (tree && tree->elements == 0)
+ {
+ /* everything fits in memory */
+ sum->count= (longlong) tree->elements_in_tree();
+ endup_done= TRUE;
+ }
+ if (!tree)
+ {
+ /* there were blobs */
+ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ sum->count= table->file->stats.records;
+ endup_done= TRUE;
+ }
+ }
+ else
+ {
+ /*
+ We don't have a tree only if 'setup()' hasn't been called;
+ this is the case of sql_select.cc:return_zero_rows.
+ */
+ if (tree)
+ table->field[0]->set_notnull();
+ }
+
+ if (tree && !endup_done)
+ {
+ /* go over the tree of distinct keys and calculate the aggregate value */
+ use_distinct_values= TRUE;
+ tree->walk(item_sum_distinct_walk, (void*) this);
+ use_distinct_values= FALSE;
+ }
+ /* prevent consecutive recalculations */
+ endup_done= TRUE;
+}
+
+
String *
Item_sum_num::val_str(String *str)
{
@@ -795,10 +1325,27 @@ void Item_sum_sum::fix_length_and_dec()
bool Item_sum_sum::add()
{
DBUG_ENTER("Item_sum_sum::add");
+ bool arg_is_null;
if (hybrid_type == DECIMAL_RESULT)
{
- my_decimal value, *val= args[0]->val_decimal(&value);
- if (!args[0]->null_value)
+ my_decimal value, *val;
+ if (aggr->use_distinct_values)
+ {
+ /*
+ We are aggregating distinct rows. Get the value from the distinct
+ table pointer
+ */
+ Aggregator_distinct *daggr= (Aggregator_distinct *)aggr;
+ val= daggr->table->field[0]->val_decimal (&value);
+ arg_is_null= daggr->table->field[0]->is_null();
+ }
+ else
+ {
+ /* non-distinct aggregation */
+ val= args[0]->val_decimal(&value);
+ arg_is_null= args[0]->null_value;
+ }
+ if (!arg_is_null)
{
my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
val, dec_buffs + curr_dec_buff);
@@ -808,8 +1355,25 @@ bool Item_sum_sum::add()
}
else
{
- sum+= args[0]->val_real();
- if (!args[0]->null_value)
+ double val;
+ if (aggr->use_distinct_values)
+ {
+ /*
+ We are aggregating distinct rows. Get the value from the distinct
+ table pointer
+ */
+ Aggregator_distinct *daggr= (Aggregator_distinct *)aggr;
+ val= daggr->table->field[0]->val_real ();
+ arg_is_null= daggr->table->field[0]->is_null();
+ }
+ else
+ {
+ /* non-distinct aggregation */
+ val= args[0]->val_real();
+ arg_is_null= args[0]->null_value;
+ }
+ sum+= val;
+ if (!arg_is_null)
null_value= 0;
}
DBUG_RETURN(0);
@@ -819,6 +1383,8 @@ bool Item_sum_sum::add()
longlong Item_sum_sum::val_int()
{
DBUG_ASSERT(fixed == 1);
+ if (aggr)
+ aggr->endup();
if (hybrid_type == DECIMAL_RESULT)
{
longlong result;
@@ -833,6 +1399,8 @@ longlong Item_sum_sum::val_int()
double Item_sum_sum::val_real()
{
DBUG_ASSERT(fixed == 1);
+ if (aggr)
+ aggr->endup();
if (hybrid_type == DECIMAL_RESULT)
my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum);
return sum;
@@ -841,6 +1409,8 @@ double Item_sum_sum::val_real()
String *Item_sum_sum::val_str(String *str)
{
+ if (aggr)
+ aggr->endup();
if (hybrid_type == DECIMAL_RESULT)
return val_string_from_decimal(str);
return val_string_from_real(str);
@@ -849,311 +1419,54 @@ String *Item_sum_sum::val_str(String *str)
my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
{
+ if (aggr)
+ aggr->endup();
if (hybrid_type == DECIMAL_RESULT)
return (dec_buffs + curr_dec_buff);
return val_decimal_from_real(val);
}
-/***************************************************************************/
-
-C_MODE_START
-
-/* Declarations for auxilary C-callbacks */
-
-static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
-{
- return memcmp(key1, key2, *(uint *) arg);
-}
-
-
-static int item_sum_distinct_walk(void *element, element_count num_of_dups,
- void *item)
-{
- return ((Item_sum_distinct*) (item))->unique_walk_function(element);
-}
-
-C_MODE_END
-
-/* Item_sum_distinct */
-
-Item_sum_distinct::Item_sum_distinct(Item *item_arg)
- :Item_sum_num(item_arg), tree(0)
-{
- /*
- quick_group is an optimizer hint, which means that GROUP BY can be
- handled with help of index on grouped columns.
- By setting quick_group to zero we force creation of temporary table
- to perform GROUP BY.
- */
- quick_group= 0;
-}
-
-
-Item_sum_distinct::Item_sum_distinct(THD *thd, Item_sum_distinct *original)
- :Item_sum_num(thd, original), val(original->val), tree(0),
- table_field_type(original->table_field_type)
-{
- quick_group= 0;
-}
-
-
/**
- Behaves like an Integer except to fix_length_and_dec().
- Additionally div() converts val with this traits to a val with true
- decimal traits along with conversion of integer value to decimal value.
- This is to speedup SUM/AVG(DISTINCT) evaluation for 8-32 bit integer
- values.
+ Aggregate a distinct row from the distinct hash table.
+
+ Called for each row into the hash table 'Aggregator_distinct::table'.
+ Includes the current distinct row into the calculation of the
+ aggregate value. Uses the Field classes to get the value from the row.
+ This function is used for AVG/SUM(DISTINCT). For COUNT(DISTINCT)
+ it's called only when there are no blob arguments and the data don't
+ fit into memory (so Unique makes persisted trees on disk).
+
+ @param element pointer to the row data.
+
+ @return status
+ @retval FALSE success
+ @retval TRUE failure
*/
-struct Hybrid_type_traits_fast_decimal: public
- Hybrid_type_traits_integer
-{
- virtual Item_result type() const { return DECIMAL_RESULT; }
- virtual void fix_length_and_dec(Item *item, Item *arg) const
- { Hybrid_type_traits_decimal::instance()->fix_length_and_dec(item, arg); }
-
- virtual void div(Hybrid_type *val, ulonglong u) const
- {
- int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, val->dec_buf);
- val->used_dec_buf_no= 0;
- val->traits= Hybrid_type_traits_decimal::instance();
- val->traits->div(val, u);
- }
- static const Hybrid_type_traits_fast_decimal *instance();
- Hybrid_type_traits_fast_decimal() {};
-};
-
-static const Hybrid_type_traits_fast_decimal fast_decimal_traits_instance;
-
-const Hybrid_type_traits_fast_decimal
- *Hybrid_type_traits_fast_decimal::instance()
-{
- return &fast_decimal_traits_instance;
-}
-
-void Item_sum_distinct::fix_length_and_dec()
+
+bool Aggregator_distinct::unique_walk_function(void *element)
{
- DBUG_ASSERT(args[0]->fixed);
-
- table_field_type= args[0]->field_type();
-
- /* Adjust tmp table type according to the chosen aggregation type */
- switch (args[0]->result_type()) {
- case STRING_RESULT:
- case REAL_RESULT:
- val.traits= Hybrid_type_traits::instance();
- if (table_field_type != MYSQL_TYPE_FLOAT)
- table_field_type= MYSQL_TYPE_DOUBLE;
- break;
- case INT_RESULT:
- /*
- Preserving int8, int16, int32 field types gives ~10% performance boost
- as the size of result tree becomes significantly smaller.
- Another speed up we gain by using longlong for intermediate
- calculations. The range of int64 is enough to hold sum 2^32 distinct
- integers each <= 2^32.
- */
- if (table_field_type == MYSQL_TYPE_INT24 ||
- (table_field_type >= MYSQL_TYPE_TINY &&
- table_field_type <= MYSQL_TYPE_LONG))
- {
- val.traits= Hybrid_type_traits_fast_decimal::instance();
- break;
- }
- table_field_type= MYSQL_TYPE_LONGLONG;
- /* fallthrough */
- case DECIMAL_RESULT:
- val.traits= Hybrid_type_traits_decimal::instance();
- if (table_field_type != MYSQL_TYPE_LONGLONG)
- table_field_type= MYSQL_TYPE_NEWDECIMAL;
- break;
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- }
- val.traits->fix_length_and_dec(this, args[0]);
+ memcpy(table->field[0]->ptr, element, tree_key_length);
+ item_sum->add();
+ return 0;
}
-/**
- @todo
- check that the case of CHAR(0) works OK
-*/
-bool Item_sum_distinct::setup(THD *thd)
+Aggregator_distinct::~Aggregator_distinct()
{
- List<Create_field> field_list;
- Create_field field_def; /* field definition */
- DBUG_ENTER("Item_sum_distinct::setup");
- /* It's legal to call setup() more than once when in a subquery */
if (tree)
- DBUG_RETURN(FALSE);
-
- /*
- Virtual table and the tree are created anew on each re-execution of
- PS/SP. Hence all further allocations are performed in the runtime
- mem_root.
- */
- if (field_list.push_back(&field_def))
- DBUG_RETURN(TRUE);
-
- null_value= maybe_null= 1;
- quick_group= 0;
-
- DBUG_ASSERT(args[0]->fixed);
-
- field_def.init_for_tmp_table(table_field_type, args[0]->max_length,
- args[0]->decimals, args[0]->maybe_null,
- args[0]->unsigned_flag);
-
- if (! (table= create_virtual_tmp_table(thd, field_list)))
- DBUG_RETURN(TRUE);
-
- /* XXX: check that the case of CHAR(0) works OK */
- tree_key_length= table->s->reclength - table->s->null_bytes;
-
- /*
- Unique handles all unique elements in a tree until they can't fit
- in. Then the tree is dumped to the temporary file. We can use
- simple_raw_key_cmp because the table contains numbers only; decimals
- are converted to binary representation as well.
- */
- tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length,
- thd->variables.max_heap_table_size);
-
- is_evaluated= FALSE;
- DBUG_RETURN(tree == 0);
-}
-
-
-bool Item_sum_distinct::add()
-{
- args[0]->save_in_field(table->field[0], FALSE);
- is_evaluated= FALSE;
- if (!table->field[0]->is_null())
{
- DBUG_ASSERT(tree);
- null_value= 0;
- /*
- '0' values are also stored in the tree. This doesn't matter
- for SUM(DISTINCT), but is important for AVG(DISTINCT)
- */
- return tree->unique_add(table->field[0]->ptr);
+ delete tree;
+ tree= NULL;
}
- return 0;
-}
-
-
-bool Item_sum_distinct::unique_walk_function(void *element)
-{
- memcpy(table->field[0]->ptr, element, tree_key_length);
- ++count;
- val.traits->add(&val, table->field[0]);
- return 0;
-}
-
-
-void Item_sum_distinct::clear()
-{
- DBUG_ENTER("Item_sum_distinct::clear");
- DBUG_ASSERT(tree != 0); /* we always have a tree */
- null_value= 1;
- tree->reset();
- is_evaluated= FALSE;
- DBUG_VOID_RETURN;
-}
-
-void Item_sum_distinct::cleanup()
-{
- Item_sum_num::cleanup();
- delete tree;
- tree= 0;
- table= 0;
- is_evaluated= FALSE;
-}
-
-Item_sum_distinct::~Item_sum_distinct()
-{
- delete tree;
- /* no need to free the table */
-}
-
-
-void Item_sum_distinct::calculate_val_and_count()
-{
- if (!is_evaluated)
+ if (table)
{
- count= 0;
- val.traits->set_zero(&val);
- /*
- We don't have a tree only if 'setup()' hasn't been called;
- this is the case of sql_select.cc:return_zero_rows.
- */
- if (tree)
- {
- table->field[0]->set_notnull();
- tree->walk(item_sum_distinct_walk, (void*) this);
- }
- is_evaluated= TRUE;
+ free_tmp_table(table->in_use, table);
+ table=NULL;
}
-}
-
-
-double Item_sum_distinct::val_real()
-{
- calculate_val_and_count();
- return val.traits->val_real(&val);
-}
-
-
-my_decimal *Item_sum_distinct::val_decimal(my_decimal *to)
-{
- calculate_val_and_count();
- if (null_value)
- return 0;
- return val.traits->val_decimal(&val, to);
-}
-
-
-longlong Item_sum_distinct::val_int()
-{
- calculate_val_and_count();
- return val.traits->val_int(&val, unsigned_flag);
-}
-
-
-String *Item_sum_distinct::val_str(String *str)
-{
- calculate_val_and_count();
- if (null_value)
- return 0;
- return val.traits->val_str(&val, str, decimals);
-}
-
-/* end of Item_sum_distinct */
-
-/* Item_sum_avg_distinct */
-
-void
-Item_sum_avg_distinct::fix_length_and_dec()
-{
- Item_sum_distinct::fix_length_and_dec();
- prec_increment= current_thd->variables.div_precincrement;
- /*
- AVG() will divide val by count. We need to reserve digits
- after decimal point as the result can be fractional.
- */
- decimals= min(decimals + prec_increment, NOT_FIXED_DEC);
-}
-
-
-void
-Item_sum_avg_distinct::calculate_val_and_count()
-{
- if (!is_evaluated)
+ if (tmp_table_param)
{
- Item_sum_distinct::calculate_val_and_count();
- if (count)
- val.traits->div(&val, count);
- is_evaluated= TRUE;
+ delete tmp_table_param;
+ tmp_table_param= NULL;
}
}
@@ -1180,6 +1493,8 @@ bool Item_sum_count::add()
longlong Item_sum_count::val_int()
{
DBUG_ASSERT(fixed == 1);
+ if (aggr)
+ aggr->endup();
return (longlong) count;
}
@@ -1269,6 +1584,8 @@ bool Item_sum_avg::add()
double Item_sum_avg::val_real()
{
DBUG_ASSERT(fixed == 1);
+ if (aggr)
+ aggr->endup();
if (!count)
{
null_value=1;
@@ -1283,6 +1600,8 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
my_decimal sum_buff, cnt;
const my_decimal *sum_dec;
DBUG_ASSERT(fixed == 1);
+ if (aggr)
+ aggr->endup();
if (!count)
{
null_value=1;
@@ -1305,6 +1624,8 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
String *Item_sum_avg::val_str(String *str)
{
+ if (aggr)
+ aggr->endup();
if (hybrid_type == DECIMAL_RESULT)
return val_string_from_decimal(str);
return val_string_from_real(str);
@@ -1562,7 +1883,7 @@ void Item_sum_variance::update_field()
void Item_sum_hybrid::clear()
{
- value->null_value= 1;
+ value->clear();
null_value= 1;
}
@@ -1837,6 +2158,7 @@ void Item_sum_hybrid::reset_field()
void Item_sum_sum::reset_field()
{
+ DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
if (hybrid_type == DECIMAL_RESULT)
{
my_decimal value, *arg_val= args[0]->val_decimal(&value);
@@ -1861,6 +2183,7 @@ void Item_sum_count::reset_field()
{
uchar *res=result_field->ptr;
longlong nr=0;
+ DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
if (!args[0]->maybe_null || !args[0]->is_null())
nr=1;
@@ -1871,6 +2194,7 @@ void Item_sum_count::reset_field()
void Item_sum_avg::reset_field()
{
uchar *res=result_field->ptr;
+ DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
if (hybrid_type == DECIMAL_RESULT)
{
longlong tmp;
@@ -1924,6 +2248,7 @@ void Item_sum_bit::update_field()
void Item_sum_sum::update_field()
{
+ DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
if (hybrid_type == DECIMAL_RESULT)
{
my_decimal value, *arg_val= args[0]->val_decimal(&value);
@@ -1976,6 +2301,9 @@ void Item_sum_avg::update_field()
{
longlong field_count;
uchar *res=result_field->ptr;
+
+ DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
+
if (hybrid_type == DECIMAL_RESULT)
{
my_decimal value, *arg_val= args[0]->val_decimal(&value);
@@ -2279,319 +2607,6 @@ double Item_variance_field::val_real()
/****************************************************************************
-** COUNT(DISTINCT ...)
-****************************************************************************/
-
-int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2)
-{
- Field *f= (Field*) arg;
- return f->cmp(key1, key2);
-}
-
-/**
- Did not make this one static - at least gcc gets confused when
- I try to declare a static function as a friend. If you can figure
- out the syntax to make a static function a friend, make this one
- static
-*/
-
-int composite_key_cmp(void* arg, uchar* key1, uchar* key2)
-{
- Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
- Field **field = item->table->field;
- Field **field_end= field + item->table->s->fields;
- uint32 *lengths=item->field_lengths;
- for (; field < field_end; ++field)
- {
- Field* f = *field;
- int len = *lengths++;
- int res = f->cmp(key1, key2);
- if (res)
- return res;
- key1 += len;
- key2 += len;
- }
- return 0;
-}
-
-
-C_MODE_START
-
-static int count_distinct_walk(void *elem, element_count count, void *arg)
-{
- (*((ulonglong*)arg))++;
- return 0;
-}
-
-C_MODE_END
-
-
-void Item_sum_count_distinct::cleanup()
-{
- DBUG_ENTER("Item_sum_count_distinct::cleanup");
- Item_sum_int::cleanup();
-
- /* Free objects only if we own them. */
- if (!original)
- {
- /*
- We need to delete the table and the tree in cleanup() as
- they were allocated in the runtime memroot. Using the runtime
- memroot reduces memory footprint for PS/SP and simplifies setup().
- */
- delete tree;
- tree= 0;
- is_evaluated= FALSE;
- if (table)
- {
- free_tmp_table(table->in_use, table);
- table= 0;
- }
- delete tmp_table_param;
- tmp_table_param= 0;
- }
- always_null= FALSE;
- DBUG_VOID_RETURN;
-}
-
-
-/**
- This is used by rollup to create a separate usable copy of
- the function.
-*/
-
-void Item_sum_count_distinct::make_unique()
-{
- table=0;
- original= 0;
- force_copy_fields= 1;
- tree= 0;
- is_evaluated= FALSE;
- tmp_table_param= 0;
- always_null= FALSE;
-}
-
-
-Item_sum_count_distinct::~Item_sum_count_distinct()
-{
- cleanup();
-}
-
-
-bool Item_sum_count_distinct::setup(THD *thd)
-{
- List<Item> list;
- SELECT_LEX *select_lex= thd->lex->current_select;
-
- /*
- Setup can be called twice for ROLLUP items. This is a bug.
- Please add DBUG_ASSERT(tree == 0) here when it's fixed.
- It's legal to call setup() more than once when in a subquery
- */
- if (tree || table || tmp_table_param)
- return FALSE;
-
- if (!(tmp_table_param= new TMP_TABLE_PARAM))
- return TRUE;
-
- /* Create a table with an unique key over all parameters */
- for (uint i=0; i < arg_count ; i++)
- {
- Item *item=args[i];
- if (list.push_back(item))
- return TRUE; // End of memory
- if (item->const_item() && item->is_null())
- always_null= 1;
- }
- if (always_null)
- return FALSE;
- count_field_types(select_lex, tmp_table_param, list, 0);
- tmp_table_param->force_copy_fields= force_copy_fields;
- DBUG_ASSERT(table == 0);
- /*
- Make create_tmp_table() convert BIT columns to BIGINT.
- This is needed because BIT fields store parts of their data in table's
- null bits, and we don't have methods to compare two table records, which
- is needed by Unique which is used when HEAP table is used.
- */
- {
- List_iterator_fast<Item> li(list);
- Item *item;
- while ((item= li++))
- {
- if (item->type() == Item::FIELD_ITEM &&
- ((Item_field*)item)->field->type() == FIELD_TYPE_BIT)
- item->marker=4;
- }
- }
-
- if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
- 0,
- (select_lex->options | thd->options),
- HA_POS_ERROR, (char*)"")))
- return TRUE;
- table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
- table->no_rows=1;
-
- if (table->s->db_type() == heap_hton)
- {
- /*
- No blobs, otherwise it would have been MyISAM: set up a compare
- function and its arguments to use with Unique.
- */
- qsort_cmp2 compare_key;
- void* cmp_arg;
- Field **field= table->field;
- Field **field_end= field + table->s->fields;
- bool all_binary= TRUE;
-
- for (tree_key_length= 0; field < field_end; ++field)
- {
- Field *f= *field;
- enum enum_field_types f_type= f->type();
- tree_key_length+= f->pack_length();
- if ((f_type == MYSQL_TYPE_VARCHAR) ||
- (!f->binary() && (f_type == MYSQL_TYPE_STRING ||
- f_type == MYSQL_TYPE_VAR_STRING)))
- {
- all_binary= FALSE;
- break;
- }
- }
- if (all_binary)
- {
- cmp_arg= (void*) &tree_key_length;
- compare_key= (qsort_cmp2) simple_raw_key_cmp;
- }
- else
- {
- if (table->s->fields == 1)
- {
- /*
- If we have only one field, which is the most common use of
- count(distinct), it is much faster to use a simpler key
- compare method that can take advantage of not having to worry
- about other fields.
- */
- compare_key= (qsort_cmp2) simple_str_key_cmp;
- cmp_arg= (void*) table->field[0];
- /* tree_key_length has been set already */
- }
- else
- {
- uint32 *length;
- compare_key= (qsort_cmp2) composite_key_cmp;
- cmp_arg= (void*) this;
- field_lengths= (uint32*) thd->alloc(table->s->fields * sizeof(uint32));
- for (tree_key_length= 0, length= field_lengths, field= table->field;
- field < field_end; ++field, ++length)
- {
- *length= (*field)->pack_length();
- tree_key_length+= *length;
- }
- }
- }
- DBUG_ASSERT(tree == 0);
- tree= new Unique(compare_key, cmp_arg, tree_key_length,
- thd->variables.max_heap_table_size);
- /*
- The only time tree_key_length could be 0 is if someone does
- count(distinct) on a char(0) field - stupid thing to do,
- but this has to be handled - otherwise someone can crash
- the server with a DoS attack
- */
- is_evaluated= FALSE;
- if (! tree)
- return TRUE;
- }
- return FALSE;
-}
-
-
-Item *Item_sum_count_distinct::copy_or_same(THD* thd)
-{
- return new (thd->mem_root) Item_sum_count_distinct(thd, this);
-}
-
-
-void Item_sum_count_distinct::clear()
-{
- /* tree and table can be both null only if always_null */
- is_evaluated= FALSE;
- if (tree)
- {
- tree->reset();
- }
- else if (table)
- {
- table->file->extra(HA_EXTRA_NO_CACHE);
- table->file->ha_delete_all_rows();
- table->file->extra(HA_EXTRA_WRITE_CACHE);
- }
-}
-
-bool Item_sum_count_distinct::add()
-{
- int error;
- if (always_null)
- return 0;
- copy_fields(tmp_table_param);
- if (copy_funcs(tmp_table_param->items_to_copy, table->in_use))
- return TRUE;
-
- for (Field **field=table->field ; *field ; field++)
- if ((*field)->is_real_null(0))
- return 0; // Don't count NULL
-
- is_evaluated= FALSE;
- if (tree)
- {
- /*
- The first few bytes of record (at least one) are just markers
- for deleted and NULLs. We want to skip them since they will
- bloat the tree without providing any valuable info. Besides,
- key_length used to initialize the tree didn't include space for them.
- */
- return tree->unique_add(table->record[0] + table->s->null_bytes);
- }
- if ((error= table->file->ha_write_row(table->record[0])) &&
- table->file->is_fatal_error(error, HA_CHECK_DUP))
- return TRUE;
- return FALSE;
-}
-
-
-longlong Item_sum_count_distinct::val_int()
-{
- int error;
- DBUG_ASSERT(fixed == 1);
- if (!table) // Empty query
- return LL(0);
- if (tree)
- {
- if (is_evaluated)
- return count;
-
- if (tree->elements == 0)
- return (longlong) tree->elements_in_tree(); // everything fits in memory
- count= 0;
- tree->walk(count_distinct_walk, (void*) &count);
- is_evaluated= TRUE;
- return (longlong) count;
- }
-
- error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
-
- if(error)
- {
- table->file->print_error(error, MYF(0));
- }
-
- return table->file->stats.records;
-}
-
-
-/****************************************************************************
** Functions to handle dynamic loadable aggregates
** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su>
** Adapted for UDAs by: Andreas F. Bobak <bobak@relog.ch>.
@@ -2792,6 +2807,7 @@ String *Item_sum_udf_str::val_str(String *str)
@retval 1 : key1 > key2
*/
+extern "C"
int group_concat_key_cmp_with_distinct(void* arg, const void* key1,
const void* key2)
{
@@ -2826,6 +2842,7 @@ int group_concat_key_cmp_with_distinct(void* arg, const void* key1,
function of sort for syntax: GROUP_CONCAT(expr,... ORDER BY col,... )
*/
+extern "C"
int group_concat_key_cmp_with_order(void* arg, const void* key1,
const void* key2)
{
@@ -2870,13 +2887,16 @@ int group_concat_key_cmp_with_order(void* arg, const void* key1,
Append data from current leaf to item->result.
*/
-int dump_leaf_key(uchar* key, element_count count __attribute__((unused)),
- Item_func_group_concat *item)
+extern "C"
+int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)),
+ void* item_arg)
{
+ Item_func_group_concat *item= (Item_func_group_concat *) item_arg;
TABLE *table= item->table;
String tmp((char *)table->record[1], table->s->reclength,
default_charset_info);
String tmp2;
+ uchar *key= (uchar *) key_arg;
String *result= &item->result;
Item **arg= item->args, **arg_end= item->args + item->arg_count_field;
uint old_length= result->length();
@@ -2912,6 +2932,8 @@ int dump_leaf_key(uchar* key, element_count count __attribute__((unused)),
result->append(*res);
}
+ item->row_count++;
+
/* stop if length of result more than max_length */
if (result->length() > item->max_length)
{
@@ -2930,8 +2952,11 @@ int dump_leaf_key(uchar* key, element_count count __attribute__((unused)),
result->length(),
&well_formed_error);
result->length(old_length + add_length);
- item->count_cut_values++;
item->warning_for_row= TRUE;
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CUT_VALUE_GROUP_CONCAT, ER(ER_CUT_VALUE_GROUP_CONCAT),
+ item->row_count);
+
return 1;
}
return 0;
@@ -2951,12 +2976,12 @@ Item_func_group_concat::
Item_func_group_concat(Name_resolution_context *context_arg,
bool distinct_arg, List<Item> *select_list,
SQL_I_List<ORDER> *order_list, String *separator_arg)
- :tmp_table_param(0), warning(0),
- separator(separator_arg), tree(0), unique_filter(NULL), table(0),
+ :tmp_table_param(0), separator(separator_arg), tree(0),
+ unique_filter(NULL), table(0),
order(0), context(context_arg),
arg_count_order(order_list ? order_list->elements : 0),
arg_count_field(select_list->elements),
- count_cut_values(0),
+ row_count(0),
distinct(distinct_arg),
warning_for_row(FALSE),
force_copy_fields(0), original(0)
@@ -3010,7 +3035,6 @@ Item_func_group_concat::Item_func_group_concat(THD *thd,
Item_func_group_concat *item)
:Item_sum(thd, item),
tmp_table_param(item->tmp_table_param),
- warning(item->warning),
separator(item->separator),
tree(item->tree),
unique_filter(item->unique_filter),
@@ -3018,7 +3042,7 @@ Item_func_group_concat::Item_func_group_concat(THD *thd,
context(item->context),
arg_count_order(item->arg_count_order),
arg_count_field(item->arg_count_field),
- count_cut_values(item->count_cut_values),
+ row_count(item->row_count),
distinct(item->distinct),
warning_for_row(item->warning_for_row),
always_null(item->always_null),
@@ -3054,15 +3078,6 @@ void Item_func_group_concat::cleanup()
DBUG_ENTER("Item_func_group_concat::cleanup");
Item_sum::cleanup();
- /* Adjust warning message to include total number of cut values */
- if (warning)
- {
- char warn_buff[MYSQL_ERRMSG_SIZE];
- sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
- warning->set_msg(current_thd, warn_buff);
- warning= 0;
- }
-
/*
Free table and tree if they belong to this item (if item have not pointer
to original item from which was made copy => it own its objects )
@@ -3086,15 +3101,8 @@ void Item_func_group_concat::cleanup()
delete unique_filter;
unique_filter= NULL;
}
- if (warning)
- {
- char warn_buff[MYSQL_ERRMSG_SIZE];
- sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
- warning->set_msg(thd, warn_buff);
- warning= 0;
- }
}
- DBUG_ASSERT(tree == 0 && warning == 0);
+ DBUG_ASSERT(tree == 0);
}
DBUG_VOID_RETURN;
}
@@ -3197,11 +3205,9 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
return TRUE;
}
- if (agg_item_charsets(collation, func_name(),
- args,
- /* skip charset aggregation for order columns */
- arg_count - arg_count_order,
- MY_COLL_ALLOW_CONV, 1))
+ /* skip charset aggregation for order columns */
+ if (agg_item_charsets_for_string_result(collation, func_name(),
+ args, arg_count - arg_count_order))
return 1;
result.set_charset(collation.collation);
@@ -3326,7 +3332,7 @@ bool Item_func_group_concat::setup(THD *thd)
*/
if (!(table= create_tmp_table(thd, tmp_table_param, all_fields,
(ORDER*) 0, 0, TRUE,
- (select_lex->options | thd->options),
+ (select_lex->options | thd->variables.option_bits),
HA_POS_ERROR, (char*) "")))
DBUG_RETURN(TRUE);
table->file->extra(HA_EXTRA_NO_ROWS);
@@ -3357,7 +3363,7 @@ bool Item_func_group_concat::setup(THD *thd)
unique_filter= new Unique(group_concat_key_cmp_with_distinct,
(void*)this,
tree_key_length,
- thd->variables.max_heap_table_size);
+ ram_limitation(thd));
DBUG_RETURN(FALSE);
}
@@ -3382,19 +3388,7 @@ String* Item_func_group_concat::val_str(String* str)
return 0;
if (no_appended && tree)
/* Tree is used for sorting as in ORDER BY */
- tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
- left_root_right);
- if (count_cut_values && !warning)
- {
- /*
- ER_CUT_VALUE_GROUP_CONCAT needs an argument, but this gets set in
- Item_func_group_concat::cleanup().
- */
- DBUG_ASSERT(table);
- warning= push_warning(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_CUT_VALUE_GROUP_CONCAT,
- ER(ER_CUT_VALUE_GROUP_CONCAT));
- }
+ tree_walk(tree, &dump_leaf_key, this, left_root_right);
return &result;
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 26290a812f4..06a8c2c58a4 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -1,3 +1,6 @@
+#ifndef ITEM_SUM_INCLUDED
+#define ITEM_SUM_INCLUDED
+
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
@@ -21,8 +24,89 @@
#endif
#include <my_tree.h>
+#include "sql_udf.h" /* udf_handler */
+
+class Item_sum;
+class Aggregator_distinct;
+class Aggregator_simple;
+
+/**
+ The abstract base class for the Aggregator_* classes.
+ It implements the data collection functions (setup/add/clear)
+ as either pass-through to the real functionality or
+ as collectors into an Unique (for distinct) structure.
+
+ Note that update_field/reset_field are not in that
+ class, because they're simply not called when
+ GROUP BY/DISTINCT can be handled with help of index on grouped
+ fields (quick_group = 0);
+*/
-/*
+class Aggregator : public Sql_alloc
+{
+ friend class Item_sum;
+ friend class Item_sum_sum;
+ friend class Item_sum_count;
+ friend class Item_sum_avg;
+
+ /*
+ All members are protected as this class is not usable outside of an
+ Item_sum descendant.
+ */
+protected:
+ /* the aggregate function class to act on */
+ Item_sum *item_sum;
+
+ /**
+ When feeding back the data in endup() from Unique/temp table back to
+ Item_sum::add() methods we must read the data from Unique (and not
+ recalculate the functions that are given as arguments to the aggregate
+ function.
+ This flag is to tell the add() methods to take the data from the Unique
+ instead by calling the relevant val_..() method
+ */
+
+ bool use_distinct_values;
+
+public:
+ Aggregator (Item_sum *arg): item_sum(arg), use_distinct_values(FALSE) {}
+ virtual ~Aggregator () {} /* Keep gcc happy */
+
+ enum Aggregator_type { SIMPLE_AGGREGATOR, DISTINCT_AGGREGATOR };
+ virtual Aggregator_type Aggrtype() = 0;
+
+ /**
+ Called before adding the first row.
+ Allocates and sets up the internal aggregation structures used,
+ e.g. the Unique instance used to calculate distinct.
+ */
+ virtual bool setup(THD *) = 0;
+
+ /**
+ Called when we need to wipe out all the data from the aggregator :
+ all the values acumulated and all the state.
+ Cleans up the internal structures and resets them to their initial state.
+ */
+ virtual void clear() = 0;
+
+ /**
+ Called when there's a new value to be aggregated.
+ Updates the internal state of the aggregator to reflect the new value.
+ */
+ virtual bool add() = 0;
+
+ /**
+ Called when there are no more data and the final value is to be retrieved.
+ Finalises the state of the aggregator, so the final result can be retrieved.
+ */
+ virtual void endup() = 0;
+
+};
+
+
+class st_select_lex;
+
+/**
Class Item_sum is the base class used for special expressions that SQL calls
'set functions'. These expressions are formed with the help of aggregate
functions such as SUM, MAX, GROUP_CONCAT etc.
@@ -215,13 +299,40 @@
TODO: to catch queries where the limit is exceeded to make the
code clean here.
-*/
-
-class st_select_lex;
+*/
class Item_sum :public Item_result_field
{
+ friend class Aggregator_distinct;
+
+protected:
+ /**
+ Aggregator class instance. Not set initially. Allocated only after
+ it is determined if the incoming data are already distinct.
+ */
+ Aggregator *aggr;
+
+private:
+ /**
+ Used in making ROLLUP. Set for the ROLLUP copies of the original
+ Item_sum and passed to create_tmp_field() to cause it to work
+ over the temp table buffer that is referenced by
+ Item_result_field::result_field.
+ */
+ bool force_copy_fields;
+
+ /**
+ Indicates how the aggregate function was specified by the parser :
+ 1 if it was written as AGGREGATE(DISTINCT),
+ 0 if it was AGGREGATE()
+ */
+ bool with_distinct;
+
public:
+
+ bool has_force_copy_fields() const { return force_copy_fields; }
+ bool has_with_distinct() const { return with_distinct; }
+
enum Sumfunctype
{ COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,
AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_FUNC,
@@ -256,6 +367,7 @@ protected:
Item **orig_args, *tmp_orig_args[2];
table_map used_tables_cache;
bool forced_const;
+ static ulonglong ram_limitation(THD *thd);
public:
@@ -263,47 +375,28 @@ public:
Item_sum() :quick_group(1), arg_count(0), forced_const(FALSE)
{
mark_as_sum_func();
+ init_aggregator();
}
Item_sum(Item *a) :quick_group(1), arg_count(1), args(tmp_args),
orig_args(tmp_orig_args), forced_const(FALSE)
{
args[0]=a;
mark_as_sum_func();
+ init_aggregator();
}
Item_sum( Item *a, Item *b ) :quick_group(1), arg_count(2), args(tmp_args),
orig_args(tmp_orig_args), forced_const(FALSE)
{
args[0]=a; args[1]=b;
mark_as_sum_func();
+ init_aggregator();
}
Item_sum(List<Item> &list);
//Copy constructor, need to perform subselects with temporary tables
Item_sum(THD *thd, Item_sum *item);
enum Type type() const { return SUM_FUNC_ITEM; }
virtual enum Sumfunctype sum_func () const=0;
-
- /*
- This method is similar to add(), but it is called when the current
- aggregation group changes. Thus it performs a combination of
- clear() and add().
- */
- inline bool reset() { clear(); return add(); };
-
- /*
- Prepare this item for evaluation of an aggregate value. This is
- called by reset() when a group changes, or, for correlated
- subqueries, between subquery executions. E.g. for COUNT(), this
- method should set count= 0;
- */
- virtual void clear()= 0;
-
- /*
- This method is called for the next row in the same group. Its
- purpose is to aggregate the new value to the previous values in
- the group (i.e. since clear() was called last time). For example,
- for COUNT(), do count++.
- */
- virtual bool add()=0;
+ inline bool reset() { aggregator_clear(); return aggregator_add(); };
/*
Called when new group is started and results are being saved in
@@ -327,11 +420,6 @@ public:
{ return new Item_field(field); }
table_map used_tables() const { return used_tables_cache; }
void update_used_tables ();
- void cleanup()
- {
- Item::cleanup();
- forced_const= FALSE;
- }
bool is_null() { return null_value; }
void make_const ()
{
@@ -342,7 +430,9 @@ public:
virtual void print(String *str, enum_query_type query_type);
void fix_num_length_and_dec();
- /*
+ /**
+ Mark an aggregate as having no rows.
+
This function is called by the execution engine to assign 'NO ROWS
FOUND' value to an aggregate item, when the underlying result set
has no rows. Such value, in a general case, may be different from
@@ -350,10 +440,15 @@ public:
may be initialized to 0 by clear() and to NULL by
no_rows_in_result().
*/
- void no_rows_in_result() { clear(); }
-
- virtual bool setup(THD* thd) {return 0;}
- virtual void make_unique() {}
+ virtual void no_rows_in_result()
+ {
+ if (!aggr)
+ set_aggregator(with_distinct ?
+ Aggregator::DISTINCT_AGGREGATOR :
+ Aggregator::SIMPLE_AGGREGATOR);
+ reset();
+ }
+ virtual void make_unique() { force_copy_fields= TRUE; }
Item *get_tmp_table_item(THD *thd);
virtual Field *create_tmp_field(bool group, TABLE *table,
uint convert_blob_length);
@@ -364,9 +459,170 @@ public:
st_select_lex *depended_from()
{ return (nest_level == aggr_level ? 0 : aggr_sel); }
- Item *get_arg(int i) { return args[i]; }
- Item *set_arg(int i, THD *thd, Item *new_val);
+ Item *get_arg(uint i) { return args[i]; }
+ Item *set_arg(uint i, THD *thd, Item *new_val);
uint get_arg_count() { return arg_count; }
+
+ /* Initialization of distinct related members */
+ void init_aggregator()
+ {
+ aggr= NULL;
+ with_distinct= FALSE;
+ force_copy_fields= FALSE;
+ }
+
+ /**
+ Called to initialize the aggregator.
+ */
+
+ inline bool aggregator_setup(THD *thd) { return aggr->setup(thd); };
+
+ /**
+ Called to cleanup the aggregator.
+ */
+
+ inline void aggregator_clear() { aggr->clear(); }
+
+ /**
+ Called to add value to the aggregator.
+ */
+
+ inline bool aggregator_add() { return aggr->add(); };
+
+ /* stores the declared DISTINCT flag (from the parser) */
+ void set_distinct(bool distinct)
+ {
+ with_distinct= distinct;
+ quick_group= with_distinct ? 0 : 1;
+ }
+
+ /**
+ Set the type of aggregation : DISTINCT or not.
+
+ Called when the final determination is done about the aggregation
+ type and the object is about to be used.
+ */
+
+ int set_aggregator(Aggregator::Aggregator_type aggregator);
+
+ virtual void clear()= 0;
+ virtual bool add()= 0;
+ virtual bool setup(THD *thd) { return false; }
+
+ virtual void cleanup();
+};
+
+
+class Unique;
+
+
+/**
+ The distinct aggregator.
+ Implements AGGFN (DISTINCT ..)
+ Collects all the data into an Unique (similarly to what Item_sum_distinct
+ does currently) and then (if applicable) iterates over the list of
+ unique values and pumps them back into its object
+*/
+
+class Aggregator_distinct : public Aggregator
+{
+ friend class Item_sum_sum;
+
+ /*
+ flag to prevent consecutive runs of endup(). Normally in endup there are
+ expensive calculations (like walking the distinct tree for example)
+ which we must do only once if there are no data changes.
+ We can re-use the data for the second and subsequent val_xxx() calls.
+ endup_done set to TRUE also means that the calculated values for
+ the aggregate functions are correct and don't need recalculation.
+ */
+ bool endup_done;
+
+ /*
+ Used depending on the type of the aggregate function and the presence of
+ blob columns in it:
+ - For COUNT(DISTINCT) and no blob fields this points to a real temporary
+ table. It's used as a hash table.
+ - For AVG/SUM(DISTINCT) or COUNT(DISTINCT) with blob fields only the
+ in-memory data structure of a temporary table is constructed.
+ It's used by the Field classes to transform data into row format.
+ */
+ TABLE *table;
+
+ /*
+ An array of field lengths on row allocated and used only for
+ COUNT(DISTINCT) with multiple columns and no blobs. Used in
+ Aggregator_distinct::composite_key_cmp (called from Unique to compare
+ nodes
+ */
+ uint32 *field_lengths;
+
+ /*
+ Used in conjunction with 'table' to support the access to Field classes
+ for COUNT(DISTINCT). Needed by copy_fields()/copy_funcs().
+ */
+ TMP_TABLE_PARAM *tmp_table_param;
+
+ /*
+ If there are no blobs in the COUNT(DISTINCT) arguments, we can use a tree,
+ which is faster than heap table. In that case, we still use the table
+ to help get things set up, but we insert nothing in it.
+ For AVG/SUM(DISTINCT) we always use this tree (as it takes a single
+ argument) to get the distinct rows.
+ */
+ Unique *tree;
+
+ /*
+ The length of the temp table row. Must be a member of the class as it
+ gets passed down to simple_raw_key_cmp () as a compare function argument
+ to Unique. simple_raw_key_cmp () is used as a fast comparison function
+ when the entire row can be binary compared.
+ */
+ uint tree_key_length;
+
+ /*
+ Set to true if the result is known to be always NULL.
+ If set deactivates creation and usage of the temporary table (in the
+ 'table' member) and the Unique instance (in the 'tree' member) as well as
+ the calculation of the final value on the first call to
+ Item_[sum|avg|count]::val_xxx().
+ */
+ bool always_null;
+
+public:
+ Aggregator_distinct (Item_sum *sum) :
+ Aggregator(sum), table(NULL), tmp_table_param(NULL), tree(NULL),
+ always_null(FALSE) {}
+ virtual ~Aggregator_distinct ();
+ Aggregator_type Aggrtype() { return DISTINCT_AGGREGATOR; }
+
+ bool setup(THD *);
+ void clear();
+ bool add();
+ void endup();
+
+ bool unique_walk_function(void *element);
+ static int composite_key_cmp(void* arg, uchar* key1, uchar* key2);
+};
+
+
+/**
+ The pass-through aggregator.
+ Implements AGGFN (DISTINCT ..) by knowing it gets distinct data on input.
+ So it just pumps them back to the Item_sum descendant class.
+*/
+class Aggregator_simple : public Aggregator
+{
+public:
+
+ Aggregator_simple (Item_sum *sum) :
+ Aggregator(sum) {}
+ Aggregator_type Aggrtype() { return Aggregator::SIMPLE_AGGREGATOR; }
+
+ bool setup(THD * thd) { return item_sum->setup(thd); }
+ void clear() { item_sum->clear(); }
+ bool add() { return item_sum->add(); }
+ void endup() {};
};
@@ -426,9 +682,15 @@ protected:
void fix_length_and_dec();
public:
- Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {}
+ Item_sum_sum(Item *item_par, bool distinct) :Item_sum_num(item_par)
+ {
+ set_distinct(distinct);
+ }
Item_sum_sum(THD *thd, Item_sum_sum *item);
- enum Sumfunctype sum_func () const {return SUM_FUNC;}
+ enum Sumfunctype sum_func () const
+ {
+ return has_with_distinct() ? SUM_DISTINCT_FUNC : SUM_FUNC;
+ }
void clear();
bool add();
double val_real();
@@ -439,109 +701,50 @@ public:
void reset_field();
void update_field();
void no_rows_in_result() {}
- const char *func_name() const { return "sum("; }
+ const char *func_name() const
+ {
+ return has_with_distinct() ? "sum(distinct " : "sum(";
+ }
Item *copy_or_same(THD* thd);
};
-
-/* Common class for SUM(DISTINCT), AVG(DISTINCT) */
-
-class Unique;
-
-class Item_sum_distinct :public Item_sum_num
+class Item_sum_count :public Item_sum_int
{
-protected:
- /* storage for the summation result */
- ulonglong count;
- Hybrid_type val;
- /* storage for unique elements */
- Unique *tree;
- TABLE *table;
- enum enum_field_types table_field_type;
- uint tree_key_length;
-protected:
- Item_sum_distinct(THD *thd, Item_sum_distinct *item);
-public:
- Item_sum_distinct(Item *item_par);
- ~Item_sum_distinct();
+ longlong count;
+
+ friend class Aggregator_distinct;
- bool setup(THD *thd);
void clear();
- void cleanup();
bool add();
- double val_real();
- my_decimal *val_decimal(my_decimal *);
- longlong val_int();
- String *val_str(String *str);
-
- /* XXX: does it need make_unique? */
-
- enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
- void reset_field() {} // not used
- void update_field() {} // not used
- virtual void no_rows_in_result() {}
- void fix_length_and_dec();
- enum Item_result result_type () const { return val.traits->type(); }
- virtual void calculate_val_and_count();
- virtual bool unique_walk_function(void *elem);
-};
-
-
-/*
- Item_sum_sum_distinct - implementation of SUM(DISTINCT expr).
- See also: MySQL manual, chapter 'Adding New Functions To MySQL'
- and comments in item_sum.cc.
-*/
-
-class Item_sum_sum_distinct :public Item_sum_distinct
-{
-private:
- Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item)
- :Item_sum_distinct(thd, item) {}
-public:
- Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {}
-
- enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
- const char *func_name() const { return "sum(distinct "; }
- Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); }
-};
-
-
-/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */
-
-class Item_sum_avg_distinct: public Item_sum_distinct
-{
-private:
- Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original)
- :Item_sum_distinct(thd, original) {}
-public:
- uint prec_increment;
- Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {}
-
- void fix_length_and_dec();
- virtual void calculate_val_and_count();
- enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; }
- const char *func_name() const { return "avg(distinct "; }
- Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); }
-};
-
-
-class Item_sum_count :public Item_sum_int
-{
- longlong count;
+ void cleanup();
public:
Item_sum_count(Item *item_par)
:Item_sum_int(item_par),count(0)
{}
+
+ /**
+ Constructs an instance for COUNT(DISTINCT)
+
+ @param list a list of the arguments to the aggregate function
+
+ This constructor is called by the parser only for COUNT (DISTINCT).
+ */
+
+ Item_sum_count(List<Item> &list)
+ :Item_sum_int(list),count(0)
+ {
+ set_distinct(TRUE);
+ }
Item_sum_count(THD *thd, Item_sum_count *item)
:Item_sum_int(thd, item), count(item->count)
{}
- enum Sumfunctype sum_func () const { return COUNT_FUNC; }
- void clear();
+ enum Sumfunctype sum_func () const
+ {
+ return has_with_distinct() ? COUNT_DISTINCT_FUNC : COUNT_FUNC;
+ }
void no_rows_in_result() { count=0; }
- bool add();
void make_const(longlong count_arg)
{
count=count_arg;
@@ -549,76 +752,12 @@ class Item_sum_count :public Item_sum_int
}
longlong val_int();
void reset_field();
- void cleanup();
void update_field();
- const char *func_name() const { return "count("; }
- Item *copy_or_same(THD* thd);
-};
-
-
-class TMP_TABLE_PARAM;
-
-class Item_sum_count_distinct :public Item_sum_int
-{
- TABLE *table;
- uint32 *field_lengths;
- TMP_TABLE_PARAM *tmp_table_param;
- bool force_copy_fields;
- /*
- If there are no blobs, we can use a tree, which
- is faster than heap table. In that case, we still use the table
- to help get things set up, but we insert nothing in it
- */
- Unique *tree;
- /*
- Storage for the value of count between calls to val_int() so val_int()
- will not recalculate on each call. Validitiy of the value is stored in
- is_evaluated.
- */
- longlong count;
- /*
- Following is 0 normal object and pointer to original one for copy
- (to correctly free resources)
- */
- Item_sum_count_distinct *original;
- uint tree_key_length;
-
-
- bool always_null; // Set to 1 if the result is always NULL
-
-
- friend int composite_key_cmp(void* arg, uchar* key1, uchar* key2);
- friend int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2);
-
-public:
- Item_sum_count_distinct(List<Item> &list)
- :Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0),
- force_copy_fields(0), tree(0), count(0),
- original(0), always_null(FALSE)
- { quick_group= 0; }
- Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item)
- :Item_sum_int(thd, item), table(item->table),
- field_lengths(item->field_lengths),
- tmp_table_param(item->tmp_table_param),
- force_copy_fields(0), tree(item->tree), count(item->count),
- original(item), tree_key_length(item->tree_key_length),
- always_null(item->always_null)
- {}
- ~Item_sum_count_distinct();
-
- void cleanup();
-
- enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; }
- void clear();
- bool add();
- longlong val_int();
- void reset_field() { return ;} // Never called
- void update_field() { return ; } // Never called
- const char *func_name() const { return "count(distinct "; }
- bool setup(THD *thd);
- void make_unique();
+ const char *func_name() const
+ {
+ return has_with_distinct() ? "count(distinct " : "count(";
+ }
Item *copy_or_same(THD* thd);
- void no_rows_in_result() {}
};
@@ -658,13 +797,18 @@ public:
uint prec_increment;
uint f_precision, f_scale, dec_bin_size;
- Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {}
+ Item_sum_avg(Item *item_par, bool distinct)
+ :Item_sum_sum(item_par, distinct), count(0)
+ {}
Item_sum_avg(THD *thd, Item_sum_avg *item)
:Item_sum_sum(thd, item), count(item->count),
prec_increment(item->prec_increment) {}
void fix_length_and_dec();
- enum Sumfunctype sum_func () const {return AVG_FUNC;}
+ enum Sumfunctype sum_func () const
+ {
+ return has_with_distinct() ? AVG_DISTINCT_FUNC : AVG_FUNC;
+ }
void clear();
bool add();
double val_real();
@@ -677,7 +821,10 @@ public:
Item *result_item(Field *field)
{ return new Item_avg_field(hybrid_type, this); }
void no_rows_in_result() {}
- const char *func_name() const { return "avg("; }
+ const char *func_name() const
+ {
+ return has_with_distinct() ? "avg(distinct " : "avg(";
+ }
Item *copy_or_same(THD* thd);
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
void cleanup()
@@ -862,6 +1009,11 @@ protected:
void no_rows_in_result();
Field *create_tmp_field(bool group, TABLE *table,
uint convert_blob_length);
+ /*
+ MIN/MAX uses Item_cache_datetime for storing DATETIME values, thus
+ in this case a correct INT value can be provided.
+ */
+ bool result_as_longlong() { return args[0]->result_as_longlong(); }
};
@@ -1171,12 +1323,19 @@ public:
#endif /* HAVE_DLOPEN */
-class MYSQL_ERROR;
+C_MODE_START
+int group_concat_key_cmp_with_distinct(void* arg, const void* key1,
+ const void* key2);
+int group_concat_key_cmp_with_order(void* arg, const void* key1,
+ const void* key2);
+int dump_leaf_key(void* key_arg,
+ element_count count __attribute__((unused)),
+ void* item_arg);
+C_MODE_END
class Item_func_group_concat : public Item_sum
{
TMP_TABLE_PARAM *tmp_table_param;
- MYSQL_ERROR *warning;
String result;
String *separator;
TREE tree_base;
@@ -1197,7 +1356,7 @@ class Item_func_group_concat : public Item_sum
uint arg_count_order;
/** The number of selected items, aka the expr list. */
uint arg_count_field;
- uint count_cut_values;
+ uint row_count;
bool distinct;
bool warning_for_row;
bool always_null;
@@ -1213,9 +1372,9 @@ class Item_func_group_concat : public Item_sum
const void* key2);
friend int group_concat_key_cmp_with_order(void* arg, const void* key1,
const void* key2);
- friend int dump_leaf_key(uchar* key,
+ friend int dump_leaf_key(void* key_arg,
element_count count __attribute__((unused)),
- Item_func_group_concat *group_concat_item);
+ void* item_arg);
public:
Item_func_group_concat(Name_resolution_context *context_arg,
@@ -1269,3 +1428,5 @@ public:
virtual bool change_context_processor(uchar *cntx)
{ context= (Name_resolution_context *)cntx; return FALSE; }
};
+
+#endif /* ITEM_SUM_INCLUDED */
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 103bd96efd4..3771706fb63 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -28,7 +28,28 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" // set_var.h: THD
+#include "set_var.h"
+#include "sql_locale.h" // MY_LOCALE my_locale_en_US
+#include "strfunc.h" // check_word
+#include "sql_time.h" // make_truncated_value_warning,
+ // make_time, get_date_from_daynr,
+ // calc_weekday, calc_week,
+ // convert_month_to_period,
+ // convert_period_to_month,
+ // TIME_to_timestamp, make_date,
+ // calc_time_diff,
+ // calc_time_from_sec,
+ // known_date_time_format,
+ // get_date_time_format_str
+#include "tztime.h" // struct Time_zone
+#include "sql_class.h" // THD
#include <m_ctype.h>
#include <time.h>
@@ -57,7 +78,7 @@ static bool make_datetime(date_time_format_types format, MYSQL_TIME *ltime,
String *str)
{
char *buff;
- CHARSET_INFO *cs= &my_charset_bin;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length= MAX_DATE_STRING_REP_LENGTH;
if (str->alloc(length))
@@ -597,7 +618,7 @@ err:
{
char buff[128];
strmake(buff, val_begin, min(length, sizeof(buff)-1));
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE),
date_time_type, buff, "str_to_date");
}
@@ -859,6 +880,8 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
{
const char *end=str+length;
uint i;
+ long msec_length= 0;
+
while (str != end && !my_isdigit(cs,*str))
str++;
@@ -868,12 +891,7 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
const char *start= str;
for (value=0; str != end && my_isdigit(cs,*str) ; str++)
value= value*LL(10) + (longlong) (*str - '0');
- if (transform_msec && i == count - 1) // microseconds always last
- {
- int msec_length= 6 - (int) (str - start);
- if (msec_length > 0)
- value*= (long)log_10_int[msec_length];
- }
+ msec_length= 6 - (str - start);
values[i]= value;
while (str != end && !my_isdigit(cs,*str))
str++;
@@ -887,6 +905,10 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
break;
}
}
+
+ if (transform_msec && msec_length > 0)
+ values[count - 1] *= (long) log_10_int[msec_length];
+
return (str != end);
}
@@ -930,6 +952,48 @@ longlong Item_func_to_days::val_int()
}
+longlong Item_func_to_seconds::val_int_endpoint(bool left_endp,
+ bool *incl_endp)
+{
+ DBUG_ASSERT(fixed == 1);
+ MYSQL_TIME ltime;
+ longlong seconds;
+ longlong days;
+ int dummy; /* unused */
+ if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
+ {
+ /* got NULL, leave the incl_endp intact */
+ return LONGLONG_MIN;
+ }
+ seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second;
+ seconds= ltime.neg ? -seconds : seconds;
+ days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day);
+ seconds+= days * 24L * 3600L;
+ /* Set to NULL if invalid date, but keep the value */
+ null_value= check_date(&ltime,
+ (ltime.year || ltime.month || ltime.day),
+ (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE),
+ &dummy);
+ /*
+ Even if the evaluation return NULL, seconds is useful for pruning
+ */
+ return seconds;
+}
+
+longlong Item_func_to_seconds::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ MYSQL_TIME ltime;
+ longlong seconds;
+ longlong days;
+ if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
+ return 0;
+ seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second;
+ seconds=ltime.neg ? -seconds : seconds;
+ days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day);
+ return seconds + days * 24L * 3600L;
+}
+
/*
Get information about this Item tree monotonicity
@@ -956,6 +1020,17 @@ enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const
return NON_MONOTONIC;
}
+enum_monotonicity_info Item_func_to_seconds::get_monotonicity_info() const
+{
+ if (args[0]->type() == Item::FIELD_ITEM)
+ {
+ if (args[0]->field_type() == MYSQL_TYPE_DATE ||
+ args[0]->field_type() == MYSQL_TYPE_DATETIME)
+ return MONOTONIC_STRICT_INCREASING_NOT_NULL;
+ }
+ return NON_MONOTONIC;
+}
+
longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
{
@@ -1526,9 +1601,7 @@ bool Item_func_from_days::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
void Item_func_curdate::fix_length_and_dec()
{
- collation.set(&my_charset_bin);
- decimals=0;
- max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ Item_date::fix_length_and_dec();
store_now_in_TIME(&ltime);
@@ -1589,7 +1662,7 @@ bool Item_func_curdate::get_date(MYSQL_TIME *res,
String *Item_func_curtime::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- str_value.set(buff, buff_length, &my_charset_bin);
+ str_value.set(buff, buff_length, &my_charset_latin1);
return &str_value;
}
@@ -1599,11 +1672,10 @@ void Item_func_curtime::fix_length_and_dec()
MYSQL_TIME ltime;
decimals= DATETIME_DEC;
- collation.set(&my_charset_bin);
store_now_in_TIME(&ltime);
value= TIME_to_ulonglong_time(&ltime);
buff_length= (uint) my_time_to_str(&ltime, buff);
- max_length= buff_length;
+ fix_length_and_charset_datetime(buff_length);
}
@@ -1638,7 +1710,7 @@ void Item_func_curtime_utc::store_now_in_TIME(MYSQL_TIME *now_time)
String *Item_func_now::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- str_value.set(buff,buff_length, &my_charset_bin);
+ str_value.set(buff, buff_length, &my_charset_numeric);
return &str_value;
}
@@ -1646,13 +1718,12 @@ String *Item_func_now::val_str(String *str)
void Item_func_now::fix_length_and_dec()
{
decimals= DATETIME_DEC;
- collation.set(&my_charset_bin);
store_now_in_TIME(&ltime);
value= (longlong) TIME_to_ulonglong_datetime(&ltime);
buff_length= (uint) my_datetime_to_str(&ltime, buff);
- max_length= buff_length;
+ fix_length_and_charset_datetime(buff_length);
}
@@ -1716,7 +1787,7 @@ String *Item_func_sysdate_local::val_str(String *str)
DBUG_ASSERT(fixed == 1);
store_now_in_TIME(&ltime);
buff_length= (uint) my_datetime_to_str(&ltime, buff);
- str_value.set(buff, buff_length, &my_charset_bin);
+ str_value.set(buff, buff_length, &my_charset_numeric);
return &str_value;
}
@@ -1740,8 +1811,7 @@ double Item_func_sysdate_local::val_real()
void Item_func_sysdate_local::fix_length_and_dec()
{
decimals= 0;
- collation.set(&my_charset_bin);
- max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ fix_length_and_charset_datetime(MAX_DATETIME_WIDTH);
}
@@ -1795,7 +1865,7 @@ longlong Item_func_sec_to_time::val_int()
sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
return (ltime.neg ? -1 : 1) *
- ((ltime.hour)*10000 + ltime.minute*100 + ltime.second);
+ (longlong) ((ltime.hour)*10000 + ltime.minute*100 + ltime.second);
}
@@ -1945,7 +2015,8 @@ String *Item_func_date_format::val_str(String *str)
{
String *res;
if (!(res=args[0]->val_str(str)) ||
- (str_to_time_with_warn(res->ptr(), res->length(), &l_time)))
+ (str_to_time_with_warn(res->charset(), res->ptr(), res->length(),
+ &l_time)))
goto null_date;
l_time.year=l_time.month=l_time.day=0;
@@ -1989,9 +2060,8 @@ null_date:
void Item_func_from_unixtime::fix_length_and_dec()
{
thd= current_thd;
- collation.set(&my_charset_bin);
decimals= DATETIME_DEC;
- max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ fix_length_and_charset_datetime(MAX_DATETIME_WIDTH);
maybe_null= 1;
thd->time_zone_used= 1;
}
@@ -2049,9 +2119,8 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
void Item_func_convert_tz::fix_length_and_dec()
{
- collation.set(&my_charset_bin);
decimals= 0;
- max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ fix_length_and_charset_datetime(MAX_DATETIME_WIDTH);
maybe_null= 1;
}
@@ -2095,13 +2164,13 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
if (!from_tz_cached)
{
- from_tz= my_tz_find(thd, args[1]->val_str(&str));
+ from_tz= my_tz_find(thd, args[1]->val_str_ascii(&str));
from_tz_cached= args[1]->const_item();
}
if (!to_tz_cached)
{
- to_tz= my_tz_find(thd, args[2]->val_str(&str));
+ to_tz= my_tz_find(thd, args[2]->val_str_ascii(&str));
to_tz_cached= args[2]->const_item();
}
@@ -2135,9 +2204,8 @@ void Item_date_add_interval::fix_length_and_dec()
{
enum_field_types arg0_field_type;
- collation.set(&my_charset_bin);
maybe_null=1;
- max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ fix_length_and_charset_datetime(MAX_DATETIME_FULL_WIDTH);
value.alloc(max_length);
/*
@@ -2315,7 +2383,9 @@ longlong Item_extract::val_int()
char buf[40];
String value(buf, sizeof(buf), &my_charset_bin);;
String *res= args[0]->val_str(&value);
- if (!res || str_to_time_with_warn(res->ptr(), res->length(), &ltime))
+ if (!res ||
+ str_to_time_with_warn(res->charset(), res->ptr(), res->length(),
+ &ltime))
{
null_value=1;
return 0;
@@ -2487,10 +2557,11 @@ String *Item_char_typecast::val_str(String *str)
str_value= *res; // Not malloced string
res= &str_value;
}
+ ErrConvString err(res);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE), char_type,
- res->c_ptr_safe());
+ err.ptr());
res->length((uint) length);
}
else if (cast_cs == &my_charset_bin && res->length() < (uint) cast_length)
@@ -2606,7 +2677,8 @@ longlong Item_time_typecast::val_int()
null_value= 1;
return 0;
}
- return ltime.hour * 10000L + ltime.minute * 100 + ltime.second;
+ return (ltime.neg ? -1 : 1) *
+ (longlong) ((ltime.hour)*10000 + ltime.minute*100 + ltime.second);
}
String *Item_time_typecast::val_str(String *str)
@@ -2752,7 +2824,7 @@ void Item_func_add_time::fix_length_and_dec()
{
enum_field_types arg0_field_type;
decimals=0;
- max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ fix_length_and_charset_datetime(MAX_DATETIME_FULL_WIDTH);
maybe_null= 1;
/*
@@ -2785,10 +2857,11 @@ void Item_func_add_time::fix_length_and_dec()
Result: Time value or datetime value
*/
-String *Item_func_add_time::val_str(String *str)
+MYSQL_TIME *Item_func_add_time::val_datetime(MYSQL_TIME *time,
+ date_time_format_types *format)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME l_time1, l_time2, l_time3;
+ MYSQL_TIME l_time1, l_time2;
bool is_time= 0;
long days, microseconds;
longlong seconds;
@@ -2814,41 +2887,38 @@ String *Item_func_add_time::val_str(String *str)
if (l_time1.neg != l_time2.neg)
l_sign= -l_sign;
- bzero((char *)&l_time3, sizeof(l_time3));
+ bzero((char *)time, sizeof(MYSQL_TIME));
- l_time3.neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
- &seconds, &microseconds);
+ time->neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
+ &seconds, &microseconds);
/*
If first argument was negative and diff between arguments
is non-zero we need to swap sign to get proper result.
*/
if (l_time1.neg && (seconds || microseconds))
- l_time3.neg= 1-l_time3.neg; // Swap sign of result
+ time->neg= 1 - time->neg; // Swap sign of result
- if (!is_time && l_time3.neg)
+ if (!is_time && time->neg)
goto null_date;
days= (long)(seconds/86400L);
- calc_time_from_sec(&l_time3, (long)(seconds%86400L), microseconds);
+ calc_time_from_sec(time, (long)(seconds%86400L), microseconds);
if (!is_time)
{
- get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day);
- if (l_time3.day &&
- !make_datetime(l_time1.second_part || l_time2.second_part ?
- DATE_TIME_MICROSECOND : DATE_TIME,
- &l_time3, str))
- return str;
+ get_date_from_daynr(days, &time->year, &time->month, &time->day);
+ *format= l_time1.second_part || l_time2.second_part ?
+ DATE_TIME_MICROSECOND : DATE_TIME;
+ if (time->day)
+ return time;
goto null_date;
}
-
- l_time3.hour+= days*24;
- if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ?
- TIME_MICROSECOND : TIME_ONLY,
- &l_time3, str))
- return str;
+ *format= l_time1.second_part || l_time2.second_part ?
+ TIME_MICROSECOND : TIME_ONLY;
+ time->hour+= days*24;
+ return time;
null_date:
null_value=1;
@@ -2856,6 +2926,38 @@ null_date:
}
+String *Item_func_add_time::val_str(String *str)
+{
+ MYSQL_TIME ltime;
+ date_time_format_types format;
+
+ val_datetime(&ltime, &format);
+
+ if (null_value)
+ return 0;
+
+ if (!make_datetime_with_warn(format, &ltime, str))
+ return str;
+
+ null_value= 1;
+ return 0;
+}
+
+
+longlong Item_func_add_time::val_int()
+{
+ MYSQL_TIME ltime;
+ date_time_format_types format;
+
+ val_datetime(&ltime, &format);
+
+ if (null_value)
+ return 0;
+
+ return TIME_to_ulonglong_datetime(&ltime);
+}
+
+
void Item_func_add_time::print(String *str, enum_query_type query_type)
{
if (is_date)
@@ -3163,12 +3265,12 @@ void Item_func_timestamp_diff::print(String *str, enum_query_type query_type)
}
-String *Item_func_get_format::val_str(String *str)
+String *Item_func_get_format::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
const char *format_name;
KNOWN_DATE_TIME_FORMAT *format;
- String *val= args[0]->val_str(str);
+ String *val= args[0]->val_str_ascii(str);
ulong val_len;
if ((null_value= args[0]->null_value))
@@ -3187,7 +3289,7 @@ String *Item_func_get_format::val_str(String *str)
(const uchar *) format_name, val_len))
{
const char *format_str= get_date_time_format_str(format, type);
- str->set(format_str, (uint) strlen(format_str), &my_charset_bin);
+ str->set(format_str, (uint) strlen(format_str), &my_charset_numeric);
return str;
}
}
@@ -3296,6 +3398,8 @@ void Item_func_str_to_date::fix_length_and_dec()
cached_field_type= MYSQL_TYPE_DATETIME;
max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
cached_timestamp_type= MYSQL_TIMESTAMP_NONE;
+ sql_mode= (current_thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE));
if ((const_item= args[1]->const_item()))
{
char format_buff[64];
@@ -3361,6 +3465,14 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
return 0;
null_date:
+ if (val && (fuzzy_date & TIME_NO_ZERO_DATE))
+ {
+ char buff[128];
+ strmake(buff, val->ptr(), min(val->length(), sizeof(buff)-1));
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE),
+ "datetime", buff, "str_to_date");
+ }
return (null_value=1);
}
@@ -3370,7 +3482,7 @@ String *Item_func_str_to_date::val_str(String *str)
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
- if (Item_func_str_to_date::get_date(&ltime, TIME_FUZZY_DATE))
+ if (Item_func_str_to_date::get_date(&ltime, TIME_FUZZY_DATE | sql_mode))
return 0;
if (!make_datetime((const_item ? cached_format_type :
@@ -3381,6 +3493,29 @@ String *Item_func_str_to_date::val_str(String *str)
}
+longlong Item_func_str_to_date::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ MYSQL_TIME ltime;
+
+ if (Item_func_str_to_date::get_date(&ltime, TIME_FUZZY_DATE | sql_mode))
+ return 0;
+
+ if (const_item)
+ {
+ switch (cached_field_type) {
+ case MYSQL_TYPE_DATE:
+ return TIME_to_ulonglong_date(&ltime);
+ case MYSQL_TYPE_TIME:
+ return TIME_to_ulonglong_time(&ltime);
+ default:
+ return TIME_to_ulonglong_datetime(&ltime);
+ }
+ }
+ return TIME_to_ulonglong_datetime(&ltime);
+}
+
+
bool Item_func_last_day::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE) ||
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 47bb9509582..72a5aa0c296 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -1,3 +1,6 @@
+#ifndef ITEM_TIMEFUNC_INCLUDED
+#define ITEM_TIMEFUNC_INCLUDED
+
/* Copyright (C) 2000-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -20,6 +23,8 @@
#pragma interface /* gcc class implementation */
#endif
+class MY_LOCALE;
+
enum date_time_format_types
{
TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND
@@ -73,6 +78,33 @@ public:
};
+class Item_func_to_seconds :public Item_int_func
+{
+public:
+ Item_func_to_seconds(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "to_seconds"; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
+ maybe_null=1;
+ }
+ enum_monotonicity_info get_monotonicity_info() const;
+ longlong val_int_endpoint(bool left_endp, bool *incl_endp);
+ bool check_partition_func_processor(uchar *bool_arg) { return FALSE;}
+
+ bool intro_version(uchar *int_arg)
+ {
+ int *input_version= (int*)int_arg;
+ /* This function was introduced in 5.5 */
+ int output_version= max(*input_version, 50500);
+ *input_version= output_version;
+ return 0;
+ }
+};
+
+
class Item_func_dayofmonth :public Item_int_func
{
public:
@@ -92,23 +124,22 @@ public:
class Item_func_month :public Item_func
{
public:
- Item_func_month(Item *a) :Item_func(a) {}
+ Item_func_month(Item *a) :Item_func(a) { collation.set_numeric(); }
longlong val_int();
double val_real()
{ DBUG_ASSERT(fixed == 1); return (double) Item_func_month::val_int(); }
String *val_str(String *str)
{
- str->set(val_int(), &my_charset_bin);
+ str->set(val_int(), collation.collation);
return null_value ? 0 : str;
}
const char *func_name() const { return "month"; }
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec()
{
- collation.set(&my_charset_bin);
- decimals=0;
- max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
- maybe_null=1;
+ decimals= 0;
+ fix_char_length(2);
+ maybe_null= 1;
}
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -135,9 +166,9 @@ public:
const char *func_name() const { return "dayofyear"; }
void fix_length_and_dec()
{
- decimals=0;
- max_length=3*MY_CHARSET_BIN_MB_MAXLEN;
- maybe_null=1;
+ decimals= 0;
+ fix_char_length(3);
+ maybe_null= 1;
}
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -260,7 +291,7 @@ class Item_func_weekday :public Item_func
bool odbc_type;
public:
Item_func_weekday(Item *a,bool type_arg)
- :Item_func(a), odbc_type(type_arg) {}
+ :Item_func(a), odbc_type(type_arg) { collation.set_numeric(); }
longlong val_int();
double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
String *val_str(String *str)
@@ -276,10 +307,9 @@ public:
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec()
{
- collation.set(&my_charset_bin);
- decimals=0;
- max_length=1*MY_CHARSET_BIN_MB_MAXLEN;
- maybe_null=1;
+ decimals= 0;
+ fix_char_length(1);
+ maybe_null= 1;
}
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -350,15 +380,15 @@ public:
Item_date(Item *a) :Item_func(a) {}
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
+ CHARSET_INFO *charset_for_protocol(void) const { return &my_charset_bin; }
String *val_str(String *str);
longlong val_int();
double val_real() { return val_real_from_decimal(); }
const char *func_name() const { return "date"; }
void fix_length_and_dec()
{
- collation.set(&my_charset_bin);
- decimals=0;
- max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ decimals= 0;
+ fix_length_and_charset_datetime(MAX_DATE_WIDTH);
}
Field *tmp_table_field(TABLE *table)
{
@@ -385,6 +415,7 @@ public:
Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {}
Item_date_func(Item *a,Item *b, Item *c) :Item_str_func(a,b,c) {}
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
+ CHARSET_INFO *charset_for_protocol(void) const { return &my_charset_bin; }
Field *tmp_table_field(TABLE *table)
{
return tmp_table_field_from_field_type(table, 0);
@@ -411,10 +442,11 @@ public:
Item_str_timefunc(Item *a,Item *b) :Item_str_func(a,b) {}
Item_str_timefunc(Item *a, Item *b, Item *c) :Item_str_func(a, b ,c) {}
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
+ CHARSET_INFO *charset_for_protocol(void) const { return &my_charset_bin; }
void fix_length_and_dec()
{
decimals= DATETIME_DEC;
- max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ fix_length_and_charset_datetime(MAX_TIME_WIDTH);
}
Field *tmp_table_field(TABLE *table)
{
@@ -672,7 +704,6 @@ public:
void fix_length_and_dec()
{
Item_str_timefunc::fix_length_and_dec();
- collation.set(&my_charset_bin);
maybe_null=1;
}
const char *func_name() const { return "sec_to_time"; }
@@ -744,13 +775,7 @@ public:
class Item_typecast_maybe_null :public Item_typecast
{
public:
- Item_typecast_maybe_null(Item *a) :Item_typecast(a) {}
- void fix_length_and_dec()
- {
- collation.set(&my_charset_bin);
- max_length=args[0]->max_length;
- maybe_null= 1;
- }
+ Item_typecast_maybe_null(Item *a) :Item_typecast(a) { maybe_null= 1; }
};
@@ -783,16 +808,12 @@ public:
bool get_time(MYSQL_TIME *ltime);
const char *cast_type() const { return "date"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
+ CHARSET_INFO *charset_for_protocol(void) const { return &my_charset_bin; }
Field *tmp_table_field(TABLE *table)
{
return tmp_table_field_from_field_type(table, 0);
- }
- void fix_length_and_dec()
- {
- collation.set(&my_charset_bin);
- max_length= 10;
- maybe_null= 1;
}
+ void fix_length_and_dec() { fix_length_and_charset_datetime(10); }
bool result_as_longlong() { return TRUE; }
longlong val_int();
double val_real() { return (double) val_int(); }
@@ -817,6 +838,7 @@ public:
bool get_time(MYSQL_TIME *ltime);
const char *cast_type() const { return "time"; }
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
+ CHARSET_INFO *charset_for_protocol(void) const { return &my_charset_bin; }
Field *tmp_table_field(TABLE *table)
{
return tmp_table_field_from_field_type(table, 0);
@@ -833,6 +855,8 @@ public:
{
return save_time_in_field(field);
}
+ void fix_length_and_dec()
+ { fix_length_and_charset_datetime(args[0]->max_char_length()); }
};
@@ -844,15 +868,14 @@ public:
String *val_str(String *str);
const char *cast_type() const { return "datetime"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
+ CHARSET_INFO *charset_for_protocol(void) const { return &my_charset_bin; }
Field *tmp_table_field(TABLE *table)
{
return tmp_table_field_from_field_type(table, 0);
}
void fix_length_and_dec()
{
- collation.set(&my_charset_bin);
- maybe_null= 1;
- max_length= MAX_DATETIME_FULL_WIDTH * MY_CHARSET_BIN_MB_MAXLEN;
+ fix_length_and_charset_datetime(MAX_DATETIME_FULL_WIDTH);
decimals= DATETIME_DEC;
}
bool result_as_longlong() { return TRUE; }
@@ -877,11 +900,11 @@ public:
String *val_str(String *str);
const char *func_name() const { return "makedate"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
+ CHARSET_INFO *charset_for_protocol(void) const { return &my_charset_bin; }
void fix_length_and_dec()
{
decimals=0;
- max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- /* It returns NULL when the second argument is less or equal to 0 */
+ fix_length_and_charset_datetime(MAX_DATE_WIDTH);
maybe_null= 1;
}
longlong val_int();
@@ -900,6 +923,7 @@ public:
String *val_str(String *str);
enum_field_types field_type() const { return cached_field_type; }
void fix_length_and_dec();
+ CHARSET_INFO *charset_for_protocol(void) const { return &my_charset_bin; }
Field *tmp_table_field(TABLE *table)
{
@@ -925,6 +949,8 @@ public:
return save_date_in_field(field);
return Item_str_func::save_in_field(field, no_conversions);
}
+ longlong val_int();
+ MYSQL_TIME *val_datetime(MYSQL_TIME *time, date_time_format_types *format);
};
class Item_func_timediff :public Item_str_timefunc
@@ -990,20 +1016,20 @@ enum date_time_format
USA_FORMAT, JIS_FORMAT, ISO_FORMAT, EUR_FORMAT, INTERNAL_FORMAT
};
-class Item_func_get_format :public Item_str_func
+class Item_func_get_format :public Item_str_ascii_func
{
public:
const timestamp_type type; // keep it public
Item_func_get_format(timestamp_type type_arg, Item *a)
- :Item_str_func(a), type(type_arg)
+ :Item_str_ascii_func(a), type(type_arg)
{}
- String *val_str(String *str);
+ String *val_str_ascii(String *str);
const char *func_name() const { return "get_format"; }
void fix_length_and_dec()
{
maybe_null= 1;
decimals=0;
- max_length=17*MY_CHARSET_BIN_MB_MAXLEN;
+ fix_length_and_charset(17, default_charset());
}
virtual void print(String *str, enum_query_type query_type);
};
@@ -1015,6 +1041,7 @@ class Item_func_str_to_date :public Item_str_func
date_time_format_types cached_format_type;
timestamp_type cached_timestamp_type;
bool const_item;
+ ulonglong sql_mode;
public:
Item_func_str_to_date(Item *a, Item *b)
:Item_str_func(a, b), const_item(false)
@@ -1028,6 +1055,8 @@ public:
{
return tmp_table_field_from_field_type(table, 1);
}
+ longlong val_int();
+ bool result_as_longlong() { return TRUE; }
};
@@ -1037,4 +1066,17 @@ public:
Item_func_last_day(Item *a) :Item_date(a) {}
const char *func_name() const { return "last_day"; }
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
+ void fix_length_and_dec()
+ {
+ Item_date::fix_length_and_dec();
+ maybe_null= 1;
+ }
};
+
+
+/* Function prototypes */
+
+bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
+ timestamp_type type, String *str);
+
+#endif /* ITEM_TIMEFUNC_INCLUDED */
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 3e20b90e68e..f124c37f0eb 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -17,9 +17,17 @@
#pragma implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" // set_var.h: THD
+#include "set_var.h"
#include "my_xml.h"
#include "sp_pcontext.h"
+#include "sql_class.h" // THD
/*
TODO: future development directions:
@@ -2569,7 +2577,7 @@ void Item_xml_str_func::fix_length_and_dec()
nodeset_func= 0;
- if (agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1))
+ if (agg_arg_charsets_for_comparison(collation, args, arg_count))
return;
if (collation.collation->mbminlen > 1)
diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h
index dadbb5ccf42..6373bde0aab 100644
--- a/sql/item_xmlfunc.h
+++ b/sql/item_xmlfunc.h
@@ -1,3 +1,6 @@
+#ifndef ITEM_XMLFUNC_INCLUDED
+#define ITEM_XMLFUNC_INCLUDED
+
/* Copyright (C) 2000-2005 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -61,3 +64,4 @@ public:
String *val_str(String *);
};
+#endif /* ITEM_XMLFUNC_INCLUDED */
diff --git a/sql/key.cc b/sql/key.cc
index 5b2ae8029dd..e28e0803986 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -16,7 +16,10 @@
/* Functions to handle keys and fields in forms */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: by includes later
+#include "key.h" // key_rec_cmp
+#include "field.h" // Field
/*
Search after a key that starts with 'field'
@@ -349,10 +352,39 @@ void key_unpack(String *to,TABLE *table,uint idx)
}
if ((field=key_part->field))
{
+ CHARSET_INFO *cs= field->charset();
field->val_str(&tmp);
+ /*
+ For BINARY(N) strip trailing zeroes to make
+ the error message nice-looking
+ */
+ if (field->binary() && field->type() == MYSQL_TYPE_STRING && tmp.length())
+ {
+ const char *tmp_end= tmp.ptr() + tmp.length();
+ while (tmp_end > tmp.ptr() && !*--tmp_end) ;
+ tmp.length(tmp_end - tmp.ptr() + 1);
+ }
+ if (cs->mbmaxlen > 1 &&
+ table->field[key_part->fieldnr - 1]->field_length !=
+ key_part->length)
+ {
+ /*
+ Prefix key, multi-byte charset.
+ For the columns of type CHAR(N), the above val_str()
+ call will return exactly "key_part->length" bytes,
+ which can break a multi-byte characters in the middle.
+ Align, returning not more than "char_length" characters.
+ */
+ uint charpos, char_length= key_part->length / cs->mbmaxlen;
+ if ((charpos= my_charpos(cs, tmp.ptr(),
+ tmp.ptr() + tmp.length(),
+ char_length)) < tmp.length())
+ tmp.length(charpos);
+ }
if (key_part->length < field->pack_length())
tmp.length(min(tmp.length(),key_part->length));
- to->append(tmp);
+ ErrConvString err(&tmp);
+ to->append(err.ptr());
}
else
to->append(STRING_WITH_LEN("???"));
diff --git a/sql/key.h b/sql/key.h
new file mode 100644
index 00000000000..8b416da5846
--- /dev/null
+++ b/sql/key.h
@@ -0,0 +1,39 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 KEY_INCLUDED
+#define KEY_INCLUDED
+
+#include "my_global.h" /* uchar */
+
+class Field;
+class String;
+struct TABLE;
+typedef struct st_bitmap MY_BITMAP;
+typedef struct st_key KEY;
+typedef struct st_key_part_info KEY_PART_INFO;
+
+int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field,
+ uint *key_length, uint *keypart);
+void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, uint key_length);
+void key_restore(uchar *to_record, uchar *from_key, KEY *key_info,
+ uint key_length);
+bool key_cmp_if_same(TABLE *form,const uchar *key,uint index,uint key_length);
+void key_unpack(String *to,TABLE *form,uint index);
+bool is_key_used(TABLE *table, uint idx, const MY_BITMAP *fields);
+int key_cmp(KEY_PART_INFO *key_part, const uchar *key, uint key_length);
+extern "C" int key_rec_cmp(void *key_info, uchar *a, uchar *b);
+
+#endif /* KEY_INCLUDED */
diff --git a/sql/keycaches.cc b/sql/keycaches.cc
new file mode 100644
index 00000000000..14551803cfc
--- /dev/null
+++ b/sql/keycaches.cc
@@ -0,0 +1,163 @@
+/* Copyright (C) 2002-2006 MySQL AB, 2009 Sun Microsystems, Inc.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "keycaches.h"
+
+/****************************************************************************
+ Named list handling
+****************************************************************************/
+
+NAMED_ILIST key_caches;
+
+/**
+ ilink (intrusive list element) with a name
+*/
+class NAMED_ILINK :public ilink
+{
+public:
+ const char *name;
+ uint name_length;
+ uchar* data;
+
+ NAMED_ILINK(I_List<NAMED_ILINK> *links, const char *name_arg,
+ uint name_length_arg, uchar* data_arg)
+ :name_length(name_length_arg), data(data_arg)
+ {
+ name= my_strndup(name_arg, name_length, MYF(MY_WME));
+ links->push_back(this);
+ }
+ inline bool cmp(const char *name_cmp, uint length)
+ {
+ return length == name_length && !memcmp(name, name_cmp, length);
+ }
+ ~NAMED_ILINK()
+ {
+ my_free((void *) name);
+ }
+};
+
+uchar* find_named(I_List<NAMED_ILINK> *list, const char *name, uint length,
+ NAMED_ILINK **found)
+{
+ I_List_iterator<NAMED_ILINK> it(*list);
+ NAMED_ILINK *element;
+ while ((element= it++))
+ {
+ if (element->cmp(name, length))
+ {
+ if (found)
+ *found= element;
+ return element->data;
+ }
+ }
+ return 0;
+}
+
+
+void NAMED_ILIST::delete_elements(void (*free_element)(const char *name, uchar*))
+{
+ NAMED_ILINK *element;
+ DBUG_ENTER("NAMED_ILIST::delete_elements");
+ while ((element= get()))
+ {
+ (*free_element)(element->name, element->data);
+ delete element;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/* Key cache functions */
+
+LEX_STRING default_key_cache_base= {C_STRING_WITH_LEN("default")};
+
+KEY_CACHE zero_key_cache; ///< @@nonexistent_cache.param->value_ptr() points here
+
+KEY_CACHE *get_key_cache(LEX_STRING *cache_name)
+{
+ if (!cache_name || ! cache_name->length)
+ cache_name= &default_key_cache_base;
+ return ((KEY_CACHE*) find_named(&key_caches,
+ cache_name->str, cache_name->length, 0));
+}
+
+KEY_CACHE *create_key_cache(const char *name, uint length)
+{
+ KEY_CACHE *key_cache;
+ DBUG_ENTER("create_key_cache");
+ DBUG_PRINT("enter",("name: %.*s", length, name));
+
+ if ((key_cache= (KEY_CACHE*) my_malloc(sizeof(KEY_CACHE),
+ MYF(MY_ZEROFILL | MY_WME))))
+ {
+ if (!new NAMED_ILINK(&key_caches, name, length, (uchar*) key_cache))
+ {
+ my_free(key_cache);
+ key_cache= 0;
+ }
+ else
+ {
+ /*
+ Set default values for a key cache
+ The values in dflt_key_cache_var is set by my_getopt() at startup
+
+ We don't set 'buff_size' as this is used to enable the key cache
+ */
+ key_cache->param_block_size= dflt_key_cache_var.param_block_size;
+ key_cache->param_division_limit= dflt_key_cache_var.param_division_limit;
+ key_cache->param_age_threshold= dflt_key_cache_var.param_age_threshold;
+ }
+ }
+ DBUG_RETURN(key_cache);
+}
+
+
+KEY_CACHE *get_or_create_key_cache(const char *name, uint length)
+{
+ LEX_STRING key_cache_name;
+ KEY_CACHE *key_cache;
+
+ key_cache_name.str= (char *) name;
+ key_cache_name.length= length;
+ if (!(key_cache= get_key_cache(&key_cache_name)))
+ key_cache= create_key_cache(name, length);
+ return key_cache;
+}
+
+
+void free_key_cache(const char *name, KEY_CACHE *key_cache)
+{
+ end_key_cache(key_cache, 1); // Can never fail
+ my_free(key_cache);
+}
+
+
+bool process_key_caches(process_key_cache_t func)
+{
+ I_List_iterator<NAMED_ILINK> it(key_caches);
+ NAMED_ILINK *element;
+
+ while ((element= it++))
+ {
+ KEY_CACHE *key_cache= (KEY_CACHE *) element->data;
+ func(element->name, key_cache);
+ }
+ return 0;
+}
+
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
+template class I_List_iterator<NAMED_ILINK>;
+#endif
+
diff --git a/sql/keycaches.h b/sql/keycaches.h
new file mode 100644
index 00000000000..66d24b59465
--- /dev/null
+++ b/sql/keycaches.h
@@ -0,0 +1,45 @@
+#ifndef KEYCACHES_INCLUDED
+#define KEYCACHES_INCLUDED
+
+/* Copyright (C) 2002-2006 MySQL AB, 2009 Sun Microsystems, Inc.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "sql_list.h"
+#include <keycache.h>
+
+extern "C"
+{
+ typedef int (*process_key_cache_t) (const char *, KEY_CACHE *);
+}
+
+class NAMED_ILINK;
+
+class NAMED_ILIST: public I_List<NAMED_ILINK>
+{
+ public:
+ void delete_elements(void (*free_element)(const char*, uchar*));
+};
+
+extern LEX_STRING default_key_cache_base;
+extern KEY_CACHE zero_key_cache;
+extern NAMED_ILIST key_caches;
+
+KEY_CACHE *create_key_cache(const char *name, uint length);
+KEY_CACHE *get_key_cache(LEX_STRING *cache_name);
+KEY_CACHE *get_or_create_key_cache(const char *name, uint length);
+void free_key_cache(const char *name, KEY_CACHE *key_cache);
+bool process_key_caches(process_key_cache_t func);
+
+#endif /* KEYCACHES_INCLUDED */
diff --git a/sql/lex.h b/sql/lex.h
index 0a85824f6f7..6d5d711eb60 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -1,3 +1,6 @@
+#ifndef LEX_INCLUDED
+#define LEX_INCLUDED
+
/* Copyright (C) 2000-2002 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -96,6 +99,7 @@ static SYMBOL symbols[] = {
{ "CASCADE", SYM(CASCADE)},
{ "CASCADED", SYM(CASCADED)},
{ "CASE", SYM(CASE_SYM)},
+ { "CATALOG_NAME", SYM(CATALOG_NAME_SYM)},
{ "CHAIN", SYM(CHAIN_SYM)},
{ "CHANGE", SYM(CHANGE)},
{ "CHANGED", SYM(CHANGED)},
@@ -105,6 +109,7 @@ static SYMBOL symbols[] = {
{ "CHECK", SYM(CHECK_SYM)},
{ "CHECKSUM", SYM(CHECKSUM_SYM)},
{ "CIPHER", SYM(CIPHER_SYM)},
+ { "CLASS_ORIGIN", SYM(CLASS_ORIGIN_SYM)},
{ "CLIENT", SYM(CLIENT_SYM)},
{ "CLOSE", SYM(CLOSE_SYM)},
{ "COALESCE", SYM(COALESCE)},
@@ -112,6 +117,7 @@ static SYMBOL symbols[] = {
{ "COLLATE", SYM(COLLATE_SYM)},
{ "COLLATION", SYM(COLLATION_SYM)},
{ "COLUMN", SYM(COLUMN_SYM)},
+ { "COLUMN_NAME", SYM(COLUMN_NAME_SYM)},
{ "COLUMNS", SYM(COLUMNS)},
{ "COMMENT", SYM(COMMENT_SYM)},
{ "COMMIT", SYM(COMMIT_SYM)},
@@ -124,6 +130,9 @@ static SYMBOL symbols[] = {
{ "CONNECTION", SYM(CONNECTION_SYM)},
{ "CONSISTENT", SYM(CONSISTENT_SYM)},
{ "CONSTRAINT", SYM(CONSTRAINT)},
+ { "CONSTRAINT_CATALOG", SYM(CONSTRAINT_CATALOG_SYM)},
+ { "CONSTRAINT_NAME", SYM(CONSTRAINT_NAME_SYM)},
+ { "CONSTRAINT_SCHEMA", SYM(CONSTRAINT_SCHEMA_SYM)},
{ "CONTAINS", SYM(CONTAINS_SYM)},
{ "CONTEXT", SYM(CONTEXT_SYM)},
{ "CONTINUE", SYM(CONTINUE_SYM)},
@@ -138,6 +147,7 @@ static SYMBOL symbols[] = {
{ "CURRENT_TIMESTAMP", SYM(NOW_SYM)},
{ "CURRENT_USER", SYM(CURRENT_USER)},
{ "CURSOR", SYM(CURSOR_SYM)},
+ { "CURSOR_NAME", SYM(CURSOR_NAME_SYM)},
{ "DATA", SYM(DATA_SYM)},
{ "DATABASE", SYM(DATABASE)},
{ "DATABASES", SYM(DATABASES)},
@@ -186,6 +196,7 @@ static SYMBOL symbols[] = {
{ "ENGINE", SYM(ENGINE_SYM)},
{ "ENGINES", SYM(ENGINES_SYM)},
{ "ENUM", SYM(ENUM)},
+ { "ERROR", SYM(ERROR_SYM)},
{ "ERRORS", SYM(ERRORS)},
{ "ESCAPE", SYM(ESCAPE_SYM)},
{ "ESCAPED", SYM(ESCAPED)},
@@ -215,11 +226,11 @@ static SYMBOL symbols[] = {
{ "FORCE", SYM(FORCE_SYM)},
{ "FOREIGN", SYM(FOREIGN)},
{ "FOUND", SYM(FOUND_SYM)},
- { "FRAC_SECOND", SYM(FRAC_SECOND_SYM)},
{ "FROM", SYM(FROM)},
{ "FULL", SYM(FULL)},
{ "FULLTEXT", SYM(FULLTEXT_SYM)},
{ "FUNCTION", SYM(FUNCTION_SYM)},
+ { "GENERAL", SYM(GENERAL)},
{ "GEOMETRY", SYM(GEOMETRY_SYM)},
{ "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION)},
{ "GET_FORMAT", SYM(GET_FORMAT)},
@@ -241,6 +252,7 @@ static SYMBOL symbols[] = {
{ "IDENTIFIED", SYM(IDENTIFIED_SYM)},
{ "IF", SYM(IF)},
{ "IGNORE", SYM(IGNORE_SYM)},
+ { "IGNORE_SERVER_IDS", SYM(IGNORE_SERVER_IDS_SYM)},
{ "IMPORT", SYM(IMPORT)},
{ "IN", SYM(IN_SYM)},
{ "INDEX", SYM(INDEX_SYM)},
@@ -248,8 +260,6 @@ static SYMBOL symbols[] = {
{ "INFILE", SYM(INFILE)},
{ "INITIAL_SIZE", SYM(INITIAL_SIZE_SYM)},
{ "INNER", SYM(INNER_SYM)},
- { "INNOBASE", SYM(INNOBASE_SYM)},
- { "INNODB", SYM(INNOBASE_SYM)},
{ "INOUT", SYM(INOUT_SYM)},
{ "INSENSITIVE", SYM(INSENSITIVE_SYM)},
{ "INSERT", SYM(INSERT)},
@@ -320,6 +330,7 @@ static SYMBOL symbols[] = {
{ "MASTER_SSL_KEY", SYM(MASTER_SSL_KEY_SYM)},
{ "MASTER_SSL_VERIFY_SERVER_CERT", SYM(MASTER_SSL_VERIFY_SERVER_CERT_SYM)},
{ "MASTER_USER", SYM(MASTER_USER_SYM)},
+ { "MASTER_HEARTBEAT_PERIOD", SYM(MASTER_HEARTBEAT_PERIOD_SYM)},
{ "MATCH", SYM(MATCH)},
{ "MAX_CONNECTIONS_PER_HOUR", SYM(MAX_CONNECTIONS_PER_HOUR)},
{ "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR)},
@@ -334,6 +345,7 @@ static SYMBOL symbols[] = {
{ "MEDIUMTEXT", SYM(MEDIUMTEXT)},
{ "MEMORY", SYM(MEMORY_SYM)},
{ "MERGE", SYM(MERGE_SYM)},
+ { "MESSAGE_TEXT", SYM(MESSAGE_TEXT_SYM)},
{ "MICROSECOND", SYM(MICROSECOND_SYM)},
{ "MIDDLEINT", SYM(MEDIUMINT)}, /* For powerbuilder */
{ "MIGRATE", SYM(MIGRATE_SYM)},
@@ -350,6 +362,7 @@ static SYMBOL symbols[] = {
{ "MULTIPOINT", SYM(MULTIPOINT)},
{ "MULTIPOLYGON", SYM(MULTIPOLYGON)},
{ "MUTEX", SYM(MUTEX_SYM)},
+ { "MYSQL_ERRNO", SYM(MYSQL_ERRNO_SYM)},
{ "NAME", SYM(NAME_SYM)},
{ "NAMES", SYM(NAMES_SYM)},
{ "NATIONAL", SYM(NATIONAL_SYM)},
@@ -404,11 +417,12 @@ static SYMBOL symbols[] = {
{ "PREV", SYM(PREV_SYM)},
{ "PRIMARY", SYM(PRIMARY_SYM)},
{ "PRIVILEGES", SYM(PRIVILEGES)},
- { "PROCEDURE", SYM(PROCEDURE)},
+ { "PROCEDURE", SYM(PROCEDURE_SYM)},
{ "PROCESS" , SYM(PROCESS)},
{ "PROCESSLIST", SYM(PROCESSLIST_SYM)},
- { "PROFILE", SYM(PROFILE_SYM)},
- { "PROFILES", SYM(PROFILES_SYM)},
+ { "PROFILE", SYM(PROFILE_SYM)},
+ { "PROFILES", SYM(PROFILES_SYM)},
+ { "PROXY", SYM(PROXY_SYM)},
{ "PURGE", SYM(PURGE)},
{ "QUARTER", SYM(QUARTER_SYM)},
{ "QUERY", SYM(QUERY_SYM)},
@@ -426,6 +440,8 @@ static SYMBOL symbols[] = {
{ "REDUNDANT", SYM(REDUNDANT_SYM)},
{ "REFERENCES", SYM(REFERENCES)},
{ "REGEXP", SYM(REGEXP)},
+ { "RELAY", SYM(RELAY)},
+ { "RELAYLOG", SYM(RELAYLOG_SYM)},
{ "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM)},
{ "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM)},
{ "RELAY_THREAD", SYM(RELAY_THREAD)},
@@ -441,6 +457,7 @@ static SYMBOL symbols[] = {
{ "REPEAT", SYM(REPEAT_SYM)},
{ "REQUIRE", SYM(REQUIRE_SYM)},
{ "RESET", SYM(RESET_SYM)},
+ { "RESIGNAL", SYM(RESIGNAL_SYM)},
{ "RESTORE", SYM(RESTORE_SYM)},
{ "RESTRICT", SYM(RESTRICT)},
{ "RESUME", SYM(RESUME_SYM)},
@@ -459,6 +476,7 @@ static SYMBOL symbols[] = {
{ "SAVEPOINT", SYM(SAVEPOINT_SYM)},
{ "SCHEDULE", SYM(SCHEDULE_SYM)},
{ "SCHEMA", SYM(DATABASE)},
+ { "SCHEMA_NAME", SYM(SCHEMA_NAME_SYM)},
{ "SCHEMAS", SYM(DATABASES)},
{ "SECOND", SYM(SECOND_SYM)},
{ "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM)},
@@ -474,9 +492,11 @@ static SYMBOL symbols[] = {
{ "SHARE", SYM(SHARE_SYM)},
{ "SHOW", SYM(SHOW)},
{ "SHUTDOWN", SYM(SHUTDOWN)},
+ { "SIGNAL", SYM(SIGNAL_SYM)},
{ "SIGNED", SYM(SIGNED_SYM)},
{ "SIMPLE", SYM(SIMPLE_SYM)},
{ "SLAVE", SYM(SLAVE)},
+ { "SLOW", SYM(SLOW)},
{ "SNAPSHOT", SYM(SNAPSHOT_SYM)},
{ "SMALLINT", SYM(SMALLINT)},
{ "SOCKET", SYM(SOCKET_SYM)},
@@ -497,7 +517,6 @@ static SYMBOL symbols[] = {
{ "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM)},
{ "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT)},
{ "SQL_THREAD", SYM(SQL_THREAD)},
- { "SQL_TSI_FRAC_SECOND", SYM(FRAC_SECOND_SYM)},
{ "SQL_TSI_SECOND", SYM(SECOND_SYM)},
{ "SQL_TSI_MINUTE", SYM(MINUTE_SYM)},
{ "SQL_TSI_HOUR", SYM(HOUR_SYM)},
@@ -515,6 +534,7 @@ static SYMBOL symbols[] = {
{ "STORAGE", SYM(STORAGE_SYM)},
{ "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN)},
{ "STRING", SYM(STRING_SYM)},
+ { "SUBCLASS_ORIGIN", SYM(SUBCLASS_ORIGIN_SYM)},
{ "SUBJECT", SYM(SUBJECT_SYM)},
{ "SUBPARTITION", SYM(SUBPARTITION_SYM)},
{ "SUBPARTITIONS", SYM(SUBPARTITIONS_SYM)},
@@ -523,6 +543,7 @@ static SYMBOL symbols[] = {
{ "SWAPS", SYM(SWAPS_SYM)},
{ "SWITCHES", SYM(SWITCHES_SYM)},
{ "TABLE", SYM(TABLE_SYM)},
+ { "TABLE_NAME", SYM(TABLE_NAME_SYM)},
{ "TABLES", SYM(TABLES)},
{ "TABLESPACE", SYM(TABLESPACE)},
{ "TABLE_CHECKSUM", SYM(TABLE_CHECKSUM_SYM)},
@@ -593,6 +614,7 @@ static SYMBOL symbols[] = {
{ "X509", SYM(X509_SYM)},
{ "XOR", SYM(XOR)},
{ "XA", SYM(XA_SYM)},
+ { "XML", SYM(XML_SYM)}, /* LOAD XML Arnold/Erik */
{ "YEAR", SYM(YEAR_SYM)},
{ "YEAR_MONTH", SYM(YEAR_MONTH_SYM)},
{ "ZEROFILL", SYM(ZEROFILL)},
@@ -634,3 +656,5 @@ static SYMBOL sql_functions[] = {
{ "VAR_POP", SYM(VARIANCE_SYM)},
{ "VAR_SAMP", SYM(VAR_SAMP_SYM)},
};
+
+#endif /* LEX_INCLUDED */
diff --git a/sql/lock.cc b/sql/lock.cc
index e2216876635..2e141e1c9fb 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -73,7 +73,13 @@
we are forced to use mysql_lock_merge.
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "debug_sync.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "lock.h"
+#include "sql_base.h" // close_tables_for_reopen
+#include "sql_parse.h" // is_log_table_write_query
+#include "sql_acl.h" // SUPER_ACL
#include <hash.h>
#include <assert.h>
@@ -88,41 +94,15 @@ extern HASH open_cache;
#define GET_LOCK_UNLOCK 1
#define GET_LOCK_STORE_LOCKS 2
-static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
- uint flags, TABLE **write_locked);
-static void reset_lock_data(MYSQL_LOCK *sql_lock);
+static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
+ uint flags);
static int lock_external(THD *thd, TABLE **table,uint count);
static int unlock_external(THD *thd, TABLE **table,uint count);
static void print_lock_error(int error, const char *);
-/*
- Lock tables.
-
- SYNOPSIS
- mysql_lock_tables()
- thd The current thread.
- tables An array of pointers to the tables to lock.
- count The number of tables to lock.
- flags Options:
- MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
- MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
- MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables.
- MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
- or dropped tables by itself,
- mysql_lock_tables() should
- notify upper level and rely
- on caller doing this.
- need_reopen Out parameter, TRUE if some tables were altered
- or deleted and should be reopened by caller.
-
- RETURN
- A lock structure pointer on success.
- NULL on error or if some tables should be reopen.
-*/
-
/* Map the return value of thr_lock to an error from errmsg.txt */
static int thr_lock_errno_to_mysql[]=
-{ 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
+{ 0, ER_LOCK_ABORTED, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
/**
Perform semantic checks for mysql_lock_tables.
@@ -132,17 +112,18 @@ static int thr_lock_errno_to_mysql[]=
@param flags Lock flags
@return 0 if all the check passed, non zero if a check failed.
*/
-int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
+static int
+lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
{
- bool log_table_write_query;
- uint system_count;
- uint i;
+ uint system_count, i;
+ bool is_superuser, log_table_write_query;
- DBUG_ENTER("mysql_lock_tables_check");
+ DBUG_ENTER("lock_tables_check");
system_count= 0;
+ is_superuser= thd->security_ctx->master_access & SUPER_ACL;
log_table_write_query= (is_log_table_write_query(thd->lex->sql_command)
- || ((flags & MYSQL_LOCK_PERF_SCHEMA) != 0));
+ || ((flags & MYSQL_LOCK_LOG_TABLE) != 0));
for (i=0 ; i<count; i++)
{
@@ -173,10 +154,49 @@ int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
}
}
- if ((t->s->table_category == TABLE_CATEGORY_SYSTEM) &&
- (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE))
+ if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE)
{
- system_count++;
+ if (t->s->table_category == TABLE_CATEGORY_SYSTEM)
+ system_count++;
+
+ if (t->db_stat & HA_READ_ONLY)
+ {
+ my_error(ER_OPEN_AS_READONLY, MYF(0), t->alias);
+ DBUG_RETURN(1);
+ }
+ }
+
+ /*
+ If we are going to lock a non-temporary table we must own metadata
+ lock of appropriate type on it (I.e. for table to be locked for
+ write we must own metadata lock of MDL_SHARED_WRITE or stronger
+ type. For table to be locked for read we must own metadata lock
+ of MDL_SHARED_READ or stronger type).
+ The only exception are HANDLER statements which are allowed to
+ lock table for read while having only MDL_SHARED lock on it.
+ */
+ DBUG_ASSERT(t->s->tmp_table ||
+ thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ t->s->db.str, t->s->table_name.str,
+ t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE ?
+ MDL_SHARED_WRITE : MDL_SHARED_READ) ||
+ (t->open_by_handler &&
+ thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ t->s->db.str, t->s->table_name.str,
+ MDL_SHARED)));
+
+ /*
+ Prevent modifications to base tables if READ_ONLY is activated.
+ In any case, read only does not apply to temporary tables.
+ */
+ if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) && !t->s->tmp_table)
+ {
+ if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE &&
+ !is_superuser && opt_readonly && !thd->slave_thread)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
+ DBUG_RETURN(1);
+ }
}
}
@@ -194,154 +214,129 @@ int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
DBUG_RETURN(0);
}
-MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
- uint flags, bool *need_reopen)
+/**
+ Reset lock type in lock data
+
+ @param mysql_lock Lock structures to reset.
+
+ @note After a locking error we want to quit the locking of the table(s).
+ The test case in the bug report for Bug #18544 has the following
+ cases: 1. Locking error in lock_external() due to InnoDB timeout.
+ 2. Locking error in get_lock_data() due to missing write permission.
+ 3. Locking error in wait_if_global_read_lock() due to lock conflict.
+
+ @note In all these cases we have already set the lock type into the lock
+ data of the open table(s). If the table(s) are in the open table
+ cache, they could be reused with the non-zero lock type set. This
+ could lead to ignoring a different lock type with the next lock.
+
+ @note Clear the lock type of all lock data. This ensures that the next
+ lock request will set its lock type properly.
+*/
+
+
+static void reset_lock_data(MYSQL_LOCK *sql_lock)
+{
+ THR_LOCK_DATA **ldata, **ldata_end;
+ DBUG_ENTER("reset_lock_data");
+
+ /* Clear the lock type of all lock data to avoid reusage. */
+ for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count;
+ ldata < ldata_end;
+ ldata++)
+ {
+ /* Reset lock type. */
+ (*ldata)->type= TL_UNLOCK;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Reset lock type in lock data and free.
+
+ @param mysql_lock Lock structures to reset.
+
+*/
+
+static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock)
+{
+ reset_lock_data(*mysql_lock);
+ my_free(*mysql_lock);
+ *mysql_lock= 0;
+}
+
+
+/**
+ Lock tables.
+
+ @param thd The current thread.
+ @param tables An array of pointers to the tables to lock.
+ @param count The number of tables to lock.
+ @param flags Options:
+ MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
+ MYSQL_LOCK_IGNORE_TIMEOUT Use maximum timeout value.
+
+ @retval A lock structure pointer on success.
+ @retval NULL if an error or if wait on a lock was killed.
+*/
+
+MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
{
- MYSQL_LOCK *sql_lock;
- TABLE *write_lock_used;
int rc;
+ MYSQL_LOCK *sql_lock;
+ ulong timeout= (flags & MYSQL_LOCK_IGNORE_TIMEOUT) ?
+ LONG_TIMEOUT : thd->variables.lock_wait_timeout;
DBUG_ENTER("mysql_lock_tables");
- *need_reopen= FALSE;
+ if (lock_tables_check(thd, tables, count, flags))
+ DBUG_RETURN(NULL);
- if (mysql_lock_tables_check(thd, tables, count, flags))
- DBUG_RETURN (NULL);
+ if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS)))
+ DBUG_RETURN(NULL);
- for (;;)
+ thd_proc_info(thd, "System lock");
+ DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
+ if (sql_lock->table_count && lock_external(thd, sql_lock->table,
+ sql_lock->table_count))
{
- if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
- &write_lock_used)))
- break;
-
- if (global_read_lock && write_lock_used &&
- ! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))
- {
- /*
- Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
- Wait until the lock is gone
- */
- if (wait_if_global_read_lock(thd, 1, 1))
- {
- /* Clear the lock type of all lock data to avoid reusage. */
- reset_lock_data(sql_lock);
- my_free((uchar*) sql_lock,MYF(0));
- sql_lock=0;
- break;
- }
- if (thd->version != refresh_version)
- {
- /* Clear the lock type of all lock data to avoid reusage. */
- reset_lock_data(sql_lock);
- my_free((uchar*) sql_lock,MYF(0));
- goto retry;
- }
- }
-
- if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) &&
- write_lock_used &&
- opt_readonly &&
- !(thd->security_ctx->master_access & SUPER_ACL) &&
- !thd->slave_thread)
- {
- /*
- Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
- We do not wait for READ_ONLY=0, and fail.
- */
- reset_lock_data(sql_lock);
- my_free((uchar*) sql_lock, MYF(0));
- sql_lock=0;
- my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
- break;
- }
+ /* Clear the lock type of all lock data to avoid reusage. */
+ reset_lock_data_and_free(&sql_lock);
+ goto end;
+ }
- thd_proc_info(thd, "System lock");
- DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
- if (sql_lock->table_count && lock_external(thd, sql_lock->table,
- sql_lock->table_count))
- {
- /* Clear the lock type of all lock data to avoid reusage. */
- reset_lock_data(sql_lock);
- my_free((uchar*) sql_lock,MYF(0));
- sql_lock=0;
- break;
- }
- thd_proc_info(thd, "Table lock");
- DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
- thd->locked=1;
- /* Copy the lock data array. thr_multi_lock() reorders its contens. */
- memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
- sql_lock->lock_count * sizeof(*sql_lock->locks));
- /* Lock on the copied half of the lock data array. */
- rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
- sql_lock->lock_count,
- sql_lock->lock_count,
- thd->lock_id)];
- if (rc > 1) /* a timeout or a deadlock */
- {
- if (sql_lock->table_count)
- VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
+ /* Copy the lock data array. thr_multi_lock() reorders its contents. */
+ memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
+ sql_lock->lock_count * sizeof(*sql_lock->locks));
+ /* Lock on the copied half of the lock data array. */
+ rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
+ sql_lock->lock_count,
+ sql_lock->lock_count,
+ &thd->lock_info, timeout)];
+ if (rc)
+ {
+ if (sql_lock->table_count)
+ (void) unlock_external(thd, sql_lock->table, sql_lock->table_count);
+ reset_lock_data_and_free(&sql_lock);
+ if (! thd->killed)
my_error(rc, MYF(0));
- my_free((uchar*) sql_lock,MYF(0));
- sql_lock= 0;
- break;
- }
- else if (rc == 1) /* aborted */
- {
- /*
- reset_lock_data is required here. If thr_multi_lock fails it
- resets lock type for tables, which were locked before (and
- including) one that caused error. Lock type for other tables
- preserved.
- */
- reset_lock_data(sql_lock);
- thd->some_tables_deleted=1; // Try again
- sql_lock->lock_count= 0; // Locks are already freed
- }
- else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
- {
- /*
- Thread was killed or lock aborted. Let upper level close all
- used tables and retry or give error.
- */
- thd->locked=0;
- break;
- }
- else if (!thd->open_tables)
- {
- // Only using temporary tables, no need to unlock
- thd->some_tables_deleted=0;
- thd->locked=0;
- break;
- }
- thd_proc_info(thd, 0);
-
- /* some table was altered or deleted. reopen tables marked deleted */
- mysql_unlock_tables(thd,sql_lock);
- thd->locked=0;
-retry:
- sql_lock=0;
- if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN)
- {
- *need_reopen= TRUE;
- break;
- }
- if (wait_for_tables(thd))
- break; // Couldn't open tables
}
+end:
thd_proc_info(thd, 0);
+
if (thd->killed)
{
thd->send_kill_message();
if (sql_lock)
{
- mysql_unlock_tables(thd,sql_lock);
- sql_lock=0;
+ mysql_unlock_tables(thd, sql_lock);
+ sql_lock= 0;
}
}
thd->set_time_after_lock();
- DBUG_RETURN (sql_lock);
+ DBUG_RETURN(sql_lock);
}
@@ -388,8 +383,8 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
if (sql_lock->lock_count)
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
if (sql_lock->table_count)
- VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
- my_free((uchar*) sql_lock,MYF(0));
+ (void) unlock_external(thd,sql_lock->table,sql_lock->table_count);
+ my_free(sql_lock);
DBUG_VOID_RETURN;
}
@@ -402,9 +397,7 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
{
MYSQL_LOCK *sql_lock;
- TABLE *write_lock_used;
- if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK,
- &write_lock_used)))
+ if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK)))
mysql_unlock_tables(thd, sql_lock);
}
@@ -422,7 +415,7 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
THR_LOCK_DATA **lock=sql_lock->locks;
for (i=found=0 ; i < sql_lock->lock_count ; i++)
{
- if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
+ if (sql_lock->locks[i]->type > TL_WRITE_ALLOW_WRITE)
{
swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]);
lock++;
@@ -442,7 +435,7 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
for (i=found=0 ; i < sql_lock->table_count ; i++)
{
DBUG_ASSERT(sql_lock->table[i]->lock_position == i);
- if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
+ if ((uint) sql_lock->table[i]->reginfo.lock_type > TL_WRITE_ALLOW_WRITE)
{
swap_variables(TABLE *, *table, sql_lock->table[i]);
table++;
@@ -452,7 +445,7 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
/* Unlock all read locked tables */
if (i != found)
{
- VOID(unlock_external(thd,table,i-found));
+ (void) unlock_external(thd,table,i-found);
sql_lock->table_count=found;
}
/* Fix the lock positions in TABLE */
@@ -473,28 +466,15 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
/**
Try to find the table in the list of locked tables.
In case of success, unlock the table and remove it from this list.
-
- @note This function has a legacy side effect: the table is
- unlocked even if it is not found in the locked list.
- It's not clear if this side effect is intentional or still
- desirable. It might lead to unmatched calls to
- unlock_external(). Moreover, a discrepancy can be left
- unnoticed by the storage engine, because in
- unlock_external() we call handler::external_lock(F_UNLCK) only
- if table->current_lock is not F_UNLCK.
+ If a table has more than one lock instance, removes them all.
@param thd thread context
@param locked list of locked tables
@param table the table to unlock
- @param always_unlock specify explicitly if the legacy side
- effect is desired.
*/
-void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
- bool always_unlock)
+void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
{
- if (always_unlock == TRUE)
- mysql_unlock_some_tables(thd, &table, /* table count */ 1);
if (locked)
{
reg1 uint i;
@@ -508,9 +488,8 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
DBUG_ASSERT(table->lock_position == i);
- /* Unlock if not yet unlocked */
- if (always_unlock == FALSE)
- mysql_unlock_some_tables(thd, &table, /* table count */ 1);
+ /* Unlock the table. */
+ mysql_unlock_some_tables(thd, &table, /* table count */ 1);
/* Decrement table_count in advance, making below expressions easier */
old_tables= --locked->table_count;
@@ -554,37 +533,19 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
}
}
-/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
-
-void mysql_lock_downgrade_write(THD *thd, TABLE *table,
- thr_lock_type new_lock_type)
-{
- MYSQL_LOCK *locked;
- TABLE *write_lock_used;
- if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
- &write_lock_used)))
- {
- for (uint i=0; i < locked->lock_count; i++)
- thr_downgrade_write_lock(locked->locks[i], new_lock_type);
- my_free((uchar*) locked,MYF(0));
- }
-}
-
/** Abort all other threads waiting to get lock in table. */
void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
{
MYSQL_LOCK *locked;
- TABLE *write_lock_used;
DBUG_ENTER("mysql_lock_abort");
- if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
- &write_lock_used)))
+ if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK)))
{
for (uint i=0; i < locked->lock_count; i++)
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
- my_free((uchar*) locked,MYF(0));
+ my_free(locked);
}
DBUG_VOID_RETURN;
}
@@ -605,12 +566,10 @@ void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
{
MYSQL_LOCK *locked;
- TABLE *write_lock_used;
bool result= FALSE;
DBUG_ENTER("mysql_lock_abort_for_thread");
- if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
- &write_lock_used)))
+ if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK)))
{
for (uint i=0; i < locked->lock_count; i++)
{
@@ -618,7 +577,7 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
table->in_use->thread_id))
result= TRUE;
}
- my_free((uchar*) locked,MYF(0));
+ my_free(locked);
}
DBUG_RETURN(result);
}
@@ -660,111 +619,11 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
}
/* Delete old, not needed locks */
- my_free((uchar*) a,MYF(0));
- my_free((uchar*) b,MYF(0));
- DBUG_RETURN(sql_lock);
-}
-
-
-/**
- Find duplicate lock in tables.
-
- Temporary tables are ignored here like they are ignored in
- get_lock_data(). If we allow two opens on temporary tables later,
- both functions should be checked.
-
- @param thd The current thread.
- @param needle The table to check for duplicate lock.
- @param haystack The list of tables to search for the dup lock.
-
- @note
- This is mainly meant for MERGE tables in INSERT ... SELECT
- situations. The 'real', underlying tables can be found only after
- the MERGE tables are opened. This function assumes that the tables are
- already locked.
-
- @retval
- NULL No duplicate lock found.
- @retval
- !NULL First table from 'haystack' that matches a lock on 'needle'.
-*/
-
-TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
- TABLE_LIST *haystack)
-{
- MYSQL_LOCK *mylock;
- TABLE *table;
- TABLE *table2;
- THR_LOCK_DATA **lock_locks;
- THR_LOCK_DATA **table_lock_data;
- THR_LOCK_DATA **end_data;
- THR_LOCK_DATA **lock_data2;
- THR_LOCK_DATA **end_data2;
- DBUG_ENTER("mysql_lock_have_duplicate");
-
- /*
- Table may not be defined for derived or view tables.
- Table may not be part of a lock for delayed operations.
- */
- if (! (table= needle->table) || ! table->lock_count)
- goto end;
-
- /* A temporary table does not have locks. */
- if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
- goto end;
-
- /* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
- if (! (mylock= thd->lock ? thd->lock : thd->locked_tables))
- goto end;
+ my_free(a);
+ my_free(b);
- /* If we have less than two tables, we cannot have duplicates. */
- if (mylock->table_count < 2)
- goto end;
-
- lock_locks= mylock->locks;
-
- /* Prepare table related variables that don't change in loop. */
- DBUG_ASSERT((table->lock_position < mylock->table_count) &&
- (table == mylock->table[table->lock_position]));
- table_lock_data= lock_locks + table->lock_data_start;
- end_data= table_lock_data + table->lock_count;
-
- for (; haystack; haystack= haystack->next_global)
- {
- if (haystack->placeholder())
- continue;
- table2= haystack->table;
- if (table2->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
- continue;
-
- /* All tables in list must be in lock. */
- DBUG_ASSERT((table2->lock_position < mylock->table_count) &&
- (table2 == mylock->table[table2->lock_position]));
-
- for (lock_data2= lock_locks + table2->lock_data_start,
- end_data2= lock_data2 + table2->lock_count;
- lock_data2 < end_data2;
- lock_data2++)
- {
- THR_LOCK_DATA **lock_data;
- THR_LOCK *lock2= (*lock_data2)->lock;
-
- for (lock_data= table_lock_data;
- lock_data < end_data;
- lock_data++)
- {
- if ((*lock_data)->lock == lock2)
- {
- DBUG_PRINT("info", ("haystack match: '%s'", haystack->table_name));
- DBUG_RETURN(haystack);
- }
- }
- }
- }
-
- end:
- DBUG_PRINT("info", ("no duplicate found"));
- DBUG_RETURN(NULL);
+ thr_lock_merge_status(sql_lock->locks, sql_lock->lock_count);
+ DBUG_RETURN(sql_lock);
}
@@ -801,11 +660,10 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
@param flags One of:
- GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
- GET_LOCK_STORE_LOCKS : Store lock info in TABLE
- @param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
*/
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
- uint flags, TABLE **write_lock_used)
+ uint flags)
{
uint i,tables,lock_count;
MYSQL_LOCK *sql_lock;
@@ -814,9 +672,8 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
DBUG_ENTER("get_lock_data");
DBUG_ASSERT((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
-
DBUG_PRINT("info", ("count %d", count));
- *write_lock_used=0;
+
for (i=tables=lock_count=0 ; i < count ; i++)
{
TABLE *t= table_ptr[i];
@@ -848,25 +705,12 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
{
TABLE *table;
enum thr_lock_type lock_type;
+ THR_LOCK_DATA **org_locks = locks;
if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
continue;
lock_type= table->reginfo.lock_type;
DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT);
- if (lock_type >= TL_WRITE_ALLOW_WRITE)
- {
- *write_lock_used=table;
- if (table->db_stat & HA_READ_ONLY)
- {
- my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias);
- /* Clear the lock type of the lock data that are stored already. */
- sql_lock->lock_count= (uint) (locks - sql_lock->locks);
- reset_lock_data(sql_lock);
- my_free((uchar*) sql_lock,MYF(0));
- DBUG_RETURN(0);
- }
- }
- THR_LOCK_DATA **org_locks = locks;
locks_start= locks;
locks= table->file->store_lock(thd, locks,
(flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
@@ -904,384 +748,112 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
/**
- Reset lock type in lock data.
-
- After a locking error we want to quit the locking of the table(s).
- The test case in the bug report for Bug #18544 has the following
- cases:
- -# Locking error in lock_external() due to InnoDB timeout.
- -# Locking error in get_lock_data() due to missing write permission.
- -# Locking error in wait_if_global_read_lock() due to lock conflict.
-
- In all these cases we have already set the lock type into the lock
- data of the open table(s). If the table(s) are in the open table
- cache, they could be reused with the non-zero lock type set. This
- could lead to ignoring a different lock type with the next lock.
-
- Clear the lock type of all lock data. This ensures that the next
- lock request will set its lock type properly.
-
- @param sql_lock The MySQL lock.
-*/
-
-static void reset_lock_data(MYSQL_LOCK *sql_lock)
-{
- THR_LOCK_DATA **ldata;
- THR_LOCK_DATA **ldata_end;
-
- for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count;
- ldata < ldata_end;
- ldata++)
- {
- /* Reset lock type. */
- (*ldata)->type= TL_UNLOCK;
- }
-}
-
-
-/*****************************************************************************
- Lock table based on the name.
- This is used when we need total access to a closed, not open table
-*****************************************************************************/
-
-/**
- Lock and wait for the named lock.
-
- @param thd Thread handler
- @param table_list Lock first table in this list
-
-
- @note
- Works together with global read lock.
-
- @retval
- 0 ok
- @retval
- 1 error
-*/
-
-int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list)
-{
- int lock_retcode;
- int error= -1;
- DBUG_ENTER("lock_and_wait_for_table_name");
-
- if (wait_if_global_read_lock(thd, 0, 1))
- DBUG_RETURN(1);
- VOID(pthread_mutex_lock(&LOCK_open));
- if ((lock_retcode = lock_table_name(thd, table_list, TRUE)) < 0)
- goto end;
- if (lock_retcode && wait_for_locked_table_names(thd, table_list))
- {
- unlock_table_name(thd, table_list);
- goto end;
- }
- error=0;
-
-end:
- pthread_mutex_unlock(&LOCK_open);
- start_waiting_global_read_lock(thd);
- DBUG_RETURN(error);
-}
-
-
-/**
- Put a not open table with an old refresh version in the table cache.
-
- @param thd Thread handler
- @param table_list Lock first table in this list
- @param check_in_use Do we need to check if table already in use by us
-
- @note
- One must have a lock on LOCK_open!
-
- @warning
- If you are going to update the table, you should use
- lock_and_wait_for_table_name instead of this function as this works
- together with 'FLUSH TABLES WITH READ LOCK'
-
- @note
- This will force any other threads that uses the table to release it
- as soon as possible.
-
- @return
- < 0 error
- @return
- == 0 table locked
- @return
- > 0 table locked, but someone is using it
-*/
-
-int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
-{
- TABLE *table;
- char key[MAX_DBKEY_LENGTH];
- char *db= table_list->db;
- uint key_length;
- HASH_SEARCH_STATE state;
- DBUG_ENTER("lock_table_name");
- DBUG_PRINT("enter",("db: %s name: %s", db, table_list->table_name));
-
- key_length= create_table_def_key(thd, key, table_list, 0);
-
- if (check_in_use)
- {
- /* Only insert the table if we haven't insert it already */
- for (table=(TABLE*) hash_first(&open_cache, (uchar*)key,
- key_length, &state);
- table ;
- table = (TABLE*) hash_next(&open_cache,(uchar*) key,
- key_length, &state))
- {
- if (table->in_use == thd)
- {
- DBUG_PRINT("info", ("Table is in use"));
- table->s->version= 0; // Ensure no one can use this
- table->locked_by_name= 1;
- DBUG_RETURN(0);
- }
- }
- }
-
- if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
- DBUG_RETURN(-1);
-
- table_list->table=table;
-
- /* Return 1 if table is in use */
- DBUG_RETURN(test(remove_table_from_cache(thd, db, table_list->table_name,
- check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
-}
-
-
-void unlock_table_name(THD *thd, TABLE_LIST *table_list)
-{
- if (table_list->table)
- {
- hash_delete(&open_cache, (uchar*) table_list->table);
- broadcast_refresh();
- }
-}
-
-
-static bool locked_named_table(THD *thd, TABLE_LIST *table_list)
-{
- for (; table_list ; table_list=table_list->next_local)
- {
- TABLE *table= table_list->table;
- if (table)
- {
- TABLE *save_next= table->next;
- bool result;
- table->next= 0;
- result= table_is_used(table_list->table, 0);
- table->next= save_next;
- if (result)
- return 1;
- }
- }
- return 0; // All tables are locked
-}
-
-
-bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
-{
- bool result=0;
- DBUG_ENTER("wait_for_locked_table_names");
-
- safe_mutex_assert_owner(&LOCK_open);
-
- while (locked_named_table(thd,table_list))
- {
- if (thd->killed)
- {
- result=1;
- break;
- }
- wait_for_condition(thd, &LOCK_open, &COND_refresh);
- pthread_mutex_lock(&LOCK_open);
- }
- DBUG_RETURN(result);
-}
-
-
-/**
- Lock all tables in list with a name lock.
-
- REQUIREMENTS
- - One must have a lock on LOCK_open when calling this
+ Obtain an exclusive metadata lock on a schema name.
- @param thd Thread handle
- @param table_list Names of tables to lock
+ @param thd Thread handle.
+ @param db The database name.
- @note
- If you are just locking one table, you should use
- lock_and_wait_for_table_name().
+ This function cannot be called while holding LOCK_open mutex.
+ To avoid deadlocks, we do not try to obtain exclusive metadata
+ locks in LOCK TABLES mode, since in this mode there may be
+ other metadata locks already taken by the current connection,
+ and we must not wait for MDL locks while holding locks.
- @retval
- 0 ok
- @retval
- 1 Fatal error (end of memory ?)
+ @retval FALSE Success.
+ @retval TRUE Failure: we're in LOCK TABLES mode, or out of memory,
+ or this connection was killed.
*/
-bool lock_table_names(THD *thd, TABLE_LIST *table_list)
+bool lock_schema_name(THD *thd, const char *db)
{
- bool got_all_locks=1;
- TABLE_LIST *lock_table;
+ MDL_request_list mdl_requests;
+ MDL_request global_request;
+ MDL_request mdl_request;
- for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
+ if (thd->locked_tables_mode)
{
- int got_lock;
- if ((got_lock=lock_table_name(thd,lock_table, TRUE)) < 0)
- goto end; // Fatal error
- if (got_lock)
- got_all_locks=0; // Someone is using table
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
+ return TRUE;
}
- /* If some table was in use, wait until we got the lock */
- if (!got_all_locks && wait_for_locked_table_names(thd, table_list))
- goto end;
- return 0;
-
-end:
- unlock_table_names(thd, table_list, lock_table);
- return 1;
-}
-
-
-/**
- Unlock all tables in list with a name lock.
-
- @param thd Thread handle.
- @param table_list Names of tables to lock.
-
- @note
- This function needs to be protected by LOCK_open. If we're
- under LOCK TABLES, this function does not work as advertised. Namely,
- it does not exclude other threads from using this table and does not
- put an exclusive name lock on this table into the table cache.
-
- @see lock_table_names
- @see unlock_table_names
+ if (thd->global_read_lock.can_acquire_protection())
+ return TRUE;
+ global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_STATEMENT);
+ mdl_request.init(MDL_key::SCHEMA, db, "", MDL_EXCLUSIVE, MDL_TRANSACTION);
- @retval TRUE An error occured.
- @retval FALSE Name lock successfully acquired.
-*/
+ mdl_requests.push_front(&mdl_request);
+ mdl_requests.push_front(&global_request);
-bool lock_table_names_exclusively(THD *thd, TABLE_LIST *table_list)
-{
- if (lock_table_names(thd, table_list))
+ if (thd->mdl_context.acquire_locks(&mdl_requests,
+ thd->variables.lock_wait_timeout))
return TRUE;
- /*
- Upgrade the table name locks from semi-exclusive to exclusive locks.
- */
- for (TABLE_LIST *table= table_list; table; table= table->next_global)
- {
- if (table->table)
- table->table->open_placeholder= 1;
- }
+ DEBUG_SYNC(thd, "after_wait_locked_schema_name");
return FALSE;
}
/**
- Test is 'table' is protected by an exclusive name lock.
-
- @param[in] thd The current thread handler
- @param[in] table_list Table container containing the single table to be
- tested
-
- @note Needs to be protected by LOCK_open mutex.
-
- @return Error status code
- @retval TRUE Table is protected
- @retval FALSE Table is not protected
+ Obtain an exclusive metadata lock on an object name.
+
+ @param thd Thread handle.
+ @param mdl_type Object type (currently functions, procedures
+ and events can be name-locked).
+ @param db The schema the object belongs to.
+ @param name Object name in the schema.
+
+ This function assumes that no metadata locks were acquired
+ before calling it. Additionally, it cannot be called while
+ holding LOCK_open mutex. Both these invariants are enforced by
+ asserts in MDL_context::acquire_locks().
+ To avoid deadlocks, we do not try to obtain exclusive metadata
+ locks in LOCK TABLES mode, since in this mode there may be
+ other metadata locks already taken by the current connection,
+ and we must not wait for MDL locks while holding locks.
+
+ @retval FALSE Success.
+ @retval TRUE Failure: we're in LOCK TABLES mode, or out of memory,
+ or this connection was killed.
*/
-bool
-is_table_name_exclusively_locked_by_this_thread(THD *thd,
- TABLE_LIST *table_list)
+bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type,
+ const char *db, const char *name)
{
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
-
- key_length= create_table_def_key(thd, key, table_list, 0);
+ MDL_request_list mdl_requests;
+ MDL_request global_request;
+ MDL_request schema_request;
+ MDL_request mdl_request;
- return is_table_name_exclusively_locked_by_this_thread(thd, (uchar *)key,
- key_length);
-}
-
-
-/**
- Test is 'table key' is protected by an exclusive name lock.
-
- @param[in] thd The current thread handler.
- @param[in] key
- @param[in] key_length
-
- @note Needs to be protected by LOCK_open mutex
-
- @retval TRUE Table is protected
- @retval FALSE Table is not protected
- */
-
-bool
-is_table_name_exclusively_locked_by_this_thread(THD *thd, uchar *key,
- int key_length)
-{
- HASH_SEARCH_STATE state;
- TABLE *table;
-
- for (table= (TABLE*) hash_first(&open_cache, key,
- key_length, &state);
- table ;
- table= (TABLE*) hash_next(&open_cache, key,
- key_length, &state))
+ if (thd->locked_tables_mode)
{
- if (table->in_use == thd &&
- table->open_placeholder == 1 &&
- table->s->version == 0)
- return TRUE;
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
+ return TRUE;
}
- return FALSE;
-}
-
-/**
- Unlock all tables in list with a name lock.
-
- @param
- thd Thread handle
- @param
- table_list Names of tables to unlock
- @param
- last_table Don't unlock any tables after this one.
- (default 0, which will unlock all tables)
-
- @note
- One must have a lock on LOCK_open when calling this.
+ DBUG_ASSERT(name);
+ DEBUG_SYNC(thd, "before_wait_locked_pname");
- @note
- This function will broadcast refresh signals to inform other threads
- that the name locks are removed.
-
- @retval
- 0 ok
- @retval
- 1 Fatal error (end of memory ?)
-*/
+ if (thd->global_read_lock.can_acquire_protection())
+ return TRUE;
+ global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_STATEMENT);
+ schema_request.init(MDL_key::SCHEMA, db, "", MDL_INTENTION_EXCLUSIVE,
+ MDL_TRANSACTION);
+ mdl_request.init(mdl_type, db, name, MDL_EXCLUSIVE, MDL_TRANSACTION);
+
+ mdl_requests.push_front(&mdl_request);
+ mdl_requests.push_front(&schema_request);
+ mdl_requests.push_front(&global_request);
+
+ if (thd->mdl_context.acquire_locks(&mdl_requests,
+ thd->variables.lock_wait_timeout))
+ return TRUE;
-void unlock_table_names(THD *thd, TABLE_LIST *table_list,
- TABLE_LIST *last_table)
-{
- DBUG_ENTER("unlock_table_names");
- for (TABLE_LIST *table= table_list;
- table != last_table;
- table= table->next_local)
- unlock_table_name(thd,table);
- broadcast_refresh();
- DBUG_VOID_RETURN;
+ DEBUG_SYNC(thd, "after_wait_locked_pname");
+ return FALSE;
}
@@ -1320,45 +892,24 @@ static void print_lock_error(int error, const char *table)
/****************************************************************************
Handling of global read locks
+ Global read lock is implemented using metadata lock infrastructure.
+
Taking the global read lock is TWO steps (2nd step is optional; without
it, COMMIT of existing transactions will be allowed):
lock_global_read_lock() THEN make_global_read_lock_block_commit().
- The global locks are handled through the global variables:
- global_read_lock
- count of threads which have the global read lock (i.e. have completed at
- least the first step above)
- global_read_lock_blocks_commit
- count of threads which have the global read lock and block
- commits (i.e. are in or have completed the second step above)
- waiting_for_read_lock
- count of threads which want to take a global read lock but cannot
- protect_against_global_read_lock
- count of threads which have set protection against global read lock.
-
- access to them is protected with a mutex LOCK_global_read_lock
-
- (XXX: one should never take LOCK_open if LOCK_global_read_lock is
- taken, otherwise a deadlock may occur. Other mutexes could be a
- problem too - grep the code for global_read_lock if you want to use
- any other mutex here) Also one must not hold LOCK_open when calling
- wait_if_global_read_lock(). When the thread with the global read lock
- tries to close its tables, it needs to take LOCK_open in
- close_thread_table().
-
How blocking of threads by global read lock is achieved: that's
- advisory. Any piece of code which should be blocked by global read lock must
- be designed like this:
- - call to wait_if_global_read_lock(). When this returns 0, no global read
- lock is owned; if argument abort_on_refresh was 0, none can be obtained.
- - job
- - if abort_on_refresh was 0, call to start_waiting_global_read_lock() to
- allow other threads to get the global read lock. I.e. removal of the
- protection.
- (Note: it's a bit like an implementation of rwlock).
-
- [ I am sorry to mention some SQL syntaxes below I know I shouldn't but found
- no better descriptive way ]
+ semi-automatic. We assume that any statement which should be blocked
+ by global read lock will either open and acquires write-lock on tables
+ or acquires metadata locks on objects it is going to modify. For any
+ such statement global IX metadata lock is automatically acquired for
+ its duration (in case of LOCK TABLES until end of LOCK TABLES mode).
+ And lock_global_read_lock() simply acquires global S metadata lock
+ and thus prohibits execution of statements which modify data (unless
+ they modify only temporary tables). If deadlock happens it is detected
+ by MDL subsystem and resolved in the standard fashion (by backing-off
+ metadata locks acquired so far and restarting open tables process
+ if possible).
Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
@@ -1392,40 +943,37 @@ static void print_lock_error(int error, const char *table)
****************************************************************************/
-volatile uint global_read_lock=0;
-volatile uint global_read_lock_blocks_commit=0;
-static volatile uint protect_against_global_read_lock=0;
-static volatile uint waiting_for_read_lock=0;
+/**
+ Take global read lock, wait if there is protection against lock.
+
+ If the global read lock is already taken by this thread, then nothing is done.
+
+ See also "Handling of global read locks" above.
+
+ @param thd Reference to thread.
-#define GOT_GLOBAL_READ_LOCK 1
-#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
+ @retval False Success, global read lock set, commits are NOT blocked.
+ @retval True Failure, thread was killed.
+*/
-bool lock_global_read_lock(THD *thd)
+bool Global_read_lock::lock_global_read_lock(THD *thd)
{
DBUG_ENTER("lock_global_read_lock");
- if (!thd->global_read_lock)
+ if (!m_state)
{
- const char *old_message;
- (void) pthread_mutex_lock(&LOCK_global_read_lock);
- old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
- "Waiting to get readlock");
- DBUG_PRINT("info",
- ("waiting_for: %d protect_against: %d",
- waiting_for_read_lock, protect_against_global_read_lock));
-
- waiting_for_read_lock++;
- while (protect_against_global_read_lock && !thd->killed)
- pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
- waiting_for_read_lock--;
- if (thd->killed)
- {
- thd->exit_cond(old_message);
+ MDL_request mdl_request;
+
+ DBUG_ASSERT(! thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
+ MDL_SHARED));
+ mdl_request.init(MDL_key::GLOBAL, "", "", MDL_SHARED, MDL_EXPLICIT);
+
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
DBUG_RETURN(1);
- }
- thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
- global_read_lock++;
- thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
+
+ m_mdl_global_shared_lock= mdl_request.ticket;
+ m_state= GRL_ACQUIRED;
}
/*
We DON'T set global_read_lock_blocks_commit now, it will be set after
@@ -1439,162 +987,86 @@ bool lock_global_read_lock(THD *thd)
}
-void unlock_global_read_lock(THD *thd)
+/**
+ Unlock global read lock.
+
+ Commits may or may not be blocked when this function is called.
+
+ See also "Handling of global read locks" above.
+
+ @param thd Reference to thread.
+*/
+
+void Global_read_lock::unlock_global_read_lock(THD *thd)
{
- uint tmp;
DBUG_ENTER("unlock_global_read_lock");
- DBUG_PRINT("info",
- ("global_read_lock: %u global_read_lock_blocks_commit: %u",
- global_read_lock, global_read_lock_blocks_commit));
-
- pthread_mutex_lock(&LOCK_global_read_lock);
- tmp= --global_read_lock;
- if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
- --global_read_lock_blocks_commit;
- pthread_mutex_unlock(&LOCK_global_read_lock);
- /* Send the signal outside the mutex to avoid a context switch */
- if (!tmp)
+
+ DBUG_ASSERT(m_mdl_global_shared_lock && m_state);
+
+ if (m_mdl_blocks_commits_lock)
{
- DBUG_PRINT("signal", ("Broadcasting COND_global_read_lock"));
- pthread_cond_broadcast(&COND_global_read_lock);
+ thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
+ m_mdl_blocks_commits_lock= NULL;
}
- thd->global_read_lock= 0;
+ thd->mdl_context.release_lock(m_mdl_global_shared_lock);
+ m_mdl_global_shared_lock= NULL;
+ m_state= GRL_NONE;
DBUG_VOID_RETURN;
}
-#define must_wait (global_read_lock && \
- (is_not_commit || \
- global_read_lock_blocks_commit))
-
-bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
- bool is_not_commit)
-{
- const char *UNINIT_VAR(old_message);
- bool result= 0, need_exit_cond;
- DBUG_ENTER("wait_if_global_read_lock");
- /*
- Assert that we do not own LOCK_open. If we would own it, other
- threads could not close their tables. This would make a pretty
- deadlock.
- */
- safe_mutex_assert_not_owner(&LOCK_open);
+/**
+ Make global read lock also block commits.
- (void) pthread_mutex_lock(&LOCK_global_read_lock);
- if ((need_exit_cond= must_wait))
- {
- if (thd->global_read_lock) // This thread had the read locks
- {
- if (is_not_commit)
- my_message(ER_CANT_UPDATE_WITH_READLOCK,
- ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0));
- (void) pthread_mutex_unlock(&LOCK_global_read_lock);
- /*
- We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
- This allowance is needed to not break existing versions of innobackup
- which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
- */
- DBUG_RETURN(is_not_commit);
- }
- old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
- "Waiting for release of readlock");
- while (must_wait && ! thd->killed &&
- (!abort_on_refresh || thd->version == refresh_version))
- {
- DBUG_PRINT("signal", ("Waiting for COND_global_read_lock"));
- (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
- DBUG_PRINT("signal", ("Got COND_global_read_lock"));
- }
- if (thd->killed)
- result=1;
- }
- if (!abort_on_refresh && !result)
- protect_against_global_read_lock++;
- /*
- The following is only true in case of a global read locks (which is rare)
- and if old_message is set
- */
- if (unlikely(need_exit_cond))
- thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
- else
- pthread_mutex_unlock(&LOCK_global_read_lock);
- DBUG_RETURN(result);
-}
+ The scenario is:
+ - This thread has the global read lock.
+ - Global read lock blocking of commits is not set.
+ See also "Handling of global read locks" above.
-void start_waiting_global_read_lock(THD *thd)
-{
- bool tmp;
- DBUG_ENTER("start_waiting_global_read_lock");
- if (unlikely(thd->global_read_lock))
- DBUG_VOID_RETURN;
- (void) pthread_mutex_lock(&LOCK_global_read_lock);
- DBUG_ASSERT(protect_against_global_read_lock);
- tmp= (!--protect_against_global_read_lock &&
- (waiting_for_read_lock || global_read_lock_blocks_commit));
- (void) pthread_mutex_unlock(&LOCK_global_read_lock);
- if (tmp)
- pthread_cond_broadcast(&COND_global_read_lock);
- DBUG_VOID_RETURN;
-}
+ @param thd Reference to thread.
+ @retval False Success, global read lock set, commits are blocked.
+ @retval True Failure, thread was killed.
+*/
-bool make_global_read_lock_block_commit(THD *thd)
+bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
{
- bool error;
- const char *old_message;
+ MDL_request mdl_request;
DBUG_ENTER("make_global_read_lock_block_commit");
/*
If we didn't succeed lock_global_read_lock(), or if we already suceeded
make_global_read_lock_block_commit(), do nothing.
*/
- if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
+ if (m_state != GRL_ACQUIRED)
DBUG_RETURN(0);
- pthread_mutex_lock(&LOCK_global_read_lock);
- /* increment this BEFORE waiting on cond (otherwise race cond) */
- global_read_lock_blocks_commit++;
- /* For testing we set up some blocking, to see if we can be killed */
- DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
- protect_against_global_read_lock++;);
- old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
- "Waiting for all running commits to finish");
- while (protect_against_global_read_lock && !thd->killed)
- pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
- DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
- protect_against_global_read_lock--;);
- if ((error= test(thd->killed)))
- global_read_lock_blocks_commit--; // undo what we did
- else
- thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
- thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
- DBUG_RETURN(error);
+
+ mdl_request.init(MDL_key::COMMIT, "", "", MDL_SHARED, MDL_EXPLICIT);
+
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
+ DBUG_RETURN(TRUE);
+
+ m_mdl_blocks_commits_lock= mdl_request.ticket;
+ m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT;
+
+ DBUG_RETURN(FALSE);
}
/**
- Broadcast COND_refresh and COND_global_read_lock.
-
- Due to a bug in a threading library it could happen that a signal
- did not reach its target. A condition for this was that the same
- condition variable was used with different mutexes in
- pthread_cond_wait(). Some time ago we changed LOCK_open to
- LOCK_global_read_lock in global read lock handling. So COND_refresh
- was used with LOCK_open and LOCK_global_read_lock.
-
- We did now also change from COND_refresh to COND_global_read_lock
- in global read lock handling. But now it is necessary to signal
- both conditions at the same time.
-
- @note
- When signalling COND_global_read_lock within the global read lock
- handling, it is not necessary to also signal COND_refresh.
+ Set explicit duration for metadata locks which are used to implement GRL.
+
+ @param thd Reference to thread.
*/
-void broadcast_refresh(void)
+void Global_read_lock::set_explicit_lock_duration(THD *thd)
{
- VOID(pthread_cond_broadcast(&COND_refresh));
- VOID(pthread_cond_broadcast(&COND_global_read_lock));
+ if (m_mdl_global_shared_lock)
+ thd->mdl_context.set_lock_duration(m_mdl_global_shared_lock, MDL_EXPLICIT);
+ if (m_mdl_blocks_commits_lock)
+ thd->mdl_context.set_lock_duration(m_mdl_blocks_commits_lock, MDL_EXPLICIT);
}
/**
diff --git a/sql/lock.h b/sql/lock.h
new file mode 100644
index 00000000000..6f779595af8
--- /dev/null
+++ b/sql/lock.h
@@ -0,0 +1,28 @@
+#ifndef LOCK_INCLUDED
+#define LOCK_INCLUDED
+
+#include "thr_lock.h" /* thr_lock_type */
+#include "mdl.h"
+
+// Forward declarations
+struct TABLE;
+struct TABLE_LIST;
+class THD;
+typedef struct st_mysql_lock MYSQL_LOCK;
+
+
+MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags);
+void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
+void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
+void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
+void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
+void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock);
+bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
+MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
+/* Lock based on name */
+bool lock_schema_name(THD *thd, const char *db);
+/* Lock based on stored routine name */
+bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type,
+ const char *db, const char *name);
+
+#endif /* LOCK_INCLUDED */
diff --git a/sql/log.cc b/sql/log.cc
index 5fcb5fe0367..234fbae6961 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -24,24 +24,34 @@
Abort logging when we get an error in reading or writing log files
*/
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "log.h"
+#include "sql_base.h" // open_log_table
#include "sql_repl.h"
+#include "sql_delete.h" // mysql_truncate
+#include "sql_parse.h" // command_name
+#include "sql_time.h" // calc_time_from_sec, my_time_compare
+#include "tztime.h" // my_tz_OFFSET0, struct Time_zone
+#include "sql_acl.h" // SUPER_ACL
+#include "log_event.h" // Query_log_event
#include "rpl_filter.h"
#include "rpl_rli.h"
+#include "sql_audit.h"
#include <my_dir.h>
#include <stdarg.h>
#include <m_ctype.h> // For test_if_number
-#ifdef __NT__
+#ifdef _WIN32
#include "message.h"
#endif
-#include <mysql/plugin.h>
+#include "sql_plugin.h"
+#include "rpl_handler.h"
/* max size of the log message */
#define MAX_LOG_BUFFER_SIZE 1024
-#define MAX_USER_HOST_SIZE 512
#define MAX_TIME_SIZE 32
#define MY_OFF_T_UNDEF (~(my_off_t)0UL)
@@ -49,11 +59,10 @@
LOGGER logger;
-MYSQL_BIN_LOG mysql_bin_log;
-ulong sync_binlog_counter= 0;
+MYSQL_BIN_LOG mysql_bin_log(&sync_binlog_period);
static bool test_if_number(const char *str,
- long *res, bool allow_wildcards);
+ ulong *res, bool allow_wildcards);
static int binlog_init(void *p);
static int binlog_close_connection(handlerton *hton, THD *thd);
static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv);
@@ -63,6 +72,35 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all);
static int binlog_prepare(handlerton *hton, THD *thd, bool all);
/**
+ purge logs, master and slave sides both, related error code
+ convertor.
+ Called from @c purge_error_message(), @c MYSQL_BIN_LOG::reset_logs()
+
+ @param res an internal to purging routines error code
+
+ @return the user level error code ER_*
+*/
+uint purge_log_get_error_code(int res)
+{
+ uint errcode= 0;
+
+ switch (res) {
+ case 0: break;
+ case LOG_INFO_EOF: errcode= ER_UNKNOWN_TARGET_BINLOG; break;
+ case LOG_INFO_IO: errcode= ER_IO_ERR_LOG_INDEX_READ; break;
+ case LOG_INFO_INVALID:errcode= ER_BINLOG_PURGE_PROHIBITED; break;
+ case LOG_INFO_SEEK: errcode= ER_FSEEK_FAIL; break;
+ case LOG_INFO_MEM: errcode= ER_OUT_OF_RESOURCES; break;
+ case LOG_INFO_FATAL: errcode= ER_BINLOG_PURGE_FATAL_ERR; break;
+ case LOG_INFO_IN_USE: errcode= ER_LOG_IN_USE; break;
+ case LOG_INFO_EMFILE: errcode= ER_BINLOG_PURGE_EMFILE; break;
+ default: errcode= ER_LOG_PURGE_UNKNOWN_ERR; break;
+ }
+
+ return errcode;
+}
+
+/**
Silence all errors and warnings reported when performing a write
to a log table.
Errors and warnings are not reported to the client or SQL exception
@@ -80,23 +118,28 @@ public:
virtual ~Silence_log_table_errors() {}
- virtual bool handle_error(uint sql_errno, const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd);
+ virtual bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sql_state,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl);
const char *message() const { return m_message; }
};
bool
-Silence_log_table_errors::handle_error(uint /* sql_errno */,
- const char *message_arg,
- MYSQL_ERROR::enum_warning_level /* level */,
- THD * /* thd */)
-{
- strmake(m_message, message_arg, sizeof(m_message)-1);
+Silence_log_table_errors::handle_condition(THD *,
+ uint,
+ const char*,
+ MYSQL_ERROR::enum_warning_level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
+{
+ *cond_hdl= NULL;
+ strmake(m_message, msg, sizeof(m_message)-1);
return TRUE;
}
-
sql_print_message_func sql_print_message_handlers[3] =
{
sql_print_information,
@@ -104,11 +147,22 @@ sql_print_message_func sql_print_message_handlers[3] =
sql_print_error
};
+/**
+ Create the name of the log specified.
+
+ This method forms a new path + file name for the
+ log specified in @c name.
+
+ @param[IN] buff Location for building new string.
+ @param[IN] name Name of the log file.
+ @param[IN] log_ext The extension for the log (e.g. .log).
-char *make_default_log_name(char *buff,const char* log_ext)
+ @returns Pointer to new string containing the name.
+*/
+char *make_log_name(char *buff, const char *name, const char* log_ext)
{
- strmake(buff, pidfile_name, FN_REFLEN-5);
- return fn_format(buff, buff, mysql_data_home, log_ext,
+ strmake(buff, name, FN_REFLEN-5);
+ return fn_format(buff, buff, mysql_real_data_home, log_ext,
MYF(MY_UNPACK_FILENAME|MY_REPLACE_EXT));
}
@@ -123,24 +177,24 @@ char *make_default_log_name(char *buff,const char* log_ext)
class Mutex_sentry
{
public:
- Mutex_sentry(pthread_mutex_t *mutex)
+ Mutex_sentry(mysql_mutex_t *mutex)
: m_mutex(mutex)
{
if (m_mutex)
- pthread_mutex_lock(mutex);
+ mysql_mutex_lock(mutex);
}
~Mutex_sentry()
{
if (m_mutex)
- pthread_mutex_unlock(m_mutex);
+ mysql_mutex_unlock(m_mutex);
#ifndef DBUG_OFF
m_mutex= 0;
#endif
}
private:
- pthread_mutex_t *m_mutex;
+ mysql_mutex_t *m_mutex;
// It's not allowed to copy this object in any way
Mutex_sentry(Mutex_sentry const&);
@@ -148,115 +202,257 @@ private:
};
/*
- Helper class to store binary log transaction data.
+ Helper classes to store non-transactional and transactional data
+ before copying it to the binary log.
*/
-class binlog_trx_data {
+class binlog_cache_data
+{
public:
- binlog_trx_data()
- : at_least_one_stmt_committed(0), incident(FALSE), m_pending(0),
- before_stmt_pos(MY_OFF_T_UNDEF)
+ binlog_cache_data(): m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF),
+ incident(FALSE), changes_to_non_trans_temp_table_flag(FALSE),
+ saved_max_binlog_cache_size(0), ptr_binlog_cache_use(0),
+ ptr_binlog_cache_disk_use(0)
+ { }
+
+ ~binlog_cache_data()
{
- trans_log.end_of_file= max_binlog_cache_size;
+ DBUG_ASSERT(empty());
+ close_cached_file(&cache_log);
}
- ~binlog_trx_data()
+ bool empty() const
{
- DBUG_ASSERT(pending() == NULL);
- close_cached_file(&trans_log);
+ return pending() == NULL && my_b_tell(&cache_log) == 0;
}
- my_off_t position() const {
- return my_b_tell(&trans_log);
+ Rows_log_event *pending() const
+ {
+ return m_pending;
}
- bool empty() const
+ void set_pending(Rows_log_event *const pending)
{
- return pending() == NULL && my_b_tell(&trans_log) == 0;
+ m_pending= pending;
}
- /*
- Truncate the transaction cache to a certain position. This
- includes deleting the pending event.
- */
- void truncate(my_off_t pos)
+ void set_incident(void)
{
- DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
- DBUG_PRINT("info", ("before_stmt_pos=%lu", (ulong) pos));
- if (pending())
- {
- delete pending();
- }
- set_pending(0);
- reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0);
- trans_log.end_of_file= max_binlog_cache_size;
- if (pos < before_stmt_pos)
- before_stmt_pos= MY_OFF_T_UNDEF;
+ incident= TRUE;
+ }
+
+ bool has_incident(void)
+ {
+ return(incident);
+ }
- /*
- The only valid positions that can be truncated to are at the
- beginning of a statement. We are relying on this fact to be able
- to set the at_least_one_stmt_committed flag correctly. In other word, if
- we are truncating to the beginning of the transaction cache,
- there will be no statements in the cache, otherwhise, we will
- have at least one statement in the transaction cache.
- */
- at_least_one_stmt_committed= (pos > 0);
+ void set_changes_to_non_trans_temp_table()
+ {
+ changes_to_non_trans_temp_table_flag= TRUE;
}
- /*
- Reset the entire contents of the transaction cache, emptying it
- completely.
- */
- void reset() {
- if (!empty())
- truncate(0);
- before_stmt_pos= MY_OFF_T_UNDEF;
+ bool changes_to_non_trans_temp_table()
+ {
+ return (changes_to_non_trans_temp_table_flag);
+ }
+
+ void reset()
+ {
+ compute_statistics();
+ truncate(0);
+ changes_to_non_trans_temp_table_flag= FALSE;
incident= FALSE;
- trans_log.end_of_file= max_binlog_cache_size;
+ before_stmt_pos= MY_OFF_T_UNDEF;
+ /*
+ The truncate function calls reinit_io_cache that calls my_b_flush_io_cache
+ which may increase disk_writes. This breaks the disk_writes use by the
+ binary log which aims to compute the ratio between in-memory cache usage
+ and disk cache usage. To avoid this undesirable behavior, we reset the
+ variable after truncating the cache.
+ */
+ cache_log.disk_writes= 0;
DBUG_ASSERT(empty());
}
- Rows_log_event *pending() const
+ my_off_t get_byte_position() const
{
- return m_pending;
+ return my_b_tell(&cache_log);
}
- void set_pending(Rows_log_event *const pending)
+ my_off_t get_prev_position()
{
- m_pending= pending;
+ return(before_stmt_pos);
}
- IO_CACHE trans_log; // The transaction cache
-
- void set_incident(void)
+ void set_prev_position(my_off_t pos)
{
- incident= TRUE;
+ before_stmt_pos= pos;
}
- bool has_incident(void)
+ void restore_prev_position()
{
- return(incident);
+ truncate(before_stmt_pos);
}
- /**
- Boolean that is true if there is at least one statement in the
- transaction cache.
+ void restore_savepoint(my_off_t pos)
+ {
+ truncate(pos);
+ if (pos < before_stmt_pos)
+ before_stmt_pos= MY_OFF_T_UNDEF;
+ }
+
+ void set_binlog_cache_info(ulong param_max_binlog_cache_size,
+ ulong *param_ptr_binlog_cache_use,
+ ulong *param_ptr_binlog_cache_disk_use)
+ {
+ /*
+ The assertions guarantee that the set_binlog_cache_info is
+ called just once and information passed as parameters are
+ never zero.
+
+ This is done while calling the constructor binlog_cache_mngr.
+ We cannot set informaton in the constructor binlog_cache_data
+ because the space for binlog_cache_mngr is allocated through
+ a placement new.
+
+ In the future, we can refactor this and change it to avoid
+ the set_binlog_info.
+ */
+ DBUG_ASSERT(saved_max_binlog_cache_size == 0 &&
+ param_max_binlog_cache_size != 0 &&
+ ptr_binlog_cache_use == 0 &&
+ param_ptr_binlog_cache_use != 0 &&
+ ptr_binlog_cache_disk_use == 0 &&
+ param_ptr_binlog_cache_disk_use != 0);
+
+ saved_max_binlog_cache_size= param_max_binlog_cache_size;
+ ptr_binlog_cache_use= param_ptr_binlog_cache_use;
+ ptr_binlog_cache_disk_use= param_ptr_binlog_cache_disk_use;
+ cache_log.end_of_file= saved_max_binlog_cache_size;
+ }
+
+ /*
+ Cache to store data before copying it to the binary log.
*/
- bool at_least_one_stmt_committed;
- bool incident;
+ IO_CACHE cache_log;
private:
/*
- Pending binrows event. This event is the event where the rows are
- currently written.
+ Pending binrows event. This event is the event where the rows are currently
+ written.
*/
Rows_log_event *m_pending;
-public:
/*
Binlog position before the start of the current statement.
*/
my_off_t before_stmt_pos;
+
+ /*
+ This indicates that some events did not get into the cache and most likely
+ it is corrupted.
+ */
+ bool incident;
+
+ /*
+ This flag indicates if the cache has changes to temporary tables.
+ @TODO This a temporary fix and should be removed after BUG#54562.
+ */
+ bool changes_to_non_trans_temp_table_flag;
+
+ /**
+ This function computes binlog cache and disk usage.
+ */
+ void compute_statistics()
+ {
+ if (!empty())
+ {
+ statistic_increment(*ptr_binlog_cache_use, &LOCK_status);
+ if (cache_log.disk_writes != 0)
+ statistic_increment(*ptr_binlog_cache_disk_use, &LOCK_status);
+ }
+ }
+
+ /*
+ Stores the values of maximum size of the cache allowed when this cache
+ is configured. This corresponds to either
+ . max_binlog_cache_size or max_binlog_stmt_cache_size.
+ */
+ ulong saved_max_binlog_cache_size;
+
+ /*
+ Stores a pointer to the status variable that keeps track of the in-memory
+ cache usage. This corresponds to either
+ . binlog_cache_use or binlog_stmt_cache_use.
+ */
+ ulong *ptr_binlog_cache_use;
+
+ /*
+ Stores a pointer to the status variable that keeps track of the disk
+ cache usage. This corresponds to either
+ . binlog_cache_disk_use or binlog_stmt_cache_disk_use.
+ */
+ ulong *ptr_binlog_cache_disk_use;
+
+ /*
+ It truncates the cache to a certain position. This includes deleting the
+ pending event.
+ */
+ void truncate(my_off_t pos)
+ {
+ DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
+ if (pending())
+ {
+ delete pending();
+ set_pending(0);
+ }
+ reinit_io_cache(&cache_log, WRITE_CACHE, pos, 0, 0);
+ cache_log.end_of_file= saved_max_binlog_cache_size;
+ }
+
+ binlog_cache_data& operator=(const binlog_cache_data& info);
+ binlog_cache_data(const binlog_cache_data& info);
+};
+
+class binlog_cache_mngr {
+public:
+ binlog_cache_mngr(ulong param_max_binlog_stmt_cache_size,
+ ulong param_max_binlog_cache_size,
+ ulong *param_ptr_binlog_stmt_cache_use,
+ ulong *param_ptr_binlog_stmt_cache_disk_use,
+ ulong *param_ptr_binlog_cache_use,
+ ulong *param_ptr_binlog_cache_disk_use)
+ {
+ stmt_cache.set_binlog_cache_info(param_max_binlog_stmt_cache_size,
+ param_ptr_binlog_stmt_cache_use,
+ param_ptr_binlog_stmt_cache_disk_use);
+ trx_cache.set_binlog_cache_info(param_max_binlog_cache_size,
+ param_ptr_binlog_cache_use,
+ param_ptr_binlog_cache_disk_use);
+ }
+
+ void reset_cache(binlog_cache_data* cache_data)
+ {
+ cache_data->reset();
+ }
+
+ binlog_cache_data* get_binlog_cache_data(bool is_transactional)
+ {
+ return (is_transactional ? &trx_cache : &stmt_cache);
+ }
+
+ IO_CACHE* get_binlog_cache_log(bool is_transactional)
+ {
+ return (is_transactional ? &trx_cache.cache_log : &stmt_cache.cache_log);
+ }
+
+ binlog_cache_data stmt_cache;
+
+ binlog_cache_data trx_cache;
+
+private:
+
+ binlog_cache_mngr& operator=(const binlog_cache_mngr& info);
+ binlog_cache_mngr(const binlog_cache_mngr& info);
};
handlerton *binlog_hton;
@@ -276,8 +472,8 @@ bool LOGGER::is_log_table_enabled(uint log_table_type)
/* Check if a given table is opened log table */
-int check_if_log_table(uint db_len, const char *db, uint table_name_len,
- const char *table_name, uint check_if_opened)
+int check_if_log_table(size_t db_len, const char *db, size_t table_name_len,
+ const char *table_name, bool check_if_opened)
{
if (db_len == 5 &&
!(lower_case_table_names ?
@@ -369,7 +565,7 @@ bool Log_to_csv_event_handler::
bool need_rnd_end= FALSE;
uint field_index;
Silence_log_table_errors error_handler;
- Open_tables_state open_tables_backup;
+ Open_tables_backup open_tables_backup;
ulonglong save_thd_options;
bool save_time_zone_used;
@@ -379,20 +575,16 @@ bool Log_to_csv_event_handler::
*/
save_time_zone_used= thd->time_zone_used;
- save_thd_options= thd->options;
- thd->options&= ~OPTION_BIN_LOG;
-
- bzero(& table_list, sizeof(TABLE_LIST));
- table_list.alias= table_list.table_name= GENERAL_LOG_NAME.str;
- table_list.table_name_length= GENERAL_LOG_NAME.length;
-
- table_list.lock_type= TL_WRITE_CONCURRENT_INSERT;
+ save_thd_options= thd->variables.option_bits;
+ thd->variables.option_bits&= ~OPTION_BIN_LOG;
- table_list.db= MYSQL_SCHEMA_NAME.str;
- table_list.db_length= MYSQL_SCHEMA_NAME.length;
+ table_list.init_one_table(MYSQL_SCHEMA_NAME.str, MYSQL_SCHEMA_NAME.length,
+ GENERAL_LOG_NAME.str, GENERAL_LOG_NAME.length,
+ GENERAL_LOG_NAME.str,
+ TL_WRITE_CONCURRENT_INSERT);
/*
- 1) open_performance_schema_table generates an error of the
+ 1) open_log_table generates an error of the
table can not be opened or is corrupted.
2) "INSERT INTO general_log" can generate warning sometimes.
@@ -405,8 +597,7 @@ bool Log_to_csv_event_handler::
thd->push_internal_handler(& error_handler);
need_pop= TRUE;
- if (!(table= open_performance_schema_table(thd, & table_list,
- & open_tables_backup)))
+ if (!(table= open_log_table(thd, &table_list, &open_tables_backup)))
goto err;
need_close= TRUE;
@@ -486,9 +677,9 @@ err:
if (need_pop)
thd->pop_internal_handler();
if (need_close)
- close_performance_schema_table(thd, & open_tables_backup);
+ close_log_table(thd, &open_tables_backup);
- thd->options= save_thd_options;
+ thd->variables.option_bits= save_thd_options;
thd->time_zone_used= save_time_zone_used;
return result;
}
@@ -535,7 +726,7 @@ bool Log_to_csv_event_handler::
bool need_close= FALSE;
bool need_rnd_end= FALSE;
Silence_log_table_errors error_handler;
- Open_tables_state open_tables_backup;
+ Open_tables_backup open_tables_backup;
CHARSET_INFO *client_cs= thd->variables.character_set_client;
bool save_time_zone_used;
DBUG_ENTER("Log_to_csv_event_handler::log_slow");
@@ -547,17 +738,12 @@ bool Log_to_csv_event_handler::
*/
save_time_zone_used= thd->time_zone_used;
- bzero(& table_list, sizeof(TABLE_LIST));
- table_list.alias= table_list.table_name= SLOW_LOG_NAME.str;
- table_list.table_name_length= SLOW_LOG_NAME.length;
+ table_list.init_one_table(MYSQL_SCHEMA_NAME.str, MYSQL_SCHEMA_NAME.length,
+ SLOW_LOG_NAME.str, SLOW_LOG_NAME.length,
+ SLOW_LOG_NAME.str,
+ TL_WRITE_CONCURRENT_INSERT);
- table_list.lock_type= TL_WRITE_CONCURRENT_INSERT;
-
- table_list.db= MYSQL_SCHEMA_NAME.str;
- table_list.db_length= MYSQL_SCHEMA_NAME.length;
-
- if (!(table= open_performance_schema_table(thd, & table_list,
- & open_tables_backup)))
+ if (!(table= open_log_table(thd, &table_list, &open_tables_backup)))
goto err;
need_close= TRUE;
@@ -682,7 +868,7 @@ err:
table->file->ha_release_auto_increment();
}
if (need_close)
- close_performance_schema_table(thd, & open_tables_backup);
+ close_log_table(thd, &open_tables_backup);
thd->time_zone_used= save_time_zone_used;
DBUG_RETURN(result);
}
@@ -692,36 +878,31 @@ int Log_to_csv_event_handler::
{
TABLE_LIST table_list;
TABLE *table;
+ LEX_STRING *UNINIT_VAR(log_name);
int result;
- Open_tables_state open_tables_backup;
+ Open_tables_backup open_tables_backup;
DBUG_ENTER("Log_to_csv_event_handler::activate_log");
- bzero(& table_list, sizeof(TABLE_LIST));
-
if (log_table_type == QUERY_LOG_GENERAL)
{
- table_list.alias= table_list.table_name= GENERAL_LOG_NAME.str;
- table_list.table_name_length= GENERAL_LOG_NAME.length;
+ log_name= &GENERAL_LOG_NAME;
}
else
{
DBUG_ASSERT(log_table_type == QUERY_LOG_SLOW);
- table_list.alias= table_list.table_name= SLOW_LOG_NAME.str;
- table_list.table_name_length= SLOW_LOG_NAME.length;
- }
- table_list.lock_type= TL_WRITE_CONCURRENT_INSERT;
-
- table_list.db= MYSQL_SCHEMA_NAME.str;
- table_list.db_length= MYSQL_SCHEMA_NAME.length;
+ log_name= &SLOW_LOG_NAME;
+ }
+ table_list.init_one_table(MYSQL_SCHEMA_NAME.str, MYSQL_SCHEMA_NAME.length,
+ log_name->str, log_name->length, log_name->str,
+ TL_WRITE_CONCURRENT_INSERT);
- table= open_performance_schema_table(thd, & table_list,
- & open_tables_backup);
+ table= open_log_table(thd, &table_list, &open_tables_backup);
if (table)
{
result= 0;
- close_performance_schema_table(thd, & open_tables_backup);
+ close_log_table(thd, &open_tables_backup);
}
else
result= 1;
@@ -797,10 +978,10 @@ bool Log_to_file_event_handler::init()
if (!is_initialized)
{
if (opt_slow_log)
- mysql_slow_log.open_slow_log(sys_var_slow_log_path.value);
+ mysql_slow_log.open_slow_log(opt_slow_logname);
if (opt_log)
- mysql_log.open_query_log(sys_var_general_log_path.value);
+ mysql_log.open_query_log(opt_logname);
is_initialized= TRUE;
}
@@ -857,7 +1038,7 @@ bool LOGGER::error_log_print(enum loglevel level, const char *format,
void LOGGER::cleanup_base()
{
DBUG_ASSERT(inited == 1);
- rwlock_destroy(&LOCK_logger);
+ mysql_rwlock_destroy(&LOCK_logger);
if (table_log_handler)
{
table_log_handler->cleanup();
@@ -902,7 +1083,7 @@ void LOGGER::init_base()
init_error_log(LOG_FILE);
file_log_handler->init_pthread_objects();
- my_rwlock_init(&LOCK_logger, NULL);
+ mysql_rwlock_init(key_rwlock_LOCK_logger, &LOCK_logger);
}
@@ -936,6 +1117,54 @@ bool LOGGER::flush_logs(THD *thd)
}
+/**
+ Close and reopen the slow log (with locks).
+
+ @returns FALSE.
+*/
+bool LOGGER::flush_slow_log()
+{
+ /*
+ Now we lock logger, as nobody should be able to use logging routines while
+ log tables are closed
+ */
+ logger.lock_exclusive();
+
+ /* Reopen slow log file */
+ if (opt_slow_log)
+ file_log_handler->get_mysql_slow_log()->reopen_file();
+
+ /* End of log flush */
+ logger.unlock();
+
+ return 0;
+}
+
+
+/**
+ Close and reopen the general log (with locks).
+
+ @returns FALSE.
+*/
+bool LOGGER::flush_general_log()
+{
+ /*
+ Now we lock logger, as nobody should be able to use logging routines while
+ log tables are closed
+ */
+ logger.lock_exclusive();
+
+ /* Reopen general log file */
+ if (opt_log)
+ file_log_handler->get_mysql_log()->reopen_file();
+
+ /* End of log flush */
+ logger.unlock();
+
+ return 0;
+}
+
+
/*
Log slow query with all enabled log event handlers
@@ -1027,7 +1256,6 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command,
bool error= FALSE;
Log_event_handler **current_handler= general_log_handler_list;
char user_host_buff[MAX_USER_HOST_SIZE + 1];
- Security_context *sctx= thd->security_ctx;
uint user_host_len= 0;
time_t current_time;
@@ -1039,14 +1267,16 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command,
unlock();
return 0;
}
- user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE,
- sctx->priv_user ? sctx->priv_user : "", "[",
- sctx->user ? sctx->user : "", "] @ ",
- sctx->host ? sctx->host : "", " [",
- sctx->ip ? sctx->ip : "", "]", NullS) -
- user_host_buff;
+ user_host_len= make_user_name(thd, user_host_buff);
current_time= my_time(0);
+
+ mysql_audit_general_log(thd, current_time,
+ user_host_buff, user_host_len,
+ command_name[(uint) command].str,
+ command_name[(uint) command].length,
+ query, query_length);
+
while (*current_handler)
error|= (*current_handler++)->
log_general(thd, current_time, user_host_buff,
@@ -1161,7 +1391,7 @@ bool LOGGER::activate_log_handler(THD* thd, uint log_type)
{
file_log= file_log_handler->get_mysql_slow_log();
- file_log->open_slow_log(sys_var_slow_log_path.value);
+ file_log->open_slow_log(opt_slow_logname);
if (table_log_handler->activate_log(thd, QUERY_LOG_SLOW))
{
/* Error printed by open table in activate_log() */
@@ -1180,7 +1410,7 @@ bool LOGGER::activate_log_handler(THD* thd, uint log_type)
{
file_log= file_log_handler->get_mysql_log();
- file_log->open_query_log(sys_var_general_log_path.value);
+ file_log->open_query_log(opt_logname);
if (table_log_handler->activate_log(thd, QUERY_LOG_GENERAL))
{
/* Error printed by open table in activate_log() */
@@ -1264,26 +1494,6 @@ int LOGGER::set_handlers(uint error_log_printer,
return 0;
}
-/**
- This function checks if a transactional talbe was updated by the
- current statement.
-
- @param thd The client thread that executed the current statement.
- @return
- @c true if a transactional table was updated, @false otherwise.
-*/
-static bool stmt_has_updated_trans_table(THD *thd)
-{
- Ha_trx_info *ha_info;
-
- for (ha_info= thd->transaction.stmt.ha_list; ha_info && ha_info->is_started(); ha_info= ha_info->next())
- {
- if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton)
- return (TRUE);
- }
- return (FALSE);
-}
-
/*
Save position of binary log transaction cache.
@@ -1306,10 +1516,10 @@ binlog_trans_log_savepos(THD *thd, my_off_t *pos)
DBUG_ASSERT(pos != NULL);
if (thd_get_ha_data(thd, binlog_hton) == NULL)
thd->binlog_setup_trx_data();
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
DBUG_ASSERT(mysql_bin_log.is_open());
- *pos= trx_data->position();
+ *pos= cache_mngr->trx_cache.get_byte_position();
DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos));
DBUG_VOID_RETURN;
}
@@ -1340,9 +1550,9 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos)
/* Only true if binlog_trans_log_savepos() wasn't called before */
DBUG_ASSERT(pos != ~(my_off_t) 0);
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
- trx_data->truncate(pos);
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+ cache_mngr->trx_cache.restore_savepoint(pos);
DBUG_VOID_RETURN;
}
@@ -1371,60 +1581,37 @@ int binlog_init(void *p)
static int binlog_close_connection(handlerton *hton, THD *thd)
{
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
- DBUG_ASSERT(trx_data->empty());
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+ DBUG_ASSERT(cache_mngr->trx_cache.empty() && cache_mngr->stmt_cache.empty());
thd_set_ha_data(thd, binlog_hton, NULL);
- trx_data->~binlog_trx_data();
- my_free((uchar*)trx_data, MYF(0));
+ cache_mngr->~binlog_cache_mngr();
+ my_free(cache_mngr);
return 0;
}
-/*
- End a transaction.
-
- SYNOPSIS
- binlog_end_trans()
-
- thd The thread whose transaction should be ended
- trx_data Pointer to the transaction data to use
- end_ev The end event to use, or NULL
- all True if the entire transaction should be ended, false if
- only the statement transaction should be ended.
-
- DESCRIPTION
+/**
+ This function flushes a cache upon commit/rollback.
- End the currently open transaction. The transaction can be either
- a real transaction (if 'all' is true) or a statement transaction
- (if 'all' is false).
+ @param thd The thread whose transaction should be flushed
+ @param cache_data Pointer to the cache
+ @param end_ev The end event either commit/rollback
+ @param is_transactional The type of the cache: transactional or
+ non-transactional
- If 'end_ev' is NULL, the transaction is a rollback of only
- transactional tables, so the transaction cache will be truncated
- to either just before the last opened statement transaction (if
- 'all' is false), or reset completely (if 'all' is true).
- */
-static int
-binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
- Log_event *end_ev, bool all)
+ @return
+ nonzero if an error pops up when flushing the cache.
+*/
+static inline int
+binlog_flush_cache(THD *thd, binlog_cache_data* cache_data, Log_event *end_evt,
+ bool is_transactional)
{
- DBUG_ENTER("binlog_end_trans");
- int error=0;
- IO_CACHE *trans_log= &trx_data->trans_log;
- DBUG_PRINT("enter", ("transaction: %s end_ev: 0x%lx",
- all ? "all" : "stmt", (long) end_ev));
- DBUG_PRINT("info", ("thd->options={ %s%s}",
- FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
- FLAGSTR(thd->options, OPTION_BEGIN)));
+ DBUG_ENTER("binlog_flush_cache");
+ int error= 0;
- /*
- NULL denotes ROLLBACK with nothing to replicate: i.e., rollback of
- only transactional tables. If the transaction contain changes to
- any non-transactiona tables, we need write the transaction and log
- a ROLLBACK last.
- */
- if (end_ev != NULL)
+ if (!cache_data->empty())
{
- if (thd->binlog_flush_pending_rows_event(TRUE))
+ if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
DBUG_RETURN(1);
/*
Doing a commit or a rollback including non-transactional tables,
@@ -1432,42 +1619,143 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
cache to the binary log.
We can always end the statement when ending a transaction since
- transactions are not allowed inside stored functions. If they
+ transactions are not allowed inside stored functions. If they
were, we would have to ensure that we're not ending a statement
inside a stored function.
- */
- error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev,
- trx_data->has_incident());
- trx_data->reset();
-
- statistic_increment(binlog_cache_use, &LOCK_status);
- if (trans_log->disk_writes != 0)
- {
- statistic_increment(binlog_cache_disk_use, &LOCK_status);
- trans_log->disk_writes= 0;
- }
+ */
+ error= mysql_bin_log.write(thd, &cache_data->cache_log, end_evt,
+ cache_data->has_incident());
}
- else
+ cache_data->reset();
+
+ DBUG_ASSERT(cache_data->empty());
+ DBUG_RETURN(error);
+}
+
+/**
+ This function flushes the stmt-cache upon commit.
+
+ @param thd The thread whose transaction should be flushed
+ @param cache_mngr Pointer to the cache manager
+
+ @return
+ nonzero if an error pops up when flushing the cache.
+*/
+static inline int
+binlog_commit_flush_stmt_cache(THD *thd,
+ binlog_cache_mngr *cache_mngr)
+{
+ Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
+ FALSE, FALSE, TRUE, 0);
+ return (binlog_flush_cache(thd, &cache_mngr->stmt_cache, &end_evt,
+ FALSE));
+}
+
+/**
+ This function flushes the trx-cache upon commit.
+
+ @param thd The thread whose transaction should be flushed
+ @param cache_mngr Pointer to the cache manager
+
+ @return
+ nonzero if an error pops up when flushing the cache.
+*/
+static inline int
+binlog_commit_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr)
+{
+ Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
+ TRUE, FALSE, TRUE, 0);
+ return (binlog_flush_cache(thd, &cache_mngr->trx_cache, &end_evt,
+ TRUE));
+}
+
+/**
+ This function flushes the trx-cache upon rollback.
+
+ @param thd The thread whose transaction should be flushed
+ @param cache_mngr Pointer to the cache manager
+
+ @return
+ nonzero if an error pops up when flushing the cache.
+*/
+static inline int
+binlog_rollback_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr)
+{
+ Query_log_event end_evt(thd, STRING_WITH_LEN("ROLLBACK"),
+ TRUE, FALSE, TRUE, 0);
+ return (binlog_flush_cache(thd, &cache_mngr->trx_cache, &end_evt,
+ TRUE));
+}
+
+/**
+ This function flushes the trx-cache upon commit.
+
+ @param thd The thread whose transaction should be flushed
+ @param cache_mngr Pointer to the cache manager
+ @param xid Transaction Id
+
+ @return
+ nonzero if an error pops up when flushing the cache.
+*/
+static inline int
+binlog_commit_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr,
+ my_xid xid)
+{
+ Xid_log_event end_evt(thd, xid);
+ return (binlog_flush_cache(thd, &cache_mngr->trx_cache, &end_evt,
+ TRUE));
+}
+
+/**
+ This function truncates the transactional cache upon committing or rolling
+ back either a transaction or a statement.
+
+ @param thd The thread whose transaction should be flushed
+ @param cache_mngr Pointer to the cache data to be flushed
+ @param all @c true means truncate the transaction, otherwise the
+ statement must be truncated.
+
+ @return
+ nonzero if an error pops up when truncating the transactional cache.
+*/
+static int
+binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
+{
+ DBUG_ENTER("binlog_truncate_trx_cache");
+ int error=0;
+ /*
+ This function handles transactional changes and as such this flag
+ equals to true.
+ */
+ bool const is_transactional= TRUE;
+
+ DBUG_PRINT("info", ("thd->options={ %s %s}, transaction: %s",
+ FLAGSTR(thd->variables.option_bits, OPTION_NOT_AUTOCOMMIT),
+ FLAGSTR(thd->variables.option_bits, OPTION_BEGIN),
+ all ? "all" : "stmt"));
+
+ thd->binlog_remove_pending_rows_event(TRUE, is_transactional);
+ /*
+ If rolling back an entire transaction or a single statement not
+ inside a transaction, we reset the transaction cache.
+ */
+ if (ending_trans(thd, all))
{
- /*
- If rolling back an entire transaction or a single statement not
- inside a transaction, we reset the transaction cache.
+ if (cache_mngr->trx_cache.has_incident())
+ error= mysql_bin_log.write_incident(thd, TRUE);
- If rolling back a statement in a transaction, we truncate the
- transaction cache to remove the statement.
- */
- thd->binlog_remove_pending_rows_event(TRUE);
- if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
- {
- if (trx_data->has_incident())
- error= mysql_bin_log.write_incident(thd, TRUE);
- trx_data->reset();
- }
- else // ...statement
- trx_data->truncate(trx_data->before_stmt_pos);
+ thd->clear_binlog_table_maps();
+
+ cache_mngr->reset_cache(&cache_mngr->trx_cache);
}
+ /*
+ If rolling back a statement in a transaction, we truncate the
+ transaction cache to remove the statement.
+ */
+ else
+ cache_mngr->trx_cache.restore_prev_position();
- DBUG_ASSERT(thd->binlog_get_pending_rows_event() == NULL);
+ DBUG_ASSERT(thd->binlog_get_pending_rows_event(is_transactional) == NULL);
DBUG_RETURN(error);
}
@@ -1485,8 +1773,7 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all)
/**
This function is called once after each statement.
- It has the responsibility to flush the transaction cache to the
- binlog file on commits.
+ It has the responsibility to flush the caches to the binary log on commits.
@param hton The binlog handlerton.
@param thd The client thread that executes the transaction.
@@ -1499,53 +1786,50 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
{
int error= 0;
DBUG_ENTER("binlog_commit");
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
- if (trx_data->empty())
- {
- // we're here because trans_log was flushed in MYSQL_BIN_LOG::log_xid()
- trx_data->reset();
- DBUG_RETURN(0);
- }
-
- /*
- We flush the cache if:
-
- - we are committing a transaction or;
- - no statement was committed before and just non-transactional
- tables were updated.
-
- Otherwise, we collect the changes.
- */
DBUG_PRINT("debug",
- ("all: %d, empty: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s",
+ ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s",
all,
- YESNO(trx_data->empty()),
+ YESNO(thd->in_multi_stmt_transaction_mode()),
YESNO(thd->transaction.all.modified_non_trans_table),
YESNO(thd->transaction.stmt.modified_non_trans_table)));
- if (ending_trans(thd, all) ||
- (trans_has_no_stmt_committed(thd, all) &&
- !stmt_has_updated_trans_table(thd) && stmt_has_updated_non_trans_table(thd)))
+
+ if (!cache_mngr->stmt_cache.empty())
{
- Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, TRUE, 0);
- error= binlog_end_trans(thd, trx_data, &qev, all);
+ error= binlog_commit_flush_stmt_cache(thd, cache_mngr);
}
- trx_data->at_least_one_stmt_committed = my_b_tell(&trx_data->trans_log) > 0;
+ if (cache_mngr->trx_cache.empty())
+ {
+ /*
+ we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
+ */
+ cache_mngr->reset_cache(&cache_mngr->trx_cache);
+ DBUG_RETURN(error);
+ }
+
+ /*
+ We commit the transaction if:
+ - We are not in a transaction and committing a statement, or
+ - We are in a transaction and a full transaction is committed.
+ Otherwise, we accumulate the changes.
+ */
+ if (!error && ending_trans(thd, all))
+ error= binlog_commit_flush_trx_cache(thd, cache_mngr);
+ /*
+ This is part of the stmt rollback.
+ */
if (!all)
- trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt commit
+ cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
+
DBUG_RETURN(error);
}
/**
- This function is called when a transaction involving a transactional
- table is rolled back.
-
- It has the responsibility to flush the transaction cache to the
- binlog file. However, if the transaction does not involve
- non-transactional tables, nothing needs to be logged.
+ This function is called when a transaction or a statement is rolled back.
@param hton The binlog handlerton.
@param thd The client thread that executes the transaction.
@@ -1557,19 +1841,38 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
static int binlog_rollback(handlerton *hton, THD *thd, bool all)
{
DBUG_ENTER("binlog_rollback");
- int error=0;
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
-
- if (trx_data->empty()) {
- trx_data->reset();
- DBUG_RETURN(0);
- }
+ int error= 0;
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s",
YESNO(all),
YESNO(thd->transaction.all.modified_non_trans_table),
YESNO(thd->transaction.stmt.modified_non_trans_table)));
+
+ /*
+ If an incident event is set we do not flush the content of the statement
+ cache because it may be corrupted.
+ */
+ if (cache_mngr->stmt_cache.has_incident())
+ {
+ error= mysql_bin_log.write_incident(thd, TRUE);
+ cache_mngr->reset_cache(&cache_mngr->stmt_cache);
+ }
+ else if (!cache_mngr->stmt_cache.empty())
+ {
+ error= binlog_commit_flush_stmt_cache(thd, cache_mngr);
+ }
+
+ if (cache_mngr->trx_cache.empty())
+ {
+ /*
+ we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
+ */
+ cache_mngr->reset_cache(&cache_mngr->trx_cache);
+ DBUG_RETURN(error);
+ }
+
if (mysql_bin_log.check_write_error(thd))
{
/*
@@ -1580,68 +1883,61 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
*/
DBUG_ASSERT(!all);
/*
- We reach this point if either only transactional tables were modified or
- the effect of a statement that did not get into the binlog needs to be
- rolled back. In the latter case, if a statement changed non-transactional
- tables or had the OPTION_KEEP_LOG associated, we write an incident event
- to the binlog in order to stop slaves and notify users that some changes
- on the master did not get into the binlog and slaves will be inconsistent.
- On the other hand, if a statement is transactional, we just safely roll it
- back.
+ We reach this point if the effect of a statement did not properly get into
+ a cache and need to be rolled back.
*/
- if ((stmt_has_updated_non_trans_table(thd) ||
- (thd->options & OPTION_KEEP_LOG)) &&
- mysql_bin_log.check_write_error(thd))
- trx_data->set_incident();
- error= binlog_end_trans(thd, trx_data, 0, all);
+ error |= binlog_truncate_trx_cache(thd, cache_mngr, all);
}
- else
- {
- /*
- We flush the cache with a rollback, wrapped in a beging/rollback if:
- . aborting a transaction that modified a non-transactional table or
- the OPTION_KEEP_LOG is activate.
- . aborting a statement that modified both transactional and
- non-transactional tables but which is not in the boundaries of any
- transaction or there was no early change;
+ else if (!error)
+ {
+ /*
+ We flush the cache wrapped in a beging/rollback if:
+ . aborting a single or multi-statement transaction and;
+ . the OPTION_KEEP_LOG is active or;
+ . the format is STMT and a non-trans table was updated or;
+ . the format is MIXED and a temporary non-trans table was
+ updated or;
+ . the format is MIXED, non-trans table was updated and
+ aborting a single statement transaction;
*/
- if ((ending_trans(thd, all) &&
- (trans_has_updated_non_trans_table(thd) ||
- (thd->options & OPTION_KEEP_LOG))) ||
- (trans_has_no_stmt_committed(thd, all) &&
- stmt_has_updated_non_trans_table(thd) &&
- thd->current_stmt_binlog_row_based))
- {
- Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, TRUE, 0);
- error= binlog_end_trans(thd, trx_data, &qev, all);
- }
+ if (ending_trans(thd, all) &&
+ ((thd->variables.option_bits & OPTION_KEEP_LOG) ||
+ (trans_has_updated_non_trans_table(thd) &&
+ thd->variables.binlog_format == BINLOG_FORMAT_STMT) ||
+ (cache_mngr->trx_cache.changes_to_non_trans_temp_table() &&
+ thd->variables.binlog_format == BINLOG_FORMAT_MIXED) ||
+ (trans_has_updated_non_trans_table(thd) &&
+ ending_single_stmt_trans(thd,all) &&
+ thd->variables.binlog_format == BINLOG_FORMAT_MIXED)))
+ error= binlog_rollback_flush_trx_cache(thd, cache_mngr);
/*
- Otherwise, we simply truncate the cache as there is no change on
- non-transactional tables as follows.
+ Truncate the cache if:
+ . aborting a single or multi-statement transaction or;
+ . the OPTION_KEEP_LOG is not active and;
+ . the format is not STMT or no non-trans table was
+ updated and;
+ . the format is not MIXED or no temporary non-trans table
+ was updated.
*/
else if (ending_trans(thd, all) ||
- (!(thd->options & OPTION_KEEP_LOG) && !stmt_has_updated_non_trans_table(thd)))
- error= binlog_end_trans(thd, trx_data, 0, all);
+ (!(thd->variables.option_bits & OPTION_KEEP_LOG) &&
+ (!stmt_has_updated_non_trans_table(thd) ||
+ thd->variables.binlog_format != BINLOG_FORMAT_STMT) &&
+ (!cache_mngr->trx_cache.changes_to_non_trans_temp_table() ||
+ thd->variables.binlog_format != BINLOG_FORMAT_MIXED)))
+ error= binlog_truncate_trx_cache(thd, cache_mngr, all);
}
- if (!all)
- trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt rollback
- DBUG_RETURN(error);
-}
-
-/**
- Cleanup the cache.
- @param thd The client thread that wants to clean up the cache.
-*/
-void MYSQL_BIN_LOG::reset_gathered_updates(THD *thd)
-{
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
+ /*
+ This is part of the stmt rollback.
+ */
+ if (!all)
+ cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
- trx_data->reset();
+ DBUG_RETURN(error);
}
-void MYSQL_BIN_LOG::set_write_error(THD *thd)
+void MYSQL_BIN_LOG::set_write_error(THD *thd, bool is_transactional)
{
DBUG_ENTER("MYSQL_BIN_LOG::set_write_error");
@@ -1651,9 +1947,20 @@ void MYSQL_BIN_LOG::set_write_error(THD *thd)
DBUG_VOID_RETURN;
if (my_errno == EFBIG)
- my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(MY_WME));
+ {
+ if (is_transactional)
+ {
+ my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(MY_WME));
+ }
+ else
+ {
+ my_message(ER_STMT_CACHE_FULL, ER(ER_STMT_CACHE_FULL), MYF(MY_WME));
+ }
+ }
else
+ {
my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), name, errno);
+ }
DBUG_VOID_RETURN;
}
@@ -1667,9 +1974,10 @@ bool MYSQL_BIN_LOG::check_write_error(THD *thd)
if (!thd->is_error())
DBUG_RETURN(checked);
- switch (thd->main_da.sql_errno())
+ switch (thd->stmt_da->sql_errno())
{
case ER_TRANS_CACHE_FULL:
+ case ER_STMT_CACHE_FULL:
case ER_ERROR_ON_WRITE:
case ER_BINLOG_LOGGING_IMPOSSIBLE:
checked= TRUE;
@@ -1718,7 +2026,7 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
DBUG_RETURN(1);
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(),
- TRUE, TRUE, errcode);
+ TRUE, FALSE, TRUE, errcode);
DBUG_RETURN(mysql_bin_log.write(&qinfo));
}
@@ -1731,8 +2039,8 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
non-transactional table. Otherwise, truncate the binlog cache starting
from the SAVEPOINT command.
*/
- if (unlikely(trans_has_updated_non_trans_table(thd) ||
- (thd->options & OPTION_KEEP_LOG)))
+ if (unlikely(trans_has_updated_non_trans_table(thd) ||
+ (thd->variables.option_bits & OPTION_KEEP_LOG)))
{
String log_query;
if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")) ||
@@ -1742,7 +2050,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
DBUG_RETURN(1);
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(),
- TRUE, TRUE, errcode);
+ TRUE, FALSE, TRUE, errcode);
DBUG_RETURN(mysql_bin_log.write(&qinfo));
}
binlog_trans_log_truncate(thd, *(my_off_t*)sv);
@@ -1776,8 +2084,9 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
File file;
DBUG_ENTER("open_binlog");
- if ((file = my_open(log_file_name, O_RDONLY | O_BINARY | O_SHARE,
- MYF(MY_WME))) < 0)
+ if ((file= mysql_file_open(key_file_binlog,
+ log_file_name, O_RDONLY | O_BINARY | O_SHARE,
+ MYF(MY_WME))) < 0)
{
sql_print_error("Failed to open log (file '%s', errno %d)",
log_file_name, my_errno);
@@ -1799,13 +2108,13 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
err:
if (file >= 0)
{
- my_close(file,MYF(0));
+ mysql_file_close(file, MYF(0));
end_io_cache(log);
}
DBUG_RETURN(-1);
}
-#ifdef __NT__
+#ifdef _WIN32
static int eventSource = 0;
static void setup_windows_event_source()
@@ -1840,28 +2149,33 @@ static void setup_windows_event_source()
RegCloseKey(hRegKey);
}
-#endif /* __NT__ */
+#endif /* _WIN32 */
/**
Find a unique filename for 'filename.#'.
- Set '#' to a number as low as possible.
+ Set '#' to the number next to the maximum found in the most
+ recent log file extension.
+
+ This function will return nonzero if: (i) the generated name
+ exceeds FN_REFLEN; (ii) if the number of extensions is exhausted;
+ or (iii) some other error happened while examining the filesystem.
@return
- nonzero if not possible to get unique filename
+ nonzero if not possible to get unique filename.
*/
static int find_uniq_filename(char *name)
{
- long number;
uint i;
- char buff[FN_REFLEN];
+ char buff[FN_REFLEN], ext_buf[FN_REFLEN];
struct st_my_dir *dir_info;
reg1 struct fileinfo *file_info;
- ulong max_found=0;
+ ulong max_found= 0, next= 0, number= 0;
size_t buf_length, length;
char *start, *end;
+ int error= 0;
DBUG_ENTER("find_uniq_filename");
length= dirname_part(buff, name, &buf_length);
@@ -1869,16 +2183,16 @@ static int find_uniq_filename(char *name)
end= strend(start);
*end='.';
- length= (size_t) (end-start+1);
+ length= (size_t) (end - start + 1);
if ((DBUG_EVALUATE_IF("error_unique_log_filename", 1,
- !(dir_info = my_dir(buff,MYF(MY_DONT_SORT))))))
+ !(dir_info= my_dir(buff,MYF(MY_DONT_SORT))))))
{ // This shouldn't happen
strmov(end,".1"); // use name+1
DBUG_RETURN(1);
}
file_info= dir_info->dir_entry;
- for (i=dir_info->number_off_files ; i-- ; file_info++)
+ for (i= dir_info->number_off_files ; i-- ; file_info++)
{
if (memcmp(file_info->name, start, length) == 0 &&
test_if_number(file_info->name+length, &number,0))
@@ -1888,8 +2202,52 @@ static int find_uniq_filename(char *name)
}
my_dirend(dir_info);
+ /* check if reached the maximum possible extension number */
+ if ((max_found == MAX_LOG_UNIQUE_FN_EXT))
+ {
+ sql_print_error("Log filename extension number exhausted: %06lu. \
+Please fix this by archiving old logs and \
+updating the index files.", max_found);
+ error= 1;
+ goto end;
+ }
+
+ next= max_found + 1;
+ if (sprintf(ext_buf, "%06lu", next)<0)
+ {
+ error= 1;
+ goto end;
+ }
*end++='.';
- DBUG_RETURN((sprintf(end,"%06ld",max_found+1) < 0));
+
+ /*
+ Check if the generated extension size + the file name exceeds the
+ buffer size used. If one did not check this, then the filename might be
+ truncated, resulting in error.
+ */
+ if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN))
+ {
+ sql_print_error("Log filename too large: %s%s (%zu). \
+Please fix this by archiving old logs and updating the \
+index files.", name, ext_buf, (strlen(ext_buf) + (end - name)));
+ error= 1;
+ goto end;
+ }
+
+ if (sprintf(end, "%06lu", next)<0)
+ {
+ error= 1;
+ goto end;
+ }
+
+ /* print warning if reaching the end of available extensions. */
+ if ((next > (MAX_LOG_UNIQUE_FN_EXT - LOG_WARN_UNIQUE_FN_EXT_LEFT)))
+ sql_print_warning("Next log extension: %lu. \
+Remaining log filename extensions: %lu. \
+Please consider archiving some logs.", next, (MAX_LOG_UNIQUE_FN_EXT - next));
+
+end:
+ DBUG_RETURN(error);
}
@@ -1941,7 +2299,11 @@ bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
1 error
*/
-bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
+bool MYSQL_LOG::open(
+#ifdef HAVE_PSI_INTERFACE
+ PSI_file_key log_file_key,
+#endif
+ const char *log_name, enum_log_type log_type_arg,
const char *new_name, enum cache_type io_cache_type_arg)
{
char buff[FN_REFLEN];
@@ -1969,10 +2331,16 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
db[0]= 0;
- if ((file= my_open(log_file_name, open_flags,
- MYF(MY_WME | ME_WAITTANG))) < 0 ||
+#ifdef HAVE_PSI_INTERFACE
+ /* Keep the key for reopen */
+ m_log_file_key= log_file_key;
+#endif
+
+ if ((file= mysql_file_open(log_file_key,
+ log_file_name, open_flags,
+ MYF(MY_WME | ME_WAITTANG))) < 0 ||
init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
- my_tell(file, MYF(MY_WME)), 0,
+ mysql_file_tell(file, MYF(MY_WME)), 0,
MYF(MY_WME | MY_NABP |
((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0))))
goto err;
@@ -1984,7 +2352,7 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
#ifdef EMBEDDED_LIBRARY
"embedded library\n",
my_progname, server_version, MYSQL_COMPILATION_COMMENT
-#elif __NT__
+#elif _WIN32
"started with:\nTCP Port: %d, Named Pipe: %s\n",
my_progname, server_version, MYSQL_COMPILATION_COMMENT,
mysqld_port, mysqld_unix_port
@@ -2010,9 +2378,10 @@ Turning logging off for the whole duration of the MySQL server process. \
To turn it on again: fix the cause, \
shutdown the MySQL server and restart it.", name, errno);
if (file >= 0)
- my_close(file, MYF(0));
+ mysql_file_close(file, MYF(0));
end_io_cache(&log_file);
- safeFree(name);
+ my_free(name);
+ name= NULL;
log_state= LOG_CLOSED;
DBUG_RETURN(1);
}
@@ -2034,7 +2403,7 @@ void MYSQL_LOG::init_pthread_objects()
{
DBUG_ASSERT(inited == 0);
inited= 1;
- (void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
+ mysql_mutex_init(key_LOG_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
}
/*
@@ -2059,13 +2428,13 @@ void MYSQL_LOG::close(uint exiting)
{
end_io_cache(&log_file);
- if (my_sync(log_file.file, MYF(MY_WME)) && ! write_error)
+ if (mysql_file_sync(log_file.file, MYF(MY_WME)) && ! write_error)
{
write_error= 1;
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
}
- if (my_close(log_file.file, MYF(MY_WME)) && ! write_error)
+ if (mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error)
{
write_error= 1;
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
@@ -2073,7 +2442,8 @@ void MYSQL_LOG::close(uint exiting)
}
log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
- safeFree(name);
+ my_free(name);
+ name= NULL;
DBUG_VOID_RETURN;
}
@@ -2085,7 +2455,7 @@ void MYSQL_LOG::cleanup()
if (inited)
{
inited= 0;
- (void) pthread_mutex_destroy(&LOCK_log);
+ mysql_mutex_destroy(&LOCK_log);
close(0);
}
DBUG_VOID_RETURN;
@@ -2135,7 +2505,7 @@ void MYSQL_QUERY_LOG::reopen_file()
DBUG_VOID_RETURN;
}
- pthread_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_log);
save_name= name;
name= 0; // Don't free name
@@ -2145,10 +2515,14 @@ void MYSQL_QUERY_LOG::reopen_file()
Note that at this point, log_state != LOG_CLOSED (important for is_open()).
*/
- open(save_name, log_type, 0, io_cache_type);
- my_free(save_name, MYF(0));
+ open(
+#ifdef HAVE_PSI_INTERFACE
+ m_log_file_key,
+#endif
+ save_name, log_type, 0, io_cache_type);
+ my_free(save_name);
- pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
DBUG_VOID_RETURN;
}
@@ -2190,7 +2564,7 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host,
struct tm start;
uint time_buff_len= 0;
- (void) pthread_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_log);
/* Test if someone closed between the is_open test and lock */
if (is_open())
@@ -2239,7 +2613,7 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host,
goto err;
}
- (void) pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
return FALSE;
err:
@@ -2248,7 +2622,7 @@ err:
write_error= 1;
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
}
- (void) pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
return TRUE;
}
@@ -2291,11 +2665,11 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
bool error= 0;
DBUG_ENTER("MYSQL_QUERY_LOG::write");
- (void) pthread_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_log);
if (!is_open())
{
- (void) pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
DBUG_RETURN(0);
}
@@ -2404,7 +2778,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
}
}
}
- (void) pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
}
@@ -2437,10 +2811,11 @@ const char *MYSQL_LOG::generate_name(const char *log_name,
-MYSQL_BIN_LOG::MYSQL_BIN_LOG()
+MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period)
:bytes_written(0), prepared_xids(0), file_id(1), open_count(1),
need_start_event(TRUE),
- is_relay_log(0),
+ sync_period_ptr(sync_period),
+ is_relay_log(0), signal_cnt(0),
description_event_for_exec(0), description_event_for_queue(0)
{
/*
@@ -2465,9 +2840,9 @@ void MYSQL_BIN_LOG::cleanup()
close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
delete description_event_for_queue;
delete description_event_for_exec;
- (void) pthread_mutex_destroy(&LOCK_log);
- (void) pthread_mutex_destroy(&LOCK_index);
- (void) pthread_cond_destroy(&update_cond);
+ mysql_mutex_destroy(&LOCK_log);
+ mysql_mutex_destroy(&LOCK_index);
+ mysql_cond_destroy(&update_cond);
}
DBUG_VOID_RETURN;
}
@@ -2488,9 +2863,9 @@ void MYSQL_BIN_LOG::init_pthread_objects()
{
DBUG_ASSERT(inited == 0);
inited= 1;
- (void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
- (void) pthread_cond_init(&update_cond, 0);
+ mysql_mutex_init(key_LOG_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
+ mysql_mutex_init(key_BINLOG_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW);
+ mysql_cond_init(key_BINLOG_update_cond, &update_cond, 0);
}
@@ -2513,23 +2888,25 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
}
fn_format(index_file_name, index_file_name_arg, mysql_data_home,
".index", opt);
- if ((index_file_nr= my_open(index_file_name,
- O_RDWR | O_CREAT | O_BINARY ,
- MYF(MY_WME))) < 0 ||
- my_sync(index_file_nr, MYF(MY_WME)) ||
+ if ((index_file_nr= mysql_file_open(key_file_binlog_index,
+ index_file_name,
+ O_RDWR | O_CREAT | O_BINARY,
+ MYF(MY_WME))) < 0 ||
+ mysql_file_sync(index_file_nr, MYF(MY_WME)) ||
init_io_cache(&index_file, index_file_nr,
IO_SIZE, WRITE_CACHE,
- my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
- 0, MYF(MY_WME | MY_WAIT_IF_FULL)) ||
+ mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)),
+ 0, MYF(MY_WME | MY_WAIT_IF_FULL)) ||
DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0))
{
/*
TODO: all operations creating/deleting the index file or a log, should
call my_sync_dir() or my_sync_dir_by_file() to be durable.
- TODO: file creation should be done with my_create() not my_open().
+ TODO: file creation should be done with mysql_file_create()
+ not mysql_file_open().
*/
if (index_file_nr >= 0)
- my_close(index_file_nr,MYF(0));
+ mysql_file_close(index_file_nr, MYF(0));
return TRUE;
}
@@ -2608,8 +2985,8 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
write_error= 0;
/* open the main log file */
- if (MYSQL_LOG::open(log_name, log_type_arg, new_name,
- io_cache_type_arg))
+ if (MYSQL_LOG::open(key_file_binlog,
+ log_name, log_type_arg, new_name, io_cache_type_arg))
{
#ifdef HAVE_REPLICATION
close_purge_index_file();
@@ -2693,7 +3070,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
bytes_written+= description_event_for_queue->data_written;
}
if (flush_io_cache(&log_file) ||
- my_sync(log_file.file, MYF(MY_WME)))
+ mysql_file_sync(log_file.file, MYF(MY_WME)))
goto err;
if (write_file_name_to_index_file)
@@ -2714,7 +3091,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
strlen(log_file_name)) ||
my_b_write(&index_file, (uchar*) "\n", 1) ||
flush_io_cache(&index_file) ||
- my_sync(index_file.file, MYF(MY_WME)))
+ mysql_file_sync(index_file.file, MYF(MY_WME)))
goto err;
#ifdef HAVE_REPLICATION
@@ -2741,10 +3118,11 @@ Turning logging off for the whole duration of the MySQL server process. \
To turn it on again: fix the cause, \
shutdown the MySQL server and restart it.", name, errno);
if (file >= 0)
- my_close(file,MYF(0));
+ mysql_file_close(file, MYF(0));
end_io_cache(&log_file);
end_io_cache(&index_file);
- safeFree(name);
+ my_free(name);
+ name= NULL;
log_state= LOG_CLOSED;
DBUG_RETURN(1);
}
@@ -2752,9 +3130,9 @@ shutdown the MySQL server and restart it.", name, errno);
int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
{
- pthread_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_log);
int ret = raw_get_current_log(linfo);
- pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
return ret;
}
@@ -2794,19 +3172,20 @@ static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
for (;; offset+= bytes_read)
{
- (void) my_seek(file, offset, MY_SEEK_SET, MYF(0));
- if ((bytes_read= (int) my_read(file, io_buf, sizeof(io_buf), MYF(MY_WME)))
+ mysql_file_seek(file, offset, MY_SEEK_SET, MYF(0));
+ if ((bytes_read= (int) mysql_file_read(file, io_buf, sizeof(io_buf),
+ MYF(MY_WME)))
< 0)
goto err;
if (!bytes_read)
break; // end of file
- (void) my_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
- if (my_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
+ mysql_file_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
+ if (mysql_file_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
goto err;
}
/* The following will either truncate the file or fill the end with \n' */
- if (my_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) ||
- my_sync(file, MYF(MY_WME)))
+ if (mysql_file_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) ||
+ mysql_file_sync(file, MYF(MY_WME)))
goto err;
/* Reset data in old index cache */
@@ -2855,8 +3234,8 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
move from under our feet
*/
if (need_lock)
- pthread_mutex_lock(&LOCK_index);
- safe_mutex_assert_owner(&LOCK_index);
+ mysql_mutex_lock(&LOCK_index);
+ mysql_mutex_assert_owner(&LOCK_index);
/* As the file is flushed, we can't get an error here */
(void) reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0);
@@ -2865,8 +3244,10 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
{
uint length;
my_off_t offset= my_b_tell(&index_file);
- /* If we get 0 or 1 characters, this is the end of the file */
+ DBUG_EXECUTE_IF("simulate_find_log_pos_error",
+ error= LOG_INFO_EOF; break;);
+ /* If we get 0 or 1 characters, this is the end of the file */
if ((length= my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
{
/* Did not find the given entry; Return not found or error */
@@ -2888,7 +3269,7 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
}
if (need_lock)
- pthread_mutex_unlock(&LOCK_index);
+ mysql_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@@ -2924,8 +3305,8 @@ int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
char *fname= linfo->log_file_name;
if (need_lock)
- pthread_mutex_lock(&LOCK_index);
- safe_mutex_assert_owner(&LOCK_index);
+ mysql_mutex_lock(&LOCK_index);
+ mysql_mutex_assert_owner(&LOCK_index);
/* As the file is flushed, we can't get an error here */
(void) reinit_io_cache(&index_file, READ_CACHE, linfo->index_file_offset, 0,
@@ -2942,7 +3323,7 @@ int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
err:
if (need_lock)
- pthread_mutex_unlock(&LOCK_index);
+ mysql_mutex_unlock(&LOCK_index);
return error;
}
@@ -2968,6 +3349,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
{
LOG_INFO linfo;
bool error=0;
+ int err;
const char* save_name;
DBUG_ENTER("reset_logs");
@@ -2976,8 +3358,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
We need to get both locks to be sure that no one is trying to
write to the index log file.
*/
- pthread_mutex_lock(&LOCK_log);
- pthread_mutex_lock(&LOCK_index);
+ mysql_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_index);
/*
The following mutex is needed to ensure that no threads call
@@ -2985,7 +3367,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
thread. If the transaction involved MyISAM tables, it should go
into binlog even on rollback.
*/
- VOID(pthread_mutex_lock(&LOCK_thread_count));
+ mysql_mutex_lock(&LOCK_thread_count);
/* Save variables so that we can reopen the log */
save_name=name;
@@ -3001,9 +3383,13 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
We need to invert the steps and use the purge_index_file methods
in order to make the operation safe.
*/
- if (find_log_pos(&linfo, NullS, 0))
+
+ if ((err= find_log_pos(&linfo, NullS, 0)) != 0)
{
- error=1;
+ uint errcode= purge_log_get_error_code(err);
+ sql_print_error("Failed to locate old binlog or relay log files");
+ my_message(errcode, ER(errcode), MYF(0));
+ error= 1;
goto err;
}
@@ -3070,12 +3456,14 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
if (!open_index_file(index_file_name, 0, FALSE))
if ((error= open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE)))
goto err;
- my_free((uchar*) save_name, MYF(0));
+ my_free((void *) save_name);
err:
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- pthread_mutex_unlock(&LOCK_index);
- pthread_mutex_unlock(&LOCK_log);
+ if (error == 1)
+ name= const_cast<char*>(save_name);
+ mysql_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_index);
+ mysql_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
}
@@ -3129,7 +3517,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
DBUG_ASSERT(rli->slave_running == 1);
DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
- pthread_mutex_lock(&LOCK_index);
+ mysql_mutex_lock(&LOCK_index);
to_purge_if_included= my_strdup(rli->group_relay_log_name, MYF(0));
/*
@@ -3173,19 +3561,19 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE(););
- pthread_mutex_lock(&rli->log_space_lock);
+ mysql_mutex_lock(&rli->log_space_lock);
rli->relay_log.purge_logs(to_purge_if_included, included,
0, 0, &rli->log_space_total);
// Tell the I/O thread to take the relay_log_space_limit into account
rli->ignore_log_space_limit= 0;
- pthread_mutex_unlock(&rli->log_space_lock);
+ mysql_mutex_unlock(&rli->log_space_lock);
/*
Ok to broadcast after the critical region as there is no risk of
the mutex being destroyed by this thread later - this helps save
context switches
*/
- pthread_cond_broadcast(&rli->log_space_cond);
+ mysql_cond_broadcast(&rli->log_space_cond);
/*
* Need to update the log pos because purge logs has been called
@@ -3206,8 +3594,8 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
DBUG_ASSERT(!included || rli->linfo.index_file_start_offset == 0);
err:
- my_free(to_purge_if_included, MYF(0));
- pthread_mutex_unlock(&LOCK_index);
+ my_free(to_purge_if_included);
+ mysql_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@@ -3247,7 +3635,7 @@ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads
LOG_INFO_EOF to_log not found
LOG_INFO_EMFILE too many files opened
LOG_INFO_FATAL if any other than ENOENT error from
- my_stat() or my_delete()
+ mysql_file_stat() or mysql_file_delete()
*/
int MYSQL_BIN_LOG::purge_logs(const char *to_log,
@@ -3264,7 +3652,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
DBUG_PRINT("info",("to_log= %s",to_log));
if (need_mutex)
- pthread_mutex_lock(&LOCK_index);
+ mysql_mutex_lock(&LOCK_index);
if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
{
sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not "
@@ -3327,7 +3715,7 @@ err:
DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", DBUG_SUICIDE(););
if (need_mutex)
- pthread_mutex_unlock(&LOCK_index);
+ mysql_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@@ -3466,7 +3854,7 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
/* Get rid of the trailing '\n' */
log_info.log_file_name[length-1]= 0;
- if (!my_stat(log_info.log_file_name, &s, MYF(0)))
+ if (!mysql_file_stat(key_file_binlog, log_info.log_file_name, &s, MYF(0)))
{
if (my_errno == ENOENT)
{
@@ -3480,7 +3868,7 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
log_info.log_file_name);
}
- sql_print_information("Failed to execute my_stat on file '%s'",
+ sql_print_information("Failed to execute mysql_file_stat on file '%s'",
log_info.log_file_name);
my_errno= 0;
}
@@ -3618,7 +4006,7 @@ err:
@retval
LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated
LOG_INFO_FATAL if any other than ENOENT error from
- my_stat() or my_delete()
+ mysql_file_stat() or mysql_file_delete()
*/
int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
@@ -3631,7 +4019,7 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
DBUG_ENTER("purge_logs_before_date");
- pthread_mutex_lock(&LOCK_index);
+ mysql_mutex_lock(&LOCK_index);
to_log[0]= 0;
if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
@@ -3641,7 +4029,8 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
!is_active(log_info.log_file_name) &&
!log_in_use(log_info.log_file_name))
{
- if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)))
+ if (!mysql_file_stat(key_file_binlog,
+ log_info.log_file_name, &stat_area, MYF(0)))
{
if (my_errno == ENOENT)
{
@@ -3690,7 +4079,7 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
error= (to_log[0] ? purge_logs(to_log, 1, 0, 1, (ulonglong *) 0) : 0);
err:
- pthread_mutex_unlock(&LOCK_index);
+ mysql_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
#endif /* HAVE_REPLICATION */
@@ -3776,11 +4165,11 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
}
if (need_lock)
- pthread_mutex_lock(&LOCK_log);
- pthread_mutex_lock(&LOCK_index);
+ mysql_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_index);
- safe_mutex_assert_owner(&LOCK_log);
- safe_mutex_assert_owner(&LOCK_index);
+ mysql_mutex_assert_owner(&LOCK_log);
+ mysql_mutex_assert_owner(&LOCK_index);
/*
if binlog is used as tc log, be sure all xids are "unlogged",
@@ -3794,12 +4183,12 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
if (prepared_xids)
{
tc_log_page_waits++;
- pthread_mutex_lock(&LOCK_prep_xids);
+ mysql_mutex_lock(&LOCK_prep_xids);
while (prepared_xids) {
DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
- pthread_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
+ mysql_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
}
- pthread_mutex_unlock(&LOCK_prep_xids);
+ mysql_mutex_unlock(&LOCK_prep_xids);
}
/* Reuse old name if not binlog and not update log */
@@ -3876,7 +4265,7 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
close_on_error= TRUE;
}
- my_free(old_name,MYF(0));
+ my_free(old_name);
end:
@@ -3904,8 +4293,8 @@ end:
}
if (need_lock)
- pthread_mutex_unlock(&LOCK_log);
- pthread_mutex_unlock(&LOCK_index);
+ mysql_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@@ -3914,7 +4303,7 @@ end:
bool MYSQL_BIN_LOG::append(Log_event* ev)
{
bool error = 0;
- pthread_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_log);
DBUG_ENTER("MYSQL_BIN_LOG::append");
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
@@ -3929,10 +4318,12 @@ bool MYSQL_BIN_LOG::append(Log_event* ev)
}
bytes_written+= ev->data_written;
DBUG_PRINT("info",("max_size: %lu",max_size));
+ if (flush_and_sync(0))
+ goto err;
if ((uint) my_b_append_tell(&log_file) > max_size)
error= new_file_without_locking();
err:
- pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
signal_update(); // Safe as we don't call close
DBUG_RETURN(error);
}
@@ -3947,7 +4338,7 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
- safe_mutex_assert_owner(&LOCK_log);
+ mysql_mutex_assert_owner(&LOCK_log);
do
{
if (my_b_append(&log_file,(uchar*) buf,len))
@@ -3958,6 +4349,8 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
bytes_written += len;
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
DBUG_PRINT("info",("max_size: %lu",max_size));
+ if (flush_and_sync(0))
+ goto err;
if ((uint) my_b_append_tell(&log_file) > max_size)
error= new_file_without_locking();
err:
@@ -3966,17 +4359,21 @@ err:
DBUG_RETURN(error);
}
-
-bool MYSQL_BIN_LOG::flush_and_sync()
+bool MYSQL_BIN_LOG::flush_and_sync(bool *synced)
{
int err=0, fd=log_file.file;
- safe_mutex_assert_owner(&LOCK_log);
+ if (synced)
+ *synced= 0;
+ mysql_mutex_assert_owner(&LOCK_log);
if (flush_io_cache(&log_file))
return 1;
- if (++sync_binlog_counter >= sync_binlog_period && sync_binlog_period)
+ uint sync_period= get_sync_period();
+ if (sync_period && ++sync_counter >= sync_period)
{
- sync_binlog_counter= 0;
- err=my_sync(fd, MYF(MY_WME));
+ sync_counter= 0;
+ err= mysql_file_sync(fd, MYF(MY_WME));
+ if (synced)
+ *synced= 1;
}
return err;
}
@@ -4002,6 +4399,72 @@ bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
query_id_param >= thd->binlog_evt_union.first_query_id);
}
+/**
+ This function checks if a transactional table was updated by the
+ current transaction.
+
+ @param thd The client thread that executed the current statement.
+ @return
+ @c true if a transactional table was updated, @c false otherwise.
+*/
+bool
+trans_has_updated_trans_table(const THD* thd)
+{
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+
+ return (cache_mngr ? !cache_mngr->trx_cache.empty() : 0);
+}
+
+/**
+ This function checks if a transactional table was updated by the
+ current statement.
+
+ @param thd The client thread that executed the current statement.
+ @return
+ @c true if a transactional table was updated, @c false otherwise.
+*/
+bool
+stmt_has_updated_trans_table(const THD *thd)
+{
+ Ha_trx_info *ha_info;
+
+ for (ha_info= thd->transaction.stmt.ha_list; ha_info;
+ ha_info= ha_info->next())
+ {
+ if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton)
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/**
+ This function checks if either a trx-cache or a non-trx-cache should
+ be used. If @c bin_log_direct_non_trans_update is active or the format
+ is either MIXED or ROW, the cache to be used depends on the flag @c
+ is_transactional.
+
+ On the other hand, if binlog_format is STMT or direct option is
+ OFF, the trx-cache should be used if and only if the statement is
+ transactional or the trx-cache is not empty. Otherwise, the
+ non-trx-cache should be used.
+
+ @param thd The client thread.
+ @param is_transactional The changes are related to a trx-table.
+ @return
+ @c true if a trx-cache should be used, @c false otherwise.
+*/
+bool use_trans_cache(const THD* thd, bool is_transactional)
+{
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+
+ return
+ ((thd->is_current_stmt_binlog_format_row() ||
+ thd->variables.binlog_direct_non_trans_update) ? is_transactional :
+ (is_transactional || !cache_mngr->trx_cache.empty()));
+}
+
/**
This function checks if a transaction, either a multi-statement
or a single statement transaction is about to commit or not.
@@ -4012,43 +4475,40 @@ bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
@return
@c true if committing a transaction, otherwise @c false.
*/
-bool ending_trans(const THD* thd, const bool all)
+bool ending_trans(THD* thd, const bool all)
{
- return (all || (!all && !(thd->options &
- (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))));
+ return (all || ending_single_stmt_trans(thd, all));
}
/**
- This function checks if a non-transactional table was updated by
- the current transaction.
+ This function checks if a single statement transaction is about
+ to commit or not.
@param thd The client thread that executed the current statement.
+ @param all Committing a transaction (i.e. TRUE) or a statement
+ (i.e. FALSE).
@return
- @c true if a non-transactional table was updated, @c false
- otherwise.
+ @c true if committing a single statement transaction, otherwise
+ @c false.
*/
-bool trans_has_updated_non_trans_table(const THD* thd)
+bool ending_single_stmt_trans(THD* thd, const bool all)
{
- return (thd->transaction.all.modified_non_trans_table ||
- thd->transaction.stmt.modified_non_trans_table);
+ return (!all && !thd->in_multi_stmt_transaction_mode());
}
/**
- This function checks if any statement was committed and cached.
+ This function checks if a non-transactional table was updated by
+ the current transaction.
@param thd The client thread that executed the current statement.
- @param all Committing a transaction (i.e. TRUE) or a statement
- (i.e. FALSE).
@return
- @c true if at a statement was committed and cached, @c false
+ @c true if a non-transactional table was updated, @c false
otherwise.
*/
-bool trans_has_no_stmt_committed(const THD* thd, bool all)
+bool trans_has_updated_non_trans_table(const THD* thd)
{
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
-
- return (!all && !trx_data->at_least_one_stmt_committed);
+ return (thd->transaction.all.modified_non_trans_table ||
+ thd->transaction.stmt.modified_non_trans_table);
}
/**
@@ -4072,24 +4532,31 @@ bool stmt_has_updated_non_trans_table(const THD* thd)
int THD::binlog_setup_trx_data()
{
DBUG_ENTER("THD::binlog_setup_trx_data");
- binlog_trx_data *trx_data=
- (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
+ binlog_cache_mngr *cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
- if (trx_data)
+ if (cache_mngr)
DBUG_RETURN(0); // Already set up
- trx_data= (binlog_trx_data*) my_malloc(sizeof(binlog_trx_data), MYF(MY_ZEROFILL));
- if (!trx_data ||
- open_cached_file(&trx_data->trans_log, mysql_tmpdir,
+ cache_mngr= (binlog_cache_mngr*) my_malloc(sizeof(binlog_cache_mngr), MYF(MY_ZEROFILL));
+ if (!cache_mngr ||
+ open_cached_file(&cache_mngr->stmt_cache.cache_log, mysql_tmpdir,
+ LOG_PREFIX, binlog_stmt_cache_size, MYF(MY_WME)) ||
+ open_cached_file(&cache_mngr->trx_cache.cache_log, mysql_tmpdir,
LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
{
- my_free((uchar*)trx_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(cache_mngr);
DBUG_RETURN(1); // Didn't manage to set it up
}
- thd_set_ha_data(this, binlog_hton, trx_data);
-
- trx_data= new (thd_get_ha_data(this, binlog_hton)) binlog_trx_data;
+ thd_set_ha_data(this, binlog_hton, cache_mngr);
+ cache_mngr= new (thd_get_ha_data(this, binlog_hton))
+ binlog_cache_mngr(max_binlog_stmt_cache_size,
+ max_binlog_cache_size,
+ &binlog_stmt_cache_use,
+ &binlog_stmt_cache_disk_use,
+ &binlog_cache_use,
+ &binlog_cache_disk_use);
DBUG_RETURN(0);
}
@@ -4106,11 +4573,10 @@ int THD::binlog_setup_trx_data()
- Start a transaction if not in autocommit mode or if a BEGIN
statement has been seen.
- - Start a statement transaction to allow us to truncate the binary
- log.
+ - Start a statement transaction to allow us to truncate the cache.
- Save the currrent binlog position so that we can roll back the
- statement by truncating the transaction log.
+ statement by truncating the cache.
We only update the saved position if the old one was undefined,
the reason is that there are some cases (e.g., for CREATE-SELECT)
@@ -4124,18 +4590,18 @@ int THD::binlog_setup_trx_data()
void
THD::binlog_start_trans_and_stmt()
{
- binlog_trx_data *trx_data= (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
+ binlog_cache_mngr *cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
DBUG_ENTER("binlog_start_trans_and_stmt");
- DBUG_PRINT("enter", ("trx_data: 0x%lx trx_data->before_stmt_pos: %lu",
- (long) trx_data,
- (trx_data ? (ulong) trx_data->before_stmt_pos :
+ DBUG_PRINT("enter", ("cache_mngr: %p cache_mngr->trx_cache.get_prev_position(): %lu",
+ cache_mngr,
+ (cache_mngr ? (ulong) cache_mngr->trx_cache.get_prev_position() :
(ulong) 0)));
- if (trx_data == NULL ||
- trx_data->before_stmt_pos == MY_OFF_T_UNDEF)
+ if (cache_mngr == NULL ||
+ cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF)
{
this->binlog_set_stmt_begin();
- if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ if (in_multi_stmt_transaction_mode())
trans_register_ha(this, TRUE, binlog_hton);
trans_register_ha(this, FALSE, binlog_hton);
/*
@@ -4153,27 +4619,35 @@ THD::binlog_start_trans_and_stmt()
}
void THD::binlog_set_stmt_begin() {
- binlog_trx_data *trx_data=
- (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
+ binlog_cache_mngr *cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
/*
- The call to binlog_trans_log_savepos() might create the trx_data
+ The call to binlog_trans_log_savepos() might create the cache_mngr
structure, if it didn't exist before, so we save the position
into an auto variable and then write it into the transaction
- data for the binary log (i.e., trx_data).
+ data for the binary log (i.e., cache_mngr).
*/
my_off_t pos= 0;
binlog_trans_log_savepos(this, &pos);
- trx_data= (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
- trx_data->before_stmt_pos= pos;
+ cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+ cache_mngr->trx_cache.set_prev_position(pos);
}
-/*
- Write a table map to the binary log.
- */
-
-int THD::binlog_write_table_map(TABLE *table, bool is_trans)
+/**
+ This function writes a table map to the binary log.
+ Note that in order to keep the signature uniform with related methods,
+ we use a redundant parameter to indicate whether a transactional table
+ was changed or not.
+
+ @param table a pointer to the table.
+ @param is_transactional @c true indicates a transactional table,
+ otherwise @c false a non-transactional.
+ @return
+ nonzero if an error pops up when writing the table map event.
+*/
+int THD::binlog_write_table_map(TABLE *table, bool is_transactional)
{
int error;
DBUG_ENTER("THD::binlog_write_table_map");
@@ -4182,140 +4656,169 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans)
table->s->table_map_id));
/* Pre-conditions */
- DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
+ DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
Table_map_log_event
- the_event(this, table, table->s->table_map_id, is_trans);
+ the_event(this, table, table->s->table_map_id, is_transactional);
- if (is_trans && binlog_table_maps == 0)
+ if (binlog_table_maps == 0)
binlog_start_trans_and_stmt();
- if ((error= mysql_bin_log.write(&the_event)))
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+
+ IO_CACHE *file=
+ cache_mngr->get_binlog_cache_log(use_trans_cache(this, is_transactional));
+ if ((error= the_event.write(file)))
DBUG_RETURN(error);
binlog_table_maps++;
DBUG_RETURN(0);
}
+/**
+ This function retrieves a pending row event from a cache which is
+ specified through the parameter @c is_transactional. Respectively, when it
+ is @c true, the pending event is returned from the transactional cache.
+ Otherwise from the non-transactional cache.
+
+ @param is_transactional @c true indicates a transactional cache,
+ otherwise @c false a non-transactional.
+ @return
+ The row event if any.
+*/
Rows_log_event*
-THD::binlog_get_pending_rows_event() const
+THD::binlog_get_pending_rows_event(bool is_transactional) const
{
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
+ Rows_log_event* rows= NULL;
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+
/*
- This is less than ideal, but here's the story: If there is no
- trx_data, prepare_pending_rows_event() has never been called
- (since the trx_data is set up there). In that case, we just return
- NULL.
+ This is less than ideal, but here's the story: If there is no cache_mngr,
+ prepare_pending_rows_event() has never been called (since the cache_mngr
+ is set up there). In that case, we just return NULL.
*/
- return trx_data ? trx_data->pending() : NULL;
+ if (cache_mngr)
+ {
+ binlog_cache_data *cache_data=
+ cache_mngr->get_binlog_cache_data(use_trans_cache(this, is_transactional));
+
+ rows= cache_data->pending();
+ }
+ return (rows);
}
+/**
+ This function stores a pending row event into a cache which is specified
+ through the parameter @c is_transactional. Respectively, when it is @c
+ true, the pending event is stored into the transactional cache. Otherwise
+ into the non-transactional cache.
+
+ @param evt a pointer to the row event.
+ @param is_transactional @c true indicates a transactional cache,
+ otherwise @c false a non-transactional.
+*/
void
-THD::binlog_set_pending_rows_event(Rows_log_event* ev)
+THD::binlog_set_pending_rows_event(Rows_log_event* ev, bool is_transactional)
{
if (thd_get_ha_data(this, binlog_hton) == NULL)
binlog_setup_trx_data();
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+
+ DBUG_ASSERT(cache_mngr);
+
+ binlog_cache_data *cache_data=
+ cache_mngr->get_binlog_cache_data(use_trans_cache(this, is_transactional));
- DBUG_ASSERT(trx_data);
- trx_data->set_pending(ev);
+ cache_data->set_pending(ev);
}
/**
- Remove the pending rows event, discarding any outstanding rows.
-
- If there is no pending rows event available, this is effectively a
+ This function removes the pending rows event, discarding any outstanding
+ rows. If there is no pending rows event available, this is effectively a
no-op.
- */
+
+ @param thd a pointer to the user thread.
+ @param is_transactional @c true indicates a transactional cache,
+ otherwise @c false a non-transactional.
+*/
int
-MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd)
+MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd, bool is_transactional)
{
DBUG_ENTER("MYSQL_BIN_LOG::remove_pending_rows_event");
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
- DBUG_ASSERT(trx_data);
+ DBUG_ASSERT(cache_mngr);
- if (Rows_log_event* pending= trx_data->pending())
+ binlog_cache_data *cache_data=
+ cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
+
+ if (Rows_log_event* pending= cache_data->pending())
{
delete pending;
- trx_data->set_pending(NULL);
+ cache_data->set_pending(NULL);
}
DBUG_RETURN(0);
}
/*
- Moves the last bunch of rows from the pending Rows event to the binlog
- (either cached binlog if transaction, or disk binlog). Sets a new pending
- event.
+ Moves the last bunch of rows from the pending Rows event to a cache (either
+ transactional cache if is_transaction is @c true, or the non-transactional
+ cache otherwise. Sets a new pending event.
+
+ @param thd a pointer to the user thread.
+ @param evt a pointer to the row event.
+ @param is_transactional @c true indicates a transactional cache,
+ otherwise @c false a non-transactional.
*/
int
MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
- Rows_log_event* event)
+ Rows_log_event* event,
+ bool is_transactional)
{
DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)");
DBUG_ASSERT(mysql_bin_log.is_open());
DBUG_PRINT("enter", ("event: 0x%lx", (long) event));
int error= 0;
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
+ DBUG_ASSERT(cache_mngr);
- DBUG_ASSERT(trx_data);
+ binlog_cache_data *cache_data=
+ cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
- DBUG_PRINT("info", ("trx_data->pending(): 0x%lx", (long) trx_data->pending()));
+ DBUG_PRINT("info", ("cache_mngr->pending(): 0x%lx", (long) cache_data->pending()));
- if (Rows_log_event* pending= trx_data->pending())
+ if (Rows_log_event* pending= cache_data->pending())
{
- IO_CACHE *file= &log_file;
-
- /*
- Decide if we should write to the log file directly or to the
- transaction log.
- */
- if (pending->get_cache_stmt() || my_b_tell(&trx_data->trans_log))
- file= &trx_data->trans_log;
+ IO_CACHE *file= &cache_data->cache_log;
/*
- If we are not writing to the log file directly, we could avoid
- locking the log.
- */
- pthread_mutex_lock(&LOCK_log);
-
- /*
- Write pending event to log file or transaction cache
+ Write pending event to the cache.
*/
if (pending->write(file))
{
- pthread_mutex_unlock(&LOCK_log);
- set_write_error(thd);
+ set_write_error(thd, is_transactional);
+ if (check_write_error(thd) && cache_data &&
+ stmt_has_updated_non_trans_table(thd))
+ cache_data->set_incident();
DBUG_RETURN(1);
}
delete pending;
-
- if (file == &log_file)
- {
- error= flush_and_sync();
- if (!error)
- {
- signal_update();
- error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
- }
- }
-
- pthread_mutex_unlock(&LOCK_log);
}
- thd->binlog_set_pending_rows_event(event);
+ thd->binlog_set_pending_rows_event(event, is_transactional);
DBUG_RETURN(error);
}
@@ -4329,6 +4832,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
THD *thd= event_info->thd;
bool error= 1;
DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)");
+ binlog_cache_data *cache_data= 0;
+ bool is_trans_cache= FALSE;
if (thd->binlog_evt_union.do_union)
{
@@ -4337,27 +4842,22 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
We will log the function call to the binary log on function exit
*/
thd->binlog_evt_union.unioned_events= TRUE;
- thd->binlog_evt_union.unioned_events_trans |= event_info->cache_stmt;
+ thd->binlog_evt_union.unioned_events_trans |=
+ event_info->use_trans_cache();
DBUG_RETURN(0);
}
/*
- Flush the pending rows event to the transaction cache or to the
- log file. Since this function potentially aquire the LOCK_log
- mutex, we do this before aquiring the LOCK_log mutex in this
- function.
-
We only end the statement if we are in a top-level statement. If
we are inside a stored function, we do not end the statement since
this will close all tables on the slave.
*/
bool const end_stmt=
- thd->prelocked_mode && thd->lex->requires_prelocking();
- if (thd->binlog_flush_pending_rows_event(end_stmt))
+ thd->locked_tables_mode && thd->lex->requires_prelocking();
+ if (thd->binlog_flush_pending_rows_event(end_stmt,
+ event_info->use_trans_cache()))
DBUG_RETURN(error);
- pthread_mutex_lock(&LOCK_log);
-
/*
In most cases this is only called if 'is_open()' is true; in fact this is
mostly called if is_open() *was* true a few instructions before, but it
@@ -4365,7 +4865,6 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
*/
if (likely(is_open()))
{
- IO_CACHE *file= &log_file;
#ifdef HAVE_REPLICATION
/*
In the future we need to add to the following if tests like
@@ -4373,80 +4872,50 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
binlog_[wild_]{do|ignore}_table?" (WL#1049)"
*/
const char *local_db= event_info->get_db();
- if ((thd && !(thd->options & OPTION_BIN_LOG)) ||
+ if ((thd && !(thd->variables.option_bits & OPTION_BIN_LOG)) ||
(thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT &&
thd->lex->sql_command != SQLCOM_SAVEPOINT &&
!binlog_filter->db_ok(local_db)))
- {
- VOID(pthread_mutex_unlock(&LOCK_log));
DBUG_RETURN(0);
- }
#endif /* HAVE_REPLICATION */
-#if defined(USING_TRANSACTIONS)
- /*
- Should we write to the binlog cache or to the binlog on disk?
-
- Write to the binlog cache if:
- 1 - a transactional engine/table is updated (stmt_has_updated_trans_table == TRUE);
- 2 - or the event asks for it (cache_stmt == TRUE);
- 3 - or the cache is already not empty (meaning we're in a transaction;
- note that the present event could be about a non-transactional table, but
- still we need to write to the binlog cache in that case to handle updates
- to mixed trans/non-trans table types).
-
- Write to the binlog on disk if only a non-transactional engine is
- updated and:
- 1 - the binlog cache is empty or;
- 2 - --binlog-direct-non-transactional-updates is set and we are about to
- use the statement format. When using the row format (cache_stmt == TRUE).
- */
- if (opt_using_transactions && thd)
+ IO_CACHE *file= NULL;
+
+ if (event_info->use_direct_logging())
+ {
+ file= &log_file;
+ mysql_mutex_lock(&LOCK_log);
+ }
+ else
{
if (thd->binlog_setup_trx_data())
goto err;
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
- IO_CACHE *trans_log= &trx_data->trans_log;
- my_off_t trans_log_pos= my_b_tell(trans_log);
- if (event_info->get_cache_stmt() || stmt_has_updated_trans_table(thd) ||
- (!thd->variables.binlog_direct_non_trans_update &&
- trans_log_pos != 0))
- {
- DBUG_PRINT("info", ("Using trans_log: cache: %d, trans_log_pos: %lu",
- event_info->get_cache_stmt(),
- (ulong) trans_log_pos));
- thd->binlog_start_trans_and_stmt();
- file= trans_log;
- }
- /*
- TODO as Mats suggested, for all the cases above where we write to
- trans_log, it sounds unnecessary to lock LOCK_log. We should rather
- test first if we want to write to trans_log, and if not, lock
- LOCK_log.
- */
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+
+ is_trans_cache= use_trans_cache(thd, event_info->use_trans_cache());
+ file= cache_mngr->get_binlog_cache_log(is_trans_cache);
+ cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache);
+
+ if (thd->lex->stmt_accessed_non_trans_temp_table())
+ cache_data->set_changes_to_non_trans_temp_table();
+
+ thd->binlog_start_trans_and_stmt();
}
-#endif /* USING_TRANSACTIONS */
DBUG_PRINT("info",("event type: %d",event_info->get_type_code()));
/*
- No check for auto events flag here - this write method should
- never be called if auto-events are enabled
- */
-
- /*
- 1. Write first log events which describe the 'run environment'
- of the SQL command
- */
+ No check for auto events flag here - this write method should
+ never be called if auto-events are enabled.
- /*
- If row-based binlogging, Insert_id, Rand and other kind of "setting
- context" events are not needed.
+ Write first log events which describe the 'run environment'
+ of the SQL command. If row-based binlogging, Insert_id, Rand
+ and other kind of "setting context" events are not needed.
*/
if (thd)
{
- if (!thd->current_stmt_binlog_row_based)
+ if (!thd->is_current_stmt_binlog_format_row())
{
if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
{
@@ -4478,12 +4947,19 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
{
BINLOG_USER_VAR_EVENT *user_var_event;
get_dynamic(&thd->user_var_events,(uchar*) &user_var_event, i);
+
+ /* setting flags for user var log event */
+ uchar flags= User_var_log_event::UNDEF_F;
+ if (user_var_event->unsigned_flag)
+ flags|= User_var_log_event::UNSIGNED_F;
+
User_var_log_event e(thd, user_var_event->user_var_event->name.str,
user_var_event->user_var_event->name.length,
user_var_event->value,
user_var_event->length,
user_var_event->type,
- user_var_event->charset_number);
+ user_var_event->charset_number,
+ flags);
if (e.write(file))
goto err;
}
@@ -4492,30 +4968,44 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
}
/*
- Write the SQL command
- */
-
- if (event_info->write(file) ||
+ Write the event.
+ */
+ if (event_info->write(file) ||
DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
goto err;
- if (file == &log_file) // we are writing to the real log (disk)
+ error= 0;
+err:
+ if (event_info->use_direct_logging())
{
- if (flush_and_sync())
- goto err;
- signal_update();
- if ((error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED)))
- goto err;
-
+ if (!error)
+ {
+ bool synced;
+ if ((error= flush_and_sync(&synced)))
+ goto unlock;
+
+ if ((error= RUN_HOOK(binlog_storage, after_flush,
+ (thd, log_file_name, file->pos_in_file, synced))))
+ {
+ sql_print_error("Failed to run 'after_flush' hooks");
+ goto unlock;
+ }
+ signal_update();
+ rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
+ }
+unlock:
+ mysql_mutex_unlock(&LOCK_log);
}
- error=0;
-err:
if (error)
- set_write_error(thd);
+ {
+ set_write_error(thd, is_trans_cache);
+ if (check_write_error(thd) && cache_data &&
+ stmt_has_updated_non_trans_table(thd))
+ cache_data->set_incident();
+ }
}
- pthread_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
}
@@ -4545,7 +5035,7 @@ bool LOGGER::log_command(THD *thd, enum enum_server_command command)
*/
if (*general_log_handler_list && (what_to_log & (1L << (uint) command)))
{
- if ((thd->options & OPTION_LOG_OFF)
+ if ((thd->variables.option_bits & OPTION_LOG_OFF)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
&& (sctx->master_access & SUPER_ACL)
#endif
@@ -4606,7 +5096,7 @@ int MYSQL_BIN_LOG::rotate_and_purge(uint flags)
bool check_purge= false;
#endif
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
- pthread_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_log);
if ((flags & RP_FORCE_ROTATE) ||
(my_b_tell(&log_file) >= (my_off_t) max_size))
{
@@ -4628,7 +5118,7 @@ int MYSQL_BIN_LOG::rotate_and_purge(uint flags)
#endif
}
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
- pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
#ifdef HAVE_REPLICATION
/*
NOTE: Run purge_logs wo/ holding LOCK_log
@@ -4647,9 +5137,9 @@ int MYSQL_BIN_LOG::rotate_and_purge(uint flags)
uint MYSQL_BIN_LOG::next_file_id()
{
uint res;
- pthread_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_log);
res = file_id++;
- pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
return res;
}
@@ -4661,7 +5151,7 @@ uint MYSQL_BIN_LOG::next_file_id()
write_cache()
cache Cache to write to the binary log
lock_log True if the LOCK_log mutex should be aquired, false otherwise
- sync_log True if the log should be flushed and sync:ed
+ sync_log True if the log should be flushed and synced
DESCRIPTION
Write the contents of the cache to the binary log. The cache will
@@ -4697,7 +5187,6 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
do
{
-
/*
if we only got a partial header in the last iteration,
get the other half now and process a full header.
@@ -4790,7 +5279,7 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
DBUG_ASSERT(carry == 0);
if (sync_log)
- flush_and_sync();
+ return flush_and_sync(0);
return 0; // All OK
}
@@ -4804,9 +5293,9 @@ int query_error_code(THD *thd, bool not_killed)
if (not_killed || (thd->killed == THD::KILL_BAD_DATA))
{
- error= thd->is_error() ? thd->main_da.sql_errno() : 0;
+ error= thd->is_error() ? thd->stmt_da->sql_errno() : 0;
- /* thd->main_da.sql_errno() might be ER_SERVER_SHUTDOWN or
+ /* thd->stmt_da->sql_errno() might be ER_SERVER_SHUTDOWN or
ER_QUERY_INTERRUPTED, So here we need to make sure that error
is not set to these errors when specified not_killed by the
caller.
@@ -4837,16 +5326,16 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
Incident incident= INCIDENT_LOST_EVENTS;
Incident_log_event ev(thd, incident, write_error_msg);
if (lock)
- pthread_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_log);
error= ev.write(&log_file);
if (lock)
{
- if (!error && !(error= flush_and_sync()))
+ if (!error && !(error= flush_and_sync(0)))
{
signal_update();
error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
}
- pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
}
DBUG_RETURN(error);
}
@@ -4879,10 +5368,7 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
bool incident)
{
DBUG_ENTER("MYSQL_BIN_LOG::write(THD *, IO_CACHE *, Log_event *)");
- VOID(pthread_mutex_lock(&LOCK_log));
-
- /* NULL would represent nothing to replicate after ROLLBACK */
- DBUG_ASSERT(commit_event != NULL);
+ mysql_mutex_lock(&LOCK_log);
DBUG_ASSERT(is_open());
if (likely(is_open())) // Should always be true
@@ -4898,19 +5384,9 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
transaction is either a BEGIN..COMMIT block or a single
statement in autocommit mode.
*/
- Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, TRUE, 0);
-
- /*
- Now this Query_log_event has artificial log_pos 0. It must be
- adjusted to reflect the real position in the log. Not doing it
- would confuse the slave: it would prevent this one from
- knowing where he is in the master's binlog, which would result
- in wrong positions being shown to the user, MASTER_POS_WAIT
- undue waiting etc.
- */
+ Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE, TRUE, 0);
if (qinfo.write(&log_file))
goto err;
-
DBUG_EXECUTE_IF("crash_before_writing_xid",
{
if ((write_error= write_cache(cache, false, true)))
@@ -4929,7 +5405,8 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
if (incident && write_incident(thd, FALSE))
goto err;
- if (flush_and_sync())
+ bool synced= 0;
+ if (flush_and_sync(&synced))
goto err;
DBUG_EXECUTE_IF("half_binlogged_transaction", DBUG_SUICIDE(););
if (cache->error) // Error on read
@@ -4938,6 +5415,15 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
write_error=1; // Don't give more errors
goto err;
}
+
+ if (RUN_HOOK(binlog_storage, after_flush,
+ (thd, log_file_name, log_file.pos_in_file, synced)))
+ {
+ sql_print_error("Failed to run 'after_flush' hooks");
+ write_error=1;
+ goto err;
+ }
+
signal_update();
}
@@ -4951,15 +5437,15 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
*/
if (commit_event && commit_event->get_type_code() == XID_EVENT)
{
- pthread_mutex_lock(&LOCK_prep_xids);
+ mysql_mutex_lock(&LOCK_prep_xids);
prepared_xids++;
- pthread_mutex_unlock(&LOCK_prep_xids);
+ mysql_mutex_unlock(&LOCK_prep_xids);
}
else
if (rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED))
goto err;
}
- VOID(pthread_mutex_unlock(&LOCK_log));
+ mysql_mutex_unlock(&LOCK_log);
DBUG_RETURN(0);
@@ -4969,18 +5455,15 @@ err:
write_error= 1;
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
}
- VOID(pthread_mutex_unlock(&LOCK_log));
+ mysql_mutex_unlock(&LOCK_log);
DBUG_RETURN(1);
}
/**
- Wait until we get a signal that the binary log has been updated.
+ Wait until we get a signal that the relay log has been updated.
@param thd Thread variable
- @param is_slave If 0, the caller is the Binlog_dump thread from master;
- if 1, the caller is the SQL thread from the slave. This
- influences only thd->proc_info.
@note
One must have a lock on LOCK_log before calling this function.
@@ -4988,22 +5471,50 @@ err:
THD::enter_cond() (see NOTES in sql_class.h).
*/
-void MYSQL_BIN_LOG::wait_for_update(THD* thd, bool is_slave)
+void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd)
{
const char *old_msg;
- DBUG_ENTER("wait_for_update");
+ DBUG_ENTER("wait_for_update_relay_log");
old_msg= thd->enter_cond(&update_cond, &LOCK_log,
- is_slave ?
- "Has read all relay log; waiting for the slave I/O "
- "thread to update it" :
- "Has sent all binlog to slave; waiting for binlog "
- "to be updated");
- pthread_cond_wait(&update_cond, &LOCK_log);
+ "Slave has read all relay log; "
+ "waiting for the slave I/O "
+ "thread to update it" );
+ mysql_cond_wait(&update_cond, &LOCK_log);
thd->exit_cond(old_msg);
DBUG_VOID_RETURN;
}
+/**
+ Wait until we get a signal that the binary log has been updated.
+ Applies to master only.
+
+ NOTES
+ @param[in] thd a THD struct
+ @param[in] timeout a pointer to a timespec;
+ NULL means to wait w/o timeout.
+ @retval 0 if got signalled on update
+ @retval non-0 if wait timeout elapsed
+ @note
+ LOCK_log must be taken before calling this function.
+ LOCK_log is being released while the thread is waiting.
+ LOCK_log is released by the caller.
+*/
+
+int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd,
+ const struct timespec *timeout)
+{
+ int ret= 0;
+ DBUG_ENTER("wait_for_update_bin_log");
+
+ if (!timeout)
+ mysql_cond_wait(&update_cond, &LOCK_log);
+ else
+ ret= mysql_cond_timedwait(&update_cond, &LOCK_log,
+ const_cast<struct timespec *>(timeout));
+ DBUG_RETURN(ret);
+}
+
/**
Close the log file.
@@ -5040,16 +5551,16 @@ void MYSQL_BIN_LOG::close(uint exiting)
if (log_file.type == WRITE_CACHE && log_type == LOG_BIN)
{
my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
- my_off_t org_position= my_tell(log_file.file, MYF(0));
+ my_off_t org_position= mysql_file_tell(log_file.file, MYF(0));
uchar flags= 0; // clearing LOG_EVENT_BINLOG_IN_USE_F
- my_pwrite(log_file.file, &flags, 1, offset, MYF(0));
+ mysql_file_pwrite(log_file.file, &flags, 1, offset, MYF(0));
/*
Restore position so that anything we have in the IO_cache is written
to the correct position.
- We need the seek here, as my_pwrite() is not guaranteed to keep the
+ We need the seek here, as mysql_file_pwrite() is not guaranteed to keep the
original position on system that doesn't support pwrite().
*/
- my_seek(log_file.file, org_position, MY_SEEK_SET, MYF(0));
+ mysql_file_seek(log_file.file, org_position, MY_SEEK_SET, MYF(0));
}
/* this will cleanup IO_CACHE, sync and close the file */
@@ -5064,14 +5575,15 @@ void MYSQL_BIN_LOG::close(uint exiting)
if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file))
{
end_io_cache(&index_file);
- if (my_close(index_file.file, MYF(0)) < 0 && ! write_error)
+ if (mysql_file_close(index_file.file, MYF(0)) < 0 && ! write_error)
{
write_error= 1;
sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
}
}
log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
- safeFree(name);
+ my_free(name);
+ name= NULL;
DBUG_VOID_RETURN;
}
@@ -5086,10 +5598,10 @@ void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
it's like if the SET command was never run.
*/
DBUG_ENTER("MYSQL_BIN_LOG::set_max_size");
- pthread_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_log);
if (is_open())
max_size= max_size_arg;
- pthread_mutex_unlock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
DBUG_VOID_RETURN;
}
@@ -5108,11 +5620,11 @@ void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
@retval
1 String is a number
@retval
- 0 Error
+ 0 String is not a number
*/
static bool test_if_number(register const char *str,
- long *res, bool allow_wildcards)
+ ulong *res, bool allow_wildcards)
{
reg2 int flag;
const char *start;
@@ -5248,10 +5760,10 @@ bool flush_error_log()
bool result= 0;
if (opt_error_log)
{
- VOID(pthread_mutex_lock(&LOCK_error_log));
+ mysql_mutex_lock(&LOCK_error_log);
if (redirect_std_streams(log_error_file))
result= 1;
- VOID(pthread_mutex_unlock(&LOCK_error_log));
+ mysql_mutex_unlock(&LOCK_error_log);
}
return result;
}
@@ -5259,11 +5771,12 @@ bool flush_error_log()
void MYSQL_BIN_LOG::signal_update()
{
DBUG_ENTER("MYSQL_BIN_LOG::signal_update");
- pthread_cond_broadcast(&update_cond);
+ signal_cnt++;
+ mysql_cond_broadcast(&update_cond);
DBUG_VOID_RETURN;
}
-#ifdef __NT__
+#ifdef _WIN32
static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
size_t length, size_t buffLen)
{
@@ -5296,7 +5809,7 @@ static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
DBUG_VOID_RETURN;
}
-#endif /* __NT__ */
+#endif /* _WIN32 */
#ifndef EMBEDDED_LIBRARY
@@ -5309,7 +5822,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer,
DBUG_ENTER("print_buffer_to_file");
DBUG_PRINT("enter",("buffer: %s", buffer));
- VOID(pthread_mutex_lock(&LOCK_error_log));
+ mysql_mutex_lock(&LOCK_error_log);
skr= my_time(0);
localtime_r(&skr, &tm_tmp);
@@ -5328,7 +5841,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer,
fflush(stderr);
- VOID(pthread_mutex_unlock(&LOCK_error_log));
+ mysql_mutex_unlock(&LOCK_error_log);
DBUG_VOID_RETURN;
}
@@ -5357,7 +5870,7 @@ int vprint_msg_to_log(enum loglevel level, const char *format, va_list args)
length= my_vsnprintf(buff, sizeof(buff), format, args);
print_buffer_to_file(level, buff, length);
-#ifdef __NT__
+#ifdef _WIN32
print_buffer_to_nt_eventlog(level, buff, length, sizeof(buff));
#endif
@@ -5467,17 +5980,18 @@ int TC_LOG_MMAP::open(const char *opt_name)
DBUG_ASSERT(TC_LOG_PAGE_SIZE % tc_log_page_size == 0);
fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME);
- if ((fd= my_open(logname, O_RDWR, MYF(0))) < 0)
+ if ((fd= mysql_file_open(key_file_tclog, logname, O_RDWR, MYF(0))) < 0)
{
if (my_errno != ENOENT)
goto err;
if (using_heuristic_recover())
return 1;
- if ((fd= my_create(logname, CREATE_MODE, O_RDWR, MYF(MY_WME))) < 0)
+ if ((fd= mysql_file_create(key_file_tclog, logname, CREATE_MODE,
+ O_RDWR, MYF(MY_WME))) < 0)
goto err;
inited=1;
file_length= opt_tc_log_size;
- if (my_chsize(fd, file_length, 0, MYF(MY_WME)))
+ if (mysql_file_chsize(fd, file_length, 0, MYF(MY_WME)))
goto err;
}
else
@@ -5491,7 +6005,7 @@ int TC_LOG_MMAP::open(const char *opt_name)
"--tc-heuristic-recover is used");
goto err;
}
- file_length= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
+ file_length= mysql_file_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
if (file_length == MY_FILEPOS_ERROR || file_length % tc_log_page_size)
goto err;
}
@@ -5515,8 +6029,8 @@ int TC_LOG_MMAP::open(const char *opt_name)
pg->next=pg+1;
pg->waiters=0;
pg->state=POOL;
- pthread_mutex_init(&pg->lock, MY_MUTEX_INIT_FAST);
- pthread_cond_init (&pg->cond, 0);
+ mysql_mutex_init(key_PAGE_lock, &pg->lock, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_PAGE_cond, &pg->cond, 0);
pg->start=(my_xid *)(data + i*tc_log_page_size);
pg->end=(my_xid *)(pg->start + tc_log_page_size);
pg->size=pg->free=tc_log_page_size/sizeof(my_xid);
@@ -5535,11 +6049,11 @@ int TC_LOG_MMAP::open(const char *opt_name)
my_msync(fd, data, tc_log_page_size, MS_SYNC);
inited=5;
- pthread_mutex_init(&LOCK_sync, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&LOCK_active, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&LOCK_pool, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&COND_active, 0);
- pthread_cond_init(&COND_pool, 0);
+ mysql_mutex_init(key_LOCK_sync, &LOCK_sync, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_active, &LOCK_active, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_pool, &LOCK_pool, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_active, &COND_active, 0);
+ mysql_cond_init(key_COND_pool, &COND_pool, 0);
inited=6;
@@ -5573,7 +6087,7 @@ void TC_LOG_MMAP::get_active_from_pool()
int best_free;
if (syncing)
- pthread_mutex_lock(&LOCK_pool);
+ mysql_mutex_lock(&LOCK_pool);
do
{
@@ -5606,7 +6120,7 @@ void TC_LOG_MMAP::get_active_from_pool()
pool_last=*best_p;
if (syncing)
- pthread_mutex_unlock(&LOCK_pool);
+ mysql_mutex_unlock(&LOCK_pool);
}
/**
@@ -5621,7 +6135,7 @@ int TC_LOG_MMAP::overflow()
let's check the behaviour of tc_log_page_waits first
*/
tc_log_page_waits++;
- pthread_cond_wait(&COND_pool, &LOCK_pool);
+ mysql_cond_wait(&COND_pool, &LOCK_pool);
return 1; // always return 1
}
@@ -5658,7 +6172,7 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
PAGE *p;
ulong cookie;
- pthread_mutex_lock(&LOCK_active);
+ mysql_mutex_lock(&LOCK_active);
/*
if active page is full - just wait...
@@ -5668,14 +6182,14 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
unlog() does not signal COND_active.
*/
while (unlikely(active && active->free == 0))
- pthread_cond_wait(&COND_active, &LOCK_active);
+ mysql_cond_wait(&COND_active, &LOCK_active);
/* no active page ? take one from the pool */
if (active == 0)
get_active_from_pool();
p=active;
- pthread_mutex_lock(&p->lock);
+ mysql_mutex_lock(&p->lock);
/* searching for an empty slot */
while (*p->ptr)
@@ -5691,9 +6205,9 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
p->state= DIRTY;
/* to sync or not to sync - this is the question */
- pthread_mutex_unlock(&LOCK_active);
- pthread_mutex_lock(&LOCK_sync);
- pthread_mutex_unlock(&p->lock);
+ mysql_mutex_unlock(&LOCK_active);
+ mysql_mutex_lock(&LOCK_sync);
+ mysql_mutex_unlock(&p->lock);
if (syncing)
{ // somebody's syncing. let's wait
@@ -5703,24 +6217,24 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
as p->state may be not DIRTY when we come here
*/
while (p->state == DIRTY && syncing)
- pthread_cond_wait(&p->cond, &LOCK_sync);
+ mysql_cond_wait(&p->cond, &LOCK_sync);
p->waiters--;
err= p->state == ERROR;
if (p->state != DIRTY) // page was synced
{
if (p->waiters == 0)
- pthread_cond_signal(&COND_pool); // in case somebody's waiting
- pthread_mutex_unlock(&LOCK_sync);
+ mysql_cond_signal(&COND_pool); // in case somebody's waiting
+ mysql_mutex_unlock(&LOCK_sync);
goto done; // we're done
}
} // page was not synced! do it now
DBUG_ASSERT(active == p && syncing == 0);
- pthread_mutex_lock(&LOCK_active);
+ mysql_mutex_lock(&LOCK_active);
syncing=p; // place is vacant - take it
active=0; // page is not active anymore
- pthread_cond_broadcast(&COND_active); // in case somebody's waiting
- pthread_mutex_unlock(&LOCK_active);
- pthread_mutex_unlock(&LOCK_sync);
+ mysql_cond_broadcast(&COND_active); // in case somebody's waiting
+ mysql_mutex_unlock(&LOCK_active);
+ mysql_mutex_unlock(&LOCK_sync);
err= sync();
done:
@@ -5740,20 +6254,20 @@ int TC_LOG_MMAP::sync()
err= my_msync(fd, syncing->start, 1, MS_SYNC);
/* page is synced. let's move it to the pool */
- pthread_mutex_lock(&LOCK_pool);
+ mysql_mutex_lock(&LOCK_pool);
pool_last->next=syncing;
pool_last=syncing;
syncing->next=0;
syncing->state= err ? ERROR : POOL;
- pthread_cond_broadcast(&syncing->cond); // signal "sync done"
- pthread_cond_signal(&COND_pool); // in case somebody's waiting
- pthread_mutex_unlock(&LOCK_pool);
+ mysql_cond_broadcast(&syncing->cond); // signal "sync done"
+ mysql_cond_signal(&COND_pool); // in case somebody's waiting
+ mysql_mutex_unlock(&LOCK_pool);
/* marking 'syncing' slot free */
- pthread_mutex_lock(&LOCK_sync);
+ mysql_mutex_lock(&LOCK_sync);
syncing=0;
- pthread_cond_signal(&active->cond); // wake up a new syncer
- pthread_mutex_unlock(&LOCK_sync);
+ mysql_cond_signal(&active->cond); // wake up a new syncer
+ mysql_mutex_unlock(&LOCK_sync);
return err;
}
@@ -5771,15 +6285,15 @@ int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
DBUG_ASSERT(x >= p->start && x < p->end);
*x=0;
- pthread_mutex_lock(&p->lock);
+ mysql_mutex_lock(&p->lock);
p->free++;
DBUG_ASSERT(p->free <= p->size);
set_if_smaller(p->ptr, x);
if (p->free == p->size) // the page is completely empty
statistic_decrement(tc_log_cur_pages_used, &LOCK_status);
if (p->waiters == 0) // the page is in pool and ready to rock
- pthread_cond_signal(&COND_pool); // ping ... for overflow()
- pthread_mutex_unlock(&p->lock);
+ mysql_cond_signal(&COND_pool); // ping ... for overflow()
+ mysql_mutex_unlock(&p->lock);
return 0;
}
@@ -5788,29 +6302,29 @@ void TC_LOG_MMAP::close()
uint i;
switch (inited) {
case 6:
- pthread_mutex_destroy(&LOCK_sync);
- pthread_mutex_destroy(&LOCK_active);
- pthread_mutex_destroy(&LOCK_pool);
- pthread_cond_destroy(&COND_pool);
+ mysql_mutex_destroy(&LOCK_sync);
+ mysql_mutex_destroy(&LOCK_active);
+ mysql_mutex_destroy(&LOCK_pool);
+ mysql_cond_destroy(&COND_pool);
case 5:
- data[0]='A'; // garble the first (signature) byte, in case my_delete fails
+ data[0]='A'; // garble the first (signature) byte, in case mysql_file_delete fails
case 4:
for (i=0; i < npages; i++)
{
if (pages[i].ptr == 0)
break;
- pthread_mutex_destroy(&pages[i].lock);
- pthread_cond_destroy(&pages[i].cond);
+ mysql_mutex_destroy(&pages[i].lock);
+ mysql_cond_destroy(&pages[i].cond);
}
case 3:
- my_free((uchar*)pages, MYF(0));
+ my_free(pages);
case 2:
my_munmap((char*)data, (size_t)file_length);
case 1:
- my_close(fd, MYF(0));
+ mysql_file_close(fd, MYF(0));
}
if (inited>=5) // cannot do in the switch because of Windows
- my_delete(logname, MYF(MY_WME));
+ mysql_file_delete(key_file_tclog, logname, MYF(MY_WME));
inited=0;
}
@@ -5838,8 +6352,8 @@ int TC_LOG_MMAP::recover()
goto err1;
}
- if (hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
- sizeof(my_xid), 0, 0, MYF(0)))
+ if (my_hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
+ sizeof(my_xid), 0, 0, MYF(0)))
goto err1;
for ( ; p < end_p ; p++)
@@ -5852,12 +6366,12 @@ int TC_LOG_MMAP::recover()
if (ha_recover(&xids))
goto err2;
- hash_free(&xids);
+ my_hash_free(&xids);
bzero(data, (size_t)file_length);
return 0;
err2:
- hash_free(&xids);
+ my_hash_free(&xids);
err1:
sql_print_error("Crash recovery failed. Either correct the problem "
"(if it's, for example, out of memory error) and restart, "
@@ -5915,8 +6429,9 @@ int TC_LOG_BINLOG::open(const char *opt_name)
DBUG_ASSERT(total_ha_2pc > 1);
DBUG_ASSERT(opt_name && opt_name[0]);
- pthread_mutex_init(&LOCK_prep_xids, MY_MUTEX_INIT_FAST);
- pthread_cond_init (&COND_prep_xids, 0);
+ mysql_mutex_init(key_BINLOG_LOCK_prep_xids,
+ &LOCK_prep_xids, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_BINLOG_COND_prep_xids, &COND_prep_xids, 0);
if (!my_b_inited(&index_file))
{
@@ -5982,7 +6497,7 @@ int TC_LOG_BINLOG::open(const char *opt_name)
delete ev;
end_io_cache(&log);
- my_close(file, MYF(MY_WME));
+ mysql_file_close(file, MYF(MY_WME));
if (error)
goto err;
@@ -5996,8 +6511,8 @@ err:
void TC_LOG_BINLOG::close()
{
DBUG_ASSERT(prepared_xids==0);
- pthread_mutex_destroy(&LOCK_prep_xids);
- pthread_cond_destroy (&COND_prep_xids);
+ mysql_mutex_destroy(&LOCK_prep_xids);
+ mysql_cond_destroy(&COND_prep_xids);
}
/**
@@ -6012,26 +6527,26 @@ void TC_LOG_BINLOG::close()
int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid)
{
DBUG_ENTER("TC_LOG_BINLOG::log");
- Xid_log_event xle(thd, xid);
- binlog_trx_data *trx_data=
- (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
+ binlog_cache_mngr *cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
/*
We always commit the entire transaction when writing an XID. Also
note that the return value is inverted.
*/
- DBUG_RETURN(!binlog_end_trans(thd, trx_data, &xle, TRUE));
+ DBUG_RETURN(!binlog_commit_flush_stmt_cache(thd, cache_mngr) &&
+ !binlog_commit_flush_trx_cache(thd, cache_mngr, xid));
}
int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
{
DBUG_ENTER("TC_LOG_BINLOG::unlog");
- pthread_mutex_lock(&LOCK_prep_xids);
+ mysql_mutex_lock(&LOCK_prep_xids);
DBUG_ASSERT(prepared_xids > 0);
if (--prepared_xids == 0) {
DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
- pthread_cond_signal(&COND_prep_xids);
+ mysql_cond_signal(&COND_prep_xids);
}
- pthread_mutex_unlock(&LOCK_prep_xids);
+ mysql_mutex_unlock(&LOCK_prep_xids);
DBUG_RETURN(rotate_and_purge(0)); // as ::write() did not rotate
}
@@ -6042,8 +6557,8 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
MEM_ROOT mem_root;
if (! fdle->is_valid() ||
- hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
- sizeof(my_xid), 0, 0, MYF(0)))
+ my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
+ sizeof(my_xid), 0, 0, MYF(0)))
goto err1;
init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
@@ -6067,12 +6582,12 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
goto err2;
free_root(&mem_root, MYF(0));
- hash_free(&xids);
+ my_hash_free(&xids);
return 0;
err2:
free_root(&mem_root, MYF(0));
- hash_free(&xids);
+ my_hash_free(&xids);
err1:
sql_print_error("Crash recovery failed. Either correct the problem "
"(if it's, for example, out of memory error) and restart, "
diff --git a/sql/log.h b/sql/log.h
index 2b0bc6111b3..05f8a4ce286 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 MySQL AB
+/* Copyright (C) 2005 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -16,13 +16,19 @@
#ifndef LOG_H
#define LOG_H
+#include "unireg.h" // REQUIRED: for other includes
+#include "handler.h" /* my_xid */
+
class Relay_log_info;
class Format_description_log_event;
-bool ending_trans(const THD* thd, const bool all);
+bool trans_has_updated_trans_table(const THD* thd);
+bool stmt_has_updated_trans_table(const THD *thd);
+bool use_trans_cache(const THD* thd, bool is_transactional);
+bool ending_trans(THD* thd, const bool all);
+bool ending_single_stmt_trans(THD* thd, const bool all);
bool trans_has_updated_non_trans_table(const THD* thd);
-bool trans_has_no_stmt_committed(const THD* thd, const bool all);
bool stmt_has_updated_non_trans_table(const THD* thd);
/*
@@ -70,8 +76,8 @@ class TC_LOG_MMAP: public TC_LOG
int size, free; // max and current number of free xid slots on the page
int waiters; // number of waiters on condition
PAGE_STATE state; // see above
- pthread_mutex_t lock; // to access page data or control structure
- pthread_cond_t cond; // to wait for a sync
+ mysql_mutex_t lock; // to access page data or control structure
+ mysql_cond_t cond; // to wait for a sync
} PAGE;
char logname[FN_REFLEN];
@@ -86,8 +92,8 @@ class TC_LOG_MMAP: public TC_LOG
one has to use active->lock.
Same for LOCK_pool and LOCK_sync
*/
- pthread_mutex_t LOCK_active, LOCK_pool, LOCK_sync;
- pthread_cond_t COND_pool, COND_active;
+ mysql_mutex_t LOCK_active, LOCK_pool, LOCK_sync;
+ mysql_cond_t COND_pool, COND_active;
public:
TC_LOG_MMAP(): inited(0) {}
@@ -126,23 +132,40 @@ extern TC_LOG_DUMMY tc_log_dummy;
#define LOG_CLOSE_TO_BE_OPENED 2
#define LOG_CLOSE_STOP_EVENT 4
+/*
+ Maximum unique log filename extension.
+ Note: setting to 0x7FFFFFFF due to atol windows
+ overflow/truncate.
+ */
+#define MAX_LOG_UNIQUE_FN_EXT 0x7FFFFFFF
+
+/*
+ Number of warnings that will be printed to error log
+ before extension number is exhausted.
+*/
+#define LOG_WARN_UNIQUE_FN_EXT_LEFT 1000
+
class Relay_log_info;
+#ifdef HAVE_PSI_INTERFACE
+extern PSI_mutex_key key_LOG_INFO_lock;
+#endif
+
typedef struct st_log_info
{
char log_file_name[FN_REFLEN];
my_off_t index_file_offset, index_file_start_offset;
my_off_t pos;
bool fatal; // if the purge happens to give us a negative offset
- pthread_mutex_t lock;
+ mysql_mutex_t lock;
st_log_info()
: index_file_offset(0), index_file_start_offset(0),
pos(0), fatal(0)
{
log_file_name[0] = '\0';
- pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOG_INFO_lock, &lock, MY_MUTEX_INIT_FAST);
}
- ~st_log_info() { pthread_mutex_destroy(&lock);}
+ ~st_log_info() { mysql_mutex_destroy(&lock);}
} LOG_INFO;
/*
@@ -173,7 +196,11 @@ public:
MYSQL_LOG();
void init_pthread_objects();
void cleanup();
- bool open(const char *log_name,
+ bool open(
+#ifdef HAVE_PSI_INTERFACE
+ PSI_file_key log_file_key,
+#endif
+ const char *log_name,
enum_log_type log_type,
const char *new_name,
enum cache_type io_cache_type_arg);
@@ -190,7 +217,7 @@ public:
int generate_new_name(char *new_name, const char *log_name);
protected:
/* LOCK_log is inited by init_pthread_objects() */
- pthread_mutex_t LOCK_log;
+ mysql_mutex_t LOCK_log;
char *name;
char log_file_name[FN_REFLEN];
char time_buff[20], db[NAME_LEN + 1];
@@ -200,6 +227,10 @@ public:
volatile enum_log_state log_state;
enum cache_type io_cache_type;
friend class Log_event;
+#ifdef HAVE_PSI_INTERFACE
+ /** Instrumentation key to use for file io in @c log_file */
+ PSI_file_key m_log_file_key;
+#endif
};
class MYSQL_QUERY_LOG: public MYSQL_LOG
@@ -218,14 +249,22 @@ public:
bool open_slow_log(const char *log_name)
{
char buf[FN_REFLEN];
- return open(generate_name(log_name, "-slow.log", 0, buf), LOG_NORMAL, 0,
- WRITE_CACHE);
+ return open(
+#ifdef HAVE_PSI_INTERFACE
+ key_file_slow_log,
+#endif
+ generate_name(log_name, "-slow.log", 0, buf),
+ LOG_NORMAL, 0, WRITE_CACHE);
}
bool open_query_log(const char *log_name)
{
char buf[FN_REFLEN];
- return open(generate_name(log_name, ".log", 0, buf), LOG_NORMAL, 0,
- WRITE_CACHE);
+ return open(
+#ifdef HAVE_PSI_INTERFACE
+ key_file_query_log,
+#endif
+ generate_name(log_name, ".log", 0, buf),
+ LOG_NORMAL, 0, WRITE_CACHE);
}
private:
@@ -236,10 +275,10 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
{
private:
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */
- pthread_mutex_t LOCK_index;
- pthread_mutex_t LOCK_prep_xids;
- pthread_cond_t COND_prep_xids;
- pthread_cond_t update_cond;
+ mysql_mutex_t LOCK_index;
+ mysql_mutex_t LOCK_prep_xids;
+ mysql_cond_t COND_prep_xids;
+ mysql_cond_t update_cond;
ulonglong bytes_written;
IO_CACHE index_file;
char index_file_name[FN_REFLEN];
@@ -277,6 +316,18 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
*/
bool no_auto_events;
+ /* pointer to the sync period variable, for binlog this will be
+ sync_binlog_period, for relay log this will be
+ sync_relay_log_period
+ */
+ uint *sync_period_ptr;
+ uint sync_counter;
+
+ inline uint get_sync_period()
+ {
+ return *sync_period_ptr;
+ }
+
int write_to_file(IO_CACHE *cache);
/*
This is used to start writing to a new log file. The difference from
@@ -292,7 +343,7 @@ public:
/* This is relay log */
bool is_relay_log;
-
+ ulong signal_cnt; // update of the counter is checked by heartbeat
/*
These describe the log's format. This is used only for relay logs.
_for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
@@ -304,7 +355,7 @@ public:
Format_description_log_event *description_event_for_exec,
*description_event_for_queue;
- MYSQL_BIN_LOG();
+ MYSQL_BIN_LOG(uint *sync_period);
/*
note that there's no destructor ~MYSQL_BIN_LOG() !
The reason is that we don't want it to be automatically called
@@ -317,8 +368,10 @@ public:
int unlog(ulong cookie, my_xid xid);
int recover(IO_CACHE *log, Format_description_log_event *fdle);
#if !defined(MYSQL_CLIENT)
- int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event);
- int remove_pending_rows_event(THD *thd);
+
+ int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event,
+ bool is_transactional);
+ int remove_pending_rows_event(THD *thd, bool is_transactional);
#endif /* !defined(MYSQL_CLIENT) */
void reset_bytes_written()
@@ -339,7 +392,8 @@ public:
}
void set_max_size(ulong max_size_arg);
void signal_update();
- void wait_for_update(THD* thd, bool master_or_slave);
+ void wait_for_update_relay_log(THD* thd);
+ int wait_for_update_bin_log(THD* thd, const struct timespec * timeout);
void set_need_start_event() { need_start_event = 1; }
void init(bool no_auto_events_arg, ulong max_size);
void init_pthread_objects();
@@ -356,13 +410,12 @@ public:
/* Use this to start writing a new log file */
int new_file();
- void reset_gathered_updates(THD *thd);
bool write(Log_event* event_info); // binary log write
bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident);
-
bool write_incident(THD *thd, bool lock);
+
int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
- void set_write_error(THD *thd);
+ void set_write_error(THD *thd, bool is_transactional);
bool check_write_error(THD *thd);
void start_union_events(THD *thd, query_id_t query_id_param);
@@ -380,7 +433,20 @@ public:
bool is_active(const char* log_file_name);
int update_log_index(LOG_INFO* linfo, bool need_update_threads);
int rotate_and_purge(uint flags);
- bool flush_and_sync();
+ /**
+ Flush binlog cache and synchronize to disk.
+
+ This function flushes events in binlog cache to binary log file,
+ it will do synchronizing according to the setting of system
+ variable 'sync_binlog'. If file is synchronized, @c synced will
+ be set to 1, otherwise 0.
+
+ @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0
+
+ @retval 0 Success
+ @retval other Failure
+ */
+ bool flush_and_sync(bool *synced);
int purge_logs(const char *to_log, bool included,
bool need_mutex, bool need_update_threads,
ulonglong *decrease_log_space);
@@ -409,11 +475,12 @@ public:
inline char* get_index_fname() { return index_file_name;}
inline char* get_log_fname() { return log_file_name; }
inline char* get_name() { return name; }
- inline pthread_mutex_t* get_log_lock() { return &LOCK_log; }
+ inline mysql_mutex_t* get_log_lock() { return &LOCK_log; }
+ inline mysql_cond_t* get_log_cond() { return &update_cond; }
inline IO_CACHE* get_log_file() { return &log_file; }
- inline void lock_index() { pthread_mutex_lock(&LOCK_index);}
- inline void unlock_index() { pthread_mutex_unlock(&LOCK_index);}
+ inline void lock_index() { mysql_mutex_lock(&LOCK_index);}
+ inline void unlock_index() { mysql_mutex_unlock(&LOCK_index);}
inline IO_CACHE *get_index_file() { return &index_file;}
inline uint32 get_open_count() { return open_count; }
};
@@ -441,8 +508,8 @@ public:
};
-int check_if_log_table(uint db_len, const char *db, uint table_name_len,
- const char *table_name, uint check_if_opened);
+int check_if_log_table(size_t db_len, const char *db, size_t table_name_len,
+ const char *table_name, bool check_if_opened);
class Log_to_csv_event_handler: public Log_event_handler
{
@@ -508,7 +575,7 @@ public:
/* Class which manages slow, general and error log event handlers */
class LOGGER
{
- rw_lock_t LOCK_logger;
+ mysql_rwlock_t LOCK_logger;
/* flag to check whether logger mutex is initialized */
uint inited;
@@ -528,9 +595,9 @@ public:
LOGGER() : inited(0), table_log_handler(NULL),
file_log_handler(NULL), is_log_tables_initialized(FALSE)
{}
- void lock_shared() { rw_rdlock(&LOCK_logger); }
- void lock_exclusive() { rw_wrlock(&LOCK_logger); }
- void unlock() { rw_unlock(&LOCK_logger); }
+ void lock_shared() { mysql_rwlock_rdlock(&LOCK_logger); }
+ void lock_exclusive() { mysql_rwlock_wrlock(&LOCK_logger); }
+ void unlock() { mysql_rwlock_unlock(&LOCK_logger); }
bool is_log_table_enabled(uint log_table_type);
bool log_command(THD *thd, enum enum_server_command command);
@@ -543,6 +610,8 @@ public:
void init_base();
void init_log_tables();
bool flush_logs(THD *thd);
+ bool flush_slow_log();
+ bool flush_general_log();
/* Perform basic logger cleanup. this will leave e.g. error log open. */
void cleanup_base();
/* Free memory. Nothing could be logged after this function is called */
@@ -565,13 +634,13 @@ public:
void init_general_log(uint general_log_printer);
void deactivate_log_handler(THD* thd, uint log_type);
bool activate_log_handler(THD* thd, uint log_type);
- MYSQL_QUERY_LOG *get_slow_log_file_handler()
+ MYSQL_QUERY_LOG *get_slow_log_file_handler() const
{
if (file_log_handler)
return file_log_handler->get_mysql_slow_log();
return NULL;
}
- MYSQL_QUERY_LOG *get_log_file_handler()
+ MYSQL_QUERY_LOG *get_log_file_handler() const
{
if (file_log_handler)
return file_log_handler->get_mysql_log();
@@ -580,22 +649,45 @@ public:
};
enum enum_binlog_format {
- /*
- statement-based except for cases where only row-based can work (UUID()
- etc):
- */
- BINLOG_FORMAT_MIXED= 0,
- BINLOG_FORMAT_STMT= 1, // statement-based
- BINLOG_FORMAT_ROW= 2, // row_based
-/*
- This value is last, after the end of binlog_format_typelib: it has no
- corresponding cell in this typelib. We use this value to be able to know if
- the user has explicitely specified a binlog format at startup or not.
-*/
- BINLOG_FORMAT_UNSPEC= 3
+ BINLOG_FORMAT_MIXED= 0, ///< statement if safe, otherwise row - autodetected
+ BINLOG_FORMAT_STMT= 1, ///< statement-based
+ BINLOG_FORMAT_ROW= 2, ///< row-based
+ BINLOG_FORMAT_UNSPEC=3 ///< thd_binlog_format() returns it when binlog is closed
};
-extern TYPELIB binlog_format_typelib;
int query_error_code(THD *thd, bool not_killed);
+uint purge_log_get_error_code(int res);
+
+int vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
+void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+void sql_print_information(const char *format, ...)
+ ATTRIBUTE_FORMAT(printf, 1, 2);
+typedef void (*sql_print_message_func)(const char *format, ...)
+ ATTRIBUTE_FORMAT(printf, 1, 2);
+extern sql_print_message_func sql_print_message_handlers[];
+
+int error_log_print(enum loglevel level, const char *format,
+ va_list args);
+
+bool slow_log_print(THD *thd, const char *query, uint query_length,
+ ulonglong current_utime);
+
+bool general_log_print(THD *thd, enum enum_server_command command,
+ const char *format,...);
+
+bool general_log_write(THD *thd, enum enum_server_command command,
+ const char *query, uint query_length);
+
+void sql_perror(const char *message);
+bool flush_error_log();
+
+File open_binlog(IO_CACHE *log, const char *log_file_name,
+ const char **errmsg);
+
+char *make_log_name(char *buff, const char *name, const char* log_ext);
+
+extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
+extern LOGGER logger;
#endif /* LOG_H */
diff --git a/sql/log_event.cc b/sql/log_event.cc
index d0635ddac1a..537865197da 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -16,7 +16,7 @@
#ifdef MYSQL_CLIENT
-#include "mysql_priv.h"
+#include "sql_priv.h"
#else
@@ -24,19 +24,32 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "my_global.h" // REQUIRED by log_event.h > m_string.h > my_bitmap.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_utility.h"
#include "rpl_record.h"
+#include "transaction.h"
#include <my_dir.h>
#endif /* MYSQL_CLIENT */
#include <base64.h>
#include <my_bitmap.h>
+#include "rpl_utility.h"
#define log_cs &my_charset_latin1
@@ -134,7 +147,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error,
char buff[MAX_SLAVE_ERRMSG], *slider;
const char *buff_end= buff + sizeof(buff);
uint len;
- List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+ List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
MYSQL_ERROR *err;
buff[0]= 0;
@@ -142,11 +155,12 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error,
slider += len, err= it++)
{
len= my_snprintf(slider, buff_end - slider,
- " %s, Error_code: %d;", err->msg, err->code);
+ " %s, Error_code: %d;", err->get_message_text(),
+ err->get_sql_errno());
}
if (ha_error != 0)
- rli->report(level, thd->is_error() ? thd->main_da.sql_errno() : 0,
+ rli->report(level, thd->is_error() ? thd->stmt_da->sql_errno() : 0,
"Could not execute %s event on table %s.%s;"
"%s handler error %s; "
"the event's master log %s, end_log_pos %lu",
@@ -154,7 +168,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error,
buff, handler_error == NULL ? "<unknown>" : handler_error,
log_name, pos);
else
- rli->report(level, thd->is_error() ? thd->main_da.sql_errno() : 0,
+ rli->report(level, thd->is_error() ? thd->stmt_da->sql_errno() : 0,
"Could not execute %s event on table %s.%s;"
"%s the event's master log %s, end_log_pos %lu",
type, table->s->db.str, table->s->table_name.str,
@@ -358,13 +372,13 @@ inline int ignored_error_code(int err_code)
*/
int convert_handler_error(int error, THD* thd, TABLE *table)
{
- uint actual_error= (thd->is_error() ? thd->main_da.sql_errno() :
+ uint actual_error= (thd->is_error() ? thd->stmt_da->sql_errno() :
0);
if (actual_error == 0)
{
table->file->print_error(error, MYF(0));
- actual_error= (thd->is_error() ? thd->main_da.sql_errno() :
+ actual_error= (thd->is_error() ? thd->stmt_da->sql_errno() :
ER_UNKNOWN_ERROR);
if (actual_error == ER_UNKNOWN_ERROR)
if (global_system_variables.log_warnings)
@@ -501,7 +515,7 @@ static void cleanup_load_tmpdir()
if (is_prefix(file->name, prefbuf))
{
fn_format(fname,file->name,slave_load_tmpdir,"",MY_UNPACK_FILENAME);
- my_delete(fname, MYF(0));
+ mysql_file_delete(key_file_misc, fname, MYF(0));
}
}
@@ -665,13 +679,17 @@ const char* Log_event::get_type_str()
#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), flags(flags_arg), thd(thd_arg)
+ :log_pos(0), temp_buf(0), exec_time(0), flags(flags_arg),
+ cache_type(Log_event::EVENT_INVALID_CACHE), thd(thd_arg)
{
server_id= thd->server_id;
when= thd->start_time;
- cache_stmt= using_trans;
-}
+ if (using_trans)
+ cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
+ else
+ cache_type= Log_event::EVENT_STMT_CACHE;
+}
/**
This minimal constructor is for when you are not even sure that there
@@ -681,8 +699,8 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
*/
Log_event::Log_event()
- :temp_buf(0), exec_time(0), flags(0), cache_stmt(0),
- thd(0)
+ :temp_buf(0), exec_time(0), flags(0),
+ cache_type(Log_event::EVENT_INVALID_CACHE), thd(0)
{
server_id= ::server_id;
/*
@@ -701,7 +719,7 @@ Log_event::Log_event()
Log_event::Log_event(const char* buf,
const Format_description_log_event* description_event)
- :temp_buf(0), cache_stmt(0)
+ :temp_buf(0), cache_type(Log_event::EVENT_INVALID_CACHE)
{
#ifndef MYSQL_CLIENT
thd = 0;
@@ -971,7 +989,7 @@ bool Log_event::write_header(IO_CACHE* file, ulong event_data_length)
*/
int Log_event::read_log_event(IO_CACHE* file, String* packet,
- pthread_mutex_t* log_lock)
+ mysql_mutex_t* log_lock)
{
ulong data_len;
int result=0;
@@ -979,7 +997,7 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
DBUG_ENTER("Log_event::read_log_event");
if (log_lock)
- pthread_mutex_lock(log_lock);
+ mysql_mutex_lock(log_lock);
if (my_b_read(file, (uchar*) buf, sizeof(buf)))
{
/*
@@ -1037,14 +1055,14 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
end:
if (log_lock)
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
DBUG_RETURN(result);
}
#endif /* !MYSQL_CLIENT */
#ifndef MYSQL_CLIENT
-#define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock);
-#define LOCK_MUTEX if (log_lock) pthread_mutex_lock(log_lock);
+#define UNLOCK_MUTEX if (log_lock) mysql_mutex_unlock(log_lock);
+#define LOCK_MUTEX if (log_lock) mysql_mutex_lock(log_lock);
#else
#define UNLOCK_MUTEX
#define LOCK_MUTEX
@@ -1056,7 +1074,7 @@ end:
Allocates memory; The caller is responsible for clean-up.
*/
Log_event* Log_event::read_log_event(IO_CACHE* file,
- pthread_mutex_t* log_lock,
+ mysql_mutex_t* log_lock,
const Format_description_log_event
*description_event)
#else
@@ -1137,7 +1155,7 @@ err:
sql_print_error("Error in Log_event::read_log_event(): "
"'%s', data_len: %d, event_type: %d",
error,data_len,head[EVENT_TYPE_OFFSET]);
- my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(buf);
/*
The SQL slave thread will check if file->error<0 to know
if there was an I/O error. Even if there is no "low-level" I/O errors
@@ -1204,15 +1222,11 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
*/
if (description_event->event_type_permutation)
{
- IF_DBUG({
- int new_event_type=
- description_event->event_type_permutation[event_type];
- DBUG_PRINT("info",
- ("converting event type %d to %d (%s)",
- event_type, new_event_type,
- get_type_str((Log_event_type)new_event_type)));
- });
- event_type= description_event->event_type_permutation[event_type];
+ int new_event_type= description_event->event_type_permutation[event_type];
+ DBUG_PRINT("info", ("converting event type %d to %d (%s)",
+ event_type, new_event_type,
+ get_type_str((Log_event_type)new_event_type)));
+ event_type= new_event_type;
}
switch(event_type) {
@@ -1577,37 +1591,14 @@ log_event_print_value(IO_CACHE *file, const uchar *ptr,
/* a long CHAR() field: see #37426 */
length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
type= byte0 | 0x30;
- goto beg;
- }
-
- switch (byte0)
- {
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_STRING:
- type= byte0;
- length= byte1;
- break;
-
- default:
-
- {
- char tmp[5];
- my_snprintf(tmp, sizeof(tmp), "%04X", meta);
- my_b_printf(file,
- "!! Don't know how to handle column type=%d meta=%d (%s)",
- type, meta, tmp);
- return 0;
- }
}
+ else
+ length = meta & 0xFF;
}
else
length= meta;
}
-
-beg:
-
switch (type) {
case MYSQL_TYPE_LONG:
{
@@ -1744,6 +1735,33 @@ beg:
return 3;
}
+ case MYSQL_TYPE_NEWDATE:
+ {
+ 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);
+ my_snprintf(typestr, typestr_length, "DATE");
+ return 3;
+ }
+
case MYSQL_TYPE_DATE:
{
uint i32= uint3korr(ptr);
@@ -1762,7 +1780,7 @@ beg:
}
case MYSQL_TYPE_ENUM:
- switch (length) {
+ switch (meta & 0xFF) {
case 1:
my_b_printf(file, "%d", (int) *ptr);
my_snprintf(typestr, typestr_length, "ENUM(1 byte)");
@@ -1775,15 +1793,15 @@ beg:
return 2;
}
default:
- my_b_printf(file, "!! Unknown ENUM packlen=%d", length);
+ my_b_printf(file, "!! Unknown ENUM packlen=%d", meta & 0xFF);
return 0;
}
break;
case MYSQL_TYPE_SET:
- my_b_write_bit(file, ptr , length * 8);
- my_snprintf(typestr, typestr_length, "SET(%d bytes)", length);
- return length;
+ my_b_write_bit(file, ptr , (meta & 0xFF) * 8);
+ my_snprintf(typestr, typestr_length, "SET(%d bytes)", meta & 0xFF);
+ return meta & 0xFF;
case MYSQL_TYPE_BLOB:
switch (meta) {
@@ -2056,7 +2074,7 @@ void Log_event::print_base64(IO_CACHE* file,
}
}
- my_free(tmp_str, MYF(0));
+ my_free(tmp_str);
DBUG_VOID_RETURN;
}
@@ -2136,7 +2154,7 @@ void Query_log_event::pack_info(Protocol *protocol)
pos+= q_len;
}
protocol->store(buf, pos-buf, &my_charset_bin);
- my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(buf);
}
#endif
@@ -2424,7 +2442,7 @@ Query_log_event::Query_log_event()
*/
Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
ulong query_length, bool using_trans,
- bool suppress_use, int errcode)
+ bool direct, bool suppress_use, int errcode)
:Log_event(thd_arg,
(thd_arg->thread_specific_used ? LOG_EVENT_THREAD_SPECIFIC_F :
@@ -2486,7 +2504,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
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->options &
+ 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);
@@ -2507,6 +2525,63 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
}
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;
+
+ switch (lex->sql_command)
+ {
+ case SQLCOM_DROP_TABLE:
+ use_cache= (lex->drop_temporary && thd->in_multi_stmt_transaction_mode());
+ break;
+
+ case SQLCOM_CREATE_TABLE:
+ trx_cache= (lex->select_lex.item_list.elements &&
+ thd->is_current_stmt_binlog_format_row());
+ use_cache= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
+ thd->in_multi_stmt_transaction_mode()) || trx_cache;
+ break;
+ case SQLCOM_SET_OPTION:
+ use_cache= trx_cache= (lex->autocommit ? FALSE : 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: %lu",
(ulong) flags2, sql_mode));
}
@@ -3150,7 +3225,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
}
else
{
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
+ const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
}
/*
@@ -3166,10 +3241,8 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
if (is_trans_keyword() || rpl_filter->db_ok(thd->db))
{
thd->set_time((time_t)when);
- thd->set_query((char*)query_arg, q_len_arg);
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id = next_query_id();
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ 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()));
@@ -3178,13 +3251,13 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
{
if (flags2_inited)
/*
- all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG
+ all bits of thd->variables.option_bits which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG
must take their value from flags2.
*/
- thd->options= flags2|(thd->options & ~OPTIONS_WRITTEN_TO_BIN_LOG);
+ 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->options and sql_mode etc, so
+ Rotate_log_event which reset thd->variables.option_bits and sql_mode etc, so
nothing to do.
*/
/*
@@ -3221,6 +3294,18 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
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)
@@ -3263,10 +3348,30 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
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 (expected_error &&
+ (ignored_error_code(expected_error) ||
+ concurrency_error_code(expected_error)))
+ {
+ thd->variables.option_bits|= OPTION_MASTER_SQL_ERROR;
+ }
/* Execute the query (note that we bypass dispatch_command()) */
- const char* found_semicolon= NULL;
- mysql_parse(thd, thd->query(), thd->query_length(), &found_semicolon);
- log_slow_statement(thd);
+ Parser_state parser_state;
+ if (!parser_state.init(thd, thd->query(), thd->query_length()))
+ {
+ mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
+ /* Finalize server status flags after executing a statement. */
+ thd->update_server_status();
+ log_slow_statement(thd);
+ }
+
+ thd->variables.option_bits&= ~OPTION_MASTER_SQL_ERROR;
/*
Resetting the enable_slow_log thd variable.
@@ -3306,11 +3411,10 @@ START SLAVE; . Query: '%s'", expected_error, thd->query());
}
/* If the query was not ignored, it is printed to the general log */
- if (!thd->is_error() || thd->main_da.sql_errno() != ER_SLAVE_IGNORED_TABLE)
+ if (!thd->is_error() || thd->stmt_da->sql_errno() != ER_SLAVE_IGNORED_TABLE)
general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
compare_errors:
-
/*
In the slave thread, we may sometimes execute some DROP / * 40005
TEMPORARY * / TABLE that come from parts of binlogs (likely if we
@@ -3319,20 +3423,21 @@ compare_errors:
not exist errors", we silently clear the error if TEMPORARY was used.
*/
if (thd->lex->sql_command == SQLCOM_DROP_TABLE && thd->lex->drop_temporary &&
- thd->is_error() && thd->main_da.sql_errno() == ER_BAD_TABLE_ERROR &&
+ thd->is_error() && thd->stmt_da->sql_errno() == ER_BAD_TABLE_ERROR &&
!expected_error)
- thd->main_da.reset_diagnostics_area();
+ thd->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->main_da.sql_errno() : 0;
+ actual_error= thd->is_error() ? thd->stmt_da->sql_errno() : 0;
DBUG_PRINT("info",("expected_error: %d sql_errno: %d",
- expected_error, actual_error));
+ expected_error, actual_error));
+
if ((expected_error && expected_error != actual_error &&
!concurrency_error_code(expected_error)) &&
- !ignored_error_code(actual_error) &&
- !ignored_error_code(expected_error))
+ !ignored_error_code(actual_error) &&
+ !ignored_error_code(expected_error))
{
rli->report(ERROR_LEVEL, 0,
"\
@@ -3341,7 +3446,7 @@ Error on master: '%s' (%d), Error on slave: '%s' (%d). \
Default database: '%s'. Query: '%s'",
ER_SAFE(expected_error),
expected_error,
- actual_error ? thd->main_da.message() : "no error",
+ actual_error ? thd->stmt_da->message() : "no error",
actual_error,
print_slave_db_safe(db), query_arg);
thd->is_slave_error= 1;
@@ -3350,39 +3455,22 @@ Default database: '%s'. Query: '%s'",
If we get the same error code as expected and it is not a concurrency
issue, or should be ignored.
*/
- else if ((expected_error == actual_error &&
+ else if ((expected_error == actual_error &&
!concurrency_error_code(expected_error)) ||
- ignored_error_code(actual_error))
+ ignored_error_code(actual_error))
{
DBUG_PRINT("info",("error ignored"));
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
thd->killed= THD::NOT_KILLED;
- /*
- When an error is expected and matches the actual error the
- slave does not report any error and by consequence changes
- on transactional tables are not rolled back in the function
- close_thread_tables(). For that reason, we explicitly roll
- them back here.
- */
- if (expected_error && expected_error == actual_error)
- ha_autocommit_or_rollback(thd, TRUE);
}
/*
- If we expected a non-zero error code and get nothing and, it is a concurrency
- issue or should be ignored.
- */
- else if (expected_error && !actual_error &&
- (concurrency_error_code(expected_error) ||
- ignored_error_code(expected_error)))
- ha_autocommit_or_rollback(thd, TRUE);
- /*
Other cases: mostly we expected no error and get one.
*/
else if (thd->is_slave_error || thd->is_fatal_error)
{
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' on query. Default database: '%s'. Query: '%s'",
- (actual_error ? thd->main_da.message() :
+ (actual_error ? thd->stmt_da->message() :
"unexpected success or fatal error"),
print_slave_db_safe(thd->db), query_arg);
thd->is_slave_error= 1;
@@ -3411,12 +3499,28 @@ Default database: '%s'. Query: '%s'",
*/
} /* 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 (strcmp("COMMIT", query) != 0 &&
+ strcmp("BEGIN", query) != 0)
+ {
+ if (thd->transaction.all.modified_non_trans_table)
+ const_cast<Relay_log_info*>(rli)->abort_slave= 1;
+ };);
+ }
+
end:
/*
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.
+ 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
@@ -3424,9 +3528,8 @@ end:
*/
thd->catalog= 0;
thd->set_db(NULL, 0); /* will free the current database */
- thd->set_query(NULL, 0);
+ thd->reset_query();
DBUG_PRINT("info", ("end: query= 0"));
- close_thread_tables(thd);
/*
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
@@ -3469,13 +3572,13 @@ Query_log_event::do_shall_skip(Relay_log_info *rli)
{
if (strcmp("BEGIN", query) == 0)
{
- thd->options|= OPTION_BEGIN;
+ thd->variables.option_bits|= OPTION_BEGIN;
DBUG_RETURN(Log_event::continue_group(rli));
}
if (strcmp("COMMIT", query) == 0 || strcmp("ROLLBACK", query) == 0)
{
- thd->options&= ~OPTION_BEGIN;
+ thd->variables.option_bits&= ~OPTION_BEGIN;
DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
}
}
@@ -3629,6 +3732,7 @@ bool Start_log_event_v3::write(IO_CACHE* file)
int Start_log_event_v3::do_apply_event(Relay_log_info const *rli)
{
DBUG_ENTER("Start_log_event_v3::do_apply_event");
+ int error= 0;
switch (binlog_version)
{
case 3:
@@ -3641,7 +3745,7 @@ int Start_log_event_v3::do_apply_event(Relay_log_info const *rli)
*/
if (created)
{
- close_temporary_tables(thd);
+ error= close_temporary_tables(thd);
cleanup_load_tmpdir();
}
else
@@ -3669,7 +3773,7 @@ int Start_log_event_v3::do_apply_event(Relay_log_info const *rli)
Can distinguish, based on the value of 'created': this event was
generated at master startup.
*/
- close_temporary_tables(thd);
+ error= close_temporary_tables(thd);
}
/*
Otherwise, can't distinguish a Start_log_event generated at
@@ -3681,7 +3785,7 @@ int Start_log_event_v3::do_apply_event(Relay_log_info const *rli)
/* this case is impossible */
DBUG_RETURN(1);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -3728,10 +3832,11 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
*/
if (post_header_len)
{
+#ifndef DBUG_OFF
// Allows us to sanity-check that all events initialized their
// events (see the end of this 'if' block).
- IF_DBUG(memset(post_header_len, 255,
- number_of_event_types*sizeof(uint8)););
+ memset(post_header_len, 255, number_of_event_types*sizeof(uint8));
+#endif
/* Note: all event types must explicitly fill in their lengths here. */
post_header_len[START_EVENT_V3-1]= START_V3_HEADER_LEN;
@@ -3782,13 +3887,12 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len[UPDATE_ROWS_EVENT-1]=
post_header_len[DELETE_ROWS_EVENT-1]= 6;);
post_header_len[INCIDENT_EVENT-1]= INCIDENT_HEADER_LEN;
+ post_header_len[HEARTBEAT_LOG_EVENT-1]= 0;
// Sanity-check that all post header lengths are initialized.
- IF_DBUG({
- int i;
- for (i=0; i<number_of_event_types; i++)
- assert(post_header_len[i] != 255);
- });
+ int i;
+ for (i=0; i<number_of_event_types; i++)
+ DBUG_ASSERT(post_header_len[i] != 255);
}
break;
@@ -3952,7 +4056,7 @@ Format_description_log_event(const char* buf,
DBUG_PRINT("info", (" number_of_event_types=%d",
number_of_event_types));
/* this makes is_valid() return false. */
- my_free(post_header_len, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(post_header_len);
post_header_len= NULL;
DBUG_VOID_RETURN;
}
@@ -4013,7 +4117,6 @@ int Format_description_log_event::do_apply_event(Relay_log_info const *rli)
int ret= 0;
DBUG_ENTER("Format_description_log_event::do_apply_event");
-#ifdef USING_TRANSACTIONS
/*
As a transaction NEVER spans on 2 or more binlogs:
if we have an active transaction at this point, the master died
@@ -4035,7 +4138,7 @@ int Format_description_log_event::do_apply_event(Relay_log_info const *rli)
"its binary log, thus rolled back too.");
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, 1);
}
-#endif
+
/*
If this event comes from ourselves, there is no cleaning task to
perform, we don't call Start_log_event_v3::do_apply_event()
@@ -4185,7 +4288,7 @@ void Load_log_event::print_query(bool need_db, const char *cs, char *buf,
pos= strmov(pos, "LOAD DATA ");
- if (thd->lex->lock_option == TL_WRITE_CONCURRENT_INSERT)
+ if (is_concurrent)
pos= strmov(pos, "CONCURRENT ");
if (fn_start)
@@ -4276,7 +4379,7 @@ void Load_log_event::pack_info(Protocol *protocol)
return;
print_query(TRUE, NULL, buf, &end, 0, 0);
protocol->store(buf, end-buf, &my_charset_bin);
- my_free(buf, MYF(0));
+ my_free(buf);
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -4327,6 +4430,7 @@ bool Load_log_event::write_data_body(IO_CACHE* file)
Load_log_event::Load_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, bool using_trans)
:Log_event(thd_arg,
@@ -4337,7 +4441,8 @@ Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
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)
+ db(db_arg), fname(ex->file_name), local_fname(FALSE),
+ is_concurrent(is_concurrent_arg)
{
time_t end_time;
time(&end_time);
@@ -4418,7 +4523,13 @@ Load_log_event::Load_log_event(const char *buf, uint event_len,
const Format_description_log_event *description_event)
:Log_event(buf, description_event), num_fields(0), fields(0),
field_lens(0),field_block_len(0),
- table_name(0), db(0), fname(0), local_fname(FALSE)
+ table_name(0), db(0), fname(0), local_fname(FALSE),
+ /*
+ Load_log_event which comes from the binary log does not contain
+ information about the type of insert which was used on the master.
+ Assume that it was an ordinary, non-concurrent LOAD DATA.
+ */
+ is_concurrent(FALSE)
{
DBUG_ENTER("Load_log_event");
/*
@@ -4575,9 +4686,9 @@ void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
for (i = 0; i < num_fields; i++)
{
if (i)
- my_b_printf(&cache, ",");
+ my_b_printf(&cache, ",");
my_b_printf(&cache, "%s", field);
-
+
field += field_lens[i] + 1;
}
my_b_printf(&cache, ")");
@@ -4654,7 +4765,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length);
thd->set_db(new_db.str, new_db.length);
DBUG_ASSERT(thd->query() == 0);
- thd->set_query_inner(NULL, 0); // Should not be needed
+ thd->reset_query_inner(); // Should not be needed
thd->is_slave_error= 0;
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
@@ -4704,22 +4815,14 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
if (rpl_filter->db_ok(thd->db))
{
thd->set_time((time_t)when);
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id = next_query_id();
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- /*
- Initing thd->row_count is not necessary in theory as this variable has no
- influence in the case of the slave SQL thread (it is used to generate a
- "data truncated" warning but which is absorbed and never gets to the
- error log); still we init it to avoid a Valgrind message.
- */
- mysql_reset_errors(thd, 0);
+ thd->set_query_id(next_query_id());
+ thd->warning_info->opt_clear_warning_info(thd->query_id);
TABLE_LIST tables;
- bzero((char*) &tables,sizeof(tables));
- tables.db= thd->strmake(thd->db, thd->db_length);
- tables.alias = tables.table_name = (char*) table_name;
- tables.lock_type = TL_WRITE;
+ tables.init_one_table(thd->strmake(thd->db, thd->db_length),
+ thd->db_length,
+ table_name, strlen(table_name),
+ table_name, TL_WRITE);
tables.updating= 1;
// the table will be opened in mysql_load
@@ -4755,9 +4858,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
thd->set_query(load_data_query, (uint) (end - load_data_query));
if (sql_ex.opt_flags & REPLACE_FLAG)
- {
- handle_dup= DUP_REPLACE;
- }
+ handle_dup= DUP_REPLACE;
else if (sql_ex.opt_flags & IGNORE_FLAG)
{
ignore= 1;
@@ -4766,14 +4867,14 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
else
{
/*
- When replication is running fine, if it was DUP_ERROR on the
+ 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.
+ (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.
@@ -4805,7 +4906,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
- ex.field_term->length(0);
+ ex.field_term->length(0);
ex.skip_lines = skip_lines;
List<Item> field_list;
@@ -4814,12 +4915,10 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
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;
+ // 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
@@ -4831,7 +4930,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
thd->is_slave_error= 1;
if (thd->cuted_fields)
{
- /* log_pos is the position of the LOAD event in the master log */
+ /* 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 %s in log '%s' produced %ld "
"warning(s). Default database: '%s'",
@@ -4860,8 +4959,25 @@ error:
const char *remember_db= thd->db;
thd->catalog= 0;
thd->set_db(NULL, 0); /* will free the current database */
- thd->set_query(NULL, 0);
+ thd->reset_query();
+ thd->stmt_da->can_overwrite_status= TRUE;
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ thd->stmt_da->can_overwrite_status= FALSE;
close_thread_tables(thd);
+ /*
+ - 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->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;);
@@ -4873,8 +4989,8 @@ error:
int sql_errno;
if (thd->is_error())
{
- err= thd->main_da.message();
- sql_errno= thd->main_da.sql_errno();
+ err= thd->stmt_da->message();
+ sql_errno= thd->stmt_da->sql_errno();
}
else
{
@@ -5067,7 +5183,7 @@ int Rotate_log_event::do_update_pos(Relay_log_info *rli)
!is_relay_log_event() &&
!rli->is_in_group())
{
- pthread_mutex_lock(&rli->data_lock);
+ 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,
@@ -5079,11 +5195,11 @@ int Rotate_log_event::do_update_pos(Relay_log_info *rli)
"new group_master_log_pos: %lu",
rli->group_master_log_name,
(ulong) rli->group_master_log_pos));
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
flush_relay_log_info(rli);
/*
- Reset thd->options and sql_mode etc, because this could be the signal of
+ 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
@@ -5442,10 +5558,14 @@ void Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Xid_log_event::do_apply_event(Relay_log_info const *rli)
{
+ bool res;
/* For a slave Xid_log_event is COMMIT */
general_log_print(thd, COM_QUERY,
"COMMIT /* implicit, from Xid_log_event */");
- return end_trans(thd, COMMIT);
+ res= trans_commit(thd); /* Automatically rolls back on error. */
+ thd->mdl_context.release_transactional_locks();
+
+ return res;
}
Log_event::enum_skip_reason
@@ -5453,7 +5573,7 @@ Xid_log_event::do_shall_skip(Relay_log_info *rli)
{
DBUG_ENTER("Xid_log_event::do_shall_skip");
if (rli->slave_skip_counter > 0) {
- thd->options&= ~OPTION_BEGIN;
+ thd->variables.option_bits&= ~OPTION_BEGIN;
DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
}
DBUG_RETURN(Log_event::do_shall_skip(rli));
@@ -5485,15 +5605,18 @@ void User_var_log_event::pack_info(Protocol* protocol)
case REAL_RESULT:
double real_val;
float8get(real_val, val);
- if (!(buf= (char*) my_malloc(val_offset + FLOATING_POINT_BUFFER,
+ if (!(buf= (char*) my_malloc(val_offset + MY_GCVT_MAX_FIELD_WIDTH + 1,
MYF(MY_WME))))
return;
- event_len+= sprintf(buf + val_offset, "%.14g", real_val);
+ event_len+= my_gcvt(real_val, MY_GCVT_ARG_DOUBLE, MY_GCVT_MAX_FIELD_WIDTH,
+ buf + val_offset, NULL);
break;
case INT_RESULT:
if (!(buf= (char*) my_malloc(val_offset + 22, MYF(MY_WME))))
return;
- event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf;
+ event_len= longlong10_to_str(uint8korr(val), buf + val_offset,
+ ((flags & User_var_log_event::UNSIGNED_F) ?
+ 10 : -10))-buf;
break;
case DECIMAL_RESULT:
{
@@ -5540,7 +5663,7 @@ void User_var_log_event::pack_info(Protocol* protocol)
buf[2+name_len]= '`';
buf[3+name_len]= '=';
protocol->store(buf, event_len, &my_charset_bin);
- my_free(buf, MYF(0));
+ my_free(buf);
}
#endif /* !MYSQL_CLIENT */
@@ -5551,12 +5674,14 @@ User_var_log_event(const char* buf,
:Log_event(buf, description_event)
{
/* The Post-Header is empty. The Variable Data part begins immediately. */
+ const char *start= buf;
buf+= description_event->common_header_len +
description_event->post_header_len[USER_VAR_EVENT-1];
name_len= uint4korr(buf);
name= (char *) buf + UV_NAME_LEN_SIZE;
buf+= UV_NAME_LEN_SIZE + name_len;
is_null= (bool) *buf;
+ flags= User_var_log_event::UNDEF_F; // defaults to UNDEF_F
if (is_null)
{
type= STRING_RESULT;
@@ -5568,10 +5693,31 @@ User_var_log_event(const char* buf,
{
type= (Item_result) buf[UV_VAL_IS_NULL];
charset_number= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE);
- val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
- UV_CHARSET_NUMBER_SIZE);
+ val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
+ UV_CHARSET_NUMBER_SIZE);
val= (char *) (buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
- UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE);
+ UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE);
+
+ /**
+ We need to check if this is from an old server
+ that did not pack information for flags.
+ We do this by checking if there are extra bytes
+ after the packed value. If there are we take the
+ extra byte and it's value is assumed to contain
+ the flags value.
+
+ Old events will not have this extra byte, thence,
+ we keep the flags set to UNDEF_F.
+ */
+ uint bytes_read= ((val + val_len) - start);
+ DBUG_ASSERT(bytes_read==data_written ||
+ bytes_read==(data_written-1));
+ if ((data_written - bytes_read) > 0)
+ {
+ flags= (uint) *(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
+ UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE +
+ val_len);
+ }
}
}
@@ -5583,6 +5729,7 @@ bool User_var_log_event::write(IO_CACHE* file)
char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
uchar buf2[max(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2;
+ uint unsigned_len= 0;
uint buf1_length;
ulong event_length;
@@ -5604,6 +5751,7 @@ bool User_var_log_event::write(IO_CACHE* file)
break;
case INT_RESULT:
int8store(buf2, *(longlong*) val);
+ unsigned_len= 1;
break;
case DECIMAL_RESULT:
{
@@ -5628,13 +5776,14 @@ bool User_var_log_event::write(IO_CACHE* file)
}
/* Length of the whole event */
- event_length= sizeof(buf)+ name_len + buf1_length + val_len;
+ event_length= sizeof(buf)+ name_len + buf1_length + val_len + unsigned_len;
return (write_header(file, event_length) ||
my_b_safe_write(file, (uchar*) buf, sizeof(buf)) ||
- my_b_safe_write(file, (uchar*) name, name_len) ||
- my_b_safe_write(file, (uchar*) buf1, buf1_length) ||
- my_b_safe_write(file, pos, val_len));
+ my_b_safe_write(file, (uchar*) name, name_len) ||
+ my_b_safe_write(file, (uchar*) buf1, buf1_length) ||
+ my_b_safe_write(file, pos, val_len) ||
+ my_b_safe_write(file, &flags, unsigned_len));
}
#endif
@@ -5675,7 +5824,8 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
break;
case INT_RESULT:
char int_buf[22];
- longlong10_to_str(uint8korr(val), int_buf, -10);
+ longlong10_to_str(uint8korr(val), int_buf,
+ ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10));
my_b_printf(&cache, ":=%s%s\n", int_buf, print_event_info->delimiter);
break;
case DECIMAL_RESULT:
@@ -5822,7 +5972,8 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli)
a single record and with a single column. Thus, like
a column value, it could always have IMPLICIT derivation.
*/
- e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0);
+ e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT,
+ (flags & User_var_log_event::UNSIGNED_F));
free_root(thd->mem_root,0);
return 0;
@@ -5899,13 +6050,13 @@ Slave_log_event::Slave_log_event(THD* thd_arg,
Master_info* mi = rli->mi;
// TODO: re-write this better without holding both locks at the same time
- pthread_mutex_lock(&mi->data_lock);
- pthread_mutex_lock(&rli->data_lock);
+ mysql_mutex_lock(&mi->data_lock);
+ mysql_mutex_lock(&rli->data_lock);
master_host_len = strlen(mi->host);
master_log_len = strlen(rli->group_master_log_name);
// on OOM, just do not initialize the structure and print the error
if ((mem_pool = (char*)my_malloc(get_data_size() + 1,
- MYF(MY_WME))))
+ MYF(MY_WME))))
{
master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
memcpy(master_host, mi->host, master_host_len + 1);
@@ -5914,12 +6065,12 @@ Slave_log_event::Slave_log_event(THD* thd_arg,
master_port = mi->port;
master_pos = rli->group_master_log_pos;
DBUG_PRINT("info", ("master_log: %s pos: %lu", master_log,
- (ulong) master_pos));
+ (ulong) master_pos));
}
else
sql_print_error("Out of memory while recording slave event");
- pthread_mutex_unlock(&rli->data_lock);
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_VOID_RETURN;
}
#endif /* !MYSQL_CLIENT */
@@ -5927,7 +6078,7 @@ Slave_log_event::Slave_log_event(THD* thd_arg,
Slave_log_event::~Slave_log_event()
{
- my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mem_pool);
}
@@ -6057,7 +6208,7 @@ int Stop_log_event::do_update_pos(Relay_log_info *rli)
could give false triggers in MASTER_POS_WAIT() that we have reached
the target position when in fact we have not.
*/
- if (thd->options & OPTION_BEGIN)
+ if (thd->variables.option_bits & OPTION_BEGIN)
rli->inc_event_relay_log_pos();
else
{
@@ -6083,11 +6234,14 @@ int Stop_log_event::do_update_pos(Relay_log_info *rli)
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, enum enum_duplicates handle_dup,
+ 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,handle_dup, ignore,
- 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())
{
@@ -6280,10 +6434,12 @@ int Create_file_log_event::do_apply_event(Relay_log_info const *rli)
fname_buf= strmov(proc_info, "Making temp file ");
ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info");
thd_proc_info(thd, proc_info);
- my_delete(fname_buf, MYF(0)); // old copy may exist already
- if ((fd= my_create(fname_buf, CREATE_MODE,
- O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0 ||
+ /* 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)))
{
@@ -6305,20 +6461,22 @@ int Create_file_log_event::do_apply_event(Relay_log_info const *rli)
goto err;
}
end_io_cache(&file);
- my_close(fd, MYF(0));
+ mysql_file_close(fd, MYF(0));
// fname_buf now already has .data, not .info, because we did our trick
- my_delete(fname_buf, MYF(0)); // old copy may exist already
- if ((fd= my_create(fname_buf, CREATE_MODE,
- O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
+ /* 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,
"Error in Create_file event: could not open file '%s'",
fname_buf);
goto err;
}
- if (my_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
+ if (mysql_file_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
{
rli->report(ERROR_LEVEL, my_errno,
"Error in Create_file event: write to '%s' failed",
@@ -6331,7 +6489,7 @@ err:
if (error)
end_io_cache(&file);
if (fd >= 0)
- my_close(fd, MYF(0));
+ mysql_file_close(fd, MYF(0));
thd_proc_info(thd, 0);
return error != 0;
}
@@ -6462,10 +6620,12 @@ int Append_block_log_event::do_apply_event(Relay_log_info const *rli)
*/
lex_start(thd);
mysql_reset_thd_for_next_command(thd);
- my_delete(fname, MYF(0)); // old copy may exist already
- if ((fd= my_create(fname, CREATE_MODE,
- O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
+ /* 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,
"Error in %s event: could not create file '%s'",
@@ -6473,8 +6633,10 @@ int Append_block_log_event::do_apply_event(Relay_log_info const *rli)
goto err;
}
}
- else if ((fd = my_open(fname, O_WRONLY | O_APPEND | O_BINARY | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
+ 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,
"Error in %s event: could not open file '%s'",
@@ -6482,10 +6644,12 @@ int Append_block_log_event::do_apply_event(Relay_log_info const *rli)
goto err;
}
- DBUG_EXECUTE_IF("remove_slave_load_file_before_write",
- my_close(fd,MYF(0)); fd= -1; my_delete(fname, MYF(0)););
+ DBUG_EXECUTE_IF("remove_slave_load_file_before_write",
+ {
+ my_delete_allow_opened(fname, MYF(0));
+ });
- if (my_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
+ if (mysql_file_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
{
rli->report(ERROR_LEVEL, my_errno,
"Error in %s event: write to '%s' failed",
@@ -6496,7 +6660,7 @@ int Append_block_log_event::do_apply_event(Relay_log_info const *rli)
err:
if (fd >= 0)
- my_close(fd, MYF(0));
+ mysql_file_close(fd, MYF(0));
thd_proc_info(thd, 0);
DBUG_RETURN(error);
}
@@ -6590,9 +6754,9 @@ int Delete_file_log_event::do_apply_event(Relay_log_info const *rli)
{
char fname[FN_REFLEN+10];
char *ext= slave_load_file_stem(fname, file_id, server_id, ".data");
- (void) my_delete(fname, MYF(MY_WME));
+ mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
strmov(ext, ".info");
- (void) my_delete(fname, MYF(MY_WME));
+ mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME));
return 0;
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -6693,8 +6857,9 @@ int Execute_load_log_event::do_apply_event(Relay_log_info const *rli)
Load_log_event *lev= 0;
ext= slave_load_file_stem(fname, file_id, server_id, ".info");
- if ((fd = my_open(fname, O_RDONLY | O_BINARY | O_NOFOLLOW,
- MYF(MY_WME))) < 0 ||
+ 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)))
{
@@ -6704,7 +6869,7 @@ int Execute_load_log_event::do_apply_event(Relay_log_info const *rli)
goto err;
}
if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,
- (pthread_mutex_t*)0,
+ (mysql_mutex_t*)0,
rli->relay_log.description_event_for_exec)) ||
lev->get_type_code() != NEW_LOAD_EVENT)
{
@@ -6738,30 +6903,30 @@ int Execute_load_log_event::do_apply_event(Relay_log_info const *rli)
{
rli->report(ERROR_LEVEL, rli->last_error().number,
"%s. Failed executing load from '%s'", tmp, fname);
- my_free(tmp,MYF(0));
+ 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 my_delete().
+ or Windows will refuse to delete the file in mysql_file_delete().
*/
if (fd >= 0)
{
- my_close(fd, MYF(0));
+ mysql_file_close(fd, MYF(0));
end_io_cache(&file);
fd= -1;
}
- (void) my_delete(fname, MYF(MY_WME));
+ mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME));
memcpy(ext, ".data", 6);
- (void) my_delete(fname, MYF(MY_WME));
+ mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
error = 0;
err:
delete lev;
if (fd >= 0)
{
- my_close(fd, MYF(0));
+ mysql_file_close(fd, MYF(0));
end_io_cache(&file);
}
return error;
@@ -6826,9 +6991,9 @@ 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 suppress_use,
+ bool using_trans, bool direct, bool suppress_use,
int errcode):
- Query_log_event(thd_arg, query_arg, query_length_arg, using_trans,
+ 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)
@@ -6943,7 +7108,7 @@ void Execute_load_query_log_event::pack_info(Protocol *protocol)
pos= strmov(pos, " ;file_id=");
pos= int10_to_str((long) file_id, pos, 10);
protocol->store(buf, pos-buf, &my_charset_bin);
- my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(buf);
}
@@ -6959,7 +7124,7 @@ Execute_load_query_log_event::do_apply_event(Relay_log_info const *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, MYF(0)); buf= NULL;);
+ 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)
@@ -7000,9 +7165,9 @@ Execute_load_query_log_event::do_apply_event(Relay_log_info const *rli)
file so that we can re-execute this event at START SLAVE.
*/
if (!error)
- (void) my_delete(fname, MYF(MY_WME));
+ mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
- my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(buf);
return error;
}
#endif
@@ -7123,9 +7288,9 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
DBUG_ASSERT((tbl_arg && tbl_arg->s && tid != ~0UL) ||
(!tbl_arg && !cols && tid == ~0UL));
- if (thd_arg->options & OPTION_NO_FOREIGN_KEY_CHECKS)
+ if (thd_arg->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS)
set_flags(NO_FOREIGN_KEY_CHECKS_F);
- if (thd_arg->options & OPTION_RELAXED_UNIQUE_CHECKS)
+ if (thd_arg->variables.option_bits & OPTION_RELAXED_UNIQUE_CHECKS)
set_flags(RELAXED_UNIQUE_CHECKS_F);
/* if bitmap_init fails, caught in is_valid() */
if (likely(!bitmap_init(&m_cols,
@@ -7267,7 +7432,7 @@ Rows_log_event::~Rows_log_event()
if (m_cols.bitmap == m_bitbuf) // no my_malloc happened
m_cols.bitmap= 0; // so no my_free in bitmap_free
bitmap_free(&m_cols); // To pair with bitmap_init().
- my_free((uchar*)m_rows_buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(m_rows_buf);
}
int Rows_log_event::get_data_size()
@@ -7370,8 +7535,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
DBUG_ASSERT(get_flags(STMT_END_F));
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
- close_thread_tables(thd);
+ const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
thd->clear_error();
DBUG_RETURN(0);
}
@@ -7397,7 +7561,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
We also call the mysql_reset_thd_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_row_based, so
+ call might reset the value of current_stmt_binlog_format, so
we need to do any changes to that value after this function.
*/
lex_start(thd);
@@ -7409,16 +7573,12 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
thd->transaction.stmt.modified_non_trans_table= FALSE;
/*
- Check if the slave is set to use SBR. If so, it should switch
- to using RBR until the end of the "statement", i.e., next
- STMT_END_F or next error.
+ 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.
*/
- if (!thd->current_stmt_binlog_row_based &&
- mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG))
- {
- thd->set_current_stmt_binlog_row_based();
- }
-
+ thd->lex->set_stmt_row_injection();
/*
There are a few flags that are replicated with each row event.
@@ -7426,20 +7586,20 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
the event.
*/
if (get_flags(NO_FOREIGN_KEY_CHECKS_F))
- thd->options|= OPTION_NO_FOREIGN_KEY_CHECKS;
+ thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
else
- thd->options&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
+ thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
if (get_flags(RELAXED_UNIQUE_CHECKS_F))
- thd->options|= OPTION_RELAXED_UNIQUE_CHECKS;
+ thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS;
else
- thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS;
+ thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
/* A small test to verify that objects have consistent types */
- DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
+ DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
- if (simple_open_n_lock_tables(thd, rli->tables_to_lock))
+ if (open_and_lock_tables(thd, rli->tables_to_lock, FALSE, 0))
{
- uint actual_error= thd->main_da.sql_errno();
+ uint actual_error= thd->stmt_da->sql_errno();
if (thd->is_slave_error || thd->is_fatal_error)
{
/*
@@ -7449,12 +7609,12 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
having severe errors which should not be skiped.
*/
rli->report(ERROR_LEVEL, actual_error,
- "Error '%s' on opening tables",
- (actual_error ? thd->main_da.message() :
+ "Error executing row event: '%s'",
+ (actual_error ? thd->stmt_da->message() :
"unexpected success or fatal error"));
thd->is_slave_error= 1;
}
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
+ const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
DBUG_RETURN(actual_error);
}
@@ -7467,27 +7627,37 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
{
+ DBUG_PRINT("debug", ("Checking compability of tables to lock - tables_to_lock: %p",
+ rli->tables_to_lock));
RPL_TABLE_LIST *ptr= rli->tables_to_lock;
for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global))
{
- if (ptr->m_tabledef.compatible_with(rli, ptr->table))
+ TABLE *conv_table;
+ if (!ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli),
+ 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.
*/
- mysql_unlock_tables(thd, thd->lock);
- thd->lock= 0;
thd->is_slave_error= 1;
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
+ const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
DBUG_RETURN(ERR_BAD_TABLE_DEF);
}
+ 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 remove
- them from tables to lock.
+ ... 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.
@@ -7589,7 +7759,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
{
int actual_error= convert_handler_error(error, thd, table);
bool idempotent_error= (idempotent_error_code(error) &&
- (slave_exec_mode & SLAVE_EXEC_MODE_IDEMPOTENT));
+ (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT));
bool ignored_error= (idempotent_error == 0 ?
ignored_error_code(actual_error) : 0);
@@ -7631,8 +7801,16 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
thd->transaction.stmt.modified_non_trans_table= TRUE;
} // row processing loop
- DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event",
- const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
+ {/**
+ 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 ((error= do_after_row_operations(rli, error)) &&
ignored_error_code(convert_handler_error(error, thd, table)))
@@ -7647,47 +7825,22 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
}
} // if (table)
- /*
- We need to delay this clear until here bacause unpack_current_row() uses
- master-side table definitions stored in rli.
- */
- if (rli->tables_to_lock && get_flags(STMT_END_F))
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
if (error)
{
slave_rows_error_report(ERROR_LEVEL, error, rli, thd, table,
get_type_str(),
RPL_LOG_NAME, (ulong) log_pos);
- thd->reset_current_stmt_binlog_row_based();
- thd->is_slave_error= 1;
- DBUG_RETURN(error);
- }
- /*
- This code would ideally be placed in do_update_pos() instead, but
- since we have no access to table there, we do the setting of
- last_event_start_time here instead.
- */
- else if (table && (table->s->primary_key == MAX_KEY) &&
- !cache_stmt && get_flags(STMT_END_F) == RLE_NO_FLAGS)
- {
/*
- ------------ Temporary fix until WL#2975 is implemented ---------
-
- This event is not the last one (no STMT_END_F). If we stop now
- (in case of terminate_slave_thread()), how will we restart? We
- have to restart from Table_map_log_event, but as this table is
- not transactional, the rows already inserted will still be
- present, and idempotency is not guaranteed (no PK) so we risk
- that repeating leads to double insert. So we desperately try to
- continue, hope we'll eventually leave this buggy situation (by
- executing the final Rows_log_event). If we are in a hopeless
- wait (reached end of last relay log and nothing gets appended
- there), we timeout after one minute, and notify DBA about the
- problem. When WL#2975 is implemented, just remove the member
- Relay_log_info::last_event_start_time and all its occurrences.
+ @todo We should probably not call
+ reset_current_stmt_binlog_format_row() from here.
+
+ Note: this applies to log_event_old.cc too.
+ /Sven
*/
- const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0);
+ thd->reset_current_stmt_binlog_format_row();
+ thd->is_slave_error= 1;
+ DBUG_RETURN(error);
}
if (get_flags(STMT_END_F) && (error= rows_event_stmt_cleanup(rli, thd)))
@@ -7743,7 +7896,7 @@ static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD * thd)
(assume the last master's transaction is ignored by the slave because of
replicate-ignore rules).
*/
- error= thd->binlog_flush_pending_rows_event(true);
+ error= thd->binlog_flush_pending_rows_event(TRUE);
/*
If this event is not in a transaction, the call below will, if some
@@ -7754,7 +7907,7 @@ static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD * thd)
are involved, commit the transaction and flush the pending event to the
binlog.
*/
- error|= ha_autocommit_or_rollback(thd, error);
+ error|= (error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd));
/*
Now what if this is not a transactional engine? we still need to
@@ -7766,7 +7919,17 @@ static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD * thd)
event flushed.
*/
- thd->reset_current_stmt_binlog_row_based();
+ /*
+ @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();
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, 0);
}
@@ -7973,7 +8136,10 @@ 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) */
@@ -7986,7 +8152,7 @@ int Table_map_log_event::save_field_metadata()
#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, true),
+ : Log_event(thd, 0, is_transactional),
m_table(tbl),
m_dbnam(tbl->s->db.str),
m_dblen(m_dbnam ? tbl->s->db.length : 0),
@@ -8185,8 +8351,8 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
Table_map_log_event::~Table_map_log_event()
{
- my_free(m_meta_memory, MYF(MY_ALLOW_ZERO_PTR));
- my_free(m_memory, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(m_meta_memory);
+ my_free(m_memory);
}
/*
@@ -8211,9 +8377,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
DBUG_ASSERT(rli->sql_thd == thd);
/* Step the query id to mark what columns that are actually used. */
- pthread_mutex_lock(&LOCK_thread_count);
- thd->query_id= next_query_id();
- pthread_mutex_unlock(&LOCK_thread_count);
+ thd->set_query_id(next_query_id());
if (!(memory= my_multi_malloc(MYF(MY_WME),
&table_list, (uint) sizeof(RPL_TABLE_LIST),
@@ -8222,15 +8386,15 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
NullS)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
- bzero(table_list, sizeof(*table_list));
- table_list->db = db_mem;
- table_list->alias= table_list->table_name = tname_mem;
- table_list->lock_type= TL_WRITE;
- table_list->next_global= table_list->next_local= 0;
+ strmov(db_mem, rpl_filter->get_rewrite_db(m_dbnam, &dummy_len));
+ strmov(tname_mem, m_tblnam);
+
+ table_list->init_one_table(db_mem, strlen(db_mem),
+ tname_mem, strlen(tname_mem),
+ tname_mem, TL_WRITE);
+
table_list->table_id= m_table_id;
table_list->updating= 1;
- strmov(table_list->db, rpl_filter->get_rewrite_db(m_dbnam, &dummy_len));
- strmov(table_list->table_name, m_tblnam);
int error= 0;
@@ -8238,7 +8402,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
(!rpl_filter->db_ok(table_list->db) ||
(rpl_filter->is_on() && !rpl_filter->tables_ok("", table_list))))
{
- my_free(memory, MYF(MY_WME));
+ my_free(memory);
}
else
{
@@ -8258,7 +8422,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
m_field_metadata, m_field_metadata_size,
m_null_bits, m_flags);
table_list->m_tabledef_valid= TRUE;
- table_list->skip_temporary= 1;
+ table_list->open_type= OT_BASE_ONLY;
/*
We record in the slave's information that the table should be
@@ -8415,8 +8579,8 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability
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) ||
- m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER)
+ if ((slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT) ||
+ (m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER))
{
/*
We are using REPLACE semantics and not INSERT IGNORE semantics
@@ -8494,7 +8658,7 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *
int local_error= 0;
m_table->next_number_field=0;
m_table->auto_increment_field_not_null= FALSE;
- if ((slave_exec_mode & SLAVE_EXEC_MODE_IDEMPOTENT) ||
+ if ((slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT) ||
m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER)
{
m_table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
@@ -8791,19 +8955,19 @@ Rows_log_event::write_row(const Relay_log_info *const rli,
#endif
-int
+int
Write_rows_log_event::do_exec_row(const Relay_log_info *const rli)
{
DBUG_ASSERT(m_table != NULL);
- int error= write_row(rli, (slave_exec_mode & SLAVE_EXEC_MODE_IDEMPOTENT));
+ int error= write_row(rli, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT);
if (error && !thd->is_error())
{
DBUG_ASSERT(0);
my_error(ER_UNKNOWN_ERROR, MYF(0));
}
-
- return error;
+
+ return error;
}
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
@@ -9294,7 +9458,7 @@ Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability
{
/*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, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(m_key);
m_key= NULL;
return error;
@@ -9417,7 +9581,7 @@ Update_rows_log_event::do_after_row_operations(const Slave_reporting_capability
{
/*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, MYF(MY_ALLOW_ZERO_PTR)); // Free for multi_malloc
+ my_free(m_key); // Free for multi_malloc
m_key= NULL;
return error;
@@ -9637,3 +9801,16 @@ st_print_event_info::st_print_event_info()
open_cached_file(&body_cache, NULL, NULL, 0, flags);
}
#endif
+
+
+#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
diff --git a/sql/log_event.h b/sql/log_event.h
index 75f2015a684..a4d76e692a8 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2006 MySQL AB
+/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -28,7 +28,7 @@
#ifndef _log_event_h
#define _log_event_h
-#if defined(USE_PRAGMA_INTERFACE) && !defined(MYSQL_CLIENT)
+#if defined(USE_PRAGMA_INTERFACE) && defined(MYSQL_SERVER)
#pragma interface /* gcc class implementation */
#endif
@@ -36,17 +36,22 @@
#include "rpl_constants.h"
#ifdef MYSQL_CLIENT
+#include "sql_const.h"
#include "rpl_utility.h"
#include "hash.h"
#include "rpl_tblmap.h"
#include "rpl_tblmap.cc"
#endif
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
#include "rpl_record.h"
#include "rpl_reporting.h"
+#include "sql_class.h" /* THD */
#endif
+/* Forward declarations */
+class String;
+
#define PREFIX_SQL_LOAD "SQL_LOAD-"
/**
@@ -250,6 +255,7 @@ struct sql_ex_info
#define EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN (4 + 4 + 4 + 1)
#define EXECUTE_LOAD_QUERY_HEADER_LEN (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN)
#define INCIDENT_HEADER_LEN 2
+#define HEARTBEAT_HEADER_LEN 0
/*
Max number of possible extra bytes in a replication event compared to a
packet (i.e. a query) sent from client to master;
@@ -583,6 +589,12 @@ enum Log_event_type
INCIDENT_EVENT= 26,
/*
+ Heartbeat event to be send by master at its idle time
+ to ensure master's online status to slave
+ */
+ HEARTBEAT_LOG_EVENT= 27,
+
+ /*
Add new events here - right above this comment!
Existing events (except ENUM_END_EVENT) should never change their numbers
*/
@@ -603,7 +615,7 @@ enum Int_event_type
};
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
class String;
class MYSQL_BIN_LOG;
class THD;
@@ -681,11 +693,9 @@ typedef struct st_print_event_info
uint8 common_header_len;
char delimiter[16];
-#ifdef MYSQL_CLIENT
uint verbose;
table_mapping m_table_map;
table_mapping m_table_map_ignored;
-#endif
/*
These two caches are used by the row-based replication events to
@@ -697,6 +707,20 @@ typedef struct st_print_event_info
} PRINT_EVENT_INFO;
#endif
+/**
+ the struct aggregates two paramenters that identify an event
+ uniquely in scope of communication of a particular master and slave couple.
+ I.e there can not be 2 events from the same staying connected master which
+ have the same coordinates.
+ @note
+ Such identifier is not yet unique generally as the event originating master
+ is resetable. Also the crashed master can be replaced with some other.
+*/
+struct event_coordinates
+{
+ char * file_name; // binlog file name (directories stripped)
+ my_off_t pos; // event's position in the binlog file
+};
/**
@class Log_event
@@ -857,6 +881,31 @@ public:
EVENT_SKIP_COUNT
};
+ enum enum_event_cache_type
+ {
+ EVENT_INVALID_CACHE,
+ /*
+ If possible the event should use a non-transactional cache before
+ being flushed to the binary log. This means that it must be flushed
+ right after its correspondent statement is completed.
+ */
+ EVENT_STMT_CACHE,
+ /*
+ The event should use a transactional cache before being flushed to
+ the binary log. This means that it must be flushed upon commit or
+ rollback.
+ */
+ EVENT_TRANSACTIONAL_CACHE,
+ /*
+ The event must be written directly to the binary log without going
+ through a cache.
+ */
+ EVENT_NO_CACHE,
+ /**
+ If there is a need for different types, introduce them before this.
+ */
+ EVENT_CACHE_COUNT
+ };
/*
The following type definition is to be used whenever data is placed
@@ -907,8 +956,12 @@ public:
LOG_EVENT_SUPPRESS_USE_F for notes.
*/
uint16 flags;
-
- bool cache_stmt;
+
+ /*
+ Defines the type of the cache, if any, where the event will be
+ stored before being flushed to disk.
+ */
+ uint16 cache_type;
/**
A storage to cache the global system variable's value.
@@ -916,11 +969,11 @@ public:
*/
ulong slave_exec_mode;
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
THD* thd;
Log_event();
- Log_event(THD* thd_arg, uint16 flags_arg, bool cache_stmt);
+ Log_event(THD* thd_arg, uint16 flags_arg, bool is_transactional);
/*
read_log_event() functions read an event from a binlog or relay
log; used by SHOW BINLOG EVENTS, the binlog_dump thread on the
@@ -933,11 +986,11 @@ public:
constructor and pass description_event as an argument.
*/
static Log_event* read_log_event(IO_CACHE* file,
- pthread_mutex_t* log_lock,
+ mysql_mutex_t* log_lock,
const Format_description_log_event
*description_event);
static int read_log_event(IO_CACHE* file, String* packet,
- pthread_mutex_t* log_lock);
+ mysql_mutex_t* log_lock);
/*
init_show_field_list() prepares the column names and types for the
output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG
@@ -981,14 +1034,14 @@ public:
static void operator delete(void *ptr, size_t)
{
- my_free(ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
+ my_free(ptr);
}
/* Placement version of the above operators */
static void *operator new(size_t, void* ptr) { return ptr; }
static void operator delete(void*, void*) { }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write_header(IO_CACHE* file, ulong data_length);
virtual bool write(IO_CACHE* file)
{
@@ -1018,7 +1071,18 @@ public:
void set_relay_log_event() { flags |= LOG_EVENT_RELAY_LOG_F; }
bool is_artificial_event() const { return flags & LOG_EVENT_ARTIFICIAL_F; }
bool is_relay_log_event() const { return flags & LOG_EVENT_RELAY_LOG_F; }
- inline bool get_cache_stmt() const { return cache_stmt; }
+ inline bool use_trans_cache() const
+ {
+ return (cache_type == Log_event::EVENT_TRANSACTIONAL_CACHE);
+ }
+ inline void set_direct_logging()
+ {
+ cache_type = Log_event::EVENT_NO_CACHE;
+ }
+ inline bool use_direct_logging()
+ {
+ return (cache_type == Log_event::EVENT_NO_CACHE);
+ }
Log_event(const char* buf, const Format_description_log_event
*description_event);
virtual ~Log_event() { free_temp_buf();}
@@ -1027,7 +1091,7 @@ public:
{
if (temp_buf)
{
- my_free(temp_buf, MYF(0));
+ my_free(temp_buf);
temp_buf = 0;
}
}
@@ -1051,7 +1115,7 @@ public:
/* Return start of query time or current time */
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
public:
/**
@@ -1355,7 +1419,7 @@ protected:
<td>Q_SQL_MODE_CODE == 1</td>
<td>8 byte bitfield</td>
<td>The @c sql_mode variable. See the section "SQL Modes" in the
- MySQL manual, and see mysql_priv.h for a list of the possible
+ MySQL manual, and see sql_priv.h for a list of the possible
flags. Currently (2007-10-04), the following flags are available:
<pre>
MODE_REAL_AS_FLOAT==0x1
@@ -1641,10 +1705,10 @@ public:
*/
uint32 master_data_written;
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
- bool using_trans, bool suppress_use, int error);
+ bool using_trans, bool direct, bool suppress_use, int error);
const char* get_db() { return db; }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
@@ -1661,10 +1725,10 @@ public:
~Query_log_event()
{
if (data_buf)
- my_free((uchar*) data_buf, MYF(0));
+ my_free(data_buf);
}
Log_event_type get_type_code() { return QUERY_EVENT; }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; }
#endif
@@ -1678,7 +1742,7 @@ public:
/* Writes derived event-specific part of post header. */
public: /* !!! Public in this patch to allow old usage */
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
virtual int do_apply_event(Relay_log_info const *rli);
virtual int do_update_pos(Relay_log_info *rli);
@@ -1775,7 +1839,7 @@ public:
int master_log_len;
uint16 master_port;
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Slave_log_event(THD* thd_arg, Relay_log_info* rli);
void pack_info(Protocol* protocol);
#else
@@ -1789,12 +1853,12 @@ public:
int get_data_size();
bool is_valid() const { return master_host != 0; }
Log_event_type get_type_code() { return SLAVE_EVENT; }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
#endif
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const* rli);
#endif
};
@@ -2034,6 +2098,17 @@ public:
uint32 skip_lines;
sql_ex_info sql_ex;
bool local_fname;
+ /**
+ Indicates that this event corresponds to LOAD DATA CONCURRENT,
+
+ @note Since Load_log_event event coming from the binary log
+ lacks information whether LOAD DATA on master was concurrent
+ or not, this flag is only set to TRUE for an auxiliary
+ Load_log_event object which is used in mysql_load() to
+ re-construct LOAD DATA statement from function parameters,
+ for logging.
+ */
+ bool is_concurrent;
/* fname doesn't point to memory inside Log_event::temp_buf */
void set_fname_outside_temp_buf(const char *afname, uint alen)
@@ -2048,13 +2123,15 @@ public:
return local_fname;
}
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
String field_lens_buf;
String fields_buf;
Load_log_event(THD* thd, sql_exchange* ex, const char* db_arg,
const char* table_name_arg,
- List<Item>& fields_arg, enum enum_duplicates handle_dup, bool ignore,
+ List<Item>& fields_arg,
+ bool is_concurrent_arg,
+ enum enum_duplicates handle_dup, bool ignore,
bool using_trans);
void set_fields(const char* db, List<Item> &fields_arg,
Name_resolution_context *context);
@@ -2081,7 +2158,7 @@ public:
{
return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT;
}
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write_data_header(IO_CACHE* file);
bool write_data_body(IO_CACHE* file);
#endif
@@ -2094,7 +2171,7 @@ public:
}
public: /* !!! Public in this patch to allow old usage */
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const* rli)
{
return do_apply_event(thd->slave_net,rli,0);
@@ -2156,7 +2233,7 @@ public:
*/
bool dont_set_created;
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Start_log_event_v3();
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
@@ -2170,7 +2247,7 @@ public:
const Format_description_log_event* description_event);
~Start_log_event_v3() {}
Log_event_type get_type_code() { return START_EVENT_V3;}
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; }
@@ -2180,7 +2257,7 @@ public:
}
protected:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
virtual enum_skip_reason do_shall_skip(Relay_log_info*)
{
@@ -2229,10 +2306,10 @@ public:
*description_event);
~Format_description_log_event()
{
- my_free((uchar*)post_header_len, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(post_header_len);
}
Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;}
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
#endif
bool is_valid() const
@@ -2254,7 +2331,7 @@ public:
void calc_server_version_split();
protected:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
virtual int do_update_pos(Relay_log_info *rli);
virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
@@ -2306,7 +2383,7 @@ public:
ulonglong val;
uchar type;
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg)
:Log_event(thd_arg,0,0),val(val_arg),type(type_arg)
{}
@@ -2323,13 +2400,13 @@ public:
Log_event_type get_type_code() { return INTVAR_EVENT;}
const char* get_var_type_name();
int get_data_size() { return 9; /* sizeof(type) + sizeof(val) */;}
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; }
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
virtual int do_update_pos(Relay_log_info *rli);
virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
@@ -2382,7 +2459,7 @@ class Rand_log_event: public Log_event
ulonglong seed1;
ulonglong seed2;
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Rand_log_event(THD* thd_arg, ulonglong seed1_arg, ulonglong seed2_arg)
:Log_event(thd_arg,0,0),seed1(seed1_arg),seed2(seed2_arg)
{}
@@ -2398,13 +2475,13 @@ class Rand_log_event: public Log_event
~Rand_log_event() {}
Log_event_type get_type_code() { return RAND_EVENT;}
int get_data_size() { return 16; /* sizeof(ulonglong) * 2*/ }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; }
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
virtual int do_update_pos(Relay_log_info *rli);
virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
@@ -2428,8 +2505,8 @@ class Xid_log_event: public Log_event
public:
my_xid xid;
-#ifndef MYSQL_CLIENT
- Xid_log_event(THD* thd_arg, my_xid x): Log_event(thd_arg,0,0), xid(x) {}
+#ifdef MYSQL_SERVER
+ Xid_log_event(THD* thd_arg, my_xid x): Log_event(thd_arg, 0, TRUE), xid(x) {}
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
@@ -2442,13 +2519,13 @@ class Xid_log_event: public Log_event
~Xid_log_event() {}
Log_event_type get_type_code() { return XID_EVENT;}
int get_data_size() { return sizeof(xid); }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; }
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
enum_skip_reason do_shall_skip(Relay_log_info *rli);
#endif
@@ -2466,6 +2543,10 @@ private:
class User_var_log_event: public Log_event
{
public:
+ enum {
+ UNDEF_F= 0,
+ UNSIGNED_F= 1
+ };
char *name;
uint name_len;
char *val;
@@ -2473,12 +2554,14 @@ public:
Item_result type;
uint charset_number;
bool is_null;
-#ifndef MYSQL_CLIENT
+ uchar flags;
+#ifdef MYSQL_SERVER
User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg,
char *val_arg, ulong val_len_arg, Item_result type_arg,
- uint charset_number_arg)
+ uint charset_number_arg, uchar flags_arg)
:Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg),
- val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg)
+ val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg),
+ flags(flags_arg)
{ is_null= !val; }
void pack_info(Protocol* protocol);
#else
@@ -2489,13 +2572,13 @@ public:
const Format_description_log_event *description_event);
~User_var_log_event() {}
Log_event_type get_type_code() { return USER_VAR_EVENT;}
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; }
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
virtual int do_update_pos(Relay_log_info *rli);
virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
@@ -2514,7 +2597,7 @@ private:
class Stop_log_event: public Log_event
{
public:
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Stop_log_event() :Log_event()
{}
#else
@@ -2530,7 +2613,7 @@ public:
bool is_valid() const { return 1; }
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_update_pos(Relay_log_info *rli);
virtual enum_skip_reason do_shall_skip(Relay_log_info *rli)
{
@@ -2606,7 +2689,7 @@ public:
ulonglong pos;
uint ident_len;
uint flags;
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Rotate_log_event(const char* new_log_ident_arg,
uint ident_len_arg,
ulonglong pos_arg, uint flags);
@@ -2622,17 +2705,17 @@ public:
~Rotate_log_event()
{
if (flags & DUP_NAME)
- my_free((uchar*) new_log_ident, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((void*) new_log_ident);
}
Log_event_type get_type_code() { return ROTATE_EVENT;}
int get_data_size() { return ident_len + ROTATE_HEADER_LEN;}
bool is_valid() const { return new_log_ident != 0; }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
#endif
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_update_pos(Relay_log_info *rli);
virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
#endif
@@ -2663,10 +2746,11 @@ public:
uint file_id;
bool inited_from_old;
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Create_file_log_event(THD* thd, 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);
@@ -2683,7 +2767,7 @@ public:
const Format_description_log_event* description_event);
~Create_file_log_event()
{
- my_free((char*) event_buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((void*) event_buf);
}
Log_event_type get_type_code()
@@ -2697,7 +2781,7 @@ public:
4 + 1 + block_len);
}
bool is_valid() const { return inited_from_old || block != 0; }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write_data_header(IO_CACHE* file);
bool write_data_body(IO_CACHE* file);
/*
@@ -2708,7 +2792,7 @@ public:
#endif
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
#endif
};
@@ -2739,7 +2823,7 @@ public:
*/
const char* db;
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Append_block_log_event(THD* thd, const char* db_arg, uchar* block_arg,
uint block_len_arg, bool using_trans);
#ifdef HAVE_REPLICATION
@@ -2757,13 +2841,13 @@ public:
Log_event_type get_type_code() { return APPEND_BLOCK_EVENT;}
int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;}
bool is_valid() const { return block != 0; }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
const char* get_db() { return db; }
#endif
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
#endif
};
@@ -2781,7 +2865,7 @@ public:
uint file_id;
const char* db; /* see comment in Append_block_log_event */
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Delete_file_log_event(THD* thd, const char* db_arg, bool using_trans);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
@@ -2798,13 +2882,13 @@ public:
Log_event_type get_type_code() { return DELETE_FILE_EVENT;}
int get_data_size() { return DELETE_FILE_HEADER_LEN ;}
bool is_valid() const { return file_id != 0; }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
const char* get_db() { return db; }
#endif
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
#endif
};
@@ -2822,7 +2906,7 @@ public:
uint file_id;
const char* db; /* see comment in Append_block_log_event */
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Execute_load_log_event(THD* thd, const char* db_arg, bool using_trans);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
@@ -2838,13 +2922,13 @@ public:
Log_event_type get_type_code() { return EXEC_LOAD_EVENT;}
int get_data_size() { return EXEC_LOAD_HEADER_LEN ;}
bool is_valid() const { return file_id != 0; }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
const char* get_db() { return db; }
#endif
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
#endif
};
@@ -2862,7 +2946,7 @@ private:
class Begin_load_query_log_event: public Append_block_log_event
{
public:
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Begin_load_query_log_event(THD* thd_arg, const char *db_arg,
uchar* block_arg, uint block_len_arg,
bool using_trans);
@@ -2877,7 +2961,7 @@ public:
~Begin_load_query_log_event() {}
Log_event_type get_type_code() { return BEGIN_LOAD_QUERY_EVENT; }
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
#endif
};
@@ -2913,13 +2997,13 @@ public:
*/
enum_load_dup_handling dup_handling;
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Execute_load_query_log_event(THD* thd, const char* query_arg,
ulong query_length, uint fn_pos_start_arg,
uint fn_pos_end_arg,
enum_load_dup_handling dup_handling_arg,
- bool using_trans, bool suppress_use,
- int errcode);
+ bool using_trans, bool direct,
+ bool suppress_use, int errcode);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
@@ -2938,12 +3022,12 @@ public:
bool is_valid() const { return Query_log_event::is_valid() && file_id != 0; }
ulong get_post_header_size_for_derived();
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
bool write_post_header_for_derived(IO_CACHE* file);
#endif
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
#endif
};
@@ -3333,7 +3417,7 @@ public:
flag_set get_flags(flag_set flag) const { return m_flags & flag; }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, bool is_transactional);
#endif
#ifdef HAVE_REPLICATION
@@ -3349,23 +3433,23 @@ public:
return new table_def(m_coltype, m_colcnt, m_field_metadata,
m_field_metadata_size, m_null_bits, m_flags);
}
+#endif
ulong get_table_id() const { return m_table_id; }
const char *get_table_name() const { return m_tblnam; }
const char *get_db_name() const { return m_dbnam; }
-#endif
virtual Log_event_type get_type_code() { return TABLE_MAP_EVENT; }
virtual bool is_valid() const { return m_memory != NULL; /* we check malloc */ }
virtual int get_data_size() { return (uint) m_data_size; }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
virtual int save_field_metadata();
virtual bool write_data_header(IO_CACHE *file);
virtual bool write_data_body(IO_CACHE *file);
virtual const char *get_db() { return m_dbnam; }
#endif
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual void pack_info(Protocol *protocol);
#endif
@@ -3375,13 +3459,13 @@ public:
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
virtual int do_update_pos(Relay_log_info *rli);
virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
#endif
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
TABLE *m_table;
#endif
char const *m_dbnam;
@@ -3477,7 +3561,7 @@ public:
void clear_flags(flag_set flags_arg) { m_flags &= ~flags_arg; }
flag_set get_flags(flag_set flags_arg) const { return m_flags & flags_arg; }
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual void pack_info(Protocol *protocol);
#endif
@@ -3492,7 +3576,7 @@ public:
const uchar *ptr, const uchar *prefix);
#endif
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
int add_row_data(uchar *data, size_t length)
{
return do_add_row_data(data,length);
@@ -3506,7 +3590,7 @@ public:
size_t get_width() const { return m_width; }
ulong get_table_id() const { return m_table_id; }
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
virtual bool write_data_header(IO_CACHE *file);
virtual bool write_data_body(IO_CACHE *file);
virtual const char *get_db() { return m_table->s->db.str; }
@@ -3529,7 +3613,7 @@ protected:
The constructors are protected since you're supposed to inherit
this class, not create instances of this class.
*/
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Rows_log_event(THD*, TABLE*, ulong table_id,
MY_BITMAP const *cols, bool is_transactional);
#endif
@@ -3541,11 +3625,11 @@ protected:
void print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name);
#endif
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
virtual int do_add_row_data(uchar *data, size_t length);
#endif
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
TABLE *m_table; /* The table the rows belong to */
#endif
ulong m_table_id; /* Table ID */
@@ -3574,7 +3658,7 @@ protected:
/* helper functions */
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
const uchar *m_curr_row; /* Start of the row being processed */
const uchar *m_curr_row_end; /* One-after the end of the current row */
uchar *m_key; /* Buffer to keep key value during searches */
@@ -3602,7 +3686,7 @@ protected:
private:
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
virtual int do_update_pos(Relay_log_info *rli);
virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
@@ -3657,7 +3741,7 @@ private:
*/
virtual int do_exec_row(const Relay_log_info *const rli) = 0;
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
+#endif /* defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) */
friend class Old_rows_log_event;
};
@@ -3680,7 +3764,7 @@ public:
TYPE_CODE = WRITE_ROWS_EVENT
};
-#if !defined(MYSQL_CLIENT)
+#if defined(MYSQL_SERVER)
Write_rows_log_event(THD*, TABLE*, ulong table_id,
MY_BITMAP const *cols, bool is_transactional);
#endif
@@ -3688,7 +3772,7 @@ public:
Write_rows_log_event(const char *buf, uint event_len,
const Format_description_log_event *description_event);
#endif
-#if !defined(MYSQL_CLIENT)
+#if defined(MYSQL_SERVER)
static bool binlog_row_logging_function(THD *thd, TABLE *table,
bool is_transactional,
MY_BITMAP *cols,
@@ -3709,7 +3793,7 @@ private:
void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_before_row_operations(const Slave_reporting_capability *const);
virtual int do_after_row_operations(const Slave_reporting_capability *const,int);
virtual int do_exec_row(const Relay_log_info *const);
@@ -3738,7 +3822,7 @@ public:
TYPE_CODE = UPDATE_ROWS_EVENT
};
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Update_rows_log_event(THD*, TABLE*, ulong table_id,
MY_BITMAP const *cols_bi,
MY_BITMAP const *cols_ai,
@@ -3758,7 +3842,7 @@ public:
const Format_description_log_event *description_event);
#endif
-#if !defined(MYSQL_CLIENT)
+#ifdef MYSQL_SERVER
static bool binlog_row_logging_function(THD *thd, TABLE *table,
bool is_transactional,
MY_BITMAP *cols,
@@ -3783,11 +3867,11 @@ protected:
void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_before_row_operations(const Slave_reporting_capability *const);
virtual int do_after_row_operations(const Slave_reporting_capability *const,int);
virtual int do_exec_row(const Relay_log_info *const);
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
+#endif /* defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) */
};
/**
@@ -3819,7 +3903,7 @@ public:
TYPE_CODE = DELETE_ROWS_EVENT
};
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Delete_rows_log_event(THD*, TABLE*, ulong,
MY_BITMAP const *cols, bool is_transactional);
#endif
@@ -3827,7 +3911,7 @@ public:
Delete_rows_log_event(const char *buf, uint event_len,
const Format_description_log_event *description_event);
#endif
-#if !defined(MYSQL_CLIENT)
+#ifdef MYSQL_SERVER
static bool binlog_row_logging_function(THD *thd, TABLE *table,
bool is_transactional,
MY_BITMAP *cols,
@@ -3848,7 +3932,7 @@ protected:
void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_before_row_operations(const Slave_reporting_capability *const);
virtual int do_after_row_operations(const Slave_reporting_capability *const,int);
virtual int do_exec_row(const Relay_log_info *const);
@@ -3896,7 +3980,7 @@ protected:
*/
class Incident_log_event : public Log_event {
public:
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
Incident_log_event(THD *thd_arg, Incident incident)
: Log_event(thd_arg, 0, FALSE), m_incident(incident)
{
@@ -3904,6 +3988,7 @@ public:
DBUG_PRINT("enter", ("m_incident: %d", m_incident));
m_message.str= NULL; /* Just as a precaution */
m_message.length= 0;
+ set_direct_logging();
DBUG_VOID_RETURN;
}
@@ -3913,11 +3998,12 @@ public:
DBUG_ENTER("Incident_log_event::Incident_log_event");
DBUG_PRINT("enter", ("m_incident: %d", m_incident));
m_message= msg;
+ set_direct_logging();
DBUG_VOID_RETURN;
}
#endif
-#ifndef MYSQL_CLIENT
+#ifdef MYSQL_SERVER
void pack_info(Protocol*);
#endif
@@ -3930,7 +4016,7 @@ public:
virtual void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
#endif
@@ -3962,6 +4048,45 @@ static inline bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache,
reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
}
+#ifdef MYSQL_SERVER
+/*****************************************************************************
+
+ Heartbeat Log Event class
+
+ Replication event to ensure to slave that master is alive.
+ The event is originated by master's dump thread and sent straight to
+ slave without being logged. Slave itself does not store it in relay log
+ but rather uses a data for immediate checks and throws away the event.
+
+ Two members of the class log_ident and Log_event::log_pos comprise
+ @see the event_coordinates instance. The coordinates that a heartbeat
+ instance carries correspond to the last event master has sent from
+ its binlog.
+
+ ****************************************************************************/
+class Heartbeat_log_event: public Log_event
+{
+public:
+ Heartbeat_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
+ Log_event_type get_type_code() { return HEARTBEAT_LOG_EVENT; }
+ bool is_valid() const
+ {
+ return (log_ident != NULL &&
+ log_pos >= BIN_LOG_HEADER_SIZE);
+ }
+ const char * get_log_ident() { return log_ident; }
+ uint get_ident_len() { return ident_len; }
+
+private:
+ const char* log_ident;
+ uint ident_len;
+};
+#endif
+
+int append_query_string(CHARSET_INFO *csinfo,
+ String const *from, String *to);
+
/**
@} (end of group Replication)
*/
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index e901f44286c..88df4970816 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1,11 +1,22 @@
-#include "mysql_priv.h"
+#include "sql_priv.h"
#ifndef MYSQL_CLIENT
+#include "unireg.h"
+#endif
+#include "my_global.h" // REQUIRED by log_event.h > m_string.h > my_bitmap.h
+#include "log_event.h"
+#ifndef MYSQL_CLIENT
+#include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE
+#include "sql_base.h" // close_tables_for_reopen
+#include "key.h" // key_copy
+#include "lock.h" // mysql_unlock_tables
+#include "sql_parse.h" // mysql_reset_thd_for_next_command
#include "rpl_rli.h"
#include "rpl_utility.h"
#endif
#include "log_event_old.h"
#include "rpl_record_old.h"
+#include "transaction.h"
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
@@ -32,8 +43,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
*/
DBUG_ASSERT(ev->get_flags(Old_rows_log_event::STMT_END_F));
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
- close_thread_tables(ev_thd);
+ const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(ev_thd);
ev_thd->clear_error();
DBUG_RETURN(0);
}
@@ -59,26 +69,23 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
We also call the mysql_reset_thd_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_row_based, so
+ call might reset the value of current_stmt_binlog_format, so
we need to do any changes to that value after this function.
*/
lex_start(ev_thd);
mysql_reset_thd_for_next_command(ev_thd);
/*
- Check if the slave is set to use SBR. If so, it should switch
- to using RBR until the end of the "statement", i.e., next
- STMT_END_F or next error.
+ 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.
*/
- if (!ev_thd->current_stmt_binlog_row_based &&
- mysql_bin_log.is_open() && (ev_thd->options & OPTION_BIN_LOG))
- {
- ev_thd->set_current_stmt_binlog_row_based();
- }
+ ev_thd->lex->set_stmt_row_injection();
- if (simple_open_n_lock_tables(ev_thd, rli->tables_to_lock))
+ if (open_and_lock_tables(ev_thd, rli->tables_to_lock, FALSE, 0))
{
- uint actual_error= ev_thd->main_da.sql_errno();
+ uint actual_error= ev_thd->stmt_da->sql_errno();
if (ev_thd->is_slave_error || ev_thd->is_fatal_error)
{
/*
@@ -87,11 +94,11 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
*/
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' on opening tables",
- (actual_error ? ev_thd->main_da.message() :
+ (actual_error ? ev_thd->stmt_da->message() :
"unexpected success or fatal error"));
ev_thd->is_slave_error= 1;
}
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
+ const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
DBUG_RETURN(actual_error);
}
@@ -107,14 +114,19 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
RPL_TABLE_LIST *ptr= rli->tables_to_lock;
for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global))
{
- if (ptr->m_tabledef.compatible_with(rli, ptr->table))
+ TABLE *conv_table;
+ if (!ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli),
+ ptr->table, &conv_table))
{
- mysql_unlock_tables(ev_thd, ev_thd->lock);
- ev_thd->lock= 0;
ev_thd->is_slave_error= 1;
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
+ const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(ev_thd);
DBUG_RETURN(Old_rows_log_event::ERR_BAD_TABLE_DEF);
}
+ 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;
}
}
@@ -166,16 +178,16 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
the event.
*/
if (ev->get_flags(Old_rows_log_event::NO_FOREIGN_KEY_CHECKS_F))
- ev_thd->options|= OPTION_NO_FOREIGN_KEY_CHECKS;
+ ev_thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
else
- ev_thd->options&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
+ ev_thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
if (ev->get_flags(Old_rows_log_event::RELAXED_UNIQUE_CHECKS_F))
- ev_thd->options|= OPTION_RELAXED_UNIQUE_CHECKS;
+ ev_thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS;
else
- ev_thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS;
+ ev_thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
/* A small test to verify that objects have consistent types */
- DBUG_ASSERT(sizeof(ev_thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
+ DBUG_ASSERT(sizeof(ev_thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
/*
Now we are in a statement and will stay in a statement until we
@@ -216,36 +228,29 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
break;
default:
- rli->report(ERROR_LEVEL, ev_thd->main_da.sql_errno(),
+ rli->report(ERROR_LEVEL, ev_thd->stmt_da->sql_errno(),
"Error in %s event: row application failed. %s",
ev->get_type_str(),
- ev_thd->is_error() ? ev_thd->main_da.message() : "");
- ev_thd->is_slave_error= 1;
+ ev_thd->is_error() ? ev_thd->stmt_da->message() : "");
+ thd->is_slave_error= 1;
break;
}
row_start= row_end;
}
- DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event",
+ DBUG_EXECUTE_IF("stop_slave_middle_group",
const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
error= do_after_row_operations(table, error);
}
- /*
- We need to delay this clear until the table def is no longer needed.
- The table def is needed in unpack_row().
- */
- if (rli->tables_to_lock && ev->get_flags(Old_rows_log_event::STMT_END_F))
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
-
if (error)
{ /* error has occured during the transaction */
- rli->report(ERROR_LEVEL, ev_thd->main_da.sql_errno(),
+ rli->report(ERROR_LEVEL, ev_thd->stmt_da->sql_errno(),
"Error in %s event: error during transaction execution "
"on table %s.%s. %s",
ev->get_type_str(), table->s->db.str,
table->s->table_name.str,
- ev_thd->is_error() ? ev_thd->main_da.message() : "");
+ ev_thd->is_error() ? ev_thd->stmt_da->message() : "");
/*
If one day we honour --skip-slave-errors in row-based replication, and
@@ -258,40 +263,12 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
thread is certainly going to stop.
rollback at the caller along with sbr.
*/
- ev_thd->reset_current_stmt_binlog_row_based();
+ ev_thd->reset_current_stmt_binlog_format_row();
const_cast<Relay_log_info*>(rli)->cleanup_context(ev_thd, error);
ev_thd->is_slave_error= 1;
DBUG_RETURN(error);
}
- /*
- This code would ideally be placed in do_update_pos() instead, but
- since we have no access to table there, we do the setting of
- last_event_start_time here instead.
- */
- if (table && (table->s->primary_key == MAX_KEY) &&
- !ev->cache_stmt &&
- ev->get_flags(Old_rows_log_event::STMT_END_F) == Old_rows_log_event::RLE_NO_FLAGS)
- {
- /*
- ------------ Temporary fix until WL#2975 is implemented ---------
-
- This event is not the last one (no STMT_END_F). If we stop now
- (in case of terminate_slave_thread()), how will we restart? We
- have to restart from Table_map_log_event, but as this table is
- not transactional, the rows already inserted will still be
- present, and idempotency is not guaranteed (no PK) so we risk
- that repeating leads to double insert. So we desperately try to
- continue, hope we'll eventually leave this buggy situation (by
- executing the final Old_rows_log_event). If we are in a hopeless
- wait (reached end of last relay log and nothing gets appended
- there), we timeout after one minute, and notify DBA about the
- problem. When WL#2975 is implemented, just remove the member
- st_relay_log_info::last_event_start_time and all its occurences.
- */
- const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0);
- }
-
DBUG_RETURN(0);
}
#endif
@@ -1040,7 +1017,7 @@ int Delete_rows_log_event_old::do_after_row_operations(TABLE *table, int error)
{
/*error= ToDo:find out what this should really be, this triggers close_scan in nbd, returning error?*/
table->file->ha_index_or_rnd_end();
- my_free(m_memory, MYF(MY_ALLOW_ZERO_PTR)); // Free for multi_malloc
+ my_free(m_memory); // Free for multi_malloc
m_memory= NULL;
m_after_image= NULL;
m_key= NULL;
@@ -1139,7 +1116,7 @@ int Update_rows_log_event_old::do_after_row_operations(TABLE *table, int error)
{
/*error= ToDo:find out what this should really be, this triggers close_scan in nbd, returning error?*/
table->file->ha_index_or_rnd_end();
- my_free(m_memory, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(m_memory);
m_memory= NULL;
m_after_image= NULL;
m_key= NULL;
@@ -1263,9 +1240,9 @@ Old_rows_log_event::Old_rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
DBUG_ASSERT((tbl_arg && tbl_arg->s && tid != ~0UL) ||
(!tbl_arg && !cols && tid == ~0UL));
- if (thd_arg->options & OPTION_NO_FOREIGN_KEY_CHECKS)
+ if (thd_arg->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS)
set_flags(NO_FOREIGN_KEY_CHECKS_F);
- if (thd_arg->options & OPTION_RELAXED_UNIQUE_CHECKS)
+ if (thd_arg->variables.option_bits & OPTION_RELAXED_UNIQUE_CHECKS)
set_flags(RELAXED_UNIQUE_CHECKS_F);
/* if bitmap_init fails, caught in is_valid() */
if (likely(!bitmap_init(&m_cols,
@@ -1383,7 +1360,7 @@ Old_rows_log_event::~Old_rows_log_event()
if (m_cols.bitmap == m_bitbuf) // no my_malloc happened
m_cols.bitmap= 0; // so no my_free in bitmap_free
bitmap_free(&m_cols); // To pair with bitmap_init().
- my_free((uchar*)m_rows_buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(m_rows_buf);
}
@@ -1483,8 +1460,7 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
DBUG_ASSERT(get_flags(STMT_END_F));
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
- close_thread_tables(thd);
+ const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
thd->clear_error();
DBUG_RETURN(0);
}
@@ -1504,8 +1480,6 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
if (!thd->lock)
{
- bool need_reopen= 1; /* To execute the first lap of the loop below */
-
/*
lock_tables() reads the contents of thd->lex, so they must be
initialized. Contrary to in
@@ -1514,79 +1488,31 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
lex_start(thd);
- while ((error= lock_tables(thd, rli->tables_to_lock,
- rli->tables_to_lock_count, &need_reopen)))
+ if ((error= lock_tables(thd, rli->tables_to_lock,
+ rli->tables_to_lock_count, 0)))
{
- if (!need_reopen)
+ if (thd->is_slave_error || thd->is_fatal_error)
{
- if (thd->is_slave_error || thd->is_fatal_error)
- {
- /*
- Error reporting borrowed from Query_log_event with many excessive
- simplifications (we don't honour --slave-skip-errors)
- */
- uint actual_error= thd->net.last_errno;
- rli->report(ERROR_LEVEL, actual_error,
- "Error '%s' in %s event: when locking tables",
- (actual_error ? thd->net.last_error :
- "unexpected success or fatal error"),
- get_type_str());
- thd->is_fatal_error= 1;
- }
- else
- {
- rli->report(ERROR_LEVEL, error,
- "Error in %s event: when locking tables",
- get_type_str());
- }
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
- DBUG_RETURN(error);
- }
-
- /*
- So we need to reopen the tables.
-
- We need to flush the pending RBR event, since it keeps a
- pointer to an open table.
-
- ALTERNATIVE SOLUTION (not implemented): Extract a pointer to
- the pending RBR event and reset the table pointer after the
- tables has been reopened.
-
- NOTE: For this new scheme there should be no pending event:
- need to add code to assert that is the case.
- */
- error= thd->binlog_flush_pending_rows_event(false);
- if (error)
- {
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER(ER_SLAVE_FATAL_ERROR),
- "call to binlog_flush_pending_rows_event() failed");
- thd->is_slave_error= 1;
- DBUG_RETURN(error);
+ /*
+ Error reporting borrowed from Query_log_event with many excessive
+ simplifications (we don't honour --slave-skip-errors)
+ */
+ uint actual_error= thd->net.last_errno;
+ rli->report(ERROR_LEVEL, actual_error,
+ "Error '%s' in %s event: when locking tables",
+ (actual_error ? thd->net.last_error :
+ "unexpected success or fatal error"),
+ get_type_str());
+ thd->is_fatal_error= 1;
}
- TABLE_LIST *tables= rli->tables_to_lock;
- close_tables_for_reopen(thd, &tables);
-
- uint tables_count= rli->tables_to_lock_count;
- if ((error= open_tables(thd, &tables, &tables_count, 0)))
+ else
{
- if (thd->is_slave_error || thd->is_fatal_error)
- {
- /*
- Error reporting borrowed from Query_log_event with many excessive
- simplifications (we don't honour --slave-skip-errors)
- */
- uint actual_error= thd->net.last_errno;
- rli->report(ERROR_LEVEL, actual_error,
- "Error '%s' on reopening tables",
- (actual_error ? thd->net.last_error :
- "unexpected success or fatal error"));
- thd->is_slave_error= 1;
- }
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
- DBUG_RETURN(error);
+ rli->report(ERROR_LEVEL, error,
+ "Error in %s event: when locking tables",
+ get_type_str());
}
+ const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
+ DBUG_RETURN(error);
}
/*
@@ -1601,20 +1527,22 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
RPL_TABLE_LIST *ptr= rli->tables_to_lock;
for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global))
{
- if (ptr->m_tabledef.compatible_with(rli, ptr->table))
+ TABLE *conv_table;
+ if (ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli),
+ ptr->table, &conv_table))
{
- mysql_unlock_tables(thd, thd->lock);
- thd->lock= 0;
thd->is_slave_error= 1;
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
+ const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
DBUG_RETURN(ERR_BAD_TABLE_DEF);
}
+ ptr->m_conv_table= conv_table;
}
}
/*
- ... and then we add all the tables to the table map and remove
- them from tables to lock.
+ ... and then we add all the tables to the table map 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.
@@ -1662,16 +1590,16 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
the event.
*/
if (get_flags(NO_FOREIGN_KEY_CHECKS_F))
- thd->options|= OPTION_NO_FOREIGN_KEY_CHECKS;
+ thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
else
- thd->options&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
+ thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
if (get_flags(RELAXED_UNIQUE_CHECKS_F))
- thd->options|= OPTION_RELAXED_UNIQUE_CHECKS;
+ thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS;
else
- thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS;
+ thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
/* A small test to verify that objects have consistent types */
- DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
+ DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
/*
Now we are in a statement and will stay in a statement until we
@@ -1767,18 +1695,11 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
} // row processing loop
- DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event",
+ DBUG_EXECUTE_IF("stop_slave_middle_group",
const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
error= do_after_row_operations(rli, error);
} // if (table)
- /*
- We need to delay this clear until here bacause unpack_current_row() uses
- master-side table definitions stored in rli.
- */
- if (rli->tables_to_lock && get_flags(STMT_END_F))
- const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
-
if (error)
{ /* error has occured during the transaction */
rli->report(ERROR_LEVEL, thd->net.last_errno,
@@ -1799,7 +1720,7 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
thread is certainly going to stop.
rollback at the caller along with sbr.
*/
- thd->reset_current_stmt_binlog_row_based();
+ thd->reset_current_stmt_binlog_format_row();
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
thd->is_slave_error= 1;
DBUG_RETURN(error);
@@ -1811,7 +1732,7 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
last_event_start_time here instead.
*/
if (table && (table->s->primary_key == MAX_KEY) &&
- !cache_stmt && get_flags(STMT_END_F) == RLE_NO_FLAGS)
+ !use_trans_cache() && get_flags(STMT_END_F) == RLE_NO_FLAGS)
{
/*
------------ Temporary fix until WL#2975 is implemented ---------
@@ -1849,7 +1770,7 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
(assume the last master's transaction is ignored by the slave because of
replicate-ignore rules).
*/
- int binlog_error= thd->binlog_flush_pending_rows_event(true);
+ int binlog_error= thd->binlog_flush_pending_rows_event(TRUE);
/*
If this event is not in a transaction, the call below will, if some
@@ -1860,7 +1781,7 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
are involved, commit the transaction and flush the pending event to the
binlog.
*/
- if ((error= ha_autocommit_or_rollback(thd, binlog_error)))
+ if ((error= (binlog_error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd))))
rli->report(ERROR_LEVEL, error,
"Error in %s event: commit of row events failed, "
"table `%s`.`%s`",
@@ -1878,7 +1799,7 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
event flushed.
*/
- thd->reset_current_stmt_binlog_row_based();
+ thd->reset_current_stmt_binlog_format_row();
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, 0);
}
@@ -2777,7 +2698,7 @@ Delete_rows_log_event_old::do_after_row_operations(const Slave_reporting_capabil
{
/*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, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(m_key);
m_key= NULL;
return error;
@@ -2876,7 +2797,7 @@ Update_rows_log_event_old::do_after_row_operations(const Slave_reporting_capabil
{
/*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, MYF(MY_ALLOW_ZERO_PTR)); // Free for multi_malloc
+ my_free(m_key); // Free for multi_malloc
m_key= NULL;
return error;
diff --git a/sql/main.cc b/sql/main.cc
new file mode 100644
index 00000000000..249a2a883fe
--- /dev/null
+++ b/sql/main.cc
@@ -0,0 +1,25 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ main() for mysqld.
+ Calls mysqld_main() entry point exported by sql library.
+*/
+extern int mysqld_main(int argc, char **argv);
+
+int main(int argc, char **argv)
+{
+ return mysqld_main(argc, argv);
+}
diff --git a/sql/mdl.cc b/sql/mdl.cc
new file mode 100644
index 00000000000..3aed54ce12d
--- /dev/null
+++ b/sql/mdl.cc
@@ -0,0 +1,2628 @@
+/* Copyright (C) 2007-2008 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include "mdl.h"
+#include "debug_sync.h"
+#include <hash.h>
+#include <mysqld_error.h>
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_MDL_map_mutex;
+static PSI_mutex_key key_MDL_wait_LOCK_wait_status;
+
+static PSI_mutex_info all_mdl_mutexes[]=
+{
+ { &key_MDL_map_mutex, "MDL_map::mutex", PSI_FLAG_GLOBAL},
+ { &key_MDL_wait_LOCK_wait_status, "MDL_wait::LOCK_wait_status", 0}
+};
+
+static PSI_rwlock_key key_MDL_lock_rwlock;
+static PSI_rwlock_key key_MDL_context_LOCK_waiting_for;
+
+static PSI_rwlock_info all_mdl_rwlocks[]=
+{
+ { &key_MDL_lock_rwlock, "MDL_lock::rwlock", 0},
+ { &key_MDL_context_LOCK_waiting_for, "MDL_context::LOCK_waiting_for", 0}
+};
+
+static PSI_cond_key key_MDL_wait_COND_wait_status;
+
+static PSI_cond_info all_mdl_conds[]=
+{
+ { &key_MDL_wait_COND_wait_status, "MDL_context::COND_wait_status", 0}
+};
+
+/**
+ Initialise all the performance schema instrumentation points
+ used by the MDL subsystem.
+*/
+static void init_mdl_psi_keys(void)
+{
+ const char *category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_mdl_mutexes);
+ PSI_server->register_mutex(category, all_mdl_mutexes, count);
+
+ count= array_elements(all_mdl_rwlocks);
+ PSI_server->register_rwlock(category, all_mdl_rwlocks, count);
+
+ count= array_elements(all_mdl_conds);
+ PSI_server->register_cond(category, all_mdl_conds, count);
+}
+#endif /* HAVE_PSI_INTERFACE */
+
+
+/**
+ Thread state names to be used in case when we have to wait on resource
+ belonging to certain namespace.
+*/
+
+const char *MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]=
+{
+ "Waiting for global read lock",
+ "Waiting for schema metadata lock",
+ "Waiting for table metadata lock",
+ "Waiting for stored function metadata lock",
+ "Waiting for stored procedure metadata lock",
+ "Waiting for trigger metadata lock",
+ "Waiting for event metadata lock",
+ "Waiting for commit lock"
+};
+
+static bool mdl_initialized= 0;
+
+
+/**
+ A collection of all MDL locks. A singleton,
+ there is only one instance of the map in the server.
+ Maps MDL_key to MDL_lock instances.
+*/
+
+class MDL_map
+{
+public:
+ void init();
+ void destroy();
+ MDL_lock *find_or_insert(const MDL_key *key);
+ void remove(MDL_lock *lock);
+private:
+ bool move_from_hash_to_lock_mutex(MDL_lock *lock);
+private:
+ /** All acquired locks in the server. */
+ HASH m_locks;
+ /* Protects access to m_locks hash. */
+ mysql_mutex_t m_mutex;
+ /** Pre-allocated MDL_lock object for GLOBAL namespace. */
+ MDL_lock *m_global_lock;
+ /** Pre-allocated MDL_lock object for COMMIT namespace. */
+ MDL_lock *m_commit_lock;
+};
+
+
+/**
+ A context of the recursive traversal through all contexts
+ in all sessions in search for deadlock.
+*/
+
+class Deadlock_detection_visitor: public MDL_wait_for_graph_visitor
+{
+public:
+ Deadlock_detection_visitor(MDL_context *start_node_arg)
+ : m_start_node(start_node_arg),
+ m_victim(NULL),
+ m_current_search_depth(0),
+ m_found_deadlock(FALSE)
+ {}
+ virtual bool enter_node(MDL_context *node);
+ virtual void leave_node(MDL_context *node);
+
+ virtual bool inspect_edge(MDL_context *dest);
+
+ MDL_context *get_victim() const { return m_victim; }
+private:
+ /**
+ Change the deadlock victim to a new one if it has lower deadlock
+ weight.
+ */
+ void opt_change_victim_to(MDL_context *new_victim);
+private:
+ /**
+ The context which has initiated the search. There
+ can be multiple searches happening in parallel at the same time.
+ */
+ MDL_context *m_start_node;
+ /** If a deadlock is found, the context that identifies the victim. */
+ MDL_context *m_victim;
+ /** Set to the 0 at start. Increased whenever
+ we descend into another MDL context (aka traverse to the next
+ wait-for graph node). When MAX_SEARCH_DEPTH is reached, we
+ assume that a deadlock is found, even if we have not found a
+ loop.
+ */
+ uint m_current_search_depth;
+ /** TRUE if we found a deadlock. */
+ bool m_found_deadlock;
+ /**
+ Maximum depth for deadlock searches. After this depth is
+ achieved we will unconditionally declare that there is a
+ deadlock.
+
+ @note This depth should be small enough to avoid stack
+ being exhausted by recursive search algorithm.
+
+ TODO: Find out what is the optimal value for this parameter.
+ Current value is safe, but probably sub-optimal,
+ as there is an anecdotal evidence that real-life
+ deadlocks are even shorter typically.
+ */
+ static const uint MAX_SEARCH_DEPTH= 32;
+};
+
+
+/**
+ Enter a node of a wait-for graph. After
+ a node is entered, inspect_edge() will be called
+ for all wait-for destinations of this node. Then
+ leave_node() will be called.
+ We call "enter_node()" for all nodes we inspect,
+ including the starting node.
+
+ @retval TRUE Maximum search depth exceeded.
+ @retval FALSE OK.
+*/
+
+bool Deadlock_detection_visitor::enter_node(MDL_context *node)
+{
+ m_found_deadlock= ++m_current_search_depth >= MAX_SEARCH_DEPTH;
+ if (m_found_deadlock)
+ {
+ DBUG_ASSERT(! m_victim);
+ opt_change_victim_to(node);
+ }
+ return m_found_deadlock;
+}
+
+
+/**
+ Done inspecting this node. Decrease the search
+ depth. If a deadlock is found, and we are
+ backtracking to the start node, optionally
+ change the deadlock victim to one with lower
+ deadlock weight.
+*/
+
+void Deadlock_detection_visitor::leave_node(MDL_context *node)
+{
+ --m_current_search_depth;
+ if (m_found_deadlock)
+ opt_change_victim_to(node);
+}
+
+
+/**
+ Inspect a wait-for graph edge from one MDL context to another.
+
+ @retval TRUE A loop is found.
+ @retval FALSE No loop is found.
+*/
+
+bool Deadlock_detection_visitor::inspect_edge(MDL_context *node)
+{
+ m_found_deadlock= node == m_start_node;
+ return m_found_deadlock;
+}
+
+
+/**
+ Change the deadlock victim to a new one if it has lower deadlock
+ weight.
+
+ @retval new_victim Victim is not changed.
+ @retval !new_victim New victim became the current.
+*/
+
+void
+Deadlock_detection_visitor::opt_change_victim_to(MDL_context *new_victim)
+{
+ if (m_victim == NULL ||
+ m_victim->get_deadlock_weight() >= new_victim->get_deadlock_weight())
+ {
+ /* Swap victims, unlock the old one. */
+ MDL_context *tmp= m_victim;
+ m_victim= new_victim;
+ m_victim->lock_deadlock_victim();
+ if (tmp)
+ tmp->unlock_deadlock_victim();
+ }
+}
+
+
+/**
+ Get a bit corresponding to enum_mdl_type value in a granted/waiting bitmaps
+ and compatibility matrices.
+*/
+
+#define MDL_BIT(A) static_cast<MDL_lock::bitmap_t>(1U << A)
+
+/**
+ The lock context. Created internally for an acquired lock.
+ For a given name, there exists only one MDL_lock instance,
+ and it exists only when the lock has been granted.
+ Can be seen as an MDL subsystem's version of TABLE_SHARE.
+
+ This is an abstract class which lacks information about
+ compatibility rules for lock types. They should be specified
+ in its descendants.
+*/
+
+class MDL_lock
+{
+public:
+ typedef uchar bitmap_t;
+
+ class Ticket_list
+ {
+ public:
+ typedef I_P_List<MDL_ticket,
+ I_P_List_adapter<MDL_ticket,
+ &MDL_ticket::next_in_lock,
+ &MDL_ticket::prev_in_lock>,
+ I_P_List_null_counter,
+ I_P_List_fast_push_back<MDL_ticket> >
+ List;
+ operator const List &() const { return m_list; }
+ Ticket_list() :m_bitmap(0) {}
+
+ void add_ticket(MDL_ticket *ticket);
+ void remove_ticket(MDL_ticket *ticket);
+ bool is_empty() const { return m_list.is_empty(); }
+ bitmap_t bitmap() const { return m_bitmap; }
+ private:
+ void clear_bit_if_not_in_list(enum_mdl_type type);
+ private:
+ /** List of tickets. */
+ List m_list;
+ /** Bitmap of types of tickets in this list. */
+ bitmap_t m_bitmap;
+ };
+
+ typedef Ticket_list::List::Iterator Ticket_iterator;
+
+public:
+ /** The key of the object (data) being protected. */
+ MDL_key key;
+ /**
+ Read-write lock protecting this lock context.
+
+ @note The fact that we use read-write lock prefers readers here is
+ important as deadlock detector won't work correctly otherwise.
+
+ For example, imagine that we have following waiters graph:
+
+ ctxA -> obj1 -> ctxB -> obj1 -|
+ ^ |
+ |----------------------------|
+
+ and both ctxA and ctxB start deadlock detection process:
+
+ ctxA read-locks obj1 ctxB read-locks obj2
+ ctxA goes deeper ctxB goes deeper
+
+ Now ctxC comes in who wants to start waiting on obj1, also
+ ctxD comes in who wants to start waiting on obj2.
+
+ ctxC tries to write-lock obj1 ctxD tries to write-lock obj2
+ ctxC is blocked ctxD is blocked
+
+ Now ctxA and ctxB resume their search:
+
+ ctxA tries to read-lock obj2 ctxB tries to read-lock obj1
+
+ If m_rwlock prefers writes (or fair) both ctxA and ctxB would be
+ blocked because of pending write locks from ctxD and ctxC
+ correspondingly. Thus we will get a deadlock in deadlock detector.
+ If m_wrlock prefers readers (actually ignoring pending writers is
+ enough) ctxA and ctxB will continue and no deadlock will occur.
+ */
+ mysql_prlock_t m_rwlock;
+
+ bool is_empty() const
+ {
+ return (m_granted.is_empty() && m_waiting.is_empty());
+ }
+
+ virtual const bitmap_t *incompatible_granted_types_bitmap() const = 0;
+ virtual const bitmap_t *incompatible_waiting_types_bitmap() const = 0;
+
+ bool has_pending_conflicting_lock(enum_mdl_type type);
+
+ bool can_grant_lock(enum_mdl_type type, MDL_context *requstor_ctx) const;
+
+ inline static MDL_lock *create(const MDL_key *key);
+
+ void reschedule_waiters();
+
+ void remove_ticket(Ticket_list MDL_lock::*queue, MDL_ticket *ticket);
+
+ bool visit_subgraph(MDL_ticket *waiting_ticket,
+ MDL_wait_for_graph_visitor *gvisitor);
+
+ virtual bool needs_notification(const MDL_ticket *ticket) const = 0;
+ virtual void notify_conflicting_locks(MDL_context *ctx) = 0;
+
+ /** List of granted tickets for this lock. */
+ Ticket_list m_granted;
+ /** Tickets for contexts waiting to acquire a lock. */
+ Ticket_list m_waiting;
+public:
+
+ MDL_lock(const MDL_key *key_arg)
+ : key(key_arg),
+ m_ref_usage(0),
+ m_ref_release(0),
+ m_is_destroyed(FALSE)
+ {
+ mysql_prlock_init(key_MDL_lock_rwlock, &m_rwlock);
+ }
+
+ virtual ~MDL_lock()
+ {
+ mysql_prlock_destroy(&m_rwlock);
+ }
+ inline static void destroy(MDL_lock *lock);
+public:
+ /**
+ These three members are used to make it possible to separate
+ the mdl_locks.m_mutex mutex and MDL_lock::m_rwlock in
+ MDL_map::find_or_insert() for increased scalability.
+ The 'm_is_destroyed' member is only set by destroyers that
+ have both the mdl_locks.m_mutex and MDL_lock::m_rwlock, thus
+ holding any of the mutexes is sufficient to read it.
+ The 'm_ref_usage; is incremented under protection by
+ mdl_locks.m_mutex, but when 'm_is_destroyed' is set to TRUE, this
+ member is moved to be protected by the MDL_lock::m_rwlock.
+ This means that the MDL_map::find_or_insert() which only
+ holds the MDL_lock::m_rwlock can compare it to 'm_ref_release'
+ without acquiring mdl_locks.m_mutex again and if equal it can also
+ destroy the lock object safely.
+ The 'm_ref_release' is incremented under protection by
+ MDL_lock::m_rwlock.
+ Note since we are only interested in equality of these two
+ counters we don't have to worry about overflows as long as
+ their size is big enough to hold maximum number of concurrent
+ threads on the system.
+ */
+ uint m_ref_usage;
+ uint m_ref_release;
+ bool m_is_destroyed;
+};
+
+
+/**
+ An implementation of the scoped metadata lock. The only locking modes
+ which are supported at the moment are SHARED and INTENTION EXCLUSIVE
+ and EXCLUSIVE
+*/
+
+class MDL_scoped_lock : public MDL_lock
+{
+public:
+ MDL_scoped_lock(const MDL_key *key_arg)
+ : MDL_lock(key_arg)
+ { }
+
+ virtual const bitmap_t *incompatible_granted_types_bitmap() const
+ {
+ return m_granted_incompatible;
+ }
+ virtual const bitmap_t *incompatible_waiting_types_bitmap() const
+ {
+ return m_waiting_incompatible;
+ }
+ virtual bool needs_notification(const MDL_ticket *ticket) const
+ {
+ return (ticket->get_type() == MDL_SHARED);
+ }
+ virtual void notify_conflicting_locks(MDL_context *ctx);
+
+private:
+ static const bitmap_t m_granted_incompatible[MDL_TYPE_END];
+ static const bitmap_t m_waiting_incompatible[MDL_TYPE_END];
+};
+
+
+/**
+ An implementation of a per-object lock. Supports SHARED, SHARED_UPGRADABLE,
+ SHARED HIGH PRIORITY and EXCLUSIVE locks.
+*/
+
+class MDL_object_lock : public MDL_lock
+{
+public:
+ MDL_object_lock(const MDL_key *key_arg)
+ : MDL_lock(key_arg)
+ { }
+
+ virtual const bitmap_t *incompatible_granted_types_bitmap() const
+ {
+ return m_granted_incompatible;
+ }
+ virtual const bitmap_t *incompatible_waiting_types_bitmap() const
+ {
+ return m_waiting_incompatible;
+ }
+ virtual bool needs_notification(const MDL_ticket *ticket) const
+ {
+ return ticket->is_upgradable_or_exclusive();
+ }
+ virtual void notify_conflicting_locks(MDL_context *ctx);
+
+private:
+ static const bitmap_t m_granted_incompatible[MDL_TYPE_END];
+ static const bitmap_t m_waiting_incompatible[MDL_TYPE_END];
+};
+
+
+static MDL_map mdl_locks;
+
+extern "C"
+{
+static uchar *
+mdl_locks_key(const uchar *record, size_t *length,
+ my_bool not_used __attribute__((unused)))
+{
+ MDL_lock *lock=(MDL_lock*) record;
+ *length= lock->key.length();
+ return (uchar*) lock->key.ptr();
+}
+} /* extern "C" */
+
+
+/**
+ Initialize the metadata locking subsystem.
+
+ This function is called at server startup.
+
+ In particular, initializes the new global mutex and
+ the associated condition variable: LOCK_mdl and COND_mdl.
+ These locking primitives are implementation details of the MDL
+ subsystem and are private to it.
+*/
+
+void mdl_init()
+{
+ DBUG_ASSERT(! mdl_initialized);
+ mdl_initialized= TRUE;
+
+#ifdef HAVE_PSI_INTERFACE
+ init_mdl_psi_keys();
+#endif
+
+ mdl_locks.init();
+}
+
+
+/**
+ Release resources of metadata locking subsystem.
+
+ Destroys the global mutex and the condition variable.
+ Called at server shutdown.
+*/
+
+void mdl_destroy()
+{
+ if (mdl_initialized)
+ {
+ mdl_initialized= FALSE;
+ mdl_locks.destroy();
+ }
+}
+
+
+/** Initialize the global hash containing all MDL locks. */
+
+void MDL_map::init()
+{
+ MDL_key global_lock_key(MDL_key::GLOBAL, "", "");
+ MDL_key commit_lock_key(MDL_key::COMMIT, "", "");
+
+ mysql_mutex_init(key_MDL_map_mutex, &m_mutex, NULL);
+ my_hash_init(&m_locks, &my_charset_bin, 16 /* FIXME */, 0, 0,
+ mdl_locks_key, 0, 0);
+ m_global_lock= MDL_lock::create(&global_lock_key);
+ m_commit_lock= MDL_lock::create(&commit_lock_key);
+}
+
+
+/**
+ Destroy the global hash containing all MDL locks.
+ @pre It must be empty.
+*/
+
+void MDL_map::destroy()
+{
+ DBUG_ASSERT(!m_locks.records);
+ mysql_mutex_destroy(&m_mutex);
+ my_hash_free(&m_locks);
+ MDL_lock::destroy(m_global_lock);
+ MDL_lock::destroy(m_commit_lock);
+}
+
+
+/**
+ Find MDL_lock object corresponding to the key, create it
+ if it does not exist.
+
+ @retval non-NULL - Success. MDL_lock instance for the key with
+ locked MDL_lock::m_rwlock.
+ @retval NULL - Failure (OOM).
+*/
+
+MDL_lock* MDL_map::find_or_insert(const MDL_key *mdl_key)
+{
+ MDL_lock *lock;
+ my_hash_value_type hash_value;
+
+ if (mdl_key->mdl_namespace() == MDL_key::GLOBAL ||
+ mdl_key->mdl_namespace() == MDL_key::COMMIT)
+ {
+ /*
+ Avoid locking m_mutex when lock for GLOBAL or COMMIT namespace is
+ requested. Return pointer to pre-allocated MDL_lock instance instead.
+ Such an optimization allows to save one mutex lock/unlock for any
+ statement changing data.
+
+ It works since these namespaces contain only one element so keys
+ for them look like '<namespace-id>\0\0'.
+ */
+ DBUG_ASSERT(mdl_key->length() == 3);
+
+ lock= (mdl_key->mdl_namespace() == MDL_key::GLOBAL) ? m_global_lock :
+ m_commit_lock;
+
+ mysql_prlock_wrlock(&lock->m_rwlock);
+
+ return lock;
+ }
+
+
+ hash_value= my_calc_hash(&m_locks, mdl_key->ptr(), mdl_key->length());
+
+retry:
+ mysql_mutex_lock(&m_mutex);
+ if (!(lock= (MDL_lock*) my_hash_search_using_hash_value(&m_locks,
+ hash_value,
+ mdl_key->ptr(),
+ mdl_key->length())))
+ {
+ lock= MDL_lock::create(mdl_key);
+ if (!lock || my_hash_insert(&m_locks, (uchar*)lock))
+ {
+ mysql_mutex_unlock(&m_mutex);
+ MDL_lock::destroy(lock);
+ return NULL;
+ }
+ }
+
+ if (move_from_hash_to_lock_mutex(lock))
+ goto retry;
+
+ return lock;
+}
+
+
+/**
+ Release mdl_locks.m_mutex mutex and lock MDL_lock::m_rwlock for lock
+ object from the hash. Handle situation when object was released
+ while the held no mutex.
+
+ @retval FALSE - Success.
+ @retval TRUE - Object was released while we held no mutex, caller
+ should re-try looking up MDL_lock object in the hash.
+*/
+
+bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock)
+{
+ DBUG_ASSERT(! lock->m_is_destroyed);
+ mysql_mutex_assert_owner(&m_mutex);
+
+ /*
+ We increment m_ref_usage which is a reference counter protected by
+ mdl_locks.m_mutex under the condition it is present in the hash and
+ m_is_destroyed is FALSE.
+ */
+ lock->m_ref_usage++;
+ mysql_mutex_unlock(&m_mutex);
+
+ mysql_prlock_wrlock(&lock->m_rwlock);
+ lock->m_ref_release++;
+ if (unlikely(lock->m_is_destroyed))
+ {
+ /*
+ Object was released while we held no mutex, we need to
+ release it if no others hold references to it, while our own
+ reference count ensured that the object as such haven't got
+ its memory released yet. We can also safely compare
+ m_ref_usage and m_ref_release since the object is no longer
+ present in the hash so no one will be able to find it and
+ increment m_ref_usage anymore.
+ */
+ uint ref_usage= lock->m_ref_usage;
+ uint ref_release= lock->m_ref_release;
+ mysql_prlock_unlock(&lock->m_rwlock);
+ if (ref_usage == ref_release)
+ MDL_lock::destroy(lock);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Destroy MDL_lock object or delegate this responsibility to
+ whatever thread that holds the last outstanding reference to
+ it.
+*/
+
+void MDL_map::remove(MDL_lock *lock)
+{
+ uint ref_usage, ref_release;
+
+ if (lock->key.mdl_namespace() == MDL_key::GLOBAL ||
+ lock->key.mdl_namespace() == MDL_key::COMMIT)
+ {
+ /*
+ Never destroy pre-allocated MDL_lock objects for GLOBAL and
+ COMMIT namespaces.
+ */
+ mysql_prlock_unlock(&lock->m_rwlock);
+ return;
+ }
+
+ /*
+ Destroy the MDL_lock object, but ensure that anyone that is
+ holding a reference to the object is not remaining, if so he
+ has the responsibility to release it.
+
+ Setting of m_is_destroyed to TRUE while holding _both_
+ mdl_locks.m_mutex and MDL_lock::m_rwlock mutexes transfers the
+ protection of m_ref_usage from mdl_locks.m_mutex to
+ MDL_lock::m_rwlock while removal of object from the hash makes
+ it read-only. Therefore whoever acquires MDL_lock::m_rwlock next
+ will see most up to date version of m_ref_usage.
+
+ This means that when m_is_destroyed is TRUE and we hold the
+ MDL_lock::m_rwlock we can safely read the m_ref_usage
+ member.
+ */
+ mysql_mutex_lock(&m_mutex);
+ my_hash_delete(&m_locks, (uchar*) lock);
+ lock->m_is_destroyed= TRUE;
+ ref_usage= lock->m_ref_usage;
+ ref_release= lock->m_ref_release;
+ mysql_prlock_unlock(&lock->m_rwlock);
+ mysql_mutex_unlock(&m_mutex);
+ if (ref_usage == ref_release)
+ MDL_lock::destroy(lock);
+}
+
+
+/**
+ Initialize a metadata locking context.
+
+ This is to be called when a new server connection is created.
+*/
+
+MDL_context::MDL_context()
+ : m_thd(NULL),
+ m_needs_thr_lock_abort(FALSE),
+ m_waiting_for(NULL)
+{
+ mysql_prlock_init(key_MDL_context_LOCK_waiting_for, &m_LOCK_waiting_for);
+}
+
+
+/**
+ Destroy metadata locking context.
+
+ Assumes and asserts that there are no active or pending locks
+ associated with this context at the time of the destruction.
+
+ Currently does nothing. Asserts that there are no pending
+ or satisfied lock requests. The pending locks must be released
+ prior to destruction. This is a new way to express the assertion
+ that all tables are closed before a connection is destroyed.
+*/
+
+void MDL_context::destroy()
+{
+ DBUG_ASSERT(m_tickets[MDL_STATEMENT].is_empty() &&
+ m_tickets[MDL_TRANSACTION].is_empty() &&
+ m_tickets[MDL_EXPLICIT].is_empty());
+
+ mysql_prlock_destroy(&m_LOCK_waiting_for);
+}
+
+
+/**
+ Initialize a lock request.
+
+ This is to be used for every lock request.
+
+ Note that initialization and allocation are split into two
+ calls. This is to allow flexible memory management of lock
+ requests. Normally a lock request is stored in statement memory
+ (e.g. is a member of struct TABLE_LIST), but we would also like
+ to allow allocation of lock requests in other memory roots,
+ for example in the grant subsystem, to lock privilege tables.
+
+ The MDL subsystem does not own or manage memory of lock requests.
+
+ @param mdl_namespace Id of namespace of object to be locked
+ @param db Name of database to which the object belongs
+ @param name Name of of the object
+ @param mdl_type The MDL lock type for the request.
+*/
+
+void MDL_request::init(MDL_key::enum_mdl_namespace mdl_namespace,
+ const char *db_arg,
+ const char *name_arg,
+ enum_mdl_type mdl_type_arg,
+ enum_mdl_duration mdl_duration_arg)
+{
+ key.mdl_key_init(mdl_namespace, db_arg, name_arg);
+ type= mdl_type_arg;
+ duration= mdl_duration_arg;
+ ticket= NULL;
+}
+
+
+/**
+ Initialize a lock request using pre-built MDL_key.
+
+ @sa MDL_request::init(namespace, db, name, type).
+
+ @param key_arg The pre-built MDL key for the request.
+ @param mdl_type_arg The MDL lock type for the request.
+*/
+
+void MDL_request::init(const MDL_key *key_arg,
+ enum_mdl_type mdl_type_arg,
+ enum_mdl_duration mdl_duration_arg)
+{
+ key.mdl_key_init(key_arg);
+ type= mdl_type_arg;
+ duration= mdl_duration_arg;
+ ticket= NULL;
+}
+
+
+/**
+ Auxiliary functions needed for creation/destruction of MDL_lock objects.
+
+ @note Also chooses an MDL_lock descendant appropriate for object namespace.
+
+ @todo This naive implementation should be replaced with one that saves
+ on memory allocation by reusing released objects.
+*/
+
+inline MDL_lock *MDL_lock::create(const MDL_key *mdl_key)
+{
+ switch (mdl_key->mdl_namespace())
+ {
+ case MDL_key::GLOBAL:
+ case MDL_key::SCHEMA:
+ case MDL_key::COMMIT:
+ return new MDL_scoped_lock(mdl_key);
+ default:
+ return new MDL_object_lock(mdl_key);
+ }
+}
+
+
+void MDL_lock::destroy(MDL_lock *lock)
+{
+ delete lock;
+}
+
+
+/**
+ Auxiliary functions needed for creation/destruction of MDL_ticket
+ objects.
+
+ @todo This naive implementation should be replaced with one that saves
+ on memory allocation by reusing released objects.
+*/
+
+MDL_ticket *MDL_ticket::create(MDL_context *ctx_arg, enum_mdl_type type_arg
+#ifndef DBUG_OFF
+ , enum_mdl_duration duration_arg
+#endif
+ )
+{
+ return new MDL_ticket(ctx_arg, type_arg
+#ifndef DBUG_OFF
+ , duration_arg
+#endif
+ );
+}
+
+
+void MDL_ticket::destroy(MDL_ticket *ticket)
+{
+ delete ticket;
+}
+
+
+/**
+ Return the 'weight' of this ticket for the
+ victim selection algorithm. Requests with
+ lower weight are preferred to requests
+ with higher weight when choosing a victim.
+*/
+
+uint MDL_ticket::get_deadlock_weight() const
+{
+ return (m_lock->key.mdl_namespace() == MDL_key::GLOBAL ||
+ m_type >= MDL_SHARED_NO_WRITE ?
+ DEADLOCK_WEIGHT_DDL : DEADLOCK_WEIGHT_DML);
+}
+
+
+/** Construct an empty wait slot. */
+
+MDL_wait::MDL_wait()
+ :m_wait_status(EMPTY)
+{
+ mysql_mutex_init(key_MDL_wait_LOCK_wait_status, &m_LOCK_wait_status, NULL);
+ mysql_cond_init(key_MDL_wait_COND_wait_status, &m_COND_wait_status, NULL);
+}
+
+
+/** Destroy system resources. */
+
+MDL_wait::~MDL_wait()
+{
+ mysql_mutex_destroy(&m_LOCK_wait_status);
+ mysql_cond_destroy(&m_COND_wait_status);
+}
+
+
+/**
+ Set the status unless it's already set. Return FALSE if set,
+ TRUE otherwise.
+*/
+
+bool MDL_wait::set_status(enum_wait_status status_arg)
+{
+ bool was_occupied= TRUE;
+ mysql_mutex_lock(&m_LOCK_wait_status);
+ if (m_wait_status == EMPTY)
+ {
+ was_occupied= FALSE;
+ m_wait_status= status_arg;
+ mysql_cond_signal(&m_COND_wait_status);
+ }
+ mysql_mutex_unlock(&m_LOCK_wait_status);
+ return was_occupied;
+}
+
+
+/** Query the current value of the wait slot. */
+
+MDL_wait::enum_wait_status MDL_wait::get_status()
+{
+ enum_wait_status result;
+ mysql_mutex_lock(&m_LOCK_wait_status);
+ result= m_wait_status;
+ mysql_mutex_unlock(&m_LOCK_wait_status);
+ return result;
+}
+
+
+/** Clear the current value of the wait slot. */
+
+void MDL_wait::reset_status()
+{
+ mysql_mutex_lock(&m_LOCK_wait_status);
+ m_wait_status= EMPTY;
+ mysql_mutex_unlock(&m_LOCK_wait_status);
+}
+
+
+/**
+ Wait for the status to be assigned to this wait slot.
+
+ @param abs_timeout Absolute time after which waiting should stop.
+ @param set_status_on_timeout TRUE - If in case of timeout waiting
+ context should close the wait slot by
+ sending TIMEOUT to itself.
+ FALSE - Otherwise.
+ @param wait_state_name Thread state name to be set for duration of wait.
+
+ @returns Signal posted.
+*/
+
+MDL_wait::enum_wait_status
+MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout,
+ bool set_status_on_timeout, const char *wait_state_name)
+{
+ const char *old_msg;
+ enum_wait_status result;
+ int wait_result= 0;
+
+ mysql_mutex_lock(&m_LOCK_wait_status);
+
+ old_msg= thd_enter_cond(thd, &m_COND_wait_status, &m_LOCK_wait_status,
+ wait_state_name);
+
+ while (!m_wait_status && !thd_killed(thd) &&
+ wait_result != ETIMEDOUT && wait_result != ETIME)
+ wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status,
+ abs_timeout);
+
+ if (m_wait_status == EMPTY)
+ {
+ /*
+ Wait has ended not due to a status being set from another
+ thread but due to this connection/statement being killed or a
+ time out.
+ To avoid races, which may occur if another thread sets
+ GRANTED status before the code which calls this method
+ processes the abort/timeout, we assign the status under
+ protection of the m_LOCK_wait_status, within the critical
+ section. An exception is when set_status_on_timeout is
+ false, which means that the caller intends to restart the
+ wait.
+ */
+ if (thd_killed(thd))
+ m_wait_status= KILLED;
+ else if (set_status_on_timeout)
+ m_wait_status= TIMEOUT;
+ }
+ result= m_wait_status;
+
+ thd_exit_cond(thd, old_msg);
+
+ return result;
+}
+
+
+/**
+ Clear bit corresponding to the type of metadata lock in bitmap representing
+ set of such types if list of tickets does not contain ticket with such type.
+
+ @param[in,out] bitmap Bitmap representing set of types of locks.
+ @param[in] list List to inspect.
+ @param[in] type Type of metadata lock to look up in the list.
+*/
+
+void MDL_lock::Ticket_list::clear_bit_if_not_in_list(enum_mdl_type type)
+{
+ MDL_lock::Ticket_iterator it(m_list);
+ const MDL_ticket *ticket;
+
+ while ((ticket= it++))
+ if (ticket->get_type() == type)
+ return;
+ m_bitmap&= ~ MDL_BIT(type);
+}
+
+
+/**
+ Add ticket to MDL_lock's list of waiting requests and
+ update corresponding bitmap of lock types.
+*/
+
+void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket)
+{
+ /*
+ Ticket being added to the list must have MDL_ticket::m_lock set,
+ since for such tickets methods accessing this member might be
+ called by other threads.
+ */
+ DBUG_ASSERT(ticket->get_lock());
+ /*
+ Add ticket to the *back* of the queue to ensure fairness
+ among requests with the same priority.
+ */
+ m_list.push_back(ticket);
+ m_bitmap|= MDL_BIT(ticket->get_type());
+}
+
+
+/**
+ Remove ticket from MDL_lock's list of requests and
+ update corresponding bitmap of lock types.
+*/
+
+void MDL_lock::Ticket_list::remove_ticket(MDL_ticket *ticket)
+{
+ m_list.remove(ticket);
+ /*
+ Check if waiting queue has another ticket with the same type as
+ one which was removed. If there is no such ticket, i.e. we have
+ removed last ticket of particular type, then we need to update
+ bitmap of waiting ticket's types.
+ Note that in most common case, i.e. when shared lock is removed
+ from waiting queue, we are likely to find ticket of the same
+ type early without performing full iteration through the list.
+ So this method should not be too expensive.
+ */
+ clear_bit_if_not_in_list(ticket->get_type());
+}
+
+
+/**
+ Determine waiting contexts which requests for the lock can be
+ satisfied, grant lock to them and wake them up.
+
+ @note Together with MDL_lock::add_ticket() this method implements
+ fair scheduling among requests with the same priority.
+ It tries to grant lock from the head of waiters list, while
+ add_ticket() adds new requests to the back of this list.
+
+*/
+
+void MDL_lock::reschedule_waiters()
+{
+ MDL_lock::Ticket_iterator it(m_waiting);
+ MDL_ticket *ticket;
+
+ /*
+ Find the first (and hence the oldest) waiting request which
+ can be satisfied (taking into account priority). Grant lock to it.
+ Repeat the process for the remainder of waiters.
+ Note we don't need to re-start iteration from the head of the
+ list after satisfying the first suitable request as in our case
+ all compatible types of requests have the same priority.
+
+ TODO/FIXME: We should:
+ - Either switch to scheduling without priorities
+ which will allow to stop iteration through the
+ list of waiters once we found the first ticket
+ which can't be satisfied
+ - Or implement some check using bitmaps which will
+ allow to stop iteration in cases when, e.g., we
+ grant SNRW lock and there are no pending S or
+ SH locks.
+ */
+ while ((ticket= it++))
+ {
+ if (can_grant_lock(ticket->get_type(), ticket->get_ctx()))
+ {
+ if (! ticket->get_ctx()->m_wait.set_status(MDL_wait::GRANTED))
+ {
+ /*
+ Satisfy the found request by updating lock structures.
+ It is OK to do so even after waking up the waiter since any
+ session which tries to get any information about the state of
+ this lock has to acquire MDL_lock::m_rwlock first and thus,
+ when manages to do so, already sees an updated state of the
+ MDL_lock object.
+ */
+ m_waiting.remove_ticket(ticket);
+ m_granted.add_ticket(ticket);
+ }
+ /*
+ If we could not update the wait slot of the waiter,
+ it can be due to fact that its connection/statement was
+ killed or it has timed out (i.e. the slot is not empty).
+ Since in all such cases the waiter assumes that the lock was
+ not been granted, we should keep the request in the waiting
+ queue and look for another request to reschedule.
+ */
+ }
+ }
+}
+
+
+/**
+ Compatibility (or rather "incompatibility") matrices for scoped metadata
+ lock. Arrays of bitmaps which elements specify which granted/waiting locks
+ are incompatible with type of lock being requested.
+
+ Here is how types of individual locks are translated to type of scoped lock:
+
+ ----------------+-------------+
+ Type of request | Correspond. |
+ for indiv. lock | scoped lock |
+ ----------------+-------------+
+ S, SH, SR, SW | IS |
+ SNW, SNRW, X | IX |
+ SNW, SNRW -> X | IX (*) |
+
+ The first array specifies if particular type of request can be satisfied
+ if there is granted scoped lock of certain type.
+
+ | Type of active |
+ Request | scoped lock |
+ type | IS(**) IX S X |
+ ---------+------------------+
+ IS | + + + + |
+ IX | + + - - |
+ S | + - + - |
+ X | + - - - |
+
+ The second array specifies if particular type of request can be satisfied
+ if there is already waiting request for the scoped lock of certain type.
+ I.e. it specifies what is the priority of different lock types.
+
+ | Pending |
+ Request | scoped lock |
+ type | IS(**) IX S X |
+ ---------+-----------------+
+ IS | + + + + |
+ IX | + + - - |
+ S | + + + - |
+ X | + + + + |
+
+ Here: "+" -- means that request can be satisfied
+ "-" -- means that request can't be satisfied and should wait
+
+ (*) Since for upgradable locks we always take intention exclusive scoped
+ lock at the same time when obtaining the shared lock, there is no
+ need to obtain such lock during the upgrade itself.
+ (**) Since intention shared scoped locks are compatible with all other
+ type of locks we don't even have any accounting for them.
+*/
+
+const MDL_lock::bitmap_t MDL_scoped_lock::m_granted_incompatible[MDL_TYPE_END] =
+{
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED),
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_INTENTION_EXCLUSIVE), 0, 0, 0, 0, 0,
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED) | MDL_BIT(MDL_INTENTION_EXCLUSIVE)
+};
+
+const MDL_lock::bitmap_t MDL_scoped_lock::m_waiting_incompatible[MDL_TYPE_END] =
+{
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED),
+ MDL_BIT(MDL_EXCLUSIVE), 0, 0, 0, 0, 0, 0
+};
+
+
+/**
+ Compatibility (or rather "incompatibility") matrices for per-object
+ metadata lock. Arrays of bitmaps which elements specify which granted/
+ waiting locks are incompatible with type of lock being requested.
+
+ The first array specifies if particular type of request can be satisfied
+ if there is granted lock of certain type.
+
+ Request | Granted requests for lock |
+ type | S SH SR SW SNW SNRW X |
+ ----------+------------------------------+
+ S | + + + + + + - |
+ SH | + + + + + + - |
+ SR | + + + + + - - |
+ SW | + + + + - - - |
+ SNW | + + + - - - - |
+ SNRW | + + - - - - - |
+ X | - - - - - - - |
+ SNW -> X | - - - 0 0 0 0 |
+ SNRW -> X | - - 0 0 0 0 0 |
+
+ The second array specifies if particular type of request can be satisfied
+ if there is waiting request for the same lock of certain type. In other
+ words it specifies what is the priority of different lock types.
+
+ Request | Pending requests for lock |
+ type | S SH SR SW SNW SNRW X |
+ ----------+-----------------------------+
+ S | + + + + + + - |
+ SH | + + + + + + + |
+ SR | + + + + + - - |
+ SW | + + + + - - - |
+ SNW | + + + + + + - |
+ SNRW | + + + + + + - |
+ X | + + + + + + + |
+ SNW -> X | + + + + + + + |
+ SNRW -> X | + + + + + + + |
+
+ Here: "+" -- means that request can be satisfied
+ "-" -- means that request can't be satisfied and should wait
+ "0" -- means impossible situation which will trigger assert
+
+ @note In cases then current context already has "stronger" type
+ of lock on the object it will be automatically granted
+ thanks to usage of the MDL_context::find_ticket() method.
+*/
+
+const MDL_lock::bitmap_t
+MDL_object_lock::m_granted_incompatible[MDL_TYPE_END] =
+{
+ 0,
+ MDL_BIT(MDL_EXCLUSIVE),
+ MDL_BIT(MDL_EXCLUSIVE),
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE),
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
+ MDL_BIT(MDL_SHARED_NO_WRITE),
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
+ MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_WRITE),
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
+ MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_WRITE) |
+ MDL_BIT(MDL_SHARED_READ),
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
+ MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_WRITE) |
+ MDL_BIT(MDL_SHARED_READ) | MDL_BIT(MDL_SHARED_HIGH_PRIO) |
+ MDL_BIT(MDL_SHARED)
+};
+
+
+const MDL_lock::bitmap_t
+MDL_object_lock::m_waiting_incompatible[MDL_TYPE_END] =
+{
+ 0,
+ MDL_BIT(MDL_EXCLUSIVE),
+ 0,
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE),
+ MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
+ MDL_BIT(MDL_SHARED_NO_WRITE),
+ MDL_BIT(MDL_EXCLUSIVE),
+ MDL_BIT(MDL_EXCLUSIVE),
+ 0
+};
+
+
+/**
+ Check if request for the metadata lock can be satisfied given its
+ current state.
+
+ @param type_arg The requested lock type.
+ @param requestor_ctx The MDL context of the requestor.
+
+ @retval TRUE Lock request can be satisfied
+ @retval FALSE There is some conflicting lock.
+
+ @note In cases then current context already has "stronger" type
+ of lock on the object it will be automatically granted
+ thanks to usage of the MDL_context::find_ticket() method.
+*/
+
+bool
+MDL_lock::can_grant_lock(enum_mdl_type type_arg,
+ MDL_context *requestor_ctx) const
+{
+ bool can_grant= FALSE;
+ bitmap_t waiting_incompat_map= incompatible_waiting_types_bitmap()[type_arg];
+ bitmap_t granted_incompat_map= incompatible_granted_types_bitmap()[type_arg];
+ /*
+ New lock request can be satisfied iff:
+ - There are no incompatible types of satisfied requests
+ in other contexts
+ - There are no waiting requests which have higher priority
+ than this request.
+ */
+ if (! (m_waiting.bitmap() & waiting_incompat_map))
+ {
+ if (! (m_granted.bitmap() & granted_incompat_map))
+ can_grant= TRUE;
+ else
+ {
+ Ticket_iterator it(m_granted);
+ MDL_ticket *ticket;
+
+ /* Check that the incompatible lock belongs to some other context. */
+ while ((ticket= it++))
+ {
+ if (ticket->get_ctx() != requestor_ctx &&
+ ticket->is_incompatible_when_granted(type_arg))
+ break;
+ }
+ if (ticket == NULL) /* Incompatible locks are our own. */
+ can_grant= TRUE;
+ }
+ }
+ return can_grant;
+}
+
+
+/** Remove a ticket from waiting or pending queue and wakeup up waiters. */
+
+void MDL_lock::remove_ticket(Ticket_list MDL_lock::*list, MDL_ticket *ticket)
+{
+ mysql_prlock_wrlock(&m_rwlock);
+ (this->*list).remove_ticket(ticket);
+ if (is_empty())
+ mdl_locks.remove(this);
+ else
+ {
+ /*
+ There can be some contexts waiting to acquire a lock
+ which now might be able to do it. Grant the lock to
+ them and wake them up!
+
+ We always try to reschedule locks, since there is no easy way
+ (i.e. by looking at the bitmaps) to find out whether it is
+ required or not.
+ In a general case, even when the queue's bitmap is not changed
+ after removal of the ticket, there is a chance that some request
+ can be satisfied (due to the fact that a granted request
+ reflected in the bitmap might belong to the same context as a
+ pending request).
+ */
+ reschedule_waiters();
+ mysql_prlock_unlock(&m_rwlock);
+ }
+}
+
+
+/**
+ Check if we have any pending locks which conflict with existing
+ shared lock.
+
+ @pre The ticket must match an acquired lock.
+
+ @return TRUE if there is a conflicting lock request, FALSE otherwise.
+*/
+
+bool MDL_lock::has_pending_conflicting_lock(enum_mdl_type type)
+{
+ bool result;
+
+ mysql_mutex_assert_not_owner(&LOCK_open);
+
+ mysql_prlock_rdlock(&m_rwlock);
+ result= (m_waiting.bitmap() & incompatible_granted_types_bitmap()[type]);
+ mysql_prlock_unlock(&m_rwlock);
+ return result;
+}
+
+
+MDL_wait_for_graph_visitor::~MDL_wait_for_graph_visitor()
+{
+}
+
+
+MDL_wait_for_subgraph::~MDL_wait_for_subgraph()
+{
+}
+
+/**
+ Check if ticket represents metadata lock of "stronger" or equal type
+ than specified one. I.e. if metadata lock represented by ticket won't
+ allow any of locks which are not allowed by specified type of lock.
+
+ @return TRUE if ticket has stronger or equal type
+ FALSE otherwise.
+*/
+
+bool MDL_ticket::has_stronger_or_equal_type(enum_mdl_type type) const
+{
+ const MDL_lock::bitmap_t *
+ granted_incompat_map= m_lock->incompatible_granted_types_bitmap();
+
+ return ! (granted_incompat_map[type] & ~(granted_incompat_map[m_type]));
+}
+
+
+bool MDL_ticket::is_incompatible_when_granted(enum_mdl_type type) const
+{
+ return (MDL_BIT(m_type) &
+ m_lock->incompatible_granted_types_bitmap()[type]);
+}
+
+
+bool MDL_ticket::is_incompatible_when_waiting(enum_mdl_type type) const
+{
+ return (MDL_BIT(m_type) &
+ m_lock->incompatible_waiting_types_bitmap()[type]);
+}
+
+
+/**
+ Check whether the context already holds a compatible lock ticket
+ on an object.
+ Start searching from list of locks for the same duration as lock
+ being requested. If not look at lists for other durations.
+
+ @param mdl_request Lock request object for lock to be acquired
+ @param[out] result_duration Duration of lock which was found.
+
+ @note Tickets which correspond to lock types "stronger" than one
+ being requested are also considered compatible.
+
+ @return A pointer to the lock ticket for the object or NULL otherwise.
+*/
+
+MDL_ticket *
+MDL_context::find_ticket(MDL_request *mdl_request,
+ enum_mdl_duration *result_duration)
+{
+ MDL_ticket *ticket;
+ int i;
+
+ for (i= 0; i < MDL_DURATION_END; i++)
+ {
+ enum_mdl_duration duration= (enum_mdl_duration)((mdl_request->duration+i) %
+ MDL_DURATION_END);
+ Ticket_iterator it(m_tickets[duration]);
+
+ while ((ticket= it++))
+ {
+ if (mdl_request->key.is_equal(&ticket->m_lock->key) &&
+ ticket->has_stronger_or_equal_type(mdl_request->type))
+ {
+ *result_duration= duration;
+ return ticket;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ Try to acquire one lock.
+
+ Unlike exclusive locks, shared locks are acquired one by
+ one. This is interface is chosen to simplify introduction of
+ the new locking API to the system. MDL_context::try_acquire_lock()
+ is currently used from open_table(), and there we have only one
+ table to work with.
+
+ This function may also be used to try to acquire an exclusive
+ lock on a destination table, by ALTER TABLE ... RENAME.
+
+ Returns immediately without any side effect if encounters a lock
+ conflict. Otherwise takes the lock.
+
+ FIXME: Compared to lock_table_name_if_not_cached() (from 5.1)
+ it gives slightly more false negatives.
+
+ @param mdl_request [in/out] Lock request object for lock to be acquired
+
+ @retval FALSE Success. The lock may have not been acquired.
+ Check the ticket, if it's NULL, a conflicting lock
+ exists.
+ @retval TRUE Out of resources, an error has been reported.
+*/
+
+bool
+MDL_context::try_acquire_lock(MDL_request *mdl_request)
+{
+ MDL_ticket *ticket;
+
+ if (try_acquire_lock_impl(mdl_request, &ticket))
+ return TRUE;
+
+ if (! mdl_request->ticket)
+ {
+ /*
+ Our attempt to acquire lock without waiting has failed.
+ Let us release resources which were acquired in the process.
+ We can't get here if we allocated a new lock object so there
+ is no need to release it.
+ */
+ DBUG_ASSERT(! ticket->m_lock->is_empty());
+ mysql_prlock_unlock(&ticket->m_lock->m_rwlock);
+ MDL_ticket::destroy(ticket);
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Auxiliary method for acquiring lock without waiting.
+
+ @param mdl_request [in/out] Lock request object for lock to be acquired
+ @param out_ticket [out] Ticket for the request in case when lock
+ has not been acquired.
+
+ @retval FALSE Success. The lock may have not been acquired.
+ Check MDL_request::ticket, if it's NULL, a conflicting
+ lock exists. In this case "out_ticket" out parameter
+ points to ticket which was constructed for the request.
+ MDL_ticket::m_lock points to the corresponding MDL_lock
+ object and MDL_lock::m_rwlock write-locked.
+ @retval TRUE Out of resources, an error has been reported.
+*/
+
+bool
+MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
+ MDL_ticket **out_ticket)
+{
+ MDL_lock *lock;
+ MDL_key *key= &mdl_request->key;
+ MDL_ticket *ticket;
+ enum_mdl_duration found_duration;
+
+ DBUG_ASSERT(mdl_request->type != MDL_EXCLUSIVE ||
+ is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE));
+ DBUG_ASSERT(mdl_request->ticket == NULL);
+
+ /* Don't take chances in production. */
+ mdl_request->ticket= NULL;
+ mysql_mutex_assert_not_owner(&LOCK_open);
+
+ /*
+ Check whether the context already holds a shared lock on the object,
+ and if so, grant the request.
+ */
+ if ((ticket= find_ticket(mdl_request, &found_duration)))
+ {
+ DBUG_ASSERT(ticket->m_lock);
+ DBUG_ASSERT(ticket->has_stronger_or_equal_type(mdl_request->type));
+ /*
+ If the request is for a transactional lock, and we found
+ a transactional lock, just reuse the found ticket.
+
+ It's possible that we found a transactional lock,
+ but the request is for a HANDLER lock. In that case HANDLER
+ code will clone the ticket (see below why it's needed).
+
+ If the request is for a transactional lock, and we found
+ a HANDLER lock, create a copy, to make sure that when user
+ does HANDLER CLOSE, the transactional lock is not released.
+
+ If the request is for a handler lock, and we found a
+ HANDLER lock, also do the clone. HANDLER CLOSE for one alias
+ should not release the lock on the table HANDLER opened through
+ a different alias.
+ */
+ mdl_request->ticket= ticket;
+ if ((found_duration != mdl_request->duration ||
+ mdl_request->duration == MDL_EXPLICIT) &&
+ clone_ticket(mdl_request))
+ {
+ /* Clone failed. */
+ mdl_request->ticket= NULL;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ if (!(ticket= MDL_ticket::create(this, mdl_request->type
+#ifndef DBUG_OFF
+ , mdl_request->duration
+#endif
+ )))
+ return TRUE;
+
+ /* The below call implicitly locks MDL_lock::m_rwlock on success. */
+ if (!(lock= mdl_locks.find_or_insert(key)))
+ {
+ MDL_ticket::destroy(ticket);
+ return TRUE;
+ }
+
+ ticket->m_lock= lock;
+
+ if (lock->can_grant_lock(mdl_request->type, this))
+ {
+ lock->m_granted.add_ticket(ticket);
+
+ mysql_prlock_unlock(&lock->m_rwlock);
+
+ m_tickets[mdl_request->duration].push_front(ticket);
+
+ mdl_request->ticket= ticket;
+ }
+ else
+ *out_ticket= ticket;
+
+ return FALSE;
+}
+
+
+/**
+ Create a copy of a granted ticket.
+ This is used to make sure that HANDLER ticket
+ is never shared with a ticket that belongs to
+ a transaction, so that when we HANDLER CLOSE,
+ we don't release a transactional ticket, and
+ vice versa -- when we COMMIT, we don't mistakenly
+ release a ticket for an open HANDLER.
+
+ @retval TRUE Out of memory.
+ @retval FALSE Success.
+*/
+
+bool
+MDL_context::clone_ticket(MDL_request *mdl_request)
+{
+ MDL_ticket *ticket;
+
+ mysql_mutex_assert_not_owner(&LOCK_open);
+ /*
+ By submitting mdl_request->type to MDL_ticket::create()
+ we effectively downgrade the cloned lock to the level of
+ the request.
+ */
+ if (!(ticket= MDL_ticket::create(this, mdl_request->type
+#ifndef DBUG_OFF
+ , mdl_request->duration
+#endif
+ )))
+ return TRUE;
+
+ /* clone() is not supposed to be used to get a stronger lock. */
+ DBUG_ASSERT(mdl_request->ticket->has_stronger_or_equal_type(ticket->m_type));
+
+ ticket->m_lock= mdl_request->ticket->m_lock;
+ mdl_request->ticket= ticket;
+
+ mysql_prlock_wrlock(&ticket->m_lock->m_rwlock);
+ ticket->m_lock->m_granted.add_ticket(ticket);
+ mysql_prlock_unlock(&ticket->m_lock->m_rwlock);
+
+ m_tickets[mdl_request->duration].push_front(ticket);
+
+ return FALSE;
+}
+
+
+/**
+ Notify threads holding a shared metadata locks on object which
+ conflict with a pending X, SNW or SNRW lock.
+
+ @param ctx MDL_context for current thread.
+*/
+
+void MDL_object_lock::notify_conflicting_locks(MDL_context *ctx)
+{
+ Ticket_iterator it(m_granted);
+ MDL_ticket *conflicting_ticket;
+
+ while ((conflicting_ticket= it++))
+ {
+ /* Only try to abort locks on which we back off. */
+ if (conflicting_ticket->get_ctx() != ctx &&
+ conflicting_ticket->get_type() < MDL_SHARED_NO_WRITE)
+
+ {
+ MDL_context *conflicting_ctx= conflicting_ticket->get_ctx();
+
+ /*
+ If thread which holds conflicting lock is waiting on table-level
+ lock or some other non-MDL resource we might need to wake it up
+ by calling code outside of MDL.
+ */
+ mysql_notify_thread_having_shared_lock(ctx->get_thd(),
+ conflicting_ctx->get_thd(),
+ conflicting_ctx->get_needs_thr_lock_abort());
+ }
+ }
+}
+
+
+/**
+ Notify threads holding scoped IX locks which conflict with a pending S lock.
+
+ @param ctx MDL_context for current thread.
+*/
+
+void MDL_scoped_lock::notify_conflicting_locks(MDL_context *ctx)
+{
+ Ticket_iterator it(m_granted);
+ MDL_ticket *conflicting_ticket;
+
+ while ((conflicting_ticket= it++))
+ {
+ if (conflicting_ticket->get_ctx() != ctx &&
+ conflicting_ticket->get_type() == MDL_INTENTION_EXCLUSIVE)
+
+ {
+ MDL_context *conflicting_ctx= conflicting_ticket->get_ctx();
+
+ /*
+ Thread which holds global IX lock can be a handler thread for
+ insert delayed. We need to kill such threads in order to get
+ global shared lock. We do this my calling code outside of MDL.
+ */
+ mysql_notify_thread_having_shared_lock(ctx->get_thd(),
+ conflicting_ctx->get_thd(),
+ conflicting_ctx->get_needs_thr_lock_abort());
+ }
+ }
+}
+
+
+/**
+ Acquire one lock with waiting for conflicting locks to go away if needed.
+
+ @param mdl_request [in/out] Lock request object for lock to be acquired
+
+ @param lock_wait_timeout [in] Seconds to wait before timeout.
+
+ @retval FALSE Success. MDL_request::ticket points to the ticket
+ for the lock.
+ @retval TRUE Failure (Out of resources or waiting is aborted),
+*/
+
+bool
+MDL_context::acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout)
+{
+ MDL_lock *lock;
+ MDL_ticket *ticket;
+ struct timespec abs_timeout;
+ MDL_wait::enum_wait_status wait_status;
+ /* Do some work outside the critical section. */
+ set_timespec(abs_timeout, lock_wait_timeout);
+
+ if (try_acquire_lock_impl(mdl_request, &ticket))
+ return TRUE;
+
+ if (mdl_request->ticket)
+ {
+ /*
+ We have managed to acquire lock without waiting.
+ MDL_lock, MDL_context and MDL_request were updated
+ accordingly, so we can simply return success.
+ */
+ return FALSE;
+ }
+
+ /*
+ Our attempt to acquire lock without waiting has failed.
+ As a result of this attempt we got MDL_ticket with m_lock
+ member pointing to the corresponding MDL_lock object which
+ has MDL_lock::m_rwlock write-locked.
+ */
+ lock= ticket->m_lock;
+
+ lock->m_waiting.add_ticket(ticket);
+
+ /*
+ Once we added a pending ticket to the waiting queue,
+ we must ensure that our wait slot is empty, so
+ that our lock request can be scheduled. Do that in the
+ critical section formed by the acquired write lock on MDL_lock.
+ */
+ m_wait.reset_status();
+
+ if (lock->needs_notification(ticket))
+ lock->notify_conflicting_locks(this);
+
+ mysql_prlock_unlock(&lock->m_rwlock);
+
+ will_wait_for(ticket);
+
+ /* There is a shared or exclusive lock on the object. */
+ DEBUG_SYNC(m_thd, "mdl_acquire_lock_wait");
+
+ find_deadlock();
+
+ if (lock->needs_notification(ticket))
+ {
+ struct timespec abs_shortwait;
+ set_timespec(abs_shortwait, 1);
+ wait_status= MDL_wait::EMPTY;
+
+ while (cmp_timespec(abs_shortwait, abs_timeout) <= 0)
+ {
+ /* abs_timeout is far away. Wait a short while and notify locks. */
+ wait_status= m_wait.timed_wait(m_thd, &abs_shortwait, FALSE,
+ mdl_request->key.get_wait_state_name());
+
+ if (wait_status != MDL_wait::EMPTY)
+ break;
+
+ mysql_prlock_wrlock(&lock->m_rwlock);
+ lock->notify_conflicting_locks(this);
+ mysql_prlock_unlock(&lock->m_rwlock);
+ set_timespec(abs_shortwait, 1);
+ }
+ if (wait_status == MDL_wait::EMPTY)
+ wait_status= m_wait.timed_wait(m_thd, &abs_timeout, TRUE,
+ mdl_request->key.get_wait_state_name());
+ }
+ else
+ wait_status= m_wait.timed_wait(m_thd, &abs_timeout, TRUE,
+ mdl_request->key.get_wait_state_name());
+
+ done_waiting_for();
+
+ if (wait_status != MDL_wait::GRANTED)
+ {
+ lock->remove_ticket(&MDL_lock::m_waiting, ticket);
+ MDL_ticket::destroy(ticket);
+ switch (wait_status)
+ {
+ case MDL_wait::VICTIM:
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ break;
+ case MDL_wait::TIMEOUT:
+ my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
+ break;
+ case MDL_wait::KILLED:
+ break;
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+ return TRUE;
+ }
+
+ /*
+ We have been granted our request.
+ State of MDL_lock object is already being appropriately updated by a
+ concurrent thread (@sa MDL_lock:reschedule_waiters()).
+ So all we need to do is to update MDL_context and MDL_request objects.
+ */
+ DBUG_ASSERT(wait_status == MDL_wait::GRANTED);
+
+ m_tickets[mdl_request->duration].push_front(ticket);
+
+ mdl_request->ticket= ticket;
+
+ return FALSE;
+}
+
+
+extern "C" int mdl_request_ptr_cmp(const void* ptr1, const void* ptr2)
+{
+ MDL_request *req1= *(MDL_request**)ptr1;
+ MDL_request *req2= *(MDL_request**)ptr2;
+ return req1->key.cmp(&req2->key);
+}
+
+
+/**
+ Acquire exclusive locks. There must be no granted locks in the
+ context.
+
+ This is a replacement of lock_table_names(). It is used in
+ RENAME, DROP and other DDL SQL statements.
+
+ @param mdl_requests List of requests for locks to be acquired.
+
+ @param lock_wait_timeout Seconds to wait before timeout.
+
+ @note The list of requests should not contain non-exclusive lock requests.
+ There should not be any acquired locks in the context.
+
+ @note Assumes that one already owns scoped intention exclusive lock.
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool MDL_context::acquire_locks(MDL_request_list *mdl_requests,
+ ulong lock_wait_timeout)
+{
+ MDL_request_list::Iterator it(*mdl_requests);
+ MDL_request **sort_buf, **p_req;
+ MDL_savepoint mdl_svp= mdl_savepoint();
+ ssize_t req_count= static_cast<ssize_t>(mdl_requests->elements());
+
+ if (req_count == 0)
+ return FALSE;
+
+ /* Sort requests according to MDL_key. */
+ if (! (sort_buf= (MDL_request **)my_malloc(req_count *
+ sizeof(MDL_request*),
+ MYF(MY_WME))))
+ return TRUE;
+
+ for (p_req= sort_buf; p_req < sort_buf + req_count; p_req++)
+ *p_req= it++;
+
+ my_qsort(sort_buf, req_count, sizeof(MDL_request*),
+ mdl_request_ptr_cmp);
+
+ for (p_req= sort_buf; p_req < sort_buf + req_count; p_req++)
+ {
+ if (acquire_lock(*p_req, lock_wait_timeout))
+ goto err;
+ }
+ my_free(sort_buf);
+ return FALSE;
+
+err:
+ /*
+ Release locks we have managed to acquire so far.
+ Use rollback_to_savepoint() since there may be duplicate
+ requests that got assigned the same ticket.
+ */
+ rollback_to_savepoint(mdl_svp);
+ /* Reset lock requests back to its initial state. */
+ for (req_count= p_req - sort_buf, p_req= sort_buf;
+ p_req < sort_buf + req_count; p_req++)
+ {
+ (*p_req)->ticket= NULL;
+ }
+ my_free(sort_buf);
+ return TRUE;
+}
+
+
+/**
+ Upgrade a shared metadata lock to exclusive.
+
+ Used in ALTER TABLE, when a copy of the table with the
+ new definition has been constructed.
+
+ @param lock_wait_timeout Seconds to wait before timeout.
+
+ @note In case of failure to upgrade lock (e.g. because upgrader
+ was killed) leaves lock in its original state (locked in
+ shared mode).
+
+ @note There can be only one upgrader for a lock or we will have deadlock.
+ This invariant is ensured by the fact that upgradeable locks SNW
+ and SNRW are not compatible with each other and themselves.
+
+ @retval FALSE Success
+ @retval TRUE Failure (thread was killed)
+*/
+
+bool
+MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket,
+ ulong lock_wait_timeout)
+{
+ MDL_request mdl_xlock_request;
+ MDL_savepoint mdl_svp= mdl_savepoint();
+ bool is_new_ticket;
+
+ DBUG_ENTER("MDL_ticket::upgrade_shared_lock_to_exclusive");
+ DEBUG_SYNC(get_thd(), "mdl_upgrade_shared_lock_to_exclusive");
+
+ /*
+ Do nothing if already upgraded. Used when we FLUSH TABLE under
+ LOCK TABLES and a table is listed twice in LOCK TABLES list.
+ */
+ if (mdl_ticket->m_type == MDL_EXCLUSIVE)
+ DBUG_RETURN(FALSE);
+
+ /* Only allow upgrades from MDL_SHARED_NO_WRITE/NO_READ_WRITE */
+ DBUG_ASSERT(mdl_ticket->m_type == MDL_SHARED_NO_WRITE ||
+ mdl_ticket->m_type == MDL_SHARED_NO_READ_WRITE);
+
+ mdl_xlock_request.init(&mdl_ticket->m_lock->key, MDL_EXCLUSIVE,
+ MDL_TRANSACTION);
+
+ if (acquire_lock(&mdl_xlock_request, lock_wait_timeout))
+ DBUG_RETURN(TRUE);
+
+ is_new_ticket= ! has_lock(mdl_svp, mdl_xlock_request.ticket);
+
+ /* Merge the acquired and the original lock. @todo: move to a method. */
+ mysql_prlock_wrlock(&mdl_ticket->m_lock->m_rwlock);
+ if (is_new_ticket)
+ mdl_ticket->m_lock->m_granted.remove_ticket(mdl_xlock_request.ticket);
+ /*
+ Set the new type of lock in the ticket. To update state of
+ MDL_lock object correctly we need to temporarily exclude
+ ticket from the granted queue and then include it back.
+ */
+ mdl_ticket->m_lock->m_granted.remove_ticket(mdl_ticket);
+ mdl_ticket->m_type= MDL_EXCLUSIVE;
+ mdl_ticket->m_lock->m_granted.add_ticket(mdl_ticket);
+
+ mysql_prlock_unlock(&mdl_ticket->m_lock->m_rwlock);
+
+ if (is_new_ticket)
+ {
+ m_tickets[MDL_TRANSACTION].remove(mdl_xlock_request.ticket);
+ MDL_ticket::destroy(mdl_xlock_request.ticket);
+ }
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ A fragment of recursive traversal of the wait-for graph
+ in search for deadlocks. Direct the deadlock visitor to all
+ contexts that own the lock the current node in the wait-for
+ graph is waiting for.
+ As long as the initial node is remembered in the visitor,
+ a deadlock is found when the same node is seen twice.
+*/
+
+bool MDL_lock::visit_subgraph(MDL_ticket *waiting_ticket,
+ MDL_wait_for_graph_visitor *gvisitor)
+{
+ MDL_ticket *ticket;
+ MDL_context *src_ctx= waiting_ticket->get_ctx();
+ bool result= TRUE;
+
+ mysql_prlock_rdlock(&m_rwlock);
+
+ /* Must be initialized after taking a read lock. */
+ Ticket_iterator granted_it(m_granted);
+ Ticket_iterator waiting_it(m_waiting);
+
+ /*
+ MDL_lock's waiting and granted queues and MDL_context::m_waiting_for
+ member are updated by different threads when the lock is granted
+ (see MDL_context::acquire_lock() and MDL_lock::reschedule_waiters()).
+ As a result, here we may encounter a situation when MDL_lock data
+ already reflects the fact that the lock was granted but
+ m_waiting_for member has not been updated yet.
+
+ For example, imagine that:
+
+ thread1: Owns SNW lock on table t1.
+ thread2: Attempts to acquire SW lock on t1,
+ but sees an active SNW lock.
+ Thus adds the ticket to the waiting queue and
+ sets m_waiting_for to point to the ticket.
+ thread1: Releases SNW lock, updates MDL_lock object to
+ grant SW lock to thread2 (moves the ticket for
+ SW from waiting to the active queue).
+ Attempts to acquire a new SNW lock on t1,
+ sees an active SW lock (since it is present in the
+ active queue), adds ticket for SNW lock to the waiting
+ queue, sets m_waiting_for to point to this ticket.
+
+ At this point deadlock detection algorithm run by thread1 will see that:
+ - Thread1 waits for SNW lock on t1 (since m_waiting_for is set).
+ - SNW lock is not granted, because it conflicts with active SW lock
+ owned by thread 2 (since ticket for SW is present in granted queue).
+ - Thread2 waits for SW lock (since its m_waiting_for has not been
+ updated yet!).
+ - SW lock is not granted because there is pending SNW lock from thread1.
+ Therefore deadlock should exist [sic!].
+
+ To avoid detection of such false deadlocks we need to check the "actual"
+ status of the ticket being waited for, before analyzing its blockers.
+ We do this by checking the wait status of the context which is waiting
+ for it. To avoid races this has to be done under protection of
+ MDL_lock::m_rwlock lock.
+ */
+ if (src_ctx->m_wait.get_status() != MDL_wait::EMPTY)
+ {
+ result= FALSE;
+ goto end;
+ }
+
+ /*
+ To avoid visiting nodes which were already marked as victims of
+ deadlock detection (or whose requests were already satisfied) we
+ enter the node only after peeking at its wait status.
+ This is necessary to avoid active waiting in a situation
+ when previous searches for a deadlock already selected the
+ node we're about to enter as a victim (see the comment
+ in MDL_context::find_deadlock() for explanation why several searches
+ can be performed for the same wait).
+ There is no guarantee that the node isn't chosen a victim while we
+ are visiting it but this is OK: in the worst case we might do some
+ extra work and one more context might be chosen as a victim.
+ */
+ if (gvisitor->enter_node(src_ctx))
+ goto end;
+
+ /*
+ We do a breadth-first search first -- that is, inspect all
+ edges of the current node, and only then follow up to the next
+ node. In workloads that involve wait-for graph loops this
+ has proven to be a more efficient strategy [citation missing].
+ */
+ while ((ticket= granted_it++))
+ {
+ /* Filter out edges that point to the same node. */
+ if (ticket->get_ctx() != src_ctx &&
+ ticket->is_incompatible_when_granted(waiting_ticket->get_type()) &&
+ gvisitor->inspect_edge(ticket->get_ctx()))
+ {
+ goto end_leave_node;
+ }
+ }
+
+ while ((ticket= waiting_it++))
+ {
+ /* Filter out edges that point to the same node. */
+ if (ticket->get_ctx() != src_ctx &&
+ ticket->is_incompatible_when_waiting(waiting_ticket->get_type()) &&
+ gvisitor->inspect_edge(ticket->get_ctx()))
+ {
+ goto end_leave_node;
+ }
+ }
+
+ /* Recurse and inspect all adjacent nodes. */
+ granted_it.rewind();
+ while ((ticket= granted_it++))
+ {
+ if (ticket->get_ctx() != src_ctx &&
+ ticket->is_incompatible_when_granted(waiting_ticket->get_type()) &&
+ ticket->get_ctx()->visit_subgraph(gvisitor))
+ {
+ goto end_leave_node;
+ }
+ }
+
+ waiting_it.rewind();
+ while ((ticket= waiting_it++))
+ {
+ if (ticket->get_ctx() != src_ctx &&
+ ticket->is_incompatible_when_waiting(waiting_ticket->get_type()) &&
+ ticket->get_ctx()->visit_subgraph(gvisitor))
+ {
+ goto end_leave_node;
+ }
+ }
+
+ result= FALSE;
+
+end_leave_node:
+ gvisitor->leave_node(src_ctx);
+
+end:
+ mysql_prlock_unlock(&m_rwlock);
+ return result;
+}
+
+
+/**
+ Traverse a portion of wait-for graph which is reachable
+ through the edge represented by this ticket and search
+ for deadlocks.
+
+ @retval TRUE A deadlock is found. A pointer to deadlock
+ victim is saved in the visitor.
+ @retval FALSE
+*/
+
+bool MDL_ticket::accept_visitor(MDL_wait_for_graph_visitor *gvisitor)
+{
+ return m_lock->visit_subgraph(this, gvisitor);
+}
+
+
+/**
+ A fragment of recursive traversal of the wait-for graph of
+ MDL contexts in the server in search for deadlocks.
+ Assume this MDL context is a node in the wait-for graph,
+ and direct the visitor to all adjacent nodes. As long
+ as the starting node is remembered in the visitor, a
+ deadlock is found when the same node is visited twice.
+ One MDL context is connected to another in the wait-for
+ graph if it waits on a resource that is held by the other
+ context.
+
+ @retval TRUE A deadlock is found. A pointer to deadlock
+ victim is saved in the visitor.
+ @retval FALSE
+*/
+
+bool MDL_context::visit_subgraph(MDL_wait_for_graph_visitor *gvisitor)
+{
+ bool result= FALSE;
+
+ mysql_prlock_rdlock(&m_LOCK_waiting_for);
+
+ if (m_waiting_for)
+ result= m_waiting_for->accept_visitor(gvisitor);
+
+ mysql_prlock_unlock(&m_LOCK_waiting_for);
+
+ return result;
+}
+
+
+/**
+ Try to find a deadlock. This function produces no errors.
+
+ @note If during deadlock resolution context which performs deadlock
+ detection is chosen as a victim it will be informed about the
+ fact by setting VICTIM status to its wait slot.
+
+ @retval TRUE A deadlock is found.
+ @retval FALSE No deadlock found.
+*/
+
+void MDL_context::find_deadlock()
+{
+ while (1)
+ {
+ /*
+ The fact that we use fresh instance of gvisitor for each
+ search performed by find_deadlock() below is important,
+ the code responsible for victim selection relies on this.
+ */
+ Deadlock_detection_visitor dvisitor(this);
+ MDL_context *victim;
+
+ if (! visit_subgraph(&dvisitor))
+ {
+ /* No deadlocks are found! */
+ break;
+ }
+
+ victim= dvisitor.get_victim();
+
+ /*
+ Failure to change status of the victim is OK as it means
+ that the victim has received some other message and is
+ about to stop its waiting/to break deadlock loop.
+ Even when the initiator of the deadlock search is
+ chosen the victim, we need to set the respective wait
+ result in order to "close" it for any attempt to
+ schedule the request.
+ This is needed to avoid a possible race during
+ cleanup in case when the lock request on which the
+ context was waiting is concurrently satisfied.
+ */
+ (void) victim->m_wait.set_status(MDL_wait::VICTIM);
+ victim->unlock_deadlock_victim();
+
+ if (victim == this)
+ break;
+ /*
+ After adding a new edge to the waiting graph we found that it
+ creates a loop (i.e. there is a deadlock). We decided to destroy
+ this loop by removing an edge, but not the one that we added.
+ Since this doesn't guarantee that all loops created by addition
+ of the new edge are destroyed, we have to repeat the search.
+ */
+ }
+}
+
+
+/**
+ Release lock.
+
+ @param duration Lock duration.
+ @param ticket Ticket for lock to be released.
+
+*/
+
+void MDL_context::release_lock(enum_mdl_duration duration, MDL_ticket *ticket)
+{
+ MDL_lock *lock= ticket->m_lock;
+ DBUG_ENTER("MDL_context::release_lock");
+ DBUG_PRINT("enter", ("db=%s name=%s", lock->key.db_name(),
+ lock->key.name()));
+
+ DBUG_ASSERT(this == ticket->get_ctx());
+ mysql_mutex_assert_not_owner(&LOCK_open);
+
+ lock->remove_ticket(&MDL_lock::m_granted, ticket);
+
+ m_tickets[duration].remove(ticket);
+ MDL_ticket::destroy(ticket);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Release lock with explicit duration.
+
+ @param ticket Ticket for lock to be released.
+
+*/
+
+void MDL_context::release_lock(MDL_ticket *ticket)
+{
+ DBUG_ASSERT(ticket->m_duration == MDL_EXPLICIT);
+
+ release_lock(MDL_EXPLICIT, ticket);
+}
+
+
+/**
+ Release all locks associated with the context. If the sentinel
+ is not NULL, do not release locks stored in the list after and
+ including the sentinel.
+
+ Statement and transactional locks are added to the beginning of
+ the corresponding lists, i.e. stored in reverse temporal order.
+ This allows to employ this function to:
+ - back off in case of a lock conflict.
+ - release all locks in the end of a statment or transaction
+ - rollback to a savepoint.
+*/
+
+void MDL_context::release_locks_stored_before(enum_mdl_duration duration,
+ MDL_ticket *sentinel)
+{
+ MDL_ticket *ticket;
+ Ticket_iterator it(m_tickets[duration]);
+ DBUG_ENTER("MDL_context::release_locks_stored_before");
+
+ if (m_tickets[duration].is_empty())
+ DBUG_VOID_RETURN;
+
+ while ((ticket= it++) && ticket != sentinel)
+ {
+ DBUG_PRINT("info", ("found lock to release ticket=%p", ticket));
+ release_lock(duration, ticket);
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Release all explicit locks in the context which correspond to the
+ same name/object as this lock request.
+
+ @param ticket One of the locks for the name/object for which all
+ locks should be released.
+*/
+
+void MDL_context::release_all_locks_for_name(MDL_ticket *name)
+{
+ /* Use MDL_ticket::m_lock to identify other locks for the same object. */
+ MDL_lock *lock= name->m_lock;
+
+ /* Remove matching lock tickets from the context. */
+ MDL_ticket *ticket;
+ Ticket_iterator it_ticket(m_tickets[MDL_EXPLICIT]);
+
+ while ((ticket= it_ticket++))
+ {
+ DBUG_ASSERT(ticket->m_lock);
+ if (ticket->m_lock == lock)
+ release_lock(MDL_EXPLICIT, ticket);
+ }
+}
+
+
+/**
+ Downgrade an exclusive lock to shared metadata lock.
+
+ @param type Type of lock to which exclusive lock should be downgraded.
+*/
+
+void MDL_ticket::downgrade_exclusive_lock(enum_mdl_type type)
+{
+ mysql_mutex_assert_not_owner(&LOCK_open);
+
+ /*
+ Do nothing if already downgraded. Used when we FLUSH TABLE under
+ LOCK TABLES and a table is listed twice in LOCK TABLES list.
+ */
+ if (m_type != MDL_EXCLUSIVE)
+ return;
+
+ mysql_prlock_wrlock(&m_lock->m_rwlock);
+ /*
+ To update state of MDL_lock object correctly we need to temporarily
+ exclude ticket from the granted queue and then include it back.
+ */
+ m_lock->m_granted.remove_ticket(this);
+ m_type= type;
+ m_lock->m_granted.add_ticket(this);
+ m_lock->reschedule_waiters();
+ mysql_prlock_unlock(&m_lock->m_rwlock);
+}
+
+
+/**
+ Auxiliary function which allows to check if we have some kind of lock on
+ a object. Returns TRUE if we have a lock of a given or stronger type.
+
+ @param mdl_namespace Id of object namespace
+ @param db Name of the database
+ @param name Name of the object
+ @param mdl_type Lock type. Pass in the weakest type to find
+ out if there is at least some lock.
+
+ @return TRUE if current context contains satisfied lock for the object,
+ FALSE otherwise.
+*/
+
+bool
+MDL_context::is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace,
+ const char *db, const char *name,
+ enum_mdl_type mdl_type)
+{
+ MDL_request mdl_request;
+ enum_mdl_duration not_unused;
+ /* We don't care about exact duration of lock here. */
+ mdl_request.init(mdl_namespace, db, name, mdl_type, MDL_TRANSACTION);
+ MDL_ticket *ticket= find_ticket(&mdl_request, &not_unused);
+
+ DBUG_ASSERT(ticket == NULL || ticket->m_lock);
+
+ return ticket;
+}
+
+
+/**
+ Check if we have any pending locks which conflict with existing shared lock.
+
+ @pre The ticket must match an acquired lock.
+
+ @return TRUE if there is a conflicting lock request, FALSE otherwise.
+*/
+
+bool MDL_ticket::has_pending_conflicting_lock() const
+{
+ return m_lock->has_pending_conflicting_lock(m_type);
+}
+
+
+/**
+ Releases metadata locks that were acquired after a specific savepoint.
+
+ @note Used to release tickets acquired during a savepoint unit.
+ @note It's safe to iterate and unlock any locks after taken after this
+ savepoint because other statements that take other special locks
+ cause a implicit commit (ie LOCK TABLES).
+*/
+
+void MDL_context::rollback_to_savepoint(const MDL_savepoint &mdl_savepoint)
+{
+ DBUG_ENTER("MDL_context::rollback_to_savepoint");
+
+ /* If savepoint is NULL, it is from the start of the transaction. */
+ release_locks_stored_before(MDL_STATEMENT, mdl_savepoint.m_stmt_ticket);
+ release_locks_stored_before(MDL_TRANSACTION, mdl_savepoint.m_trans_ticket);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Release locks acquired by normal statements (SELECT, UPDATE,
+ DELETE, etc) in the course of a transaction. Do not release
+ HANDLER locks, if there are any.
+
+ This method is used at the end of a transaction, in
+ implementation of COMMIT (implicit or explicit) and ROLLBACK.
+*/
+
+void MDL_context::release_transactional_locks()
+{
+ DBUG_ENTER("MDL_context::release_transactional_locks");
+ release_locks_stored_before(MDL_STATEMENT, NULL);
+ release_locks_stored_before(MDL_TRANSACTION, NULL);
+ DBUG_VOID_RETURN;
+}
+
+
+void MDL_context::release_statement_locks()
+{
+ DBUG_ENTER("MDL_context::release_transactional_locks");
+ release_locks_stored_before(MDL_STATEMENT, NULL);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Does this savepoint have this lock?
+
+ @retval TRUE The ticket is older than the savepoint or
+ is an LT, HA or GLR ticket. Thus it belongs
+ to the savepoint or has explicit duration.
+ @retval FALSE The ticket is newer than the savepoint.
+ and is not an LT, HA or GLR ticket.
+*/
+
+bool MDL_context::has_lock(const MDL_savepoint &mdl_savepoint,
+ MDL_ticket *mdl_ticket)
+{
+ MDL_ticket *ticket;
+ /* Start from the beginning, most likely mdl_ticket's been just acquired. */
+ MDL_context::Ticket_iterator s_it(m_tickets[MDL_STATEMENT]);
+ MDL_context::Ticket_iterator t_it(m_tickets[MDL_TRANSACTION]);
+
+ while ((ticket= s_it++) && ticket != mdl_savepoint.m_stmt_ticket)
+ {
+ if (ticket == mdl_ticket)
+ return FALSE;
+ }
+
+ while ((ticket= t_it++) && ticket != mdl_savepoint.m_trans_ticket)
+ {
+ if (ticket == mdl_ticket)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
+ Change lock duration for transactional lock.
+
+ @param ticket Ticket representing lock.
+ @param duration Lock duration to be set.
+
+ @note This method only supports changing duration of
+ transactional lock to some other duration.
+*/
+
+void MDL_context::set_lock_duration(MDL_ticket *mdl_ticket,
+ enum_mdl_duration duration)
+{
+ DBUG_ASSERT(mdl_ticket->m_duration == MDL_TRANSACTION &&
+ duration != MDL_TRANSACTION);
+
+ m_tickets[MDL_TRANSACTION].remove(mdl_ticket);
+ m_tickets[duration].push_front(mdl_ticket);
+#ifndef DBUG_OFF
+ mdl_ticket->m_duration= duration;
+#endif
+}
+
+
+/**
+ Set explicit duration for all locks in the context.
+*/
+
+void MDL_context::set_explicit_duration_for_all_locks()
+{
+ int i;
+ MDL_ticket *ticket;
+
+ /*
+ In the most common case when this function is called list
+ of transactional locks is bigger than list of locks with
+ explicit duration. So we start by swapping these two lists
+ and then move elements from new list of transactional
+ locks and list of statement locks to list of locks with
+ explicit duration.
+ */
+
+ m_tickets[MDL_EXPLICIT].swap(m_tickets[MDL_TRANSACTION]);
+
+ for (i= 0; i < MDL_EXPLICIT; i++)
+ {
+ Ticket_iterator it_ticket(m_tickets[i]);
+
+ while ((ticket= it_ticket++))
+ {
+ m_tickets[i].remove(ticket);
+ m_tickets[MDL_EXPLICIT].push_front(ticket);
+ }
+ }
+
+#ifndef DBUG_OFF
+ Ticket_iterator exp_it(m_tickets[MDL_EXPLICIT]);
+
+ while ((ticket= exp_it++))
+ ticket->m_duration= MDL_EXPLICIT;
+#endif
+}
+
+
+/**
+ Set transactional duration for all locks in the context.
+*/
+
+void MDL_context::set_transaction_duration_for_all_locks()
+{
+ MDL_ticket *ticket;
+
+ /*
+ In the most common case when this function is called list
+ of explicit locks is bigger than two other lists (in fact,
+ list of statement locks is always empty). So we start by
+ swapping list of explicit and transactional locks and then
+ move contents of new list of explicit locks to list of
+ locks with transactional duration.
+ */
+
+ DBUG_ASSERT(m_tickets[MDL_STATEMENT].is_empty());
+
+ m_tickets[MDL_TRANSACTION].swap(m_tickets[MDL_EXPLICIT]);
+
+ Ticket_iterator it_ticket(m_tickets[MDL_EXPLICIT]);
+
+ while ((ticket= it_ticket++))
+ {
+ m_tickets[MDL_EXPLICIT].remove(ticket);
+ m_tickets[MDL_TRANSACTION].push_front(ticket);
+ }
+
+#ifndef DBUG_OFF
+ Ticket_iterator trans_it(m_tickets[MDL_TRANSACTION]);
+
+ while ((ticket= trans_it++))
+ ticket->m_duration= MDL_TRANSACTION;
+#endif
+}
diff --git a/sql/mdl.h b/sql/mdl.h
new file mode 100644
index 00000000000..4a9397fe215
--- /dev/null
+++ b/sql/mdl.h
@@ -0,0 +1,856 @@
+#ifndef MDL_H
+#define MDL_H
+/* Copyright (C) 2007-2008 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#if defined(__IBMC__) || defined(__IBMCPP__)
+/* Further down, "next_in_lock" and "next_in_context" have the same type,
+ and in "sql_plist.h" this leads to an identical signature, which causes
+ problems in function overloading.
+*/
+#pragma namemangling(v5)
+#endif
+
+
+#include "sql_plist.h"
+#include <my_sys.h>
+#include <m_string.h>
+#include <mysql_com.h>
+
+class THD;
+
+class MDL_context;
+class MDL_lock;
+class MDL_ticket;
+
+/**
+ Type of metadata lock request.
+
+ @sa Comments for MDL_object_lock::can_grant_lock() and
+ MDL_scoped_lock::can_grant_lock() for details.
+*/
+
+enum enum_mdl_type {
+ /*
+ An intention exclusive metadata lock. Used only for scoped locks.
+ Owner of this type of lock can acquire upgradable exclusive locks on
+ individual objects.
+ Compatible with other IX locks, but is incompatible with scoped S and
+ X locks.
+ */
+ MDL_INTENTION_EXCLUSIVE= 0,
+ /*
+ A shared metadata lock.
+ To be used in cases when we are interested in object metadata only
+ and there is no intention to access object data (e.g. for stored
+ routines or during preparing prepared statements).
+ We also mis-use this type of lock for open HANDLERs, since lock
+ acquired by this statement has to be compatible with lock acquired
+ by LOCK TABLES ... WRITE statement, i.e. SNRW (We can't get by by
+ acquiring S lock at HANDLER ... OPEN time and upgrading it to SR
+ lock for HANDLER ... READ as it doesn't solve problem with need
+ to abort DML statements which wait on table level lock while having
+ open HANDLER in the same connection).
+ To avoid deadlock which may occur when SNRW lock is being upgraded to
+ X lock for table on which there is an active S lock which is owned by
+ thread which waits in its turn for table-level lock owned by thread
+ performing upgrade we have to use thr_abort_locks_for_thread()
+ facility in such situation.
+ This problem does not arise for locks on stored routines as we don't
+ use SNRW locks for them. It also does not arise when S locks are used
+ during PREPARE calls as table-level locks are not acquired in this
+ case.
+ */
+ MDL_SHARED,
+ /*
+ A high priority shared metadata lock.
+ Used for cases when there is no intention to access object data (i.e.
+ data in the table).
+ "High priority" means that, unlike other shared locks, it is granted
+ ignoring pending requests for exclusive locks. Intended for use in
+ cases when we only need to access metadata and not data, e.g. when
+ filling an INFORMATION_SCHEMA table.
+ Since SH lock is compatible with SNRW lock, the connection that
+ holds SH lock lock should not try to acquire any kind of table-level
+ or row-level lock, as this can lead to a deadlock. Moreover, after
+ acquiring SH lock, the connection should not wait for any other
+ resource, as it might cause starvation for X locks and a potential
+ deadlock during upgrade of SNW or SNRW to X lock (e.g. if the
+ upgrading connection holds the resource that is being waited for).
+ */
+ MDL_SHARED_HIGH_PRIO,
+ /*
+ A shared metadata lock for cases when there is an intention to read data
+ from table.
+ A connection holding this kind of lock can read table metadata and read
+ table data (after acquiring appropriate table and row-level locks).
+ This means that one can only acquire TL_READ, TL_READ_NO_INSERT, and
+ similar table-level locks on table if one holds SR MDL lock on it.
+ To be used for tables in SELECTs, subqueries, and LOCK TABLE ... READ
+ statements.
+ */
+ MDL_SHARED_READ,
+ /*
+ A shared metadata lock for cases when there is an intention to modify
+ (and not just read) data in the table.
+ A connection holding SW lock can read table metadata and modify or read
+ table data (after acquiring appropriate table and row-level locks).
+ To be used for tables to be modified by INSERT, UPDATE, DELETE
+ statements, but not LOCK TABLE ... WRITE or DDL). Also taken by
+ SELECT ... FOR UPDATE.
+ */
+ MDL_SHARED_WRITE,
+ /*
+ An upgradable shared metadata lock which blocks all attempts to update
+ table data, allowing reads.
+ A connection holding this kind of lock can read table metadata and read
+ table data.
+ Can be upgraded to X metadata lock.
+ Note, that since this type of lock is not compatible with SNRW or SW
+ lock types, acquiring appropriate engine-level locks for reading
+ (TL_READ* for MyISAM, shared row locks in InnoDB) should be
+ contention-free.
+ To be used for the first phase of ALTER TABLE, when copying data between
+ tables, to allow concurrent SELECTs from the table, but not UPDATEs.
+ */
+ MDL_SHARED_NO_WRITE,
+ /*
+ An upgradable shared metadata lock which allows other connections
+ to access table metadata, but not data.
+ It blocks all attempts to read or update table data, while allowing
+ INFORMATION_SCHEMA and SHOW queries.
+ A connection holding this kind of lock can read table metadata modify and
+ read table data.
+ Can be upgraded to X metadata lock.
+ To be used for LOCK TABLES WRITE statement.
+ Not compatible with any other lock type except S and SH.
+ */
+ MDL_SHARED_NO_READ_WRITE,
+ /*
+ An exclusive metadata lock.
+ A connection holding this lock can modify both table's metadata and data.
+ No other type of metadata lock can be granted while this lock is held.
+ To be used for CREATE/DROP/RENAME TABLE statements and for execution of
+ certain phases of other DDL statements.
+ */
+ MDL_EXCLUSIVE,
+ /* This should be the last !!! */
+ MDL_TYPE_END};
+
+
+/** Duration of metadata lock. */
+
+enum enum_mdl_duration { MDL_STATEMENT= 0,
+ MDL_TRANSACTION,
+ MDL_EXPLICIT,
+ /* This should be the last ! */
+ MDL_DURATION_END };
+
+
+/** Maximal length of key for metadata locking subsystem. */
+#define MAX_MDLKEY_LENGTH (1 + NAME_LEN + 1 + NAME_LEN + 1)
+
+
+/**
+ Metadata lock object key.
+
+ A lock is requested or granted based on a fully qualified name and type.
+ E.g. They key for a table consists of <0 (=table)>+<database>+<table name>.
+ Elsewhere in the comments this triple will be referred to simply as "key"
+ or "name".
+*/
+
+class MDL_key
+{
+public:
+ /**
+ Object namespaces.
+ Sic: when adding a new member to this enum make sure to
+ update m_namespace_to_wait_state_name array in mdl.cc!
+
+ Different types of objects exist in different namespaces
+ - TABLE is for tables and views.
+ - FUNCTION is for stored functions.
+ - PROCEDURE is for stored procedures.
+ - TRIGGER is for triggers.
+ - EVENT is for event scheduler events
+ Note that although there isn't metadata locking on triggers,
+ it's necessary to have a separate namespace for them since
+ MDL_key is also used outside of the MDL subsystem.
+ */
+ enum enum_mdl_namespace { GLOBAL=0,
+ SCHEMA,
+ TABLE,
+ FUNCTION,
+ PROCEDURE,
+ TRIGGER,
+ EVENT,
+ COMMIT,
+ /* This should be the last ! */
+ NAMESPACE_END };
+
+ const uchar *ptr() const { return (uchar*) m_ptr; }
+ uint length() const { return m_length; }
+
+ const char *db_name() const { return m_ptr + 1; }
+ uint db_name_length() const { return m_db_name_length; }
+
+ const char *name() const { return m_ptr + m_db_name_length + 2; }
+ uint name_length() const { return m_length - m_db_name_length - 3; }
+
+ enum_mdl_namespace mdl_namespace() const
+ { return (enum_mdl_namespace)(m_ptr[0]); }
+
+ /**
+ Construct a metadata lock key from a triplet (mdl_namespace,
+ database and name).
+
+ @remark The key for a table is <mdl_namespace>+<database name>+<table name>
+
+ @param mdl_namespace Id of namespace of object to be locked
+ @param db Name of database to which the object belongs
+ @param name Name of of the object
+ @param key Where to store the the MDL key.
+ */
+ void mdl_key_init(enum_mdl_namespace mdl_namespace,
+ const char *db, const char *name)
+ {
+ m_ptr[0]= (char) mdl_namespace;
+ m_db_name_length= (uint16) (strmov(m_ptr + 1, db) - m_ptr - 1);
+ m_length= (uint16) (strmov(m_ptr + m_db_name_length + 2, name) - m_ptr + 1);
+ }
+ void mdl_key_init(const MDL_key *rhs)
+ {
+ memcpy(m_ptr, rhs->m_ptr, rhs->m_length);
+ m_length= rhs->m_length;
+ m_db_name_length= rhs->m_db_name_length;
+ }
+ bool is_equal(const MDL_key *rhs) const
+ {
+ return (m_length == rhs->m_length &&
+ memcmp(m_ptr, rhs->m_ptr, m_length) == 0);
+ }
+ /**
+ Compare two MDL keys lexicographically.
+ */
+ int cmp(const MDL_key *rhs) const
+ {
+ /*
+ The key buffer is always '\0'-terminated. Since key
+ character set is utf-8, we can safely assume that no
+ character starts with a zero byte.
+ */
+ return memcmp(m_ptr, rhs->m_ptr, min(m_length, rhs->m_length));
+ }
+
+ MDL_key(const MDL_key *rhs)
+ {
+ mdl_key_init(rhs);
+ }
+ MDL_key(enum_mdl_namespace namespace_arg,
+ const char *db_arg, const char *name_arg)
+ {
+ mdl_key_init(namespace_arg, db_arg, name_arg);
+ }
+ MDL_key() {} /* To use when part of MDL_request. */
+
+ /**
+ Get thread state name to be used in case when we have to
+ wait on resource identified by key.
+ */
+ const char * get_wait_state_name() const
+ {
+ return m_namespace_to_wait_state_name[(int)mdl_namespace()];
+ }
+
+private:
+ uint16 m_length;
+ uint16 m_db_name_length;
+ char m_ptr[MAX_MDLKEY_LENGTH];
+ static const char * m_namespace_to_wait_state_name[NAMESPACE_END];
+private:
+ MDL_key(const MDL_key &); /* not implemented */
+ MDL_key &operator=(const MDL_key &); /* not implemented */
+};
+
+
+
+/**
+ Hook class which via its methods specifies which members
+ of T should be used for participating in MDL lists.
+*/
+
+template <typename T, T* T::*next, T** T::*prev>
+struct I_P_List_adapter
+{
+ static inline T **next_ptr(T *el) { return &(el->*next); }
+
+ static inline T ***prev_ptr(T *el) { return &(el->*prev); }
+};
+
+
+/**
+ A pending metadata lock request.
+
+ A lock request and a granted metadata lock are represented by
+ different classes because they have different allocation
+ sites and hence different lifetimes. The allocation of lock requests is
+ controlled from outside of the MDL subsystem, while allocation of granted
+ locks (tickets) is controlled within the MDL subsystem.
+
+ MDL_request is a C structure, you don't need to call a constructor
+ or destructor for it.
+*/
+
+class MDL_request
+{
+public:
+ /** Type of metadata lock. */
+ enum enum_mdl_type type;
+ /** Duration for requested lock. */
+ enum enum_mdl_duration duration;
+
+ /**
+ Pointers for participating in the list of lock requests for this context.
+ */
+ MDL_request *next_in_list;
+ MDL_request **prev_in_list;
+ /**
+ Pointer to the lock ticket object for this lock request.
+ Valid only if this lock request is satisfied.
+ */
+ MDL_ticket *ticket;
+
+ /** A lock is requested based on a fully qualified name and type. */
+ MDL_key key;
+
+public:
+ static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
+ { return alloc_root(mem_root, size); }
+ static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
+
+ void init(MDL_key::enum_mdl_namespace namespace_arg,
+ const char *db_arg, const char *name_arg,
+ enum_mdl_type mdl_type_arg,
+ enum_mdl_duration mdl_duration_arg);
+ void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg,
+ enum_mdl_duration mdl_duration_arg);
+ /** Set type of lock request. Can be only applied to pending locks. */
+ inline void set_type(enum_mdl_type type_arg)
+ {
+ DBUG_ASSERT(ticket == NULL);
+ type= type_arg;
+ }
+
+ /*
+ This is to work around the ugliness of TABLE_LIST
+ compiler-generated assignment operator. It is currently used
+ in several places to quickly copy "most" of the members of the
+ table list. These places currently never assume that the mdl
+ request is carried over to the new TABLE_LIST, or shared
+ between lists.
+
+ This method does not initialize the instance being assigned!
+ Use of init() for initialization after this assignment operator
+ is mandatory. Can only be used before the request has been
+ granted.
+ */
+ MDL_request& operator=(const MDL_request &rhs)
+ {
+ ticket= NULL;
+ /* Do nothing, in particular, don't try to copy the key. */
+ return *this;
+ }
+ /* Another piece of ugliness for TABLE_LIST constructor */
+ MDL_request() {}
+
+ MDL_request(const MDL_request *rhs)
+ :type(rhs->type),
+ duration(rhs->duration),
+ ticket(NULL),
+ key(&rhs->key)
+ {}
+};
+
+
+typedef void (*mdl_cached_object_release_hook)(void *);
+
+
+/**
+ An abstract class for inspection of a connected
+ subgraph of the wait-for graph.
+*/
+
+class MDL_wait_for_graph_visitor
+{
+public:
+ virtual bool enter_node(MDL_context *node) = 0;
+ virtual void leave_node(MDL_context *node) = 0;
+
+ virtual bool inspect_edge(MDL_context *dest) = 0;
+ virtual ~MDL_wait_for_graph_visitor();
+ MDL_wait_for_graph_visitor() :m_lock_open_count(0) {}
+public:
+ /**
+ XXX, hack: During deadlock search, we may need to
+ inspect TABLE_SHAREs and acquire LOCK_open. Since
+ LOCK_open is not a recursive mutex, count here how many
+ times we "took" it (but only take and release once).
+ Not using a native recursive mutex or rwlock in 5.5 for
+ LOCK_open since it has significant performance impacts.
+ */
+ uint m_lock_open_count;
+};
+
+/**
+ Abstract class representing an edge in the waiters graph
+ to be traversed by deadlock detection algorithm.
+*/
+
+class MDL_wait_for_subgraph
+{
+public:
+ virtual ~MDL_wait_for_subgraph();
+
+ /**
+ Accept a wait-for graph visitor to inspect the node
+ this edge is leading to.
+ */
+ virtual bool accept_visitor(MDL_wait_for_graph_visitor *gvisitor) = 0;
+
+ enum enum_deadlock_weight
+ {
+ DEADLOCK_WEIGHT_DML= 0,
+ DEADLOCK_WEIGHT_DDL= 100
+ };
+ /* A helper used to determine which lock request should be aborted. */
+ virtual uint get_deadlock_weight() const = 0;
+};
+
+
+/**
+ A granted metadata lock.
+
+ @warning MDL_ticket members are private to the MDL subsystem.
+
+ @note Multiple shared locks on a same object are represented by a
+ single ticket. The same does not apply for other lock types.
+
+ @note There are two groups of MDL_ticket members:
+ - "Externally accessible". These members can be accessed from
+ threads/contexts different than ticket owner in cases when
+ ticket participates in some list of granted or waiting tickets
+ for a lock. Therefore one should change these members before
+ including then to waiting/granted lists or while holding lock
+ protecting those lists.
+ - "Context private". Such members are private to thread/context
+ owning this ticket. I.e. they should not be accessed from other
+ threads/contexts.
+*/
+
+class MDL_ticket : public MDL_wait_for_subgraph
+{
+public:
+ /**
+ Pointers for participating in the list of lock requests for this context.
+ Context private.
+ */
+ MDL_ticket *next_in_context;
+ MDL_ticket **prev_in_context;
+ /**
+ Pointers for participating in the list of satisfied/pending requests
+ for the lock. Externally accessible.
+ */
+ MDL_ticket *next_in_lock;
+ MDL_ticket **prev_in_lock;
+public:
+ bool has_pending_conflicting_lock() const;
+
+ MDL_context *get_ctx() const { return m_ctx; }
+ bool is_upgradable_or_exclusive() const
+ {
+ return m_type == MDL_SHARED_NO_WRITE ||
+ m_type == MDL_SHARED_NO_READ_WRITE ||
+ m_type == MDL_EXCLUSIVE;
+ }
+ enum_mdl_type get_type() const { return m_type; }
+ MDL_lock *get_lock() const { return m_lock; }
+ void downgrade_exclusive_lock(enum_mdl_type type);
+
+ bool has_stronger_or_equal_type(enum_mdl_type type) const;
+
+ bool is_incompatible_when_granted(enum_mdl_type type) const;
+ bool is_incompatible_when_waiting(enum_mdl_type type) const;
+
+ /** Implement MDL_wait_for_subgraph interface. */
+ virtual bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor);
+ virtual uint get_deadlock_weight() const;
+private:
+ friend class MDL_context;
+
+ MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg
+#ifndef DBUG_OFF
+ , enum_mdl_duration duration_arg
+#endif
+ )
+ : m_type(type_arg),
+#ifndef DBUG_OFF
+ m_duration(duration_arg),
+#endif
+ m_ctx(ctx_arg),
+ m_lock(NULL)
+ {}
+
+ static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg
+#ifndef DBUG_OFF
+ , enum_mdl_duration duration_arg
+#endif
+ );
+ static void destroy(MDL_ticket *ticket);
+private:
+ /** Type of metadata lock. Externally accessible. */
+ enum enum_mdl_type m_type;
+#ifndef DBUG_OFF
+ /**
+ Duration of lock represented by this ticket.
+ Context private. Debug-only.
+ */
+ enum_mdl_duration m_duration;
+#endif
+ /**
+ Context of the owner of the metadata lock ticket. Externally accessible.
+ */
+ MDL_context *m_ctx;
+
+ /**
+ Pointer to the lock object for this lock ticket. Externally accessible.
+ */
+ MDL_lock *m_lock;
+
+private:
+ MDL_ticket(const MDL_ticket &); /* not implemented */
+ MDL_ticket &operator=(const MDL_ticket &); /* not implemented */
+};
+
+
+/**
+ Savepoint for MDL context.
+
+ Doesn't include metadata locks with explicit duration as
+ they are not released during rollback to savepoint.
+*/
+
+class MDL_savepoint
+{
+public:
+ MDL_savepoint() {};
+
+private:
+ MDL_savepoint(MDL_ticket *stmt_ticket, MDL_ticket *trans_ticket)
+ : m_stmt_ticket(stmt_ticket), m_trans_ticket(trans_ticket)
+ {}
+
+ friend class MDL_context;
+
+private:
+ /**
+ Pointer to last lock with statement duration which was taken
+ before creation of savepoint.
+ */
+ MDL_ticket *m_stmt_ticket;
+ /**
+ Pointer to last lock with transaction duration which was taken
+ before creation of savepoint.
+ */
+ MDL_ticket *m_trans_ticket;
+};
+
+
+/**
+ A reliable way to wait on an MDL lock.
+*/
+
+class MDL_wait
+{
+public:
+ MDL_wait();
+ ~MDL_wait();
+
+ enum enum_wait_status { EMPTY = 0, GRANTED, VICTIM, TIMEOUT, KILLED };
+
+ bool set_status(enum_wait_status result_arg);
+ enum_wait_status get_status();
+ void reset_status();
+ enum_wait_status timed_wait(THD *thd, struct timespec *abs_timeout,
+ bool signal_timeout, const char *wait_state_name);
+private:
+ /**
+ Condvar which is used for waiting until this context's pending
+ request can be satisfied or this thread has to perform actions
+ to resolve a potential deadlock (we subscribe to such
+ notification by adding a ticket corresponding to the request
+ to an appropriate queue of waiters).
+ */
+ mysql_mutex_t m_LOCK_wait_status;
+ mysql_cond_t m_COND_wait_status;
+ enum_wait_status m_wait_status;
+};
+
+
+typedef I_P_List<MDL_request, I_P_List_adapter<MDL_request,
+ &MDL_request::next_in_list,
+ &MDL_request::prev_in_list>,
+ I_P_List_counter>
+ MDL_request_list;
+
+/**
+ Context of the owner of metadata locks. I.e. each server
+ connection has such a context.
+*/
+
+class MDL_context
+{
+public:
+ typedef I_P_List<MDL_ticket,
+ I_P_List_adapter<MDL_ticket,
+ &MDL_ticket::next_in_context,
+ &MDL_ticket::prev_in_context> >
+ Ticket_list;
+
+ typedef Ticket_list::Iterator Ticket_iterator;
+
+ MDL_context();
+ void destroy();
+
+ bool try_acquire_lock(MDL_request *mdl_request);
+ bool acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout);
+ bool acquire_locks(MDL_request_list *requests, ulong lock_wait_timeout);
+ bool upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket,
+ ulong lock_wait_timeout);
+
+ bool clone_ticket(MDL_request *mdl_request);
+
+ void release_all_locks_for_name(MDL_ticket *ticket);
+ void release_lock(MDL_ticket *ticket);
+
+ bool is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace,
+ const char *db, const char *name,
+ enum_mdl_type mdl_type);
+
+ bool has_lock(const MDL_savepoint &mdl_savepoint, MDL_ticket *mdl_ticket);
+
+ inline bool has_locks() const
+ {
+ return !(m_tickets[MDL_STATEMENT].is_empty() &&
+ m_tickets[MDL_TRANSACTION].is_empty() &&
+ m_tickets[MDL_EXPLICIT].is_empty());
+ }
+
+ MDL_savepoint mdl_savepoint()
+ {
+ return MDL_savepoint(m_tickets[MDL_STATEMENT].front(),
+ m_tickets[MDL_TRANSACTION].front());
+ }
+
+ void set_explicit_duration_for_all_locks();
+ void set_transaction_duration_for_all_locks();
+ void set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration);
+
+ void release_statement_locks();
+ void release_transactional_locks();
+ void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint);
+
+ inline THD *get_thd() const { return m_thd; }
+
+ /** @pre Only valid if we started waiting for lock. */
+ inline uint get_deadlock_weight() const
+ { return m_waiting_for->get_deadlock_weight(); }
+ /**
+ Post signal to the context (and wake it up if necessary).
+
+ @retval FALSE - Success, signal was posted.
+ @retval TRUE - Failure, signal was not posted since context
+ already has received some signal or closed
+ signal slot.
+ */
+ void init(THD *thd_arg) { m_thd= thd_arg; }
+
+ void set_needs_thr_lock_abort(bool needs_thr_lock_abort)
+ {
+ /*
+ @note In theory, this member should be modified under protection
+ of some lock since it can be accessed from different threads.
+ In practice, this is not necessary as code which reads this
+ value and so might miss the fact that value was changed will
+ always re-try reading it after small timeout and therefore
+ will see the new value eventually.
+ */
+ m_needs_thr_lock_abort= needs_thr_lock_abort;
+ }
+ bool get_needs_thr_lock_abort() const
+ {
+ return m_needs_thr_lock_abort;
+ }
+public:
+ /**
+ If our request for a lock is scheduled, or aborted by the deadlock
+ detector, the result is recorded in this class.
+ */
+ MDL_wait m_wait;
+private:
+ /**
+ Lists of all MDL tickets acquired by this connection.
+
+ Lists of MDL tickets:
+ ---------------------
+ The entire set of locks acquired by a connection can be separated
+ in three subsets according to their: locks released at the end of
+ statement, at the end of transaction and locks are released
+ explicitly.
+
+ Statement and transactional locks are locks with automatic scope.
+ They are accumulated in the course of a transaction, and released
+ either at the end of uppermost statement (for statement locks) or
+ on COMMIT, ROLLBACK or ROLLBACK TO SAVEPOINT (for transactional
+ locks). They must not be (and never are) released manually,
+ i.e. with release_lock() call.
+
+ Locks with explicit duration are taken for locks that span
+ multiple transactions or savepoints.
+ These are: HANDLER SQL locks (HANDLER SQL is
+ transaction-agnostic), LOCK TABLES locks (you can COMMIT/etc
+ under LOCK TABLES, and the locked tables stay locked), and
+ locks implementing "global read lock".
+
+ Statement/transactional locks are always prepended to the
+ beginning of the appropriate list. In other words, they are
+ stored in reverse temporal order. Thus, when we rollback to
+ a savepoint, we start popping and releasing tickets from the
+ front until we reach the last ticket acquired after the savepoint.
+
+ Locks with explicit duration stored are not stored in any
+ particular order, and among each other can be split into
+ three sets:
+
+ [LOCK TABLES locks] [HANDLER locks] [GLOBAL READ LOCK locks]
+
+ The following is known about these sets:
+
+ * GLOBAL READ LOCK locks are always stored after LOCK TABLES
+ locks and after HANDLER locks. This is because one can't say
+ SET GLOBAL read_only=1 or FLUSH TABLES WITH READ LOCK
+ if one has locked tables. One can, however, LOCK TABLES
+ after having entered the read only mode. Note, that
+ subsequent LOCK TABLES statement will unlock the previous
+ set of tables, but not the GRL!
+ There are no HANDLER locks after GRL locks because
+ SET GLOBAL read_only performs a FLUSH TABLES WITH
+ READ LOCK internally, and FLUSH TABLES, in turn, implicitly
+ closes all open HANDLERs.
+ However, one can open a few HANDLERs after entering the
+ read only mode.
+ * LOCK TABLES locks include intention exclusive locks on
+ involved schemas and global intention exclusive lock.
+ */
+ Ticket_list m_tickets[MDL_DURATION_END];
+ THD *m_thd;
+ /**
+ TRUE - if for this context we will break protocol and try to
+ acquire table-level locks while having only S lock on
+ some table.
+ To avoid deadlocks which might occur during concurrent
+ upgrade of SNRW lock on such object to X lock we have to
+ abort waits for table-level locks for such connections.
+ FALSE - Otherwise.
+ */
+ bool m_needs_thr_lock_abort;
+
+ /**
+ Read-write lock protecting m_waiting_for member.
+
+ @note The fact that this read-write lock prefers readers is
+ important as deadlock detector won't work correctly
+ otherwise. @sa Comment for MDL_lock::m_rwlock.
+ */
+ mysql_prlock_t m_LOCK_waiting_for;
+ /**
+ Tell the deadlock detector what metadata lock or table
+ definition cache entry this session is waiting for.
+ In principle, this is redundant, as information can be found
+ by inspecting waiting queues, but we'd very much like it to be
+ readily available to the wait-for graph iterator.
+ */
+ MDL_wait_for_subgraph *m_waiting_for;
+private:
+ MDL_ticket *find_ticket(MDL_request *mdl_req,
+ enum_mdl_duration *duration);
+ void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel);
+ void release_lock(enum_mdl_duration duration, MDL_ticket *ticket);
+ bool try_acquire_lock_impl(MDL_request *mdl_request,
+ MDL_ticket **out_ticket);
+
+public:
+ void find_deadlock();
+
+ bool visit_subgraph(MDL_wait_for_graph_visitor *dvisitor);
+
+ /** Inform the deadlock detector there is an edge in the wait-for graph. */
+ void will_wait_for(MDL_wait_for_subgraph *waiting_for_arg)
+ {
+ mysql_prlock_wrlock(&m_LOCK_waiting_for);
+ m_waiting_for= waiting_for_arg;
+ mysql_prlock_unlock(&m_LOCK_waiting_for);
+ }
+
+ /** Remove the wait-for edge from the graph after we're done waiting. */
+ void done_waiting_for()
+ {
+ mysql_prlock_wrlock(&m_LOCK_waiting_for);
+ m_waiting_for= NULL;
+ mysql_prlock_unlock(&m_LOCK_waiting_for);
+ }
+ void lock_deadlock_victim()
+ {
+ mysql_prlock_rdlock(&m_LOCK_waiting_for);
+ }
+ void unlock_deadlock_victim()
+ {
+ mysql_prlock_unlock(&m_LOCK_waiting_for);
+ }
+private:
+ MDL_context(const MDL_context &rhs); /* not implemented */
+ MDL_context &operator=(MDL_context &rhs); /* not implemented */
+};
+
+
+void mdl_init();
+void mdl_destroy();
+
+
+/*
+ Functions in the server's kernel used by metadata locking subsystem.
+*/
+
+extern bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
+ bool needs_thr_lock_abort);
+extern "C" const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond,
+ mysql_mutex_t *mutex, const char *msg);
+extern "C" void thd_exit_cond(MYSQL_THD thd, const char *old_msg);
+
+#ifndef DBUG_OFF
+extern mysql_mutex_t LOCK_open;
+#endif
+
+#endif
diff --git a/sql/message.h b/sql/message.h
index 0e7c282d5a1..97d039352b4 100644
--- a/sql/message.h
+++ b/sql/message.h
@@ -1,3 +1,6 @@
+#ifndef MESSAGE_INCLUDED
+#define MESSAGE_INCLUDED
+
/*
To change or add messages mysqld writes to the Windows error log, run
mc.exe message.mc
@@ -6,6 +9,8 @@
mc.exe can be installed with Windows SDK, some Visual Studio distributions
do not include it.
*/
+
+
//
// Values are 32 bit values layed out as follows:
//
@@ -53,3 +58,5 @@
//
#define MSG_DEFAULT 0xC0000064L
+#endif /* MESSAGE_INCLUDED */
+
diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc
index 8c2d16c40b0..d20d93ff0b9 100644
--- a/sql/mf_iocache.cc
+++ b/sql/mf_iocache.cc
@@ -32,7 +32,8 @@
flush_io_cache().
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_class.h" // THD
#ifdef HAVE_REPLICATION
extern "C" {
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index 3aa01880b83..8a31cec6721 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -13,9 +13,12 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
#include <time.h>
+#ifndef MYSQL_CLIENT
+#include "sql_class.h" // THD
+#endif
#ifndef MYSQL_CLIENT
/**
@@ -41,17 +44,17 @@ int decimal_operation_results(int result)
"", (long)-1);
break;
case E_DEC_OVERFLOW:
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
"DECIMAL", "");
break;
case E_DEC_DIV_ZERO:
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO));
break;
case E_DEC_BAD_NUM:
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
"decimal", "", "", (long)-1);
@@ -110,10 +113,63 @@ int my_decimal2string(uint mask, const my_decimal *d,
&length, (int)fixed_prec, fixed_dec,
filler);
str->length(length);
+ str->set_charset(&my_charset_numeric);
return check_result(mask, result);
}
+/**
+ @brief Converting decimal to string with character set conversion
+
+ @details Convert given my_decimal to String; allocate buffer as needed.
+
+ @param[in] mask what problems to warn on (mask of E_DEC_* values)
+ @param[in] val the decimal to print
+ @param[in] fixed_prec overall number of digits if ZEROFILL, 0 otherwise
+ @param[in] fixed_dec number of decimal places (if fixed_prec != 0)
+ @param[in] filler what char to pad with (ZEROFILL et al.)
+ @param[out] *str where to store the resulting string
+ @param[in] cs character set
+
+ @return error coce
+ @retval E_DEC_OK
+ @retval E_DEC_TRUNCATED
+ @retval E_DEC_OVERFLOW
+ @retval E_DEC_OOM
+
+ Would be great to make it a method of the String class,
+ but this would need to include
+ my_decimal.h from sql_string.h and sql_string.cc, which is not desirable.
+*/
+bool
+str_set_decimal(uint mask, const my_decimal *val,
+ uint fixed_prec, uint fixed_dec, char filler,
+ String *str, CHARSET_INFO *cs)
+{
+ if (!(cs->state & MY_CS_NONASCII))
+ {
+ /* For ASCII-compatible character sets we can use my_decimal2string */
+ my_decimal2string(mask, val, fixed_prec, fixed_dec, filler, str);
+ str->set_charset(cs);
+ return FALSE;
+ }
+ else
+ {
+ /*
+ For ASCII-incompatible character sets (like UCS2) we
+ call my_decimal2string() on a temporary buffer first,
+ and then convert the result to the target character
+ with help of str->copy().
+ */
+ uint errors;
+ char buf[DECIMAL_MAX_STR_LENGTH];
+ String tmp(buf, sizeof(buf), &my_charset_latin1);
+ my_decimal2string(mask, val, fixed_prec, fixed_dec, filler, &tmp);
+ return str->copy(tmp.ptr(), tmp.length(), &my_charset_latin1, cs, &errors);
+ }
+}
+
+
/*
Convert from decimal to binary representation
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index a5077f397e3..e5b1573608a 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -28,10 +28,17 @@
#ifndef my_decimal_h
#define my_decimal_h
+#if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
+#include "sql_string.h" /* String */
+#endif
+
C_MODE_START
#include <decimal.h>
C_MODE_END
+class String;
+typedef struct st_mysql_time MYSQL_TIME;
+
#define DECIMAL_LONGLONG_DIGITS 22
#define DECIMAL_LONG_DIGITS 10
#define DECIMAL_LONG3_DIGITS 8
@@ -133,6 +140,12 @@ const char *dbug_decimal_as_string(char *buff, const my_decimal *val);
#define dbug_decimal_as_string(A) NULL
#endif
+bool str_set_decimal(uint mask, const my_decimal *val, uint fixed_prec,
+ uint fixed_dec, char filler, String *str,
+ CHARSET_INFO *cs);
+
+extern my_decimal decimal_zero;
+
#ifndef MYSQL_CLIENT
int decimal_operation_results(int result);
#else
@@ -289,7 +302,14 @@ int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
}
+inline bool str_set_decimal(const my_decimal *val, String *str,
+ CHARSET_INFO *cs)
+{
+ return str_set_decimal(E_DEC_FATAL_ERROR, val, 0, 0, 0, str, cs);
+}
+
#ifndef MYSQL_CLIENT
+class String;
int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
uint fixed_dec, char filler, String *str);
#endif
diff --git a/sql/my_lock.c b/sql/my_lock.c
deleted file mode 100644
index f66d7282f72..00000000000
--- a/sql/my_lock.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Copyright (C) 2000-2003 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#if defined(__NETWARE__)
-#include "../mysys/my_lock.c"
-#else
-
-#undef MAP_TO_USE_RAID /* Avoid RAID mappings */
-#include <my_global.h>
-#include <my_sys.h>
-#include <mysys_err.h>
-#include <my_pthread.h>
-#include <thr_alarm.h>
-#include <errno.h>
-
- /* Lock a part of a file */
-
-int my_lock(File fd,int locktype,my_off_t start,my_off_t length,myf MyFlags)
-{
- thr_alarm_t alarmed;
- ALARM alarm_buff;
- uint wait_for_alarm;
- struct flock m_lock;
- DBUG_ENTER("my_lock");
- DBUG_PRINT("my",("Fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
- fd,locktype,(ulong) start,(ulong) length,MyFlags));
- if (my_disable_locking)
- DBUG_RETURN(0); /* purecov: inspected */
- m_lock.l_type=(short) locktype;
- m_lock.l_whence=0L;
- m_lock.l_start=(long) start;
- m_lock.l_len=(long) length;
- wait_for_alarm=(MyFlags & MY_DONT_WAIT ? MY_HOW_OFTEN_TO_ALARM :
- (uint) 12*60*60);
- if (fcntl(fd,F_SETLK,&m_lock) != -1) /* Check if we can lock */
- DBUG_RETURN(0); /* Ok, file locked */
- DBUG_PRINT("info",("Was locked, trying with alarm"));
- if (!thr_alarm(&alarmed,wait_for_alarm,&alarm_buff))
- {
- int value;
- while ((value=fcntl(fd,F_SETLKW,&m_lock)) && !thr_got_alarm(&alarmed) &&
- errno == EINTR) ;
- thr_end_alarm(&alarmed);
- if (value != -1)
- DBUG_RETURN(0);
- }
- else
- {
- errno=EINTR;
- }
- if (errno == EINTR || errno == EACCES)
- my_errno=EAGAIN; /* Easier to check for this */
- else
- my_errno=errno;
-
- if (MyFlags & MY_WME)
- {
- if (locktype == F_UNLCK)
- my_error(EE_CANTUNLOCK,MYF(ME_BELL+ME_WAITTANG),errno);
- else
- my_error(EE_CANTLOCK,MYF(ME_BELL+ME_WAITTANG),errno);
- }
- DBUG_PRINT("error",("errno: %d",errno));
- DBUG_RETURN(-1);
-}
-#endif
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
deleted file mode 100644
index 526133c20c6..00000000000
--- a/sql/mysql_priv.h
+++ /dev/null
@@ -1,2519 +0,0 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
-
- 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/**
- @file
-
- @details
- Mostly this file is used in the server. But a little part of it is used in
- mysqlbinlog too (definition of SELECT_DISTINCT and others).
- The consequence is that 90% of the file is wrapped in \#ifndef MYSQL_CLIENT,
- except the part which must be in the server and in the client.
-*/
-
-#ifndef MYSQL_PRIV_H
-#define MYSQL_PRIV_H
-
-#ifndef MYSQL_CLIENT
-
-#include <my_global.h>
-#include <mysql_version.h>
-#include <mysql_embed.h>
-#include <my_sys.h>
-#include <my_time.h>
-#include <m_string.h>
-#include <hash.h>
-#include <signal.h>
-#include <thr_lock.h>
-#include <my_base.h> /* Needed by field.h */
-#include <queues.h>
-#include "sql_bitmap.h"
-#include "sql_array.h"
-#include "sql_plugin.h"
-#include "scheduler.h"
-
-class Parser_state;
-
-/**
- Query type constants.
-
- QT_ORDINARY -- ordinary SQL query.
- QT_IS -- SQL query to be shown in INFORMATION_SCHEMA (in utf8 and without
- character set introducers).
-*/
-enum enum_query_type
-{
- QT_ORDINARY,
- QT_IS
-};
-
-/* TODO convert all these three maps to Bitmap classes */
-typedef ulonglong table_map; /* Used for table bits in join */
-#if MAX_INDEXES <= 64
-typedef Bitmap<64> key_map; /* Used for finding keys */
-#else
-typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
-#endif
-typedef ulong nesting_map; /* Used for flags of nesting constructs */
-/*
- Used to identify NESTED_JOIN structures within a join (applicable only to
- structures that have not been simplified away and embed more the one
- element)
-*/
-typedef ulonglong nested_join_map;
-
-/* query_id */
-typedef ulonglong query_id_t;
-extern query_id_t global_query_id;
-
-/* increment query_id and return it. */
-inline query_id_t next_query_id() { return global_query_id++; }
-
-/* useful constants */
-extern MYSQL_PLUGIN_IMPORT const key_map key_map_empty;
-extern MYSQL_PLUGIN_IMPORT key_map key_map_full; /* Should be threaded as const */
-extern MYSQL_PLUGIN_IMPORT const char *primary_key_name;
-
-#include "mysql_com.h"
-#include <violite.h>
-#include "unireg.h"
-
-void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size);
-void *sql_alloc(size_t);
-void *sql_calloc(size_t);
-char *sql_strdup(const char *str);
-char *sql_strmake(const char *str, size_t len);
-void *sql_memdup(const void * ptr, size_t size);
-void sql_element_free(void *ptr);
-char *sql_strmake_with_convert(const char *str, size_t arg_length,
- CHARSET_INFO *from_cs,
- size_t max_res_length,
- CHARSET_INFO *to_cs, size_t *result_length);
-uint kill_one_thread(THD *thd, ulong id, bool only_kill_query);
-void sql_kill(THD *thd, ulong id, bool only_kill_query);
-bool net_request_file(NET* net, const char* fname);
-char* query_table_status(THD *thd,const char *db,const char *table_name);
-
-#define x_free(A) { my_free((uchar*) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
-#define safeFree(x) { if(x) { my_free((uchar*) x,MYF(0)); x = NULL; } }
-#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
-#define all_bits_set(A,B) ((A) & (B) != (B))
-
-/* Version numbers for deprecation messages */
-#define VER_BETONY "5.5"
-#define VER_CELOSIA "5.6"
-
-#define WARN_DEPRECATED(Thd,Ver,Old,New) \
- do { \
- DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) > 0); \
- if (((uchar*)Thd) != NULL) \
- push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \
- ER_WARN_DEPRECATED_SYNTAX, \
- ER(ER_WARN_DEPRECATED_SYNTAX), \
- (Old), (New)); \
- else \
- sql_print_warning("'%s' is deprecated and will be removed " \
- "in a future release. Please use '%s' instead.", \
- (Old), (New)); \
- } while(0)
-
-extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info;
-extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ;
-extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *national_charset_info;
-extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *table_alias_charset;
-
-
-enum Derivation
-{
- DERIVATION_IGNORABLE= 5,
- DERIVATION_COERCIBLE= 4,
- DERIVATION_SYSCONST= 3,
- DERIVATION_IMPLICIT= 2,
- DERIVATION_NONE= 1,
- DERIVATION_EXPLICIT= 0
-};
-
-
-typedef struct my_locale_st
-{
- uint number;
- const char *name;
- const char *description;
- const bool is_ascii;
- TYPELIB *month_names;
- TYPELIB *ab_month_names;
- TYPELIB *day_names;
- TYPELIB *ab_day_names;
- uint max_month_name_length;
- uint max_day_name_length;
-#ifdef __cplusplus
- my_locale_st(uint number_par,
- const char *name_par, const char *descr_par, bool is_ascii_par,
- TYPELIB *month_names_par, TYPELIB *ab_month_names_par,
- TYPELIB *day_names_par, TYPELIB *ab_day_names_par,
- uint max_month_name_length_par, uint max_day_name_length_par) :
- number(number_par),
- name(name_par), description(descr_par), is_ascii(is_ascii_par),
- month_names(month_names_par), ab_month_names(ab_month_names_par),
- day_names(day_names_par), ab_day_names(ab_day_names_par),
- max_month_name_length(max_month_name_length_par),
- max_day_name_length(max_day_name_length_par)
- {}
-#endif
-} MY_LOCALE;
-
-extern MY_LOCALE my_locale_en_US;
-extern MY_LOCALE *my_locales[];
-extern MY_LOCALE *my_default_lc_time_names;
-
-MY_LOCALE *my_locale_by_name(const char *name);
-MY_LOCALE *my_locale_by_number(uint number);
-
-/*************************************************************************/
-
-/**
- Object_creation_ctx -- interface for creation context of database objects
- (views, stored routines, events, triggers). Creation context -- is a set
- of attributes, that should be fixed at the creation time and then be used
- each time the object is parsed or executed.
-*/
-
-class Object_creation_ctx
-{
-public:
- Object_creation_ctx *set_n_backup(THD *thd);
-
- void restore_env(THD *thd, Object_creation_ctx *backup_ctx);
-
-protected:
- Object_creation_ctx() {}
- virtual Object_creation_ctx *create_backup_ctx(THD *thd) const = 0;
-
- virtual void change_env(THD *thd) const = 0;
-
-public:
- virtual ~Object_creation_ctx()
- { }
-};
-
-/*************************************************************************/
-
-/**
- Default_object_creation_ctx -- default implementation of
- Object_creation_ctx.
-*/
-
-class Default_object_creation_ctx : public Object_creation_ctx
-{
-public:
- CHARSET_INFO *get_client_cs()
- {
- return m_client_cs;
- }
-
- CHARSET_INFO *get_connection_cl()
- {
- return m_connection_cl;
- }
-
-protected:
- Default_object_creation_ctx(THD *thd);
-
- Default_object_creation_ctx(CHARSET_INFO *client_cs,
- CHARSET_INFO *connection_cl);
-
-protected:
- virtual Object_creation_ctx *create_backup_ctx(THD *thd) const;
-
- virtual void change_env(THD *thd) const;
-
-protected:
- /**
- client_cs stores the value of character_set_client session variable.
- The only character set attribute is used.
-
- Client character set is included into query context, because we save
- query in the original character set, which is client character set. So,
- in order to parse the query properly we have to switch client character
- set on parsing.
- */
- CHARSET_INFO *m_client_cs;
-
- /**
- connection_cl stores the value of collation_connection session
- variable. Both character set and collation attributes are used.
-
- Connection collation is included into query context, becase it defines
- the character set and collation of text literals in internal
- representation of query (item-objects).
- */
- CHARSET_INFO *m_connection_cl;
-};
-
-/***************************************************************************
- Configuration parameters
-****************************************************************************/
-
-#define ACL_CACHE_SIZE 256
-#define MAX_PASSWORD_LENGTH 32
-#define HOST_CACHE_SIZE 128
-#define MAX_ACCEPT_RETRY 10 // Test accept this many times
-#define MAX_FIELDS_BEFORE_HASH 32
-#define USER_VARS_HASH_SIZE 16
-#define TABLE_OPEN_CACHE_MIN 64
-#define TABLE_OPEN_CACHE_DEFAULT 64
-#define TABLE_DEF_CACHE_DEFAULT 256
-/**
- We must have room for at least 256 table definitions in the table
- cache, since otherwise there is no chance prepared
- statements that use these many tables can work.
- Prepared statements use table definition cache ids (table_map_id)
- as table version identifiers. If the table definition
- cache size is less than the number of tables used in a statement,
- the contents of the table definition cache is guaranteed to rotate
- between a prepare and execute. This leads to stable validation
- errors. In future we shall use more stable version identifiers,
- for now the only solution is to ensure that the table definition
- cache can contain at least all tables of a given statement.
-*/
-#define TABLE_DEF_CACHE_MIN 256
-
-/*
- Stack reservation.
- Feel free to raise this by the smallest amount you can to get the
- "execution_constants" test to pass.
-*/
-#define STACK_MIN_SIZE 16000 // Abort if less stack during eval.
-
-#define STACK_MIN_SIZE_FOR_OPEN 1024*80
-#define STACK_BUFF_ALLOC 352 ///< For stack overrun checks
-#ifndef MYSQLD_NET_RETRY_COUNT
-#define MYSQLD_NET_RETRY_COUNT 10 ///< Abort read after this many int.
-#endif
-#define TEMP_POOL_SIZE 128
-
-#define QUERY_ALLOC_BLOCK_SIZE 8192
-#define QUERY_ALLOC_PREALLOC_SIZE 8192
-#define TRANS_ALLOC_BLOCK_SIZE 4096
-#define TRANS_ALLOC_PREALLOC_SIZE 4096
-#define RANGE_ALLOC_BLOCK_SIZE 4096
-#define ACL_ALLOC_BLOCK_SIZE 1024
-#define UDF_ALLOC_BLOCK_SIZE 1024
-#define TABLE_ALLOC_BLOCK_SIZE 1024
-#define BDB_LOG_ALLOC_BLOCK_SIZE 1024
-#define WARN_ALLOC_BLOCK_SIZE 2048
-#define WARN_ALLOC_PREALLOC_SIZE 1024
-#define PROFILE_ALLOC_BLOCK_SIZE 2048
-#define PROFILE_ALLOC_PREALLOC_SIZE 1024
-
-/*
- The following parameters is to decide when to use an extra cache to
- optimise seeks when reading a big table in sorted order
-*/
-#define MIN_FILE_LENGTH_TO_USE_ROW_CACHE (10L*1024*1024)
-#define MIN_ROWS_TO_USE_TABLE_CACHE 100
-#define MIN_ROWS_TO_USE_BULK_INSERT 100
-
-/**
- The following is used to decide if MySQL should use table scanning
- instead of reading with keys. The number says how many evaluation of the
- WHERE clause is comparable to reading one extra row from a table.
-*/
-#define TIME_FOR_COMPARE 5 // 5 compares == one read
-
-/**
- Number of comparisons of table rowids equivalent to reading one row from a
- table.
-*/
-#define TIME_FOR_COMPARE_ROWID (TIME_FOR_COMPARE*2)
-
-/*
- For sequential disk seeks the cost formula is:
- DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST * #blocks_to_skip
-
- The cost of average seek
- DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST*BLOCKS_IN_AVG_SEEK =1.0.
-*/
-#define DISK_SEEK_BASE_COST ((double)0.5)
-
-#define BLOCKS_IN_AVG_SEEK 128
-
-#define DISK_SEEK_PROP_COST ((double)0.5/BLOCKS_IN_AVG_SEEK)
-
-
-/**
- Number of rows in a reference table when refereed through a not unique key.
- This value is only used when we don't know anything about the key
- distribution.
-*/
-#define MATCHING_ROWS_IN_OTHER_TABLE 10
-
-/** Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used). */
-#define KEY_DEFAULT_PACK_LENGTH 8
-
-/** Characters shown for the command in 'show processlist'. */
-#define PROCESS_LIST_WIDTH 100
-/* Characters shown for the command in 'information_schema.processlist' */
-#define PROCESS_LIST_INFO_WIDTH 65535
-
-#define PRECISION_FOR_DOUBLE 53
-#define PRECISION_FOR_FLOAT 24
-
-/* -[digits].E+## */
-#define MAX_FLOAT_STR_LENGTH (FLT_DIG + 6)
-/* -[digits].E+### */
-#define MAX_DOUBLE_STR_LENGTH (DBL_DIG + 7)
-
-/*
- Default time to wait before aborting a new client connection
- that does not respond to "initial server greeting" timely
-*/
-#define CONNECT_TIMEOUT 10
-
-/* The following can also be changed from the command line */
-#define DEFAULT_CONCURRENCY 10
-#define DELAYED_LIMIT 100 /**< pause after xxx inserts */
-#define DELAYED_QUEUE_SIZE 1000
-#define DELAYED_WAIT_TIMEOUT 5*60 /**< Wait for delayed insert */
-#define FLUSH_TIME 0 /**< Don't flush tables */
-#define MAX_CONNECT_ERRORS 10 ///< errors before disabling host
-
-#ifdef __NETWARE__
-#define IF_NETWARE(A,B) A
-#else
-#define IF_NETWARE(A,B) B
-#endif
-
-#if defined(__WIN__)
-#undef FLUSH_TIME
-#define FLUSH_TIME 1800 /**< Flush every half hour */
-
-#define INTERRUPT_PRIOR -2
-#define CONNECT_PRIOR -1
-#define WAIT_PRIOR 0
-#define QUERY_PRIOR 2
-#else
-#define INTERRUPT_PRIOR 10
-#define CONNECT_PRIOR 9
-#define WAIT_PRIOR 8
-#define QUERY_PRIOR 6
-#endif /* __WIN92__ */
-
- /* Bits from testflag */
-#define TEST_PRINT_CACHED_TABLES 1
-#define TEST_NO_KEY_GROUP 2
-#define TEST_MIT_THREAD 4
-#define TEST_BLOCKING 8
-#define TEST_KEEP_TMP_TABLES 16
-#define TEST_READCHECK 64 /**< Force use of readcheck */
-#define TEST_NO_EXTRA 128
-#define TEST_CORE_ON_SIGNAL 256 /**< Give core if signal */
-#define TEST_NO_STACKTRACE 512
-#define TEST_SIGINT 1024 /**< Allow sigint on threads */
-#define TEST_SYNCHRONIZATION 2048 /**< get server to do sleep in
- some places */
-#endif
-
-/*
- This is included in the server and in the client.
- Options for select set by the yacc parser (stored in lex->options).
-
- XXX:
- log_event.h defines OPTIONS_WRITTEN_TO_BIN_LOG to specify what THD
- options list are written into binlog. These options can NOT change their
- values, or it will break replication between version.
-
- context is encoded as following:
- SELECT - SELECT_LEX_NODE::options
- THD - THD::options
- intern - neither. used only as
- func(..., select_node->options | thd->options | OPTION_XXX, ...)
-
- TODO: separate three contexts above, move them to separate bitfields.
-*/
-
-#define SELECT_DISTINCT (ULL(1) << 0) // SELECT, user
-#define SELECT_STRAIGHT_JOIN (ULL(1) << 1) // SELECT, user
-#define SELECT_DESCRIBE (ULL(1) << 2) // SELECT, user
-#define SELECT_SMALL_RESULT (ULL(1) << 3) // SELECT, user
-#define SELECT_BIG_RESULT (ULL(1) << 4) // SELECT, user
-#define OPTION_FOUND_ROWS (ULL(1) << 5) // SELECT, user
-#define OPTION_TO_QUERY_CACHE (ULL(1) << 6) // SELECT, user
-#define SELECT_NO_JOIN_CACHE (ULL(1) << 7) // intern
-#define OPTION_BIG_TABLES (ULL(1) << 8) // THD, user
-#define OPTION_BIG_SELECTS (ULL(1) << 9) // THD, user
-#define OPTION_LOG_OFF (ULL(1) << 10) // THD, user
-#define OPTION_QUOTE_SHOW_CREATE (ULL(1) << 11) // THD, user, unused
-#define TMP_TABLE_ALL_COLUMNS (ULL(1) << 12) // SELECT, intern
-#define OPTION_WARNINGS (ULL(1) << 13) // THD, user
-#define OPTION_AUTO_IS_NULL (ULL(1) << 14) // THD, user, binlog
-#define OPTION_FOUND_COMMENT (ULL(1) << 15) // SELECT, intern, parser
-#define OPTION_SAFE_UPDATES (ULL(1) << 16) // THD, user
-#define OPTION_BUFFER_RESULT (ULL(1) << 17) // SELECT, user
-#define OPTION_BIN_LOG (ULL(1) << 18) // THD, user
-#define OPTION_NOT_AUTOCOMMIT (ULL(1) << 19) // THD, user
-#define OPTION_BEGIN (ULL(1) << 20) // THD, intern
-#define OPTION_TABLE_LOCK (ULL(1) << 21) // THD, intern
-#define OPTION_QUICK (ULL(1) << 22) // SELECT (for DELETE)
-#define OPTION_KEEP_LOG (ULL(1) << 23) // THD, user
-
-/* The following is used to detect a conflict with DISTINCT */
-#define SELECT_ALL (ULL(1) << 24) // SELECT, user, parser
-
-/** The following can be set when importing tables in a 'wrong order'
- to suppress foreign key checks */
-#define OPTION_NO_FOREIGN_KEY_CHECKS (ULL(1) << 26) // THD, user, binlog
-/** The following speeds up inserts to InnoDB tables by suppressing unique
- key checks in some cases */
-#define OPTION_RELAXED_UNIQUE_CHECKS (ULL(1) << 27) // THD, user, binlog
-#define SELECT_NO_UNLOCK (ULL(1) << 28) // SELECT, intern
-#define OPTION_SCHEMA_TABLE (ULL(1) << 29) // SELECT, intern
-/** Flag set if setup_tables already done */
-#define OPTION_SETUP_TABLES_DONE (ULL(1) << 30) // intern
-/** If not set then the thread will ignore all warnings with level notes. */
-#define OPTION_SQL_NOTES (ULL(1) << 31) // THD, user
-/**
- Force the used temporary table to be a MyISAM table (because we will use
- fulltext functions when reading from it.
-*/
-#define TMP_TABLE_FORCE_MYISAM (ULL(1) << 32)
-#define OPTION_PROFILING (ULL(1) << 33)
-
-
-
-/**
- Maximum length of time zone name that we support
- (Time zone name is char(64) in db). mysqlbinlog needs it.
-*/
-#define MAX_TIME_ZONE_NAME_LENGTH (NAME_LEN + 1)
-
-/* The rest of the file is included in the server only */
-#ifndef MYSQL_CLIENT
-
-/* Bits for different SQL modes modes (including ANSI mode) */
-#define MODE_REAL_AS_FLOAT 1
-#define MODE_PIPES_AS_CONCAT 2
-#define MODE_ANSI_QUOTES 4
-#define MODE_IGNORE_SPACE 8
-#define MODE_NOT_USED 16
-#define MODE_ONLY_FULL_GROUP_BY 32
-#define MODE_NO_UNSIGNED_SUBTRACTION 64
-#define MODE_NO_DIR_IN_CREATE 128
-#define MODE_POSTGRESQL 256
-#define MODE_ORACLE 512
-#define MODE_MSSQL 1024
-#define MODE_DB2 2048
-#define MODE_MAXDB 4096
-#define MODE_NO_KEY_OPTIONS 8192
-#define MODE_NO_TABLE_OPTIONS 16384
-#define MODE_NO_FIELD_OPTIONS 32768
-#define MODE_MYSQL323 65536L
-#define MODE_MYSQL40 (MODE_MYSQL323*2)
-#define MODE_ANSI (MODE_MYSQL40*2)
-#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
-#define MODE_NO_BACKSLASH_ESCAPES (MODE_NO_AUTO_VALUE_ON_ZERO*2)
-#define MODE_STRICT_TRANS_TABLES (MODE_NO_BACKSLASH_ESCAPES*2)
-#define MODE_STRICT_ALL_TABLES (MODE_STRICT_TRANS_TABLES*2)
-#define MODE_NO_ZERO_IN_DATE (MODE_STRICT_ALL_TABLES*2)
-#define MODE_NO_ZERO_DATE (MODE_NO_ZERO_IN_DATE*2)
-#define MODE_INVALID_DATES (MODE_NO_ZERO_DATE*2)
-#define MODE_ERROR_FOR_DIVISION_BY_ZERO (MODE_INVALID_DATES*2)
-#define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2)
-#define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2)
-#define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2)
-#define MODE_NO_ENGINE_SUBSTITUTION (MODE_HIGH_NOT_PRECEDENCE*2)
-#define MODE_PAD_CHAR_TO_FULL_LENGTH (ULL(1) << 31)
-
-/* @@optimizer_switch flags. These must be in sync with optimizer_switch_typelib */
-#define OPTIMIZER_SWITCH_INDEX_MERGE 1
-#define OPTIMIZER_SWITCH_INDEX_MERGE_UNION 2
-#define OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION 4
-#define OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT 8
-#define OPTIMIZER_SWITCH_LAST 16
-
-/* The following must be kept in sync with optimizer_switch_str in mysqld.cc */
-#define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
- OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
- OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION | \
- OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT)
-
-
-/*
- Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
- use strictly more than 64 bits by adding one more define above, you should
- contact the replication team because the replication code should then be
- updated (to store more bytes on disk).
-
- NOTE: When adding new SQL_MODE types, make sure to also add them to
- the scripts used for creating the MySQL system tables
- in scripts/mysql_system_tables.sql and scripts/mysql_system_tables_fix.sql
-
-*/
-
-#define RAID_BLOCK_SIZE 1024
-
-#define MY_CHARSET_BIN_MB_MAXLEN 1
-
-// uncachable cause
-#define UNCACHEABLE_DEPENDENT 1
-#define UNCACHEABLE_RAND 2
-#define UNCACHEABLE_SIDEEFFECT 4
-/// forcing to save JOIN for explain
-#define UNCACHEABLE_EXPLAIN 8
-/** Don't evaluate subqueries in prepare even if they're not correlated */
-#define UNCACHEABLE_PREPARE 16
-/* For uncorrelated SELECT in an UNION with some correlated SELECTs */
-#define UNCACHEABLE_UNITED 32
-#define UNCACHEABLE_CHECKOPTION 64
-
-/* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */
-#define UNDEF_POS (-1)
-
-/* BINLOG_DUMP options */
-
-#define BINLOG_DUMP_NON_BLOCK 1
-
-/* sql_show.cc:show_log_files() */
-#define SHOW_LOG_STATUS_FREE "FREE"
-#define SHOW_LOG_STATUS_INUSE "IN USE"
-
-struct TABLE_LIST;
-class String;
-void view_store_options(THD *thd, TABLE_LIST *table, String *buff);
-
-/* Options to add_table_to_list() */
-#define TL_OPTION_UPDATING 1
-#define TL_OPTION_FORCE_INDEX 2
-#define TL_OPTION_IGNORE_LEAVES 4
-#define TL_OPTION_ALIAS 8
-
-/* Some portable defines */
-
-#define portable_sizeof_char_ptr 8
-
-#define tmp_file_prefix "#sql" /**< Prefix for tmp tables */
-#define tmp_file_prefix_length 4
-
-/* Flags for calc_week() function. */
-#define WEEK_MONDAY_FIRST 1
-#define WEEK_YEAR 2
-#define WEEK_FIRST_WEEKDAY 4
-
-#define STRING_BUFFER_USUAL_SIZE 80
-
-/*
- Some defines for exit codes for ::is_equal class functions.
-*/
-#define IS_EQUAL_NO 0
-#define IS_EQUAL_YES 1
-#define IS_EQUAL_PACK_LENGTH 2
-
-enum enum_parsing_place
-{
- NO_MATTER,
- IN_HAVING,
- SELECT_LIST,
- IN_WHERE,
- IN_ON
-};
-
-struct st_table;
-
-#define thd_proc_info(thd, msg) set_thd_proc_info(thd, msg, __func__, __FILE__, __LINE__)
-class THD;
-
-enum enum_check_fields
-{
- CHECK_FIELD_IGNORE,
- CHECK_FIELD_WARN,
- CHECK_FIELD_ERROR_FOR_NULL
-};
-
-#if defined(MYSQL_DYNAMIC_PLUGIN) && defined(_WIN32)
-extern "C" THD *_current_thd_noinline();
-#define _current_thd() _current_thd_noinline()
-#else
-extern pthread_key(THD*, THR_THD);
-inline THD *_current_thd(void)
-{
- return my_pthread_getspecific_ptr(THD*,THR_THD);
-}
-#endif
-#define current_thd _current_thd()
-
-
-/**
- The meat of thd_proc_info(THD*, char*), a macro that packs the last
- three calling-info parameters.
-*/
-extern "C"
-const char *set_thd_proc_info(THD *thd, const char *info,
- const char *calling_func,
- const char *calling_file,
- const unsigned int calling_line);
-
-/**
- Enumerate possible types of a table from re-execution
- standpoint.
- TABLE_LIST class has a member of this type.
- At prepared statement prepare, this member is assigned a value
- as of the current state of the database. Before (re-)execution
- of a prepared statement, we check that the value recorded at
- prepare matches the type of the object we obtained from the
- table definition cache.
-
- @sa check_and_update_table_version()
- @sa Execute_observer
- @sa Prepared_statement::reprepare()
-*/
-
-enum enum_table_ref_type
-{
- /** Initial value set by the parser */
- TABLE_REF_NULL= 0,
- TABLE_REF_VIEW,
- TABLE_REF_BASE_TABLE,
- TABLE_REF_I_S_TABLE,
- TABLE_REF_TMP_TABLE
-};
-
-/*
- External variables
-*/
-extern ulong server_id, concurrency;
-
-
-typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
- uint key_length,
- ulonglong *engine_data);
-#include "sql_string.h"
-#include "sql_list.h"
-#include "sql_map.h"
-#include "my_decimal.h"
-#include "handler.h"
-#include "parse_file.h"
-#include "table.h"
-#include "sql_error.h"
-#include "field.h" /* Field definitions */
-#include "protocol.h"
-#include "sql_udf.h"
-#include "sql_profile.h"
-#include "sql_partition.h"
-
-class user_var_entry;
-class Security_context;
-enum enum_var_type
-{
- OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
-};
-class sys_var;
-#ifdef MYSQL_SERVER
-class Comp_creator;
-typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
-#endif
-#include "item.h"
-extern my_decimal decimal_zero;
-
-/* sql_parse.cc */
-void free_items(Item *item);
-void cleanup_items(Item *item);
-class THD;
-void close_thread_tables(THD *thd);
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables);
-bool check_single_table_access(THD *thd, ulong privilege,
- TABLE_LIST *tables, bool no_errors);
-bool check_routine_access(THD *thd,ulong want_access,char *db,char *name,
- bool is_proc, bool no_errors);
-bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
-bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc);
-#else
-inline bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables)
-{ return false; }
-inline bool check_single_table_access(THD *thd, ulong privilege,
- TABLE_LIST *tables, bool no_errors)
-{ return false; }
-inline bool check_routine_access(THD *thd,ulong want_access,char *db,
- char *name, bool is_proc, bool no_errors)
-{ return false; }
-inline bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
-{ return false; }
-inline bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list)
-{ return false; }
-inline bool check_some_routine_access(THD *thd, const char *db,
- const char *name, bool is_proc)
-{ return false; }
-#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
-
-bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
-bool multi_delete_precheck(THD *thd, TABLE_LIST *tables);
-int mysql_multi_update_prepare(THD *thd);
-int mysql_multi_delete_prepare(THD *thd);
-bool mysql_insert_select_prepare(THD *thd);
-bool update_precheck(THD *thd, TABLE_LIST *tables);
-bool delete_precheck(THD *thd, TABLE_LIST *tables);
-bool insert_precheck(THD *thd, TABLE_LIST *tables);
-bool create_table_precheck(THD *thd, TABLE_LIST *tables,
- TABLE_LIST *create_table);
-int append_query_string(CHARSET_INFO *csinfo,
- String const *from, String *to);
-
-void get_default_definer(THD *thd, LEX_USER *definer);
-LEX_USER *create_default_definer(THD *thd);
-LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
-LEX_USER *get_current_user(THD *thd, LEX_USER *user);
-bool check_string_byte_length(LEX_STRING *str, const char *err_msg,
- uint max_byte_length);
-bool check_string_char_length(LEX_STRING *str, const char *err_msg,
- uint max_char_length, CHARSET_INFO *cs,
- bool no_error);
-bool check_host_name(LEX_STRING *str);
-
-bool parse_sql(THD *thd,
- Parser_state *parser_state,
- Object_creation_ctx *creation_ctx);
-
-enum enum_mysql_completiontype {
- ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
- COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6
-};
-
-bool begin_trans(THD *thd);
-bool end_active_trans(THD *thd);
-int end_trans(THD *thd, enum enum_mysql_completiontype completion);
-
-Item *negate_expression(THD *thd, Item *expr);
-
-/* log.cc */
-int vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
-void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
-void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
-void sql_print_information(const char *format, ...)
- ATTRIBUTE_FORMAT(printf, 1, 2);
-typedef void (*sql_print_message_func)(const char *format, ...)
- ATTRIBUTE_FORMAT(printf, 1, 2);
-extern sql_print_message_func sql_print_message_handlers[];
-
-int error_log_print(enum loglevel level, const char *format,
- va_list args);
-
-bool slow_log_print(THD *thd, const char *query, uint query_length,
- ulonglong current_utime);
-
-bool general_log_print(THD *thd, enum enum_server_command command,
- const char *format,...);
-
-bool general_log_write(THD *thd, enum enum_server_command command,
- const char *query, uint query_length);
-
-#include "sql_class.h"
-#include "sql_acl.h"
-#include "tztime.h"
-#ifdef MYSQL_SERVER
-#include "sql_servers.h"
-#include "opt_range.h"
-
-#ifdef HAVE_QUERY_CACHE
-struct Query_cache_query_flags
-{
- unsigned int client_long_flag:1;
- unsigned int client_protocol_41:1;
- unsigned int result_in_binary_protocol:1;
- unsigned int more_results_exists:1;
- unsigned int in_trans:1;
- unsigned int autocommit:1;
- unsigned int pkt_nr;
- uint character_set_client_num;
- uint character_set_results_num;
- uint collation_connection_num;
- ha_rows limit;
- Time_zone *time_zone;
- ulong sql_mode;
- ulong max_sort_length;
- ulong group_concat_max_len;
- ulong default_week_format;
- ulong div_precision_increment;
- MY_LOCALE *lc_time_names;
-};
-#define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags)
-#include "sql_cache.h"
-#define query_cache_store_query(A, B) query_cache.store_query(A, B)
-#define query_cache_destroy() query_cache.destroy()
-#define query_cache_result_size_limit(A) query_cache.result_size_limit(A)
-#define query_cache_init() query_cache.init()
-#define query_cache_resize(A) query_cache.resize(A)
-#define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A)
-#define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C)
-#define query_cache_invalidate1(A) query_cache.invalidate(A)
-#define query_cache_send_result_to_client(A, B, C) \
- query_cache.send_result_to_client(A, B, C)
-#define query_cache_invalidate_by_MyISAM_filename_ref \
- &query_cache_invalidate_by_MyISAM_filename
-/* note the "maybe": it's a read without mutex */
-#define query_cache_maybe_disabled(T) \
- (T->variables.query_cache_type == 0 || query_cache.query_cache_size == 0)
-#define query_cache_is_cacheable_query(L) \
- (((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query)
-#else
-#define QUERY_CACHE_FLAGS_SIZE 0
-#define query_cache_store_query(A, B)
-#define query_cache_destroy()
-#define query_cache_result_size_limit(A)
-#define query_cache_init()
-#define query_cache_resize(A)
-#define query_cache_set_min_res_unit(A)
-#define query_cache_invalidate3(A, B, C)
-#define query_cache_invalidate1(A)
-#define query_cache_send_result_to_client(A, B, C) 0
-#define query_cache_invalidate_by_MyISAM_filename_ref NULL
-
-#define query_cache_abort(A)
-#define query_cache_end_of_result(A)
-#define query_cache_invalidate_by_MyISAM_filename_ref NULL
-#define query_cache_maybe_disabled(T) 1
-#define query_cache_is_cacheable_query(L) 0
-#endif /*HAVE_QUERY_CACHE*/
-
-/*
- Error injector Macros to enable easy testing of recovery after failures
- in various error cases.
-*/
-#ifndef ERROR_INJECT_SUPPORT
-
-#define ERROR_INJECT(x) 0
-#define ERROR_INJECT_ACTION(x,action) 0
-#define ERROR_INJECT_CRASH(x) 0
-#define ERROR_INJECT_VALUE(x) 0
-#define ERROR_INJECT_VALUE_ACTION(x,action) 0
-#define ERROR_INJECT_VALUE_CRASH(x) 0
-#define SET_ERROR_INJECT_VALUE(x)
-
-#else
-
-inline bool check_and_unset_keyword(const char *dbug_str)
-{
- const char *extra_str= "-d,";
- char total_str[200];
- if (_db_strict_keyword_ (dbug_str))
- {
- strxmov(total_str, extra_str, dbug_str, NullS);
- DBUG_SET(total_str);
- return 1;
- }
- return 0;
-}
-
-
-inline bool
-check_and_unset_inject_value(int value)
-{
- THD *thd= current_thd;
- if (thd->error_inject_value == (uint)value)
- {
- thd->error_inject_value= 0;
- return 1;
- }
- return 0;
-}
-
-/*
- ERROR INJECT MODULE:
- --------------------
- These macros are used to insert macros from the application code.
- The event that activates those error injections can be activated
- from SQL by using:
- SET SESSION dbug=+d,code;
-
- After the error has been injected, the macros will automatically
- remove the debug code, thus similar to using:
- SET SESSION dbug=-d,code
- from SQL.
-
- ERROR_INJECT_CRASH will inject a crash of the MySQL Server if code
- is set when macro is called. ERROR_INJECT_CRASH can be used in
- if-statements, it will always return FALSE unless of course it
- crashes in which case it doesn't return at all.
-
- ERROR_INJECT_ACTION will inject the action specified in the action
- parameter of the macro, before performing the action the code will
- be removed such that no more events occur. ERROR_INJECT_ACTION
- can also be used in if-statements and always returns FALSE.
- ERROR_INJECT can be used in a normal if-statement, where the action
- part is performed in the if-block. The macro returns TRUE if the
- error was activated and otherwise returns FALSE. If activated the
- code is removed.
-
- Sometimes it is necessary to perform error inject actions as a serie
- of events. In this case one can use one variable on the THD object.
- Thus one sets this value by using e.g. SET_ERROR_INJECT_VALUE(100).
- Then one can later test for it by using ERROR_INJECT_CRASH_VALUE,
- ERROR_INJECT_ACTION_VALUE and ERROR_INJECT_VALUE. This have the same
- behaviour as the above described macros except that they use the
- error inject value instead of a code used by DBUG macros.
-*/
-#define SET_ERROR_INJECT_VALUE(x) \
- current_thd->error_inject_value= (x)
-#define ERROR_INJECT_CRASH(code) \
- DBUG_EVALUATE_IF(code, (abort(), 0), 0)
-#define ERROR_INJECT_ACTION(code, action) \
- (check_and_unset_keyword(code) ? ((action), 0) : 0)
-#define ERROR_INJECT(code) \
- check_and_unset_keyword(code)
-#define ERROR_INJECT_VALUE(value) \
- check_and_unset_inject_value(value)
-#define ERROR_INJECT_VALUE_ACTION(value,action) \
- (check_and_unset_inject_value(value) ? (action) : 0)
-#define ERROR_INJECT_VALUE_CRASH(value) \
- ERROR_INJECT_VALUE_ACTION(value, (abort(), 0))
-
-#endif
-
-int write_bin_log(THD *thd, bool clear_error,
- char const *query, ulong query_length);
-
-/* sql_connect.cc */
-int check_user(THD *thd, enum enum_server_command command,
- const char *passwd, uint passwd_len, const char *db,
- bool check_count);
-pthread_handler_t handle_one_connection(void *arg);
-bool init_new_connection_handler_thread();
-void reset_mqh(LEX_USER *lu, bool get_them);
-bool check_mqh(THD *thd, uint check_command);
-void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
-void decrease_user_connections(USER_CONN *uc);
-void thd_init_client_charset(THD *thd, uint cs_number);
-bool setup_connection_thread_globals(THD *thd);
-
-int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
-bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
-bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
-bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db);
-void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
-void mysql_client_binlog_statement(THD *thd);
-bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
- my_bool drop_temporary);
-int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
- bool drop_temporary, bool drop_view, bool log_query);
-bool quick_rm_table(handlerton *base,const char *db,
- const char *table_name, uint flags);
-void close_cached_table(THD *thd, TABLE *table);
-bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent);
-bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db,
- char *new_table_name, char *new_table_alias,
- bool skip_error);
-
-bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name,
- bool force_switch);
-
-bool mysql_opt_change_db(THD *thd,
- const LEX_STRING *new_db_name,
- LEX_STRING *saved_db_name,
- bool force_switch,
- bool *cur_db_changed);
-
-void mysql_parse(THD *thd, char *rawbuf, uint length,
- const char ** semicolon);
-
-bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
-bool is_update_query(enum enum_sql_command command);
-bool is_log_table_write_query(enum enum_sql_command command);
-bool alloc_query(THD *thd, const char *packet, uint packet_length);
-void mysql_init_select(LEX *lex);
-void mysql_reset_thd_for_next_command(THD *thd);
-bool mysql_new_select(LEX *lex, bool move_down);
-void create_select_for_variable(const char *var_name);
-void mysql_init_multi_delete(LEX *lex);
-bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
-void init_max_user_conn(void);
-void init_update_queries(void);
-void free_max_user_conn(void);
-pthread_handler_t handle_bootstrap(void *arg);
-int mysql_execute_command(THD *thd);
-bool do_command(THD *thd);
-bool dispatch_command(enum enum_server_command command, THD *thd,
- char* packet, uint packet_length);
-void log_slow_statement(THD *thd);
-bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
-bool records_are_comparable(const TABLE *table);
-bool compare_records(const TABLE *table);
-bool append_file_to_dir(THD *thd, const char **filename_ptr,
- const char *table_name);
-void wait_while_table_is_used(THD *thd, TABLE *table,
- enum ha_extra_function function);
-bool table_cache_init(void);
-void table_cache_free(void);
-bool table_def_init(void);
-void table_def_free(void);
-void assign_new_table_id(TABLE_SHARE *share);
-uint cached_open_tables(void);
-uint cached_table_definitions(void);
-void kill_mysql(void);
-void close_connection(THD *thd, uint errcode, bool lock);
-bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
- int *write_to_binlog);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv,
- bool no_grant, bool no_errors, bool schema_db);
-bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables,
- uint number, bool no_errors);
-#else
-inline bool check_access(THD *thd, ulong access, const char *db,
- ulong *save_priv, bool no_grant, bool no_errors,
- bool schema_db)
-{
- if (save_priv)
- *save_priv= GLOBAL_ACLS;
- return false;
-}
-inline bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables,
- uint number, bool no_errors)
-{ return false; }
-#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
-
-#endif /* MYSQL_SERVER */
-#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-bool check_global_access(THD *thd, ulong want_access);
-#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
-#ifdef MYSQL_SERVER
-
-/*
- Support routine for SQL parser on partitioning syntax
-*/
-my_bool is_partition_management(LEX *lex);
-/*
- General routine to change field->ptr of a NULL-terminated array of Field
- objects. Useful when needed to call val_int, val_str or similar and the
- field data is not in table->record[0] but in some other structure.
- set_key_field_ptr changes all fields of an index using a key_info object.
- All methods presume that there is at least one field to change.
-*/
-
-void set_field_ptr(Field **ptr, const uchar *new_buf, const uchar *old_buf);
-void set_key_field_ptr(KEY *key_info, const uchar *new_buf,
- const uchar *old_buf);
-
-bool mysql_backup_table(THD* thd, TABLE_LIST* table_list);
-bool mysql_restore_table(THD* thd, TABLE_LIST* table_list);
-
-bool mysql_checksum_table(THD* thd, TABLE_LIST* table_list,
- HA_CHECK_OPT* check_opt);
-bool mysql_check_table(THD* thd, TABLE_LIST* table_list,
- HA_CHECK_OPT* check_opt);
-bool mysql_repair_table(THD* thd, TABLE_LIST* table_list,
- HA_CHECK_OPT* check_opt);
-bool mysql_analyze_table(THD* thd, TABLE_LIST* table_list,
- HA_CHECK_OPT* check_opt);
-bool mysql_optimize_table(THD* thd, TABLE_LIST* table_list,
- HA_CHECK_OPT* check_opt);
-bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list,
- LEX_STRING *key_cache_name);
-bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
-int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache,
- KEY_CACHE *dst_cache);
-TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list);
-
-bool mysql_xa_recover(THD *thd);
-
-bool check_simple_select();
-int mysql_alter_tablespace(THD* thd, st_alter_tablespace *ts_info);
-
-SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length,
- SORT_FIELD *sortorder);
-int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
- List<Item> &fields, List <Item> &all_fields, ORDER *order);
-int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
- List<Item> &fields, List<Item> &all_fields, ORDER *order,
- bool *hidden_group_fields);
-bool fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
- Item **ref_pointer_array, ORDER *group_list= NULL);
-
-bool handle_select(THD *thd, LEX *lex, select_result *result,
- ulong setup_tables_done_option);
-bool mysql_select(THD *thd, Item ***rref_pointer_array,
- TABLE_LIST *tables, uint wild_num, List<Item> &list,
- COND *conds, uint og_num, ORDER *order, ORDER *group,
- Item *having, ORDER *proc_param, ulonglong select_type,
- select_result *result, SELECT_LEX_UNIT *unit,
- SELECT_LEX *select_lex);
-void free_underlaid_joins(THD *thd, SELECT_LEX *select);
-bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
- select_result *result);
-int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
- select_result *result);
-bool mysql_union(THD *thd, LEX *lex, select_result *result,
- SELECT_LEX_UNIT *unit, ulong setup_tables_done_option);
-bool mysql_handle_derived(LEX *lex, bool (*processor)(THD *thd,
- LEX *lex,
- TABLE_LIST *table));
-bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
-bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
-Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
- Item ***copy_func, Field **from_field,
- Field **def_field,
- bool group, bool modify_item,
- bool table_cant_handle_bit_fields,
- bool make_copy_field,
- uint convert_blob_length);
-void sp_prepare_create_field(THD *thd, Create_field *sql_field);
-int prepare_create_field(Create_field *sql_field,
- uint *blob_columns,
- int *timestamps, int *timestamps_with_niladic,
- longlong table_flags);
-bool mysql_create_table(THD *thd,const char *db, const char *table_name,
- HA_CREATE_INFO *create_info,
- Alter_info *alter_info,
- bool tmp_table, uint select_field_count);
-bool mysql_create_table_no_lock(THD *thd, const char *db,
- const char *table_name,
- HA_CREATE_INFO *create_info,
- Alter_info *alter_info,
- bool tmp_table, uint select_field_count);
-
-bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
- HA_CREATE_INFO *create_info,
- TABLE_LIST *table_list,
- Alter_info *alter_info,
- uint order_num, ORDER *order, bool ignore);
-bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list);
-bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
- TABLE_LIST *src_table,
- HA_CREATE_INFO *create_info);
-bool mysql_rename_table(handlerton *base, const char *old_db,
- const char * old_name, const char *new_db,
- const char * new_name, uint flags);
-bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
- Item **conds, uint order_num, ORDER *order);
-int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
- List<Item> &values,COND *conds,
- uint order_num, ORDER *order, ha_rows limit,
- enum enum_duplicates handle_duplicates, bool ignore);
-bool mysql_multi_update(THD *thd, TABLE_LIST *table_list,
- List<Item> *fields, List<Item> *values,
- COND *conds, ulonglong options,
- enum enum_duplicates handle_duplicates, bool ignore,
- SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
-bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
- List<Item> &fields, List_item *values,
- List<Item> &update_fields,
- List<Item> &update_values, enum_duplicates duplic,
- COND **where, bool select_insert,
- bool check_fields, bool abort_on_warning);
-bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
- List<List_item> &values, List<Item> &update_fields,
- List<Item> &update_values, enum_duplicates flag,
- bool ignore);
-int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
- TABLE_LIST *table_list);
-void prepare_triggers_for_insert_stmt(TABLE *table);
-int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
-bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
- SQL_I_List<ORDER> *order, ha_rows rows, ulonglong options,
- bool reset_auto_increment);
-bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok);
-bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);
-uint create_table_def_key(THD *thd, char *key, TABLE_LIST *table_list,
- bool tmp_table);
-TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
- uint key_length, uint db_flags, int *error);
-void release_table_share(TABLE_SHARE *share, enum release_type type);
-TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name);
-TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
- uint lock_flags);
-TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
- bool *refresh, uint flags);
-bool name_lock_locked_table(THD *thd, TABLE_LIST *tables);
-bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in);
-TABLE *table_cache_insert_placeholder(THD *thd, const char *key,
- uint key_length);
-bool lock_table_name_if_not_cached(THD *thd, const char *db,
- const char *table_name, TABLE **table);
-TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
-void detach_merge_children(TABLE *table, bool clear_refs);
-bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last,
- TABLE_LIST *new_child_list, TABLE_LIST **new_last);
-bool reopen_table(TABLE *table);
-bool reopen_tables(THD *thd,bool get_locks,bool in_refresh);
-thr_lock_type read_lock_type_for_table(THD *thd, LEX *lex,
- TABLE_LIST *table_list);
-void close_data_files_and_morph_locks(THD *thd, const char *db,
- const char *table_name);
-void close_handle_and_leave_table_as_lock(TABLE *table);
-bool wait_for_tables(THD *thd);
-bool table_is_used(TABLE *table, bool wait_for_name_lock);
-TABLE *drop_locked_tables(THD *thd,const char *db, const char *table_name);
-void abort_locked_tables(THD *thd,const char *db, const char *table_name);
-void execute_init_command(THD *thd, sys_var_str *init_command_var,
- rw_lock_t *var_mutex);
-extern Field *not_found_field;
-extern Field *view_ref_found;
-
-enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
- IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE,
- IGNORE_EXCEPT_NON_UNIQUE};
-Field *
-find_field_in_tables(THD *thd, Item_ident *item,
- TABLE_LIST *first_table, TABLE_LIST *last_table,
- Item **ref, find_item_error_report_type report_error,
- bool check_privileges, bool register_tree_change);
-Field *
-find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
- const char *name, uint length,
- const char *item_name, const char *db_name,
- const char *table_name, Item **ref,
- bool check_privileges, bool allow_rowid,
- uint *cached_field_index_ptr,
- bool register_tree_change, TABLE_LIST **actual_table);
-Field *
-find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
- bool allow_rowid, uint *cached_field_index_ptr);
-Field *
-find_field_in_table_sef(TABLE *table, const char *name);
-
-#endif /* MYSQL_SERVER */
-
-#ifdef HAVE_OPENSSL
-#include <openssl/des.h>
-struct st_des_keyblock
-{
- DES_cblock key1, key2, key3;
-};
-struct st_des_keyschedule
-{
- DES_key_schedule ks1, ks2, ks3;
-};
-extern char *des_key_file;
-extern struct st_des_keyschedule des_keyschedule[10];
-extern uint des_default_key;
-extern pthread_mutex_t LOCK_des_key_file;
-bool load_des_key_file(const char *file_name);
-#endif /* HAVE_OPENSSL */
-
-#ifdef MYSQL_SERVER
-/* sql_do.cc */
-bool mysql_do(THD *thd, List<Item> &values);
-
-/* sql_analyse.h */
-bool append_escaped(String *to_str, String *from_str);
-
-/* sql_show.cc */
-bool mysqld_show_open_tables(THD *thd,const char *wild);
-bool mysqld_show_logs(THD *thd);
-void append_identifier(THD *thd, String *packet, const char *name,
- uint length);
-#endif /* MYSQL_SERVER */
-#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
-#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
-#ifdef MYSQL_SERVER
-void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
-int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
-bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
-bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
-
-void mysqld_list_processes(THD *thd,const char *user,bool verbose);
-int mysqld_show_status(THD *thd);
-int mysqld_show_variables(THD *thd,const char *wild);
-bool mysqld_show_storage_engines(THD *thd);
-bool mysqld_show_authors(THD *thd);
-bool mysqld_show_contributors(THD *thd);
-bool mysqld_show_privileges(THD *thd);
-bool mysqld_show_column_types(THD *thd);
-bool mysqld_help (THD *thd, const char *text);
-void calc_sum_of_all_status(STATUS_VAR *to);
-
-void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
- const LEX_STRING *definer_host);
-
-int add_status_vars(SHOW_VAR *list);
-void remove_status_vars(SHOW_VAR *list);
-void init_status_vars();
-void free_status_vars();
-void reset_status_vars();
-
-/* information schema */
-extern LEX_STRING INFORMATION_SCHEMA_NAME;
-/* log tables */
-extern LEX_STRING MYSQL_SCHEMA_NAME;
-extern LEX_STRING GENERAL_LOG_NAME;
-extern LEX_STRING SLOW_LOG_NAME;
-
-extern const LEX_STRING partition_keywords[];
-ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name);
-ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx);
-int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
- enum enum_schema_tables schema_table_idx);
-int make_schema_select(THD *thd, SELECT_LEX *sel,
- enum enum_schema_tables schema_table_idx);
-int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list);
-int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
-int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
-int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
-int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
-bool get_schema_tables_result(JOIN *join,
- enum enum_schema_table_state executed_place);
-enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table);
-
-inline bool is_schema_db(const char *name, size_t len)
-{
- return (INFORMATION_SCHEMA_NAME.length == len &&
- !my_strcasecmp(system_charset_info,
- INFORMATION_SCHEMA_NAME.str, name));
-}
-
-inline bool is_schema_db(const char *name)
-{
- return !my_strcasecmp(system_charset_info,
- INFORMATION_SCHEMA_NAME.str, name);
-}
-
-/* sql_prepare.cc */
-
-void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length);
-void mysqld_stmt_execute(THD *thd, char *packet, uint packet_length);
-void mysqld_stmt_close(THD *thd, char *packet);
-void mysql_sql_stmt_prepare(THD *thd);
-void mysql_sql_stmt_execute(THD *thd);
-void mysql_sql_stmt_close(THD *thd);
-void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length);
-void mysqld_stmt_reset(THD *thd, char *packet);
-void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
-void reinit_stmt_before_use(THD *thd, LEX *lex);
-
-/* sql_handler.cc */
-bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen);
-bool mysql_ha_close(THD *thd, TABLE_LIST *tables);
-bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
- List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
-void mysql_ha_flush(THD *thd);
-void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked);
-void mysql_ha_cleanup(THD *thd);
-
-/* sql_base.cc */
-#define TMP_TABLE_KEY_EXTRA 8
-void set_item_name(Item *item,char *pos,uint length);
-bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum enum_field_types type,
- char *length, char *decimal,
- uint type_modifier,
- Item *default_value, Item *on_update_value,
- LEX_STRING *comment,
- char *change, List<String> *interval_list,
- CHARSET_INFO *cs,
- uint uint_geom_type);
-Create_field * new_create_field(THD *thd, char *field_name, enum_field_types type,
- char *length, char *decimals,
- uint type_modifier,
- Item *default_value, Item *on_update_value,
- LEX_STRING *comment, char *change,
- List<String> *interval_list, CHARSET_INFO *cs,
- uint uint_geom_type);
-void store_position_for_column(const char *name);
-bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *group,bool asc);
-bool push_new_name_resolution_context(THD *thd,
- TABLE_LIST *left_op,
- TABLE_LIST *right_op);
-void add_join_on(TABLE_LIST *b,Item *expr);
-void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields,
- SELECT_LEX *lex);
-bool add_proc_to_list(THD *thd, Item *item);
-void unlink_open_table(THD *thd, TABLE *find, bool unlock);
-void drop_open_table(THD *thd, TABLE *table, const char *db_name,
- const char *table_name);
-void update_non_unique_table_error(TABLE_LIST *update,
- const char *operation,
- TABLE_LIST *duplicate);
-
-SQL_SELECT *make_select(TABLE *head, table_map const_tables,
- table_map read_tables, COND *conds,
- bool allow_null_cond, int *error);
-extern Item **not_found_item;
-
-/*
- A set of constants used for checking non aggregated fields and sum
- functions mixture in the ONLY_FULL_GROUP_BY_MODE.
-*/
-#define NON_AGG_FIELD_USED 1
-#define SUM_FUNC_USED 2
-
-/*
- This enumeration type is used only by the function find_item_in_list
- to return the info on how an item has been resolved against a list
- of possibly aliased items.
- The item can be resolved:
- - against an alias name of the list's element (RESOLVED_AGAINST_ALIAS)
- - against non-aliased field name of the list (RESOLVED_WITH_NO_ALIAS)
- - against an aliased field name of the list (RESOLVED_BEHIND_ALIAS)
- - ignoring the alias name in cases when SQL requires to ignore aliases
- (e.g. when the resolved field reference contains a table name or
- when the resolved item is an expression) (RESOLVED_IGNORING_ALIAS)
-*/
-enum enum_resolution_type {
- NOT_RESOLVED=0,
- RESOLVED_IGNORING_ALIAS,
- RESOLVED_BEHIND_ALIAS,
- RESOLVED_WITH_NO_ALIAS,
- RESOLVED_AGAINST_ALIAS
-};
-Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
- find_item_error_report_type report_error,
- enum_resolution_type *resolution);
-bool get_key_map_from_key_list(key_map *map, TABLE *table,
- List<String> *index_list);
-bool insert_fields(THD *thd, Name_resolution_context *context,
- const char *db_name, const char *table_name,
- List_iterator<Item> *it, bool any_privileges);
-bool setup_tables(THD *thd, Name_resolution_context *context,
- List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
- TABLE_LIST **leaves, bool select_insert);
-bool setup_tables_and_check_access(THD *thd,
- Name_resolution_context *context,
- List<TABLE_LIST> *from_clause,
- TABLE_LIST *tables,
- TABLE_LIST **leaves,
- bool select_insert,
- ulong want_access_first,
- ulong want_access);
-int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
- List<Item> *sum_func_list, uint wild_num);
-bool setup_fields(THD *thd, Item** ref_pointer_array,
- List<Item> &item, enum_mark_columns mark_used_columns,
- List<Item> *sum_func_list, bool allow_sum_func);
-inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array,
- List<Item> &item,
- enum_mark_columns mark_used_columns,
- List<Item> *sum_func_list,
- bool allow_sum_func)
-{
- bool res;
- thd->lex->select_lex.no_wrap_view_item= TRUE;
- res= setup_fields(thd, ref_pointer_array, item, mark_used_columns, sum_func_list,
- allow_sum_func);
- thd->lex->select_lex.no_wrap_view_item= FALSE;
- return res;
-}
-int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
- COND **conds);
-int setup_ftfuncs(SELECT_LEX* select);
-int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
-void wait_for_condition(THD *thd, pthread_mutex_t *mutex,
- pthread_cond_t *cond);
-int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags);
-/* open_and_lock_tables with optional derived handling */
-int open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived);
-/* simple open_and_lock_tables without derived handling */
-inline int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
-{
- return open_and_lock_tables_derived(thd, tables, FALSE);
-}
-/* open_and_lock_tables with derived handling */
-inline int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
-{
- return open_and_lock_tables_derived(thd, tables, TRUE);
-}
-/* simple open_and_lock_tables without derived handling for single table */
-TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
- thr_lock_type lock_type);
-bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags);
-int lock_tables(THD *thd, TABLE_LIST *tables, uint counter, bool *need_reopen);
-int decide_logging_format(THD *thd, TABLE_LIST *tables);
-TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
- const char *table_name, bool link_in_list);
-bool rm_temporary_table(handlerton *base, char *path);
-void free_io_cache(TABLE *entry);
-void intern_close_table(TABLE *entry);
-bool close_thread_table(THD *thd, TABLE **table_ptr);
-void close_temporary_tables(THD *thd);
-void close_tables_for_reopen(THD *thd, TABLE_LIST **tables);
-TABLE_LIST *find_table_in_list(TABLE_LIST *table,
- TABLE_LIST *TABLE_LIST::*link,
- const char *db_name,
- const char *table_name);
-TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
- bool check_alias);
-TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name);
-TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list);
-int drop_temporary_table(THD *thd, TABLE_LIST *table_list);
-void close_temporary_table(THD *thd, TABLE *table, bool free_share,
- bool delete_table);
-void close_temporary(TABLE *table, bool free_share, bool delete_table);
-bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
- const char *table_name);
-void remove_db_from_cache(const char *db);
-void flush_tables();
-bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
-char *make_default_log_name(char *buff,const char* log_ext);
-
-#ifdef WITH_PARTITION_STORAGE_ENGINE
-uint fast_alter_partition_table(THD *thd, TABLE *table,
- Alter_info *alter_info,
- HA_CREATE_INFO *create_info,
- TABLE_LIST *table_list,
- char *db,
- const char *table_name,
- uint fast_alter_partition);
-uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
- enum partition_state part_state);
-uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
- HA_CREATE_INFO *create_info,
- handlerton *old_db_type,
- bool *partition_changed,
- uint *fast_alter_partition);
-#endif
-
-/* bits for last argument to remove_table_from_cache() */
-#define RTFC_NO_FLAG 0x0000
-#define RTFC_OWNED_BY_THD_FLAG 0x0001
-#define RTFC_WAIT_OTHER_THREAD_FLAG 0x0002
-#define RTFC_CHECK_KILLED_FLAG 0x0004
-bool remove_table_from_cache(THD *thd, const char *db, const char *table,
- uint flags);
-
-#define NORMAL_PART_NAME 0
-#define TEMP_PART_NAME 1
-#define RENAMED_PART_NAME 2
-void create_partition_name(char *out, const char *in1,
- const char *in2, uint name_variant,
- bool translate);
-void create_subpartition_name(char *out, const char *in1,
- const char *in2, const char *in3,
- uint name_variant);
-
-typedef struct st_lock_param_type
-{
- TABLE_LIST table_list;
- ulonglong copied;
- ulonglong deleted;
- THD *thd;
- HA_CREATE_INFO *create_info;
- Alter_info *alter_info;
- TABLE *table;
- KEY *key_info_buffer;
- const char *db;
- const char *table_name;
- uchar *pack_frm_data;
- enum thr_lock_type old_lock_type;
- uint key_count;
- uint db_options;
- size_t pack_frm_len;
- partition_info *part_info;
-} ALTER_PARTITION_PARAM_TYPE;
-
-void mem_alloc_error(size_t size);
-
-enum ddl_log_entry_code
-{
- /*
- DDL_LOG_EXECUTE_CODE:
- This is a code that indicates that this is a log entry to
- be executed, from this entry a linked list of log entries
- can be found and executed.
- DDL_LOG_ENTRY_CODE:
- An entry to be executed in a linked list from an execute log
- entry.
- DDL_IGNORE_LOG_ENTRY_CODE:
- An entry that is to be ignored
- */
- DDL_LOG_EXECUTE_CODE = 'e',
- DDL_LOG_ENTRY_CODE = 'l',
- DDL_IGNORE_LOG_ENTRY_CODE = 'i'
-};
-
-enum ddl_log_action_code
-{
- /*
- The type of action that a DDL_LOG_ENTRY_CODE entry is to
- perform.
- DDL_LOG_DELETE_ACTION:
- Delete an entity
- DDL_LOG_RENAME_ACTION:
- Rename an entity
- DDL_LOG_REPLACE_ACTION:
- Rename an entity after removing the previous entry with the
- new name, that is replace this entry.
- */
- DDL_LOG_DELETE_ACTION = 'd',
- DDL_LOG_RENAME_ACTION = 'r',
- DDL_LOG_REPLACE_ACTION = 's'
-};
-
-
-typedef struct st_ddl_log_entry
-{
- const char *name;
- const char *from_name;
- const char *handler_name;
- uint next_entry;
- uint entry_pos;
- enum ddl_log_entry_code entry_type;
- enum ddl_log_action_code action_type;
- /*
- Most actions have only one phase. REPLACE does however have two
- phases. The first phase removes the file with the new name if
- there was one there before and the second phase renames the
- old name to the new name.
- */
- char phase;
-} DDL_LOG_ENTRY;
-
-typedef struct st_ddl_log_memory_entry
-{
- uint entry_pos;
- struct st_ddl_log_memory_entry *next_log_entry;
- struct st_ddl_log_memory_entry *prev_log_entry;
- struct st_ddl_log_memory_entry *next_active_log_entry;
-} DDL_LOG_MEMORY_ENTRY;
-
-
-bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry,
- DDL_LOG_MEMORY_ENTRY **active_entry);
-bool write_execute_ddl_log_entry(uint first_entry,
- bool complete,
- DDL_LOG_MEMORY_ENTRY **active_entry);
-bool deactivate_ddl_log_entry(uint entry_no);
-void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry);
-bool sync_ddl_log();
-void release_ddl_log();
-void execute_ddl_log_recovery();
-bool execute_ddl_log_entry(THD *thd, uint first_entry);
-
-extern pthread_mutex_t LOCK_gdl;
-
-#define WFRM_WRITE_SHADOW 1
-#define WFRM_INSTALL_SHADOW 2
-#define WFRM_PACK_FRM 4
-#define WFRM_KEEP_SHARE 8
-bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags);
-int abort_and_upgrade_lock_and_close_table(ALTER_PARTITION_PARAM_TYPE *lpt);
-void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt);
-void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table);
-
-/* Functions to work with system tables. */
-bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
- Open_tables_state *backup);
-void close_system_tables(THD *thd, Open_tables_state *backup);
-TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table);
-
-TABLE *open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
- Open_tables_state *backup);
-void close_performance_schema_table(THD *thd, Open_tables_state *backup);
-
-bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock,
- bool wait_for_refresh, bool wait_for_placeholders);
-bool close_cached_connection_tables(THD *thd, bool wait_for_refresh,
- LEX_STRING *connect_string,
- bool have_lock = FALSE);
-void copy_field_from_tmp_record(Field *field,int offset);
-bool fill_record(THD *thd, Field **field, List<Item> &values,
- bool ignore_errors);
-bool fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
- List<Item> &values,
- bool ignore_errors,
- Table_triggers_list *triggers,
- enum trg_event_type event);
-bool fill_record_n_invoke_before_triggers(THD *thd, Field **field,
- List<Item> &values,
- bool ignore_errors,
- Table_triggers_list *triggers,
- enum trg_event_type event);
-OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild);
-
-inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table,
- const char *db_name,
- const char *table_name)
-{
- return find_table_in_list(table, &TABLE_LIST::next_global,
- db_name, table_name);
-}
-
-inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table,
- const char *db_name,
- const char *table_name)
-{
- return find_table_in_list(table, &TABLE_LIST::next_local,
- db_name, table_name);
-}
-
-
-/* sql_calc.cc */
-bool eval_const_cond(COND *cond);
-
-/* sql_load.cc */
-int mysql_load(THD *thd, sql_exchange *ex, TABLE_LIST *table_list,
- List<Item> &fields_vars, List<Item> &set_fields,
- List<Item> &set_values_list,
- enum enum_duplicates handle_duplicates, bool ignore,
- bool local_file);
-int write_record(THD *thd, TABLE *table, COPY_INFO *info);
-
-/* sql_manager.cc */
-extern bool volatile mqh_used;
-void start_handle_manager();
-void stop_handle_manager();
-bool mysql_manager_submit(void (*action)());
-
-
-/* sql_test.cc */
-#ifndef DBUG_OFF
-void print_where(COND *cond,const char *info, enum_query_type query_type);
-void print_cached_tables(void);
-void TEST_filesort(SORT_FIELD *sortorder,uint s_length);
-void print_plan(JOIN* join,uint idx, double record_count, double read_time,
- double current_read_time, const char *info);
-#endif
-void mysql_print_status();
-/* key.cc */
-int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field,
- uint *key_length, uint *keypart);
-void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, uint key_length);
-void key_restore(uchar *to_record, uchar *from_key, KEY *key_info,
- uint key_length);
-bool key_cmp_if_same(TABLE *form,const uchar *key,uint index,uint key_length);
-void key_unpack(String *to,TABLE *form,uint index);
-bool is_key_used(TABLE *table, uint idx, const MY_BITMAP *fields);
-int key_cmp(KEY_PART_INFO *key_part, const uchar *key, uint key_length);
-extern "C" int key_rec_cmp(void *key_info, uchar *a, uchar *b);
-
-bool init_errmessage(void);
-#endif /* MYSQL_SERVER */
-void sql_perror(const char *message);
-
-bool fn_format_relative_to_data_home(char * to, const char *name,
- const char *dir, const char *extension);
-/**
- Test a file path to determine if the path is compatible with the secure file
- path restriction.
-*/
-bool is_secure_file_path(char *path);
-
-#ifdef MYSQL_SERVER
-File open_binlog(IO_CACHE *log, const char *log_file_name,
- const char **errmsg);
-
-/* mysqld.cc */
-extern void MYSQLerror(const char*);
-void refresh_status(THD *thd);
-my_bool mysql_rm_tmp_tables(void);
-void handle_connection_in_main_thread(THD *thd);
-void create_thread_to_handle_connection(THD *thd);
-void unlink_thd(THD *thd);
-bool one_thread_per_connection_end(THD *thd, bool put_in_cache);
-void flush_thread_cache();
-
-/* item_func.cc */
-extern bool check_reserved_words(LEX_STRING *name);
-extern enum_field_types agg_field_type(Item **items, uint nitems);
-
-/* strfunc.cc */
-ulonglong find_set(TYPELIB *lib, const char *x, uint 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,
- const char *str, uint length, CHARSET_INFO *cs,
- char **err_pos, uint *err_len, bool *set_warning);
-uint find_type(const TYPELIB *lib, const char *find, uint length,
- bool part_match);
-uint find_type2(const TYPELIB *lib, const char *find, uint length,
- CHARSET_INFO *cs);
-void unhex_type2(TYPELIB *lib);
-uint check_word(TYPELIB *lib, const char *val, const char *end,
- const char **end_of_word);
-int find_string_in_array(LEX_STRING * const haystack, LEX_STRING * const needle,
- CHARSET_INFO * const cs);
-
-
-bool is_keyword(const char *name, uint len);
-
-#define MY_DB_OPT_FILE "db.opt"
-bool my_database_names_init(void);
-void my_database_names_free(void);
-bool check_db_dir_existence(const char *db_name);
-bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
-bool load_db_opt_by_name(THD *thd, const char *db_name,
- HA_CREATE_INFO *db_create_info);
-CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name);
-bool my_dbopt_init(void);
-void my_dbopt_cleanup(void);
-extern int creating_database; // How many database locks are made
-extern int creating_table; // How many mysql_create_table() are running
-
-/*
- External variables
-*/
-
-extern time_t server_start_time, flush_status_time;
-#endif /* MYSQL_SERVER */
-#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern uint mysql_data_home_len;
-
-extern MYSQL_PLUGIN_IMPORT char *mysql_data_home;
-extern char server_version[SERVER_VERSION_LENGTH];
-extern MYSQL_PLUGIN_IMPORT char mysql_real_data_home[];
-extern char mysql_unpacked_real_data_home[];
-
-extern CHARSET_INFO *character_set_filesystem;
-#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
-#ifdef MYSQL_SERVER
-extern char *opt_mysql_tmpdir, mysql_charsets_dir[],
- def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
-extern int mysql_unpacked_real_data_home_len;
-#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list))
-extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list;
-extern const LEX_STRING command_name[];
-
-extern const char *first_keyword, *delayed_user, *binary_keyword;
-extern MYSQL_PLUGIN_IMPORT const char *my_localhost;
-extern MYSQL_PLUGIN_IMPORT const char **errmesg; /* Error messages */
-
-extern const char *myisam_recover_options_str;
-extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond;
-extern const char * const TRG_EXT;
-extern const char * const TRN_EXT;
-extern Eq_creator eq_creator;
-extern Ne_creator ne_creator;
-extern Gt_creator gt_creator;
-extern Lt_creator lt_creator;
-extern Ge_creator ge_creator;
-extern Le_creator le_creator;
-extern char language[FN_REFLEN];
-#endif /* MYSQL_SERVER */
-#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern MYSQL_PLUGIN_IMPORT char reg_ext[FN_EXTLEN];
-extern MYSQL_PLUGIN_IMPORT uint reg_ext_length;
-#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
-#ifdef MYSQL_SERVER
-extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
-extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
-extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
-extern ulonglong log_10_int[20];
-extern ulonglong keybuff_size;
-extern ulonglong thd_startup_options;
-extern ulong thread_id;
-extern ulong binlog_cache_use, binlog_cache_disk_use;
-extern ulong aborted_threads,aborted_connects;
-extern ulong delayed_insert_timeout;
-extern ulong delayed_insert_limit, delayed_queue_size;
-extern ulong delayed_insert_threads, delayed_insert_writes;
-extern ulong delayed_rows_in_use,delayed_insert_errors;
-extern ulong slave_open_temp_tables;
-extern ulong query_cache_size, query_cache_min_res_unit;
-extern ulong slow_launch_threads, slow_launch_time;
-extern ulong table_cache_size, table_def_size;
-extern MYSQL_PLUGIN_IMPORT ulong max_connections;
-extern ulong max_connect_errors, connect_timeout;
-extern ulong slave_net_timeout, slave_trans_retries;
-extern uint max_user_connections;
-extern ulong what_to_log,flush_time;
-extern ulong query_buff_size;
-extern ulong max_prepared_stmt_count, prepared_stmt_count;
-extern ulong binlog_cache_size, open_files_limit;
-extern ulonglong max_binlog_cache_size;
-extern ulong max_binlog_size, max_relay_log_size;
-extern ulong opt_binlog_rows_event_max_size;
-extern ulong rpl_recovery_rank, thread_cache_size, thread_pool_size;
-extern ulong back_log;
-#endif /* MYSQL_SERVER */
-#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern ulong MYSQL_PLUGIN_IMPORT specialflag;
-#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
-#ifdef MYSQL_SERVER
-extern ulong current_pid;
-extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter;
-extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size;
-extern ulong tc_log_page_waits;
-extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb;
-extern uint test_flags,select_errors,ha_open_options;
-extern uint protocol_version, mysqld_port, dropping_tables;
-extern uint delay_key_write_options;
-#endif /* MYSQL_SERVER */
-#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern MYSQL_PLUGIN_IMPORT uint lower_case_table_names;
-#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
-#ifdef MYSQL_SERVER
-extern bool opt_endinfo, using_udf_functions;
-extern my_bool locked_in_memory;
-extern bool opt_using_transactions;
-#endif /* MYSQL_SERVER */
-#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern MYSQL_PLUGIN_IMPORT bool mysqld_embedded;
-#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
-#ifdef MYSQL_SERVER
-extern bool opt_large_files, server_id_supplied;
-extern bool opt_update_log, opt_bin_log, opt_error_log;
-extern my_bool opt_log, opt_slow_log;
-extern ulong log_output_options;
-extern my_bool opt_log_queries_not_using_indexes;
-extern bool opt_disable_networking, opt_skip_show_db;
-extern bool opt_skip_name_resolve;
-extern bool opt_ignore_builtin_innodb;
-extern my_bool opt_character_set_client_handshake;
-extern bool volatile abort_loop, shutdown_in_progress;
-extern bool in_bootstrap;
-extern uint volatile thread_count, thread_running, global_read_lock;
-extern uint connection_count;
-extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types;
-extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap;
-extern my_bool opt_slave_compressed_protocol, use_temp_pool;
-extern ulong slave_exec_mode_options;
-extern my_bool opt_readonly, lower_case_file_system;
-extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
-extern my_bool opt_secure_auth;
-extern char* opt_secure_file_priv;
-extern my_bool opt_log_slow_admin_statements, opt_log_slow_slave_statements;
-extern my_bool sp_automatic_privileges, opt_noacl;
-extern my_bool opt_old_style_user_limits, trust_function_creators;
-extern uint opt_crash_binlog_innodb;
-extern char *shared_memory_base_name, *mysqld_unix_port;
-extern my_bool opt_enable_shared_memory;
-extern char *default_tz_name;
-#endif /* MYSQL_SERVER */
-#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern my_bool opt_large_pages;
-extern uint opt_large_page_size;
-#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
-#ifdef MYSQL_SERVER
-extern char *opt_logname, *opt_slow_logname;
-extern const char *log_output_str;
-
-extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
-extern LOGGER logger;
-extern TABLE_LIST general_log, slow_log;
-extern FILE *bootstrap_file;
-extern int bootstrap_error;
-extern FILE *stderror_file;
-extern pthread_key(MEM_ROOT**,THR_MALLOC);
-extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_lock_db,
- LOCK_mapped_file,LOCK_user_locks, LOCK_status,
- LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
- LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
- LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock,
- LOCK_global_system_variables, LOCK_user_conn,
- LOCK_prepared_stmt_count,
- LOCK_bytes_sent, LOCK_bytes_received, LOCK_connection_count;
-extern MYSQL_PLUGIN_IMPORT pthread_mutex_t LOCK_thread_count;
-#ifdef HAVE_OPENSSL
-extern pthread_mutex_t LOCK_des_key_file;
-#endif
-extern pthread_mutex_t LOCK_server_started;
-extern pthread_cond_t COND_server_started;
-extern int mysqld_server_started;
-extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
-extern rw_lock_t LOCK_system_variables_hash;
-extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
-extern pthread_cond_t COND_global_read_lock;
-extern pthread_attr_t connection_attrib;
-extern I_List<THD> threads;
-extern I_List<NAMED_LIST> key_caches;
-extern MY_BITMAP temp_pool;
-extern String my_empty_string;
-extern const String my_null_string;
-extern SHOW_VAR status_vars[];
-#endif /* MYSQL_SERVER */
-#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern MYSQL_PLUGIN_IMPORT struct system_variables global_system_variables;
-#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
-#ifdef MYSQL_SERVER
-extern struct system_variables max_system_variables;
-extern struct system_status_var global_status_var;
-extern struct rand_struct sql_rand;
-
-extern const char *opt_date_time_formats[];
-extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
-
-extern String null_string;
-extern HASH open_cache, lock_db_cache;
-extern TABLE *unused_tables;
-extern const char* any_db;
-extern struct my_option my_long_options[];
-extern const LEX_STRING view_type;
-extern scheduler_functions thread_scheduler;
-extern TYPELIB thread_handling_typelib;
-extern uint8 uc_update_queries[SQLCOM_END+1];
-extern uint sql_command_flags[];
-extern TYPELIB log_output_typelib;
-
-/* optional things, have_* variables */
-extern SHOW_COMP_OPTION have_community_features;
-
-extern handlerton *partition_hton;
-extern handlerton *myisam_hton;
-extern handlerton *heap_hton;
-
-extern SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen;
-extern SHOW_COMP_OPTION have_query_cache;
-extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
-extern SHOW_COMP_OPTION have_crypt;
-extern SHOW_COMP_OPTION have_compress;
-
-extern int orig_argc;
-extern char **orig_argv;
-extern const char *load_default_groups[];
-
-#ifndef __WIN__
-extern pthread_t signal_thread;
-#endif
-
-#ifdef HAVE_OPENSSL
-extern struct st_VioSSLFd * ssl_acceptor_fd;
-#endif /* HAVE_OPENSSL */
-
-MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
- uint flags, bool *need_reopen);
-/* mysql_lock_tables() and open_table() flags bits */
-#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
-#define MYSQL_LOCK_IGNORE_FLUSH 0x0002
-#define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004
-#define MYSQL_OPEN_TEMPORARY_ONLY 0x0008
-#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0010
-#define MYSQL_LOCK_PERF_SCHEMA 0x0020
-
-void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
-void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
-void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
-void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
- bool always_unlock);
-void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock);
-void mysql_lock_downgrade_write(THD *thd, TABLE *table,
- thr_lock_type new_lock_type);
-bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
-MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
-TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
- TABLE_LIST *haystack);
-bool lock_global_read_lock(THD *thd);
-void unlock_global_read_lock(THD *thd);
-bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
- bool is_not_commit);
-void start_waiting_global_read_lock(THD *thd);
-bool make_global_read_lock_block_commit(THD *thd);
-bool set_protect_against_global_read_lock(void);
-void unset_protect_against_global_read_lock(void);
-void broadcast_refresh(void);
-
-/* Lock based on name */
-int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list);
-int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use);
-void unlock_table_name(THD *thd, TABLE_LIST *table_list);
-bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list);
-bool lock_table_names(THD *thd, TABLE_LIST *table_list);
-void unlock_table_names(THD *thd, TABLE_LIST *table_list,
- TABLE_LIST *last_table);
-bool lock_table_names_exclusively(THD *thd, TABLE_LIST *table_list);
-bool is_table_name_exclusively_locked_by_this_thread(THD *thd,
- TABLE_LIST *table_list);
-bool is_table_name_exclusively_locked_by_this_thread(THD *thd, uchar *key,
- int key_length);
-
-
-/* old unireg functions */
-
-void unireg_init(ulong options);
-void unireg_end(void) __attribute__((noreturn));
-bool mysql_create_frm(THD *thd, const char *file_name,
- const char *db, const char *table,
- HA_CREATE_INFO *create_info,
- List<Create_field> &create_field,
- uint key_count,KEY *key_info,handler *db_type);
-int rea_create_table(THD *thd, const char *path,
- const char *db, const char *table_name,
- HA_CREATE_INFO *create_info,
- List<Create_field> &create_field,
- uint key_count,KEY *key_info,
- handler *file);
-int format_number(uint inputflag,uint max_length,char * pos,uint length,
- char * *errpos);
-
-/* table.cc */
-TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
- uint key_length);
-void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
- uint key_length,
- const char *table_name, const char *path);
-void free_table_share(TABLE_SHARE *share);
-int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags);
-void open_table_error(TABLE_SHARE *share, int error, int db_errno, int errarg);
-int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
- uint db_stat, uint prgflag, uint ha_open_flags,
- TABLE *outparam, bool is_create_table);
-int readfrm(const char *name, uchar **data, size_t *length);
-int writefrm(const char* name, const uchar* data, size_t len);
-int closefrm(TABLE *table, bool free_share);
-int read_string(File file, uchar* *to, size_t length);
-void free_blobs(TABLE *table);
-void free_field_buffers_larger_than(TABLE *table, uint32 size);
-int set_zone(int nr,int min_zone,int max_zone);
-ulong convert_period_to_month(ulong period);
-ulong convert_month_to_period(ulong month);
-void get_date_from_daynr(long daynr,uint *year, uint *month,
- uint *day);
-my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
-bool str_to_time_with_warn(const char *str,uint length,MYSQL_TIME *l_time);
-timestamp_type str_to_datetime_with_warn(const char *str, uint length,
- MYSQL_TIME *l_time, uint flags);
-void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
-void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
-
-void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
- const char *str_val,
- uint str_length, timestamp_type time_type,
- const char *field_name);
-
-bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval);
-bool calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign,
- longlong *seconds_out, long *microseconds_out);
-
-extern LEX_STRING interval_type_to_name[];
-
-extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
- const char *format_str,
- uint format_length);
-extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd,
- DATE_TIME_FORMAT *format);
-const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
- timestamp_type type);
-extern bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
- timestamp_type type, String *str);
-void make_datetime(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
- String *str);
-void make_date(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
- String *str);
-void make_time(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
- String *str);
-int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b);
-longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
- Item *warn_item, bool *is_null);
-
-int test_if_number(char *str,int *res,bool allow_wildcards);
-void change_byte(uchar *,uint,char,char);
-void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
- SQL_SELECT *select, int use_record_cache,
- bool print_errors, bool disable_rr_cache);
-void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
- bool print_error, uint idx);
-void end_read_record(READ_RECORD *info);
-ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
- uint s_length, SQL_SELECT *select,
- ha_rows max_rows, bool sort_positions,
- ha_rows *examined_rows);
-void filesort_free_buffers(TABLE *table, bool full);
-void change_double_for_sort(double nr,uchar *to);
-double my_double_round(double value, longlong dec, bool dec_unsigned,
- bool truncate);
-int get_quick_record(SQL_SELECT *select);
-
-int calc_weekday(long daynr,bool sunday_first_day_of_week);
-uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
-void find_date(char *pos,uint *vek,uint flag);
-TYPELIB *convert_strings_to_array_type(char * *typelibs, char * *end);
-TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings);
-ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
-ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
- const char *newname);
-ulong next_io_size(ulong pos);
-void append_unescaped(String *res, const char *pos, uint length);
-int create_frm(THD *thd, const char *name, const char *db, const char *table,
- uint reclength, uchar *fileinfo,
- HA_CREATE_INFO *create_info, uint keys);
-void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form);
-int rename_file_ext(const char * from,const char * to,const char * ext);
-bool check_db_name(LEX_STRING *db);
-bool check_column_name(const char *name);
-bool check_table_name(const char *name, uint length, bool check_for_path_chars);
-char *get_field(MEM_ROOT *mem, Field *field);
-bool get_field(MEM_ROOT *mem, Field *field, class String *res);
-int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
-char *fn_rext(char *name);
-
-/* Conversion functions */
-#endif /* MYSQL_SERVER */
-#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-uint strconvert(CHARSET_INFO *from_cs, const char *from,
- CHARSET_INFO *to_cs, char *to, uint to_length, uint *errors);
-/* depends on errmsg.txt Database `db`, Table `t` ... */
-#define EXPLAIN_FILENAME_MAX_EXTRA_LENGTH 63
-enum enum_explain_filename_mode
-{
- EXPLAIN_ALL_VERBOSE= 0,
- EXPLAIN_PARTITIONS_VERBOSE,
- EXPLAIN_PARTITIONS_AS_COMMENT
-};
-uint explain_filename(THD* thd, const char *from, char *to, uint to_length,
- enum_explain_filename_mode explain_mode);
-uint filename_to_tablename(const char *from, char *to, uint to_length);
-uint tablename_to_filename(const char *from, char *to, uint to_length);
-uint check_n_cut_mysql50_prefix(const char *from, char *to, uint to_length);
-bool check_mysql50_prefix(const char *name);
-#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
-#ifdef MYSQL_SERVER
-uint build_table_filename(char *buff, size_t bufflen, const char *db,
- const char *table, const char *ext, uint flags);
-const char *get_canonical_filename(handler *file, const char *path,
- char *tmp_path);
-
-#define MYSQL50_TABLE_NAME_PREFIX "#mysql50#"
-#define MYSQL50_TABLE_NAME_PREFIX_LENGTH 9
-
-uint build_table_shadow_filename(char *buff, size_t bufflen,
- ALTER_PARTITION_PARAM_TYPE *lpt);
-/* Flags for conversion functions. */
-#define FN_FROM_IS_TMP (1 << 0)
-#define FN_TO_IS_TMP (1 << 1)
-#define FN_IS_TMP (FN_FROM_IS_TMP | FN_TO_IS_TMP)
-#define NO_FRM_RENAME (1 << 2)
-#define FRM_ONLY (1 << 3)
-
-/* from hostname.cc */
-struct in_addr;
-char * ip_to_hostname(struct in_addr *in,uint *errors);
-void inc_host_errors(struct in_addr *in);
-void reset_host_errors(struct in_addr *in);
-bool hostname_cache_init();
-void hostname_cache_free();
-void hostname_cache_refresh(void);
-
-/* sql_cache.cc */
-extern bool sql_cache_init();
-extern void sql_cache_free();
-extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
-
-/* item_func.cc */
-Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
- LEX_STRING component);
-int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
- LEX_STRING &name, user_var_entry **out_entry);
-/* log.cc */
-bool flush_error_log(void);
-
-/* sql_list.cc */
-void free_list(I_List <i_string_pair> *list);
-void free_list(I_List <i_string> *list);
-
-/* sql_yacc.cc */
-#ifndef DBUG_OFF
-extern void turn_parser_debug_on();
-#endif
-
-/* frm_crypt.cc */
-#ifdef HAVE_CRYPTED_FRM
-SQL_CRYPT *get_crypt_for_frm(void);
-#endif
-
-/* password.c */
-extern "C" void my_make_scrambled_password_323(char *to, const char *password,
- size_t pass_len);
-extern "C" void my_make_scrambled_password(char *to, const char *password,
- size_t pass_len);
-
-#include "sql_view.h"
-
-/* Some inline functions for more speed */
-
-inline bool add_item_to_list(THD *thd, Item *item)
-{
- return thd->lex->current_select->add_item_to_list(thd, item);
-}
-
-inline bool add_value_to_list(THD *thd, Item *value)
-{
- return thd->lex->value_list.push_back(value);
-}
-
-inline bool add_order_to_list(THD *thd, Item *item, bool asc)
-{
- return thd->lex->current_select->add_order_to_list(thd, item, asc);
-}
-
-inline bool add_group_to_list(THD *thd, Item *item, bool asc)
-{
- return thd->lex->current_select->add_group_to_list(thd, item, asc);
-}
-
-inline void mark_as_null_row(TABLE *table)
-{
- table->null_row=1;
- table->status|=STATUS_NULL_ROW;
- bfill(table->null_flags,table->s->null_bytes,255);
-}
-
-inline void table_case_convert(char * name, uint length)
-{
- if (lower_case_table_names)
- files_charset_info->cset->casedn(files_charset_info,
- name, length, name, length);
-}
-
-inline const char *table_case_name(HA_CREATE_INFO *info, const char *name)
-{
- return ((lower_case_table_names == 2 && info->alias) ? info->alias : name);
-}
-
-inline ulong sql_rnd_with_mutex()
-{
- pthread_mutex_lock(&LOCK_thread_count);
- ulong tmp=(ulong) (my_rnd(&sql_rand) * 0xffffffff); /* make all bits random */
- pthread_mutex_unlock(&LOCK_thread_count);
- return tmp;
-}
-
-Comp_creator *comp_eq_creator(bool invert);
-Comp_creator *comp_ge_creator(bool invert);
-Comp_creator *comp_gt_creator(bool invert);
-Comp_creator *comp_le_creator(bool invert);
-Comp_creator *comp_lt_creator(bool invert);
-Comp_creator *comp_ne_creator(bool invert);
-
-Item * all_any_subquery_creator(Item *left_expr,
- chooser_compare_func_creator cmp,
- bool all,
- SELECT_LEX *select_lex);
-
-/**
- clean/setup table fields and map.
-
- @param table TABLE structure pointer (which should be setup)
- @param table_list TABLE_LIST structure pointer (owner of TABLE)
- @param tablenr table number
-*/
-
-
-inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
-{
- table->used_fields= 0;
- table->const_table= 0;
- table->null_row= 0;
- table->status= STATUS_NO_RECORD;
- table->maybe_null= table_list->outer_join;
- TABLE_LIST *embedding= table_list->embedding;
- while (!table->maybe_null && embedding)
- {
- table->maybe_null= embedding->outer_join;
- embedding= embedding->embedding;
- }
- table->tablenr= tablenr;
- table->map= (table_map) 1 << tablenr;
- table->force_index= table_list->force_index;
- table->force_index_order= table->force_index_group= 0;
- table->covering_keys= table->s->keys_for_keyread;
- table->merge_keys.clear_all();
-}
-
-
-/**
- convert a hex digit into number.
-*/
-
-inline int hexchar_to_int(char c)
-{
- if (c <= '9' && c >= '0')
- return c-'0';
- c|=32;
- if (c <= 'f' && c >= 'a')
- return c-'a'+10;
- return -1;
-}
-
-/**
- return true if the table was created explicitly.
-*/
-inline bool is_user_table(TABLE * table)
-{
- const char *name= table->s->table_name.str;
- return strncmp(name, tmp_file_prefix, tmp_file_prefix_length);
-}
-
-/*
- Some functions that are different in the embedded library and the normal
- server
-*/
-
-#ifndef EMBEDDED_LIBRARY
-extern "C" void unireg_abort(int exit_code) __attribute__((noreturn));
-void kill_delayed_threads(void);
-bool check_stack_overrun(THD *thd, long margin, uchar *dummy);
-#else
-extern "C" void unireg_clear(int exit_code);
-#define unireg_abort(exit_code) do { unireg_clear(exit_code); DBUG_RETURN(exit_code); } while(0)
-inline void kill_delayed_threads(void) {}
-#define check_stack_overrun(A, B, C) 0
-#endif
-
-/* Used by handlers to store things in schema tables */
-#define IS_FILES_FILE_ID 0
-#define IS_FILES_FILE_NAME 1
-#define IS_FILES_FILE_TYPE 2
-#define IS_FILES_TABLESPACE_NAME 3
-#define IS_FILES_TABLE_CATALOG 4
-#define IS_FILES_TABLE_SCHEMA 5
-#define IS_FILES_TABLE_NAME 6
-#define IS_FILES_LOGFILE_GROUP_NAME 7
-#define IS_FILES_LOGFILE_GROUP_NUMBER 8
-#define IS_FILES_ENGINE 9
-#define IS_FILES_FULLTEXT_KEYS 10
-#define IS_FILES_DELETED_ROWS 11
-#define IS_FILES_UPDATE_COUNT 12
-#define IS_FILES_FREE_EXTENTS 13
-#define IS_FILES_TOTAL_EXTENTS 14
-#define IS_FILES_EXTENT_SIZE 15
-#define IS_FILES_INITIAL_SIZE 16
-#define IS_FILES_MAXIMUM_SIZE 17
-#define IS_FILES_AUTOEXTEND_SIZE 18
-#define IS_FILES_CREATION_TIME 19
-#define IS_FILES_LAST_UPDATE_TIME 20
-#define IS_FILES_LAST_ACCESS_TIME 21
-#define IS_FILES_RECOVER_TIME 22
-#define IS_FILES_TRANSACTION_COUNTER 23
-#define IS_FILES_VERSION 24
-#define IS_FILES_ROW_FORMAT 25
-#define IS_FILES_TABLE_ROWS 26
-#define IS_FILES_AVG_ROW_LENGTH 27
-#define IS_FILES_DATA_LENGTH 28
-#define IS_FILES_MAX_DATA_LENGTH 29
-#define IS_FILES_INDEX_LENGTH 30
-#define IS_FILES_DATA_FREE 31
-#define IS_FILES_CREATE_TIME 32
-#define IS_FILES_UPDATE_TIME 33
-#define IS_FILES_CHECK_TIME 34
-#define IS_FILES_CHECKSUM 35
-#define IS_FILES_STATUS 36
-#define IS_FILES_EXTRA 37
-void init_fill_schema_files_row(TABLE* table);
-bool schema_table_store_record(THD *thd, TABLE *table);
-
-/* sql/item_create.cc */
-int item_create_init();
-void item_create_cleanup();
-
-bool show_create_trigger(THD *thd, const sp_name *trg_name);
-
-inline void lex_string_set(LEX_STRING *lex_str, const char *c_str)
-{
- lex_str->str= (char *) c_str;
- lex_str->length= strlen(c_str);
-}
-
-bool load_charset(MEM_ROOT *mem_root,
- Field *field,
- CHARSET_INFO *dflt_cs,
- CHARSET_INFO **cs);
-
-bool load_collation(MEM_ROOT *mem_root,
- Field *field,
- CHARSET_INFO *dflt_cl,
- CHARSET_INFO **cl);
-
-#endif /* MYSQL_SERVER */
-extern "C" int test_if_data_home_dir(const char *dir);
-
-#endif /* MYSQL_CLIENT */
-
-#endif /* MYSQL_PRIV_H */
diff --git a/sql/mysql_priv.h.pp b/sql/mysql_priv.h.pp
deleted file mode 100644
index d874a2591d1..00000000000
--- a/sql/mysql_priv.h.pp
+++ /dev/null
@@ -1,10977 +0,0 @@
-#include <my_global.h>
-#include <my_config.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <math.h>
-#include <limits.h>
-#include <float.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/timeb.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-#include <alloca.h>
-#include <errno.h>
-#include <crypt.h>
-#include <assert.h>
-#include <my_attribute.h>
-int __cxa_pure_virtual () __attribute__ ((weak));
-#include <my_dbug.h>
-struct _db_code_state_;
-extern int _db_keyword_(struct _db_code_state_ *cs, const char *keyword);
-extern int _db_strict_keyword_(const char *keyword);
-extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len);
-extern int _db_explain_init_(char *buf, size_t len);
-extern void _db_setjmp_(void);
-extern void _db_longjmp_(void);
-extern void _db_process_(const char *name);
-extern void _db_push_(const char *control);
-extern void _db_pop_(void);
-extern void _db_set_(struct _db_code_state_ *cs, const char *control);
-extern void _db_set_init_(const char *control);
-extern void _db_enter_(const char *_func_,const char *_file_,uint _line_,
- const char **_sfunc_,const char **_sfile_,
- uint *_slevel_, char ***);
-extern void _db_return_(uint _line_,const char **_sfunc_,const char **_sfile_,
- uint *_slevel_);
-extern void _db_pargs_(uint _line_,const char *keyword);
-extern void _db_doprnt_ (const char *format,...)
- __attribute__((format(printf, 1, 2)));
-extern void _db_dump_(uint _line_,const char *keyword,
- const unsigned char *memory, size_t length);
-extern void _db_end_(void);
-extern void _db_lock_file_(void);
-extern void _db_unlock_file_(void);
-extern FILE *_db_fp_(void);
-typedef int File;
-typedef int my_socket;
-typedef void (*sig_return)();
-typedef char pchar;
-typedef char puchar;
-typedef char pbool;
-typedef short pshort;
-typedef float pfloat;
-typedef int (*qsort_cmp)(const void *,const void *);
-typedef int (*qsort_cmp2)(void*, const void *,const void *);
-#include <sys/socket.h>
-typedef socklen_t size_socket;
-typedef long my_ptrdiff_t;
-typedef unsigned char uchar;
-typedef signed char int8;
-typedef unsigned char uint8;
-typedef short int16;
-typedef unsigned short uint16;
-typedef int int32;
-typedef unsigned int uint32;
-typedef unsigned long long int ulonglong;
-typedef long long int longlong;
-typedef longlong int64;
-typedef ulonglong uint64;
-typedef unsigned long long my_ulonglong;
-typedef int intptr;
-typedef ulonglong my_off_t;
-typedef off_t os_off_t;
-typedef uint8 int7;
-typedef short int15;
-typedef int myf;
-typedef char my_bool;
-typedef char bool;
-typedef union {
- double v;
- long m[2];
-} doubleget_union;
-#include <dlfcn.h>
-#include <mysql_version.h>
-#include <mysql_embed.h>
-#include <my_sys.h>
-#include <my_pthread.h>
-#include <pthread.h>
-#include <sched.h>
-extern int my_pthread_getprio(pthread_t thread_id);
-typedef void *(* pthread_handler)(void *);
-extern void my_pthread_setprio(pthread_t thread_id,int prior);
-extern void my_pthread_attr_setprio(pthread_attr_t *attr, int priority);
-typedef struct st_safe_mutex_t
-{
- pthread_mutex_t global,mutex;
- const char *file;
- uint line,count;
- pthread_t thread;
-} safe_mutex_t;
-int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr,
- const char *file, uint line);
-int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line);
-int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line);
-int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line);
-int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file,
- uint line);
-int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
- struct timespec *abstime, const char *file, uint line);
-void safe_mutex_global_init(void);
-void safe_mutex_end(FILE *file);
-typedef ulong my_thread_id;
-extern my_bool my_thread_global_init(void);
-extern void my_thread_global_end(void);
-extern my_bool my_thread_init(void);
-extern void my_thread_end(void);
-extern const char *my_thread_name(void);
-extern my_thread_id my_thread_dbug_id(void);
-extern int pthread_no_free(void *);
-extern int pthread_dummy(int);
-struct st_my_thread_var
-{
- int thr_errno;
- pthread_cond_t suspend;
- pthread_mutex_t mutex;
- pthread_mutex_t * volatile current_mutex;
- pthread_cond_t * volatile current_cond;
- pthread_t pthread_self;
- my_thread_id id;
- int cmp_length;
- int volatile abort;
- my_bool init;
- struct st_my_thread_var *next,**prev;
- void *opt_info;
- void *dbug;
- char name[10 +1];
-};
-extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const));
-extern uint my_thread_end_wait_time;
-extern uint thd_lib_detected;
-#include <m_ctype.h>
-#include <my_attribute.h>
-typedef struct unicase_info_st
-{
- uint16 toupper;
- uint16 tolower;
- uint16 sort;
-} MY_UNICASE_INFO;
-extern MY_UNICASE_INFO *my_unicase_default[256];
-extern MY_UNICASE_INFO *my_unicase_turkish[256];
-typedef struct uni_ctype_st
-{
- uchar pctype;
- uchar *ctype;
-} MY_UNI_CTYPE;
-extern MY_UNI_CTYPE my_uni_ctype[256];
-typedef struct my_uni_idx_st
-{
- uint16 from;
- uint16 to;
- uchar *tab;
-} MY_UNI_IDX;
-typedef struct
-{
- uint beg;
- uint end;
- uint mb_len;
-} my_match_t;
-enum my_lex_states
-{
- MY_LEX_START, MY_LEX_CHAR, MY_LEX_IDENT,
- MY_LEX_IDENT_SEP, MY_LEX_IDENT_START,
- MY_LEX_REAL, MY_LEX_HEX_NUMBER, MY_LEX_BIN_NUMBER,
- MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END,
- MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL,
- MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE,
- MY_LEX_LONG_COMMENT, MY_LEX_END_LONG_COMMENT, MY_LEX_SEMICOLON,
- MY_LEX_SET_VAR, MY_LEX_USER_END, MY_LEX_HOSTNAME, MY_LEX_SKIP,
- MY_LEX_USER_VARIABLE_DELIMITER, MY_LEX_SYSTEM_VAR,
- MY_LEX_IDENT_OR_KEYWORD,
- MY_LEX_IDENT_OR_HEX, MY_LEX_IDENT_OR_BIN, MY_LEX_IDENT_OR_NCHAR,
- MY_LEX_STRING_OR_DELIMITER
-};
-struct charset_info_st;
-typedef struct my_collation_handler_st
-{
- my_bool (*init)(struct charset_info_st *, void *(*alloc)(size_t));
- int (*strnncoll)(struct charset_info_st *,
- const uchar *, size_t, const uchar *, size_t, my_bool);
- int (*strnncollsp)(struct charset_info_st *,
- const uchar *, size_t, const uchar *, size_t,
- my_bool diff_if_only_endspace_difference);
- size_t (*strnxfrm)(struct charset_info_st *,
- uchar *, size_t, const uchar *, size_t);
- size_t (*strnxfrmlen)(struct charset_info_st *, size_t);
- my_bool (*like_range)(struct charset_info_st *,
- const char *s, size_t s_length,
- pchar w_prefix, pchar w_one, pchar w_many,
- size_t res_length,
- char *min_str, char *max_str,
- size_t *min_len, size_t *max_len);
- int (*wildcmp)(struct charset_info_st *,
- const char *str,const char *str_end,
- const char *wildstr,const char *wildend,
- int escape,int w_one, int w_many);
- int (*strcasecmp)(struct charset_info_st *, const char *, const char *);
- uint (*instr)(struct charset_info_st *,
- const char *b, size_t b_length,
- const char *s, size_t s_length,
- my_match_t *match, uint nmatch);
- void (*hash_sort)(struct charset_info_st *cs, const uchar *key, size_t len,
- ulong *nr1, ulong *nr2);
- my_bool (*propagate)(struct charset_info_st *cs, const uchar *str, size_t len);
-} MY_COLLATION_HANDLER;
-extern MY_COLLATION_HANDLER my_collation_mb_bin_handler;
-extern MY_COLLATION_HANDLER my_collation_8bit_bin_handler;
-extern MY_COLLATION_HANDLER my_collation_8bit_simple_ci_handler;
-extern MY_COLLATION_HANDLER my_collation_ucs2_uca_handler;
-typedef int (*my_charset_conv_mb_wc)(struct charset_info_st *, ulong *,
- const uchar *, const uchar *);
-typedef int (*my_charset_conv_wc_mb)(struct charset_info_st *, ulong,
- uchar *, uchar *);
-typedef size_t (*my_charset_conv_case)(struct charset_info_st *,
- char *, size_t, char *, size_t);
-typedef struct my_charset_handler_st
-{
- my_bool (*init)(struct charset_info_st *, void *(*alloc)(size_t));
- uint (*ismbchar)(struct charset_info_st *, const char *, const char *);
- uint (*mbcharlen)(struct charset_info_st *, uint c);
- size_t (*numchars)(struct charset_info_st *, const char *b, const char *e);
- size_t (*charpos)(struct charset_info_st *, const char *b, const char *e,
- size_t pos);
- size_t (*well_formed_len)(struct charset_info_st *,
- const char *b,const char *e,
- size_t nchars, int *error);
- size_t (*lengthsp)(struct charset_info_st *, const char *ptr, size_t length);
- size_t (*numcells)(struct charset_info_st *, const char *b, const char *e);
- my_charset_conv_mb_wc mb_wc;
- my_charset_conv_wc_mb wc_mb;
- int (*ctype)(struct charset_info_st *cs, int *ctype,
- const uchar *s, const uchar *e);
- size_t (*caseup_str)(struct charset_info_st *, char *);
- size_t (*casedn_str)(struct charset_info_st *, char *);
- my_charset_conv_case caseup;
- my_charset_conv_case casedn;
- size_t (*snprintf)(struct charset_info_st *, char *to, size_t n,
- const char *fmt,
- ...) __attribute__((format(printf, 4, 5)));
- size_t (*long10_to_str)(struct charset_info_st *, char *to, size_t n,
- int radix, long int val);
- size_t (*longlong10_to_str)(struct charset_info_st *, char *to, size_t n,
- int radix, longlong val);
- void (*fill)(struct charset_info_st *, char *to, size_t len, int fill);
- long (*strntol)(struct charset_info_st *, const char *s, size_t l,
- int base, char **e, int *err);
- ulong (*strntoul)(struct charset_info_st *, const char *s, size_t l,
- int base, char **e, int *err);
- longlong (*strntoll)(struct charset_info_st *, const char *s, size_t l,
- int base, char **e, int *err);
- ulonglong (*strntoull)(struct charset_info_st *, const char *s, size_t l,
- int base, char **e, int *err);
- double (*strntod)(struct charset_info_st *, char *s, size_t l, char **e,
- int *err);
- longlong (*strtoll10)(struct charset_info_st *cs,
- const char *nptr, char **endptr, int *error);
- ulonglong (*strntoull10rnd)(struct charset_info_st *cs,
- const char *str, size_t length,
- int unsigned_fl,
- char **endptr, int *error);
- size_t (*scan)(struct charset_info_st *, const char *b, const char *e,
- int sq);
-} MY_CHARSET_HANDLER;
-extern MY_CHARSET_HANDLER my_charset_8bit_handler;
-extern MY_CHARSET_HANDLER my_charset_ucs2_handler;
-typedef struct charset_info_st
-{
- uint number;
- uint primary_number;
- uint binary_number;
- uint state;
- const char *csname;
- const char *name;
- const char *comment;
- const char *tailoring;
- uchar *ctype;
- uchar *to_lower;
- uchar *to_upper;
- uchar *sort_order;
- uint16 *contractions;
- uint16 **sort_order_big;
- uint16 *tab_to_uni;
- MY_UNI_IDX *tab_from_uni;
- MY_UNICASE_INFO **caseinfo;
- uchar *state_map;
- uchar *ident_map;
- uint strxfrm_multiply;
- uchar caseup_multiply;
- uchar casedn_multiply;
- uint mbminlen;
- uint mbmaxlen;
- uint16 min_sort_char;
- uint16 max_sort_char;
- uchar pad_char;
- my_bool escape_with_backslash_is_dangerous;
- MY_CHARSET_HANDLER *cset;
- MY_COLLATION_HANDLER *coll;
-} CHARSET_INFO;
-extern CHARSET_INFO my_charset_bin;
-extern CHARSET_INFO my_charset_big5_chinese_ci;
-extern CHARSET_INFO my_charset_big5_bin;
-extern CHARSET_INFO my_charset_cp932_japanese_ci;
-extern CHARSET_INFO my_charset_cp932_bin;
-extern CHARSET_INFO my_charset_eucjpms_japanese_ci;
-extern CHARSET_INFO my_charset_eucjpms_bin;
-extern CHARSET_INFO my_charset_euckr_korean_ci;
-extern CHARSET_INFO my_charset_euckr_bin;
-extern CHARSET_INFO my_charset_gb2312_chinese_ci;
-extern CHARSET_INFO my_charset_gb2312_bin;
-extern CHARSET_INFO my_charset_gbk_chinese_ci;
-extern CHARSET_INFO my_charset_gbk_bin;
-extern CHARSET_INFO my_charset_latin1;
-extern CHARSET_INFO my_charset_latin1_german2_ci;
-extern CHARSET_INFO my_charset_latin1_bin;
-extern CHARSET_INFO my_charset_latin2_czech_ci;
-extern CHARSET_INFO my_charset_sjis_japanese_ci;
-extern CHARSET_INFO my_charset_sjis_bin;
-extern CHARSET_INFO my_charset_tis620_thai_ci;
-extern CHARSET_INFO my_charset_tis620_bin;
-extern CHARSET_INFO my_charset_ucs2_general_ci;
-extern CHARSET_INFO my_charset_ucs2_bin;
-extern CHARSET_INFO my_charset_ucs2_unicode_ci;
-extern CHARSET_INFO my_charset_ujis_japanese_ci;
-extern CHARSET_INFO my_charset_ujis_bin;
-extern CHARSET_INFO my_charset_utf8_general_ci;
-extern CHARSET_INFO my_charset_utf8_unicode_ci;
-extern CHARSET_INFO my_charset_utf8_bin;
-extern CHARSET_INFO my_charset_cp1250_czech_ci;
-extern CHARSET_INFO my_charset_filename;
-extern size_t my_strnxfrm_simple(CHARSET_INFO *, uchar *, size_t,
- const uchar *, size_t);
-size_t my_strnxfrmlen_simple(CHARSET_INFO *, size_t);
-extern int my_strnncoll_simple(CHARSET_INFO *, const uchar *, size_t,
- const uchar *, size_t, my_bool);
-extern int my_strnncollsp_simple(CHARSET_INFO *, const uchar *, size_t,
- const uchar *, size_t,
- my_bool diff_if_only_endspace_difference);
-extern void my_hash_sort_simple(CHARSET_INFO *cs,
- const uchar *key, size_t len,
- ulong *nr1, ulong *nr2);
-extern size_t my_lengthsp_8bit(CHARSET_INFO *cs, const char *ptr, size_t length);
-extern uint my_instr_simple(struct charset_info_st *,
- const char *b, size_t b_length,
- const char *s, size_t s_length,
- my_match_t *match, uint nmatch);
-extern size_t my_caseup_str_8bit(CHARSET_INFO *, char *);
-extern size_t my_casedn_str_8bit(CHARSET_INFO *, char *);
-extern size_t my_caseup_8bit(CHARSET_INFO *, char *src, size_t srclen,
- char *dst, size_t dstlen);
-extern size_t my_casedn_8bit(CHARSET_INFO *, char *src, size_t srclen,
- char *dst, size_t dstlen);
-extern int my_strcasecmp_8bit(CHARSET_INFO * cs, const char *, const char *);
-int my_mb_wc_8bit(CHARSET_INFO *cs,ulong *wc, const uchar *s,const uchar *e);
-int my_wc_mb_8bit(CHARSET_INFO *cs,ulong wc, uchar *s, uchar *e);
-int my_mb_ctype_8bit(CHARSET_INFO *,int *, const uchar *,const uchar *);
-int my_mb_ctype_mb(CHARSET_INFO *,int *, const uchar *,const uchar *);
-size_t my_scan_8bit(CHARSET_INFO *cs, const char *b, const char *e, int sq);
-size_t my_snprintf_8bit(struct charset_info_st *, char *to, size_t n,
- const char *fmt, ...)
- __attribute__((format(printf, 4, 5)));
-long my_strntol_8bit(CHARSET_INFO *, const char *s, size_t l, int base,
- char **e, int *err);
-ulong my_strntoul_8bit(CHARSET_INFO *, const char *s, size_t l, int base,
- char **e, int *err);
-longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, size_t l, int base,
- char **e, int *err);
-ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, size_t l, int base,
- char **e, int *err);
-double my_strntod_8bit(CHARSET_INFO *, char *s, size_t l,char **e,
- int *err);
-size_t my_long10_to_str_8bit(CHARSET_INFO *, char *to, size_t l, int radix,
- long int val);
-size_t my_longlong10_to_str_8bit(CHARSET_INFO *, char *to, size_t l, int radix,
- longlong val);
-longlong my_strtoll10_8bit(CHARSET_INFO *cs,
- const char *nptr, char **endptr, int *error);
-longlong my_strtoll10_ucs2(CHARSET_INFO *cs,
- const char *nptr, char **endptr, int *error);
-ulonglong my_strntoull10rnd_8bit(CHARSET_INFO *cs,
- const char *str, size_t length, int
- unsigned_fl, char **endptr, int *error);
-ulonglong my_strntoull10rnd_ucs2(CHARSET_INFO *cs,
- const char *str, size_t length,
- int unsigned_fl, char **endptr, int *error);
-void my_fill_8bit(CHARSET_INFO *cs, char* to, size_t l, int fill);
-my_bool my_like_range_simple(CHARSET_INFO *cs,
- const char *ptr, size_t ptr_length,
- pbool escape, pbool w_one, pbool w_many,
- size_t res_length,
- char *min_str, char *max_str,
- size_t *min_length, size_t *max_length);
-my_bool my_like_range_mb(CHARSET_INFO *cs,
- const char *ptr, size_t ptr_length,
- pbool escape, pbool w_one, pbool w_many,
- size_t res_length,
- char *min_str, char *max_str,
- size_t *min_length, size_t *max_length);
-my_bool my_like_range_ucs2(CHARSET_INFO *cs,
- const char *ptr, size_t ptr_length,
- pbool escape, pbool w_one, pbool w_many,
- size_t res_length,
- char *min_str, char *max_str,
- size_t *min_length, size_t *max_length);
-int my_wildcmp_8bit(CHARSET_INFO *,
- const char *str,const char *str_end,
- const char *wildstr,const char *wildend,
- int escape, int w_one, int w_many);
-int my_wildcmp_bin(CHARSET_INFO *,
- const char *str,const char *str_end,
- const char *wildstr,const char *wildend,
- int escape, int w_one, int w_many);
-size_t my_numchars_8bit(CHARSET_INFO *, const char *b, const char *e);
-size_t my_numcells_8bit(CHARSET_INFO *, const char *b, const char *e);
-size_t my_charpos_8bit(CHARSET_INFO *, const char *b, const char *e, size_t pos);
-size_t my_well_formed_len_8bit(CHARSET_INFO *, const char *b, const char *e,
- size_t pos, int *error);
-uint my_mbcharlen_8bit(CHARSET_INFO *, uint c);
-extern size_t my_caseup_str_mb(CHARSET_INFO *, char *);
-extern size_t my_casedn_str_mb(CHARSET_INFO *, char *);
-extern size_t my_caseup_mb(CHARSET_INFO *, char *src, size_t srclen,
- char *dst, size_t dstlen);
-extern size_t my_casedn_mb(CHARSET_INFO *, char *src, size_t srclen,
- char *dst, size_t dstlen);
-extern int my_strcasecmp_mb(CHARSET_INFO * cs,const char *, const char *);
-int my_wildcmp_mb(CHARSET_INFO *,
- const char *str,const char *str_end,
- const char *wildstr,const char *wildend,
- int escape, int w_one, int w_many);
-size_t my_numchars_mb(CHARSET_INFO *, const char *b, const char *e);
-size_t my_numcells_mb(CHARSET_INFO *, const char *b, const char *e);
-size_t my_charpos_mb(CHARSET_INFO *, const char *b, const char *e, size_t pos);
-size_t my_well_formed_len_mb(CHARSET_INFO *, const char *b, const char *e,
- size_t pos, int *error);
-uint my_instr_mb(struct charset_info_st *,
- const char *b, size_t b_length,
- const char *s, size_t s_length,
- my_match_t *match, uint nmatch);
-int my_wildcmp_unicode(CHARSET_INFO *cs,
- const char *str, const char *str_end,
- const char *wildstr, const char *wildend,
- int escape, int w_one, int w_many,
- MY_UNICASE_INFO **weights);
-extern my_bool my_parse_charset_xml(const char *bug, size_t len,
- int (*add)(CHARSET_INFO *cs));
-extern char *my_strchr(CHARSET_INFO *cs, const char *str, const char *end,
- pchar c);
-my_bool my_propagate_simple(CHARSET_INFO *cs, const uchar *str, size_t len);
-my_bool my_propagate_complex(CHARSET_INFO *cs, const uchar *str, size_t len);
-uint my_string_repertoire(CHARSET_INFO *cs, const char *str, ulong len);
-my_bool my_charset_is_ascii_based(CHARSET_INFO *cs);
-my_bool my_charset_is_8bit_pure_ascii(CHARSET_INFO *cs);
-#include <stdarg.h>
-#include <typelib.h>
-#include "my_alloc.h"
-typedef struct st_used_mem
-{
- struct st_used_mem *next;
- unsigned int left;
- unsigned int size;
-} USED_MEM;
-typedef struct st_mem_root
-{
- USED_MEM *free;
- USED_MEM *used;
- USED_MEM *pre_alloc;
- size_t min_malloc;
- size_t block_size;
- unsigned int block_num;
- unsigned int first_block_usage;
- void (*error_handler)(void);
-} MEM_ROOT;
-typedef struct st_typelib {
- unsigned int count;
- const char *name;
- const char **type_names;
- unsigned int *type_lengths;
-} TYPELIB;
-extern my_ulonglong find_typeset(char *x, TYPELIB *typelib,int *error_position);
-extern int find_type_or_exit(const char *x, TYPELIB *typelib,
- const char *option);
-extern int find_type(char *x, const TYPELIB *typelib, unsigned int full_name);
-extern void make_type(char *to,unsigned int nr,TYPELIB *typelib);
-extern const char *get_type(TYPELIB *typelib,unsigned int nr);
-extern TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from);
-extern TYPELIB sql_protocol_typelib;
-extern void *my_malloc(size_t Size,myf MyFlags);
-extern void *my_realloc(void *oldpoint, size_t Size, myf MyFlags);
-extern void my_no_flags_free(void *ptr);
-extern void *my_memdup(const void *from,size_t length,myf MyFlags);
-extern char *my_strdup(const char *from,myf MyFlags);
-extern char *my_strndup(const char *from, size_t length,
- myf MyFlags);
-extern uint my_get_large_page_size(void);
-extern uchar * my_large_malloc(size_t size, myf my_flags);
-extern void my_large_free(uchar * ptr, myf my_flags);
-extern int errno;
-extern char errbuff[(2)][(256)];
-extern char *home_dir;
-extern const char *my_progname;
-extern char curr_dir[];
-extern int (*error_handler_hook)(uint my_err, const char *str,myf MyFlags);
-extern int (*fatal_error_handler_hook)(uint my_err, const char *str,
- myf MyFlags);
-extern uint my_file_limit;
-extern ulong my_thread_stack_size;
-extern my_bool my_use_large_pages;
-extern uint my_large_page_size;
-extern CHARSET_INFO *default_charset_info;
-extern CHARSET_INFO *all_charsets[256];
-extern CHARSET_INFO compiled_charsets[];
-extern ulong my_file_opened,my_stream_opened, my_tmp_file_created;
-extern ulong my_file_total_opened;
-extern uint mysys_usage_id;
-extern my_bool my_init_done;
-extern void (*my_sigtstp_cleanup)(void),
- (*my_sigtstp_restart)(void),
- (*my_abort_hook)(int);
-extern int my_umask,
- my_umask_dir,
- my_recived_signals,
- my_safe_to_handle_signal,
- my_dont_interrupt;
-extern my_bool mysys_uses_curses, my_use_symdir;
-extern ulong sf_malloc_cur_memory, sf_malloc_max_memory;
-extern ulong my_default_record_cache_size;
-extern my_bool my_disable_locking, my_disable_async_io,
- my_disable_flush_key_blocks, my_disable_symlinks;
-extern char wild_many,wild_one,wild_prefix;
-extern const char *charsets_dir;
-extern char *my_defaults_extra_file;
-extern const char *my_defaults_group_suffix;
-extern const char *my_defaults_file;
-extern my_bool timed_mutexes;
-typedef struct wild_file_pack
-{
- uint wilds;
- uint not_pos;
- char * *wild;
-} WF_PACK;
-enum loglevel {
- ERROR_LEVEL,
- WARNING_LEVEL,
- INFORMATION_LEVEL
-};
-enum cache_type
-{
- TYPE_NOT_SET= 0, READ_CACHE, WRITE_CACHE,
- SEQ_READ_APPEND ,
- READ_FIFO, READ_NET,WRITE_NET};
-enum flush_type
-{
- FLUSH_KEEP,
- FLUSH_RELEASE,
- FLUSH_IGNORE_CHANGED,
- FLUSH_FORCE_WRITE
-};
-typedef struct st_record_cache
-{
- File file;
- int rc_seek,error,inited;
- uint rc_length,read_length,reclength;
- my_off_t rc_record_pos,end_of_file;
- uchar *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos;
- enum cache_type type;
-} RECORD_CACHE;
-enum file_type
-{
- UNOPEN = 0, FILE_BY_OPEN, FILE_BY_CREATE, STREAM_BY_FOPEN, STREAM_BY_FDOPEN,
- FILE_BY_MKSTEMP, FILE_BY_DUP
-};
-struct st_my_file_info
-{
- char * name;
- enum file_type type;
-};
-extern struct st_my_file_info *my_file_info;
-typedef struct st_dynamic_array
-{
- uchar *buffer;
- uint elements,max_element;
- uint alloc_increment;
- uint size_of_element;
-} DYNAMIC_ARRAY;
-typedef struct st_my_tmpdir
-{
- DYNAMIC_ARRAY full_list;
- char **list;
- uint cur, max;
- pthread_mutex_t mutex;
-} MY_TMPDIR;
-typedef struct st_dynamic_string
-{
- char *str;
- size_t length,max_length,alloc_increment;
-} DYNAMIC_STRING;
-struct st_io_cache;
-typedef int (*IO_CACHE_CALLBACK)(struct st_io_cache*);
-typedef struct st_io_cache_share
-{
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- pthread_cond_t cond_writer;
- my_off_t pos_in_file;
- struct st_io_cache *source_cache;
- uchar *buffer;
- uchar *read_end;
- int running_threads;
- int total_threads;
- int error;
-} IO_CACHE_SHARE;
-typedef struct st_io_cache
-{
- my_off_t pos_in_file;
- my_off_t end_of_file;
- uchar *read_pos;
- uchar *read_end;
- uchar *buffer;
- uchar *request_pos;
- uchar *write_buffer;
- uchar *append_read_pos;
- uchar *write_pos;
- uchar *write_end;
- uchar **current_pos, **current_end;
- pthread_mutex_t append_buffer_lock;
- IO_CACHE_SHARE *share;
- int (*read_function)(struct st_io_cache *,uchar *,size_t);
- int (*write_function)(struct st_io_cache *,const uchar *,size_t);
- enum cache_type type;
- IO_CACHE_CALLBACK pre_read;
- IO_CACHE_CALLBACK post_read;
- IO_CACHE_CALLBACK pre_close;
- ulong disk_writes;
- void* arg;
- char *file_name;
- char *dir,*prefix;
- File file;
- int seek_not_done,error;
- size_t buffer_length;
- size_t read_length;
- myf myflags;
- my_bool alloced_buffer;
-} IO_CACHE;
-typedef int (*qsort2_cmp)(const void *, const void *, const void *);
-int my_b_copy_to_file(IO_CACHE *cache, FILE *file);
-my_off_t my_b_append_tell(IO_CACHE* info);
-my_off_t my_b_safe_tell(IO_CACHE* info);
-typedef uint32 ha_checksum;
-typedef int (*Process_option_func)(void *ctx, const char *group_name,
- const char *option);
-#include <my_alloc.h>
-extern int my_copy(const char *from,const char *to,myf MyFlags);
-extern int my_append(const char *from,const char *to,myf MyFlags);
-extern int my_delete(const char *name,myf MyFlags);
-extern int my_getwd(char * buf,size_t size,myf MyFlags);
-extern int my_setwd(const char *dir,myf MyFlags);
-extern int my_lock(File fd,int op,my_off_t start, my_off_t length,myf MyFlags);
-extern void *my_once_alloc(size_t Size,myf MyFlags);
-extern void my_once_free(void);
-extern char *my_once_strdup(const char *src,myf myflags);
-extern void *my_once_memdup(const void *src, size_t len, myf myflags);
-extern File my_open(const char *FileName,int Flags,myf MyFlags);
-extern File my_register_filename(File fd, const char *FileName,
- enum file_type type_of_file,
- uint error_message_number, myf MyFlags);
-extern File my_create(const char *FileName,int CreateFlags,
- int AccessFlags, myf MyFlags);
-extern int my_close(File Filedes,myf MyFlags);
-extern File my_dup(File file, myf MyFlags);
-extern int my_mkdir(const char *dir, int Flags, myf MyFlags);
-extern int my_readlink(char *to, const char *filename, myf MyFlags);
-extern int my_realpath(char *to, const char *filename, myf MyFlags);
-extern File my_create_with_symlink(const char *linkname, const char *filename,
- int createflags, int access_flags,
- myf MyFlags);
-extern int my_delete_with_symlink(const char *name, myf MyFlags);
-extern int my_rename_with_symlink(const char *from,const char *to,myf MyFlags);
-extern int my_symlink(const char *content, const char *linkname, myf MyFlags);
-extern size_t my_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags);
-extern size_t my_pread(File Filedes,uchar *Buffer,size_t Count,my_off_t offset,
- myf MyFlags);
-extern int my_rename(const char *from,const char *to,myf MyFlags);
-extern my_off_t my_seek(File fd,my_off_t pos,int whence,myf MyFlags);
-extern my_off_t my_tell(File fd,myf MyFlags);
-extern size_t my_write(File Filedes,const uchar *Buffer,size_t Count,
- myf MyFlags);
-extern size_t my_pwrite(File Filedes,const uchar *Buffer,size_t Count,
- my_off_t offset,myf MyFlags);
-extern size_t my_fread(FILE *stream,uchar *Buffer,size_t Count,myf MyFlags);
-extern size_t my_fwrite(FILE *stream,const uchar *Buffer,size_t Count,
- myf MyFlags);
-extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,myf MyFlags);
-extern my_off_t my_ftell(FILE *stream,myf MyFlags);
-extern void *_mymalloc(size_t uSize,const char *sFile,
- uint uLine, myf MyFlag);
-extern void *_myrealloc(void *pPtr,size_t uSize,const char *sFile,
- uint uLine, myf MyFlag);
-extern void * my_multi_malloc (myf MyFlags, ...);
-extern void _myfree(void *pPtr,const char *sFile,uint uLine, myf MyFlag);
-extern int _sanity(const char *sFile, uint uLine);
-extern void *_my_memdup(const void *from, size_t length,
- const char *sFile, uint uLine,myf MyFlag);
-extern char * _my_strdup(const char *from, const char *sFile, uint uLine,
- myf MyFlag);
-extern char *_my_strndup(const char *from, size_t length,
- const char *sFile, uint uLine,
- myf MyFlag);
-extern void *my_memmem(const void *haystack, size_t haystacklen,
- const void *needle, size_t needlelen);
-extern int check_if_legal_filename(const char *path);
-extern int check_if_legal_tablename(const char *path);
-extern void init_glob_errs(void);
-extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags);
-extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags);
-extern int my_fclose(FILE *fd,myf MyFlags);
-extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags);
-extern int my_sync(File fd, myf my_flags);
-extern int my_sync_dir(const char *dir_name, myf my_flags);
-extern int my_sync_dir_by_file(const char *file_name, myf my_flags);
-extern int my_error (int nr,myf MyFlags, ...);
-extern int my_printf_error (uint my_err, const char *format, myf MyFlags, ...)
- __attribute__((format(printf, 2, 4)));
-extern int my_error_register(const char **errmsgs, int first, int last);
-extern const char **my_error_unregister(int first, int last);
-extern int my_message(uint my_err, const char *str,myf MyFlags);
-extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags);
-extern int my_message_curses(uint my_err, const char *str,myf MyFlags);
-extern my_bool my_init(void);
-extern void my_end(int infoflag);
-extern int my_redel(const char *from, const char *to, int MyFlags);
-extern int my_copystat(const char *from, const char *to, int MyFlags);
-extern char * my_filename(File fd);
-extern my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist);
-extern char *my_tmpdir(MY_TMPDIR *tmpdir);
-extern void free_tmpdir(MY_TMPDIR *tmpdir);
-extern void my_remember_signal(int signal_number,void (*func)(int));
-extern size_t dirname_part(char * to,const char *name, size_t *to_res_length);
-extern size_t dirname_length(const char *name);
-extern int test_if_hard_path(const char *dir_name);
-extern my_bool has_path(const char *name);
-extern char *convert_dirname(char *to, const char *from, const char *from_end);
-extern void to_unix_path(char * name);
-extern char * fn_ext(const char *name);
-extern char * fn_same(char * toname,const char *name,int flag);
-extern char * fn_format(char * to,const char *name,const char *dir,
- const char *form, uint flag);
-extern size_t strlength(const char *str);
-extern void pack_dirname(char * to,const char *from);
-extern size_t unpack_dirname(char * to,const char *from);
-extern size_t cleanup_dirname(char * to,const char *from);
-extern size_t system_filename(char * to,const char *from);
-extern size_t unpack_filename(char * to,const char *from);
-extern char * intern_filename(char * to,const char *from);
-extern char * directory_file_name(char * dst, const char *src);
-extern int pack_filename(char * to, const char *name, size_t max_length);
-extern char * my_path(char * to,const char *progname,
- const char *own_pathname_part);
-extern char * my_load_path(char * to, const char *path,
- const char *own_path_prefix);
-extern int wild_compare(const char *str,const char *wildstr,
- pbool str_is_pattern);
-extern WF_PACK *wf_comp(char * str);
-extern int wf_test(struct wild_file_pack *wf_pack,const char *name);
-extern void wf_end(struct wild_file_pack *buffer);
-extern my_bool array_append_string_unique(const char *str,
- const char **array, size_t size);
-extern void get_date(char * to,int timeflag,time_t use_time);
-extern void soundex(CHARSET_INFO *, char * out_pntr, char * in_pntr,
- pbool remove_garbage);
-extern int init_record_cache(RECORD_CACHE *info,size_t cachesize,File file,
- size_t reclength,enum cache_type type,
- pbool use_async_io);
-extern int read_cache_record(RECORD_CACHE *info,uchar *to);
-extern int end_record_cache(RECORD_CACHE *info);
-extern int write_cache_record(RECORD_CACHE *info,my_off_t filepos,
- const uchar *record,size_t length);
-extern int flush_write_cache(RECORD_CACHE *info);
-extern long my_clock(void);
-extern void sigtstp_handler(int signal_number);
-extern void handle_recived_signals(void);
-extern void my_set_alarm_variable(int signo);
-extern void my_string_ptr_sort(uchar *base,uint items,size_t size);
-extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements,
- size_t size_of_element,uchar *buffer[]);
-extern void my_qsort(void *base_ptr, size_t total_elems, size_t size,
- qsort_cmp cmp);
-extern void my_qsort2(void *base_ptr, size_t total_elems, size_t size,
- qsort2_cmp cmp, void *cmp_argument);
-extern qsort2_cmp get_ptr_compare(size_t);
-void my_store_ptr(uchar *buff, size_t pack_length, my_off_t pos);
-my_off_t my_get_ptr(uchar *ptr, size_t pack_length);
-extern int init_io_cache(IO_CACHE *info,File file,size_t cachesize,
- enum cache_type type,my_off_t seek_offset,
- pbool use_async_io, myf cache_myflags);
-extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type,
- my_off_t seek_offset,pbool use_async_io,
- pbool clear_cache);
-extern void setup_io_cache(IO_CACHE* info);
-extern int _my_b_read(IO_CACHE *info,uchar *Buffer,size_t Count);
-extern int _my_b_read_r(IO_CACHE *info,uchar *Buffer,size_t Count);
-extern void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare,
- IO_CACHE *write_cache, uint num_threads);
-extern void remove_io_thread(IO_CACHE *info);
-extern int _my_b_seq_read(IO_CACHE *info,uchar *Buffer,size_t Count);
-extern int _my_b_net_read(IO_CACHE *info,uchar *Buffer,size_t Count);
-extern int _my_b_get(IO_CACHE *info);
-extern int _my_b_async_read(IO_CACHE *info,uchar *Buffer,size_t Count);
-extern int _my_b_write(IO_CACHE *info,const uchar *Buffer,size_t Count);
-extern int my_b_append(IO_CACHE *info,const uchar *Buffer,size_t Count);
-extern int my_b_safe_write(IO_CACHE *info,const uchar *Buffer,size_t Count);
-extern int my_block_write(IO_CACHE *info, const uchar *Buffer,
- size_t Count, my_off_t pos);
-extern int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock);
-extern int end_io_cache(IO_CACHE *info);
-extern size_t my_b_fill(IO_CACHE *info);
-extern void my_b_seek(IO_CACHE *info,my_off_t pos);
-extern size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length);
-extern my_off_t my_b_filelength(IO_CACHE *info);
-extern size_t my_b_printf(IO_CACHE *info, const char* fmt, ...);
-extern size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list ap);
-extern my_bool open_cached_file(IO_CACHE *cache,const char *dir,
- const char *prefix, size_t cache_size,
- myf cache_myflags);
-extern my_bool real_open_cached_file(IO_CACHE *cache);
-extern void close_cached_file(IO_CACHE *cache);
-File create_temp_file(char *to, const char *dir, const char *pfx,
- int mode, myf MyFlags);
-extern my_bool init_dynamic_array2(DYNAMIC_ARRAY *array,uint element_size,
- void *init_buffer, uint init_alloc,
- uint alloc_increment
- );
-extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size,
- uint init_alloc,uint alloc_increment
- );
-extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,uchar * element);
-extern uchar *alloc_dynamic(DYNAMIC_ARRAY *array);
-extern uchar *pop_dynamic(DYNAMIC_ARRAY*);
-extern my_bool set_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index);
-extern my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements);
-extern void get_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index);
-extern void delete_dynamic(DYNAMIC_ARRAY *array);
-extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index);
-extern void freeze_size(DYNAMIC_ARRAY *array);
-extern int get_index_dynamic(DYNAMIC_ARRAY *array, uchar * element);
-extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
- size_t init_alloc,size_t alloc_increment);
-extern my_bool dynstr_append(DYNAMIC_STRING *str, const char *append);
-my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append,
- size_t length);
-extern my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append,
- ...);
-extern my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str);
-extern my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size);
-extern my_bool dynstr_trunc(DYNAMIC_STRING *str, size_t n);
-extern void dynstr_free(DYNAMIC_STRING *str);
-extern void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
- size_t pre_alloc_size);
-extern void *alloc_root(MEM_ROOT *mem_root, size_t Size);
-extern void *multi_alloc_root(MEM_ROOT *mem_root, ...);
-extern void free_root(MEM_ROOT *root, myf MyFLAGS);
-extern void set_prealloc_root(MEM_ROOT *root, char *ptr);
-extern void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
- size_t prealloc_size);
-extern char *strdup_root(MEM_ROOT *root,const char *str);
-extern char *strmake_root(MEM_ROOT *root,const char *str,size_t len);
-extern void *memdup_root(MEM_ROOT *root,const void *str, size_t len);
-extern int get_defaults_options(int argc, char **argv,
- char **defaults, char **extra_defaults,
- char **group_suffix);
-extern int load_defaults(const char *conf_file, const char **groups,
- int *argc, char ***argv);
-extern int modify_defaults_file(const char *file_location, const char *option,
- const char *option_value,
- const char *section_name, int remove_option);
-extern int my_search_option_files(const char *conf_file, int *argc,
- char ***argv, uint *args_used,
- Process_option_func func, void *func_ctx);
-extern void free_defaults(char **argv);
-extern void my_print_default_files(const char *conf_file);
-extern void print_defaults(const char *conf_file, const char **groups);
-extern my_bool my_compress(uchar *, size_t *, size_t *);
-extern my_bool my_uncompress(uchar *, size_t , size_t *);
-extern uchar *my_compress_alloc(const uchar *packet, size_t *len,
- size_t *complen);
-extern int packfrm(uchar *, size_t, uchar **, size_t *);
-extern int unpackfrm(uchar **, size_t *, const uchar *);
-extern ha_checksum my_checksum(ha_checksum crc, const uchar *mem,
- size_t count);
-extern void my_sleep(ulong m_seconds);
-extern ulong crc32(ulong crc, const uchar *buf, uint len);
-extern uint my_set_max_open_files(uint files);
-void my_free_open_file_info(void);
-extern time_t my_time(myf flags);
-extern ulonglong my_getsystime(void);
-extern ulonglong my_micro_time();
-extern ulonglong my_micro_time_and_time(time_t *time_arg);
-time_t my_time_possible_from_micro(ulonglong microtime);
-extern my_bool my_gethwaddr(uchar *to);
-extern int my_getncpus();
-#include <sys/mman.h>
-int my_msync(int, void *, size_t, int);
-extern uint get_charset_number(const char *cs_name, uint cs_flags);
-extern uint get_collation_number(const char *name);
-extern const char *get_charset_name(uint cs_number);
-extern CHARSET_INFO *get_charset(uint cs_number, myf flags);
-extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags);
-extern CHARSET_INFO *get_charset_by_csname(const char *cs_name,
- uint cs_flags, myf my_flags);
-extern my_bool resolve_charset(const char *cs_name,
- CHARSET_INFO *default_cs,
- CHARSET_INFO **cs);
-extern my_bool resolve_collation(const char *cl_name,
- CHARSET_INFO *default_cl,
- CHARSET_INFO **cl);
-extern void free_charsets(void);
-extern char *get_charsets_dir(char *buf);
-extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2);
-extern my_bool init_compiled_charsets(myf flags);
-extern void add_compiled_collation(CHARSET_INFO *cs);
-extern size_t escape_string_for_mysql(CHARSET_INFO *charset_info,
- char *to, size_t to_length,
- const char *from, size_t length);
-extern size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info,
- char *to, size_t to_length,
- const char *from, size_t length);
-extern void thd_increment_bytes_sent(ulong length);
-extern void thd_increment_bytes_received(ulong length);
-extern void thd_increment_net_big_packet_count(ulong length);
-#include <my_time.h>
-#include "my_global.h"
-#include "mysql_time.h"
-enum enum_mysql_timestamp_type
-{
- MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1,
- MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2
-};
-typedef struct st_mysql_time
-{
- unsigned int year, month, day, hour, minute, second;
- unsigned long second_part;
- my_bool neg;
- enum enum_mysql_timestamp_type time_type;
-} MYSQL_TIME;
-extern ulonglong log_10_int[20];
-extern uchar days_in_month[];
-typedef long my_time_t;
-my_bool check_date(const MYSQL_TIME *ltime, my_bool not_zero_date,
- ulong flags, int *was_cut);
-enum enum_mysql_timestamp_type
-str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
- uint flags, int *was_cut);
-longlong number_to_datetime(longlong nr, MYSQL_TIME *time_res,
- uint flags, int *was_cut);
-ulonglong TIME_to_ulonglong_datetime(const MYSQL_TIME *);
-ulonglong TIME_to_ulonglong_date(const MYSQL_TIME *);
-ulonglong TIME_to_ulonglong_time(const MYSQL_TIME *);
-ulonglong TIME_to_ulonglong(const MYSQL_TIME *);
-my_bool str_to_time(const char *str,uint length, MYSQL_TIME *l_time,
- int *warning);
-int check_time_range(struct st_mysql_time *, int *warning);
-long calc_daynr(uint year,uint month,uint day);
-uint calc_days_in_year(uint year);
-uint year_2000_handling(uint year);
-void my_init_time(void);
-static inline my_bool validate_timestamp_range(const MYSQL_TIME *t)
-{
- if ((t->year > 2038 || t->year < (1900 + 70 - 1)) ||
- (t->year == 2038 && (t->month > 1 || t->day > 19)) ||
- (t->year == (1900 + 70 - 1) && (t->month < 12 || t->day < 31)))
- return (0);
- return (1);
-}
-my_time_t
-my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone,
- my_bool *in_dst_time_gap);
-void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type);
-int my_time_to_str(const MYSQL_TIME *l_time, char *to);
-int my_date_to_str(const MYSQL_TIME *l_time, char *to);
-int my_datetime_to_str(const MYSQL_TIME *l_time, char *to);
-int my_TIME_to_str(const MYSQL_TIME *l_time, char *to);
-enum interval_type
-{
- INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_WEEK, INTERVAL_DAY,
- INTERVAL_HOUR, INTERVAL_MINUTE, INTERVAL_SECOND, INTERVAL_MICROSECOND,
- INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE,
- INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
- INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND,
- INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND, INTERVAL_LAST
-};
-#include <m_string.h>
-#include <strings.h>
-#include <string.h>
-#include <stdarg.h>
-#include <strings.h>
-#include <memory.h>
-extern void *(*my_str_malloc)(size_t);
-extern void (*my_str_free)(void *);
-extern char *stpcpy(char *, const char *);
-extern char _dig_vec_upper[];
-extern char _dig_vec_lower[];
-extern const double log_10[309];
-extern void bmove512(uchar *dst,const uchar *src,size_t len);
-extern void bmove_upp(uchar *dst,const uchar *src,size_t len);
-extern void bchange(uchar *dst,size_t old_len,const uchar *src,
- size_t new_len,size_t tot_len);
-extern void strappend(char *s,size_t len,pchar fill);
-extern char *strend(const char *s);
-extern char *strcend(const char *, pchar);
-extern char *strfield(char *src,int fields,int chars,int blanks,
- int tabch);
-extern char *strfill(char * s,size_t len,pchar fill);
-extern size_t strinstr(const char *str,const char *search);
-extern size_t r_strinstr(const char *str, size_t from, const char *search);
-extern char *strkey(char *dst,char *head,char *tail,char *flags);
-extern char *strmake(char *dst,const char *src,size_t length);
-extern char *strnmov(char *dst,const char *src,size_t n);
-extern char *strsuff(const char *src,const char *suffix);
-extern char *strcont(const char *src,const char *set);
-extern char *strxcat (char *dst,const char *src, ...);
-extern char *strxmov (char *dst,const char *src, ...);
-extern char *strxcpy (char *dst,const char *src, ...);
-extern char *strxncat (char *dst,size_t len, const char *src, ...);
-extern char *strxnmov (char *dst,size_t len, const char *src, ...);
-extern char *strxncpy (char *dst,size_t len, const char *src, ...);
-extern int is_prefix(const char *, const char *);
-double my_strtod(const char *str, char **end, int *error);
-double my_atof(const char *nptr);
-extern char *llstr(longlong value,char *buff);
-extern char *ullstr(longlong value,char *buff);
-extern char *int2str(long val, char *dst, int radix, int upcase);
-extern char *int10_to_str(long val,char *dst,int radix);
-extern char *str2int(const char *src,int radix,long lower,long upper,
- long *val);
-longlong my_strtoll10(const char *nptr, char **endptr, int *error);
-extern char *longlong2str(longlong val,char *dst,int radix);
-extern char *longlong10_to_str(longlong val,char *dst,int radix);
-extern size_t my_vsnprintf(char *str, size_t n,
- const char *format, va_list ap);
-extern size_t my_snprintf(char *to, size_t n, const char *fmt, ...)
- __attribute__((format(printf, 3, 4)));
-struct st_mysql_lex_string
-{
- char *str;
- size_t length;
-};
-typedef struct st_mysql_lex_string LEX_STRING;
-#include <hash.h>
-typedef uchar *(*hash_get_key)(const uchar *,size_t*,my_bool);
-typedef void (*hash_free_key)(void *);
-typedef struct st_hash {
- size_t key_offset,key_length;
- size_t blength;
- ulong records;
- uint flags;
- DYNAMIC_ARRAY array;
- hash_get_key get_key;
- void (*free)(void *);
- CHARSET_INFO *charset;
-} HASH;
-typedef uint HASH_SEARCH_STATE;
-my_bool _hash_init(HASH *hash, uint growth_size,CHARSET_INFO *charset,
- ulong default_array_elements, size_t key_offset,
- size_t key_length, hash_get_key get_key,
- void (*free_element)(void*), uint flags );
-void hash_free(HASH *tree);
-void my_hash_reset(HASH *hash);
-uchar *hash_element(HASH *hash,ulong idx);
-uchar *hash_search(const HASH *info, const uchar *key, size_t length);
-uchar *hash_first(const HASH *info, const uchar *key, size_t length,
- HASH_SEARCH_STATE *state);
-uchar *hash_next(const HASH *info, const uchar *key, size_t length,
- HASH_SEARCH_STATE *state);
-my_bool my_hash_insert(HASH *info,const uchar *data);
-my_bool hash_delete(HASH *hash,uchar *record);
-my_bool hash_update(HASH *hash,uchar *record,uchar *old_key,size_t old_key_length);
-void hash_replace(HASH *hash, HASH_SEARCH_STATE *state, uchar *new_row);
-my_bool hash_check(HASH *hash);
-#include <signal.h>
-#include <thr_lock.h>
-#include <my_pthread.h>
-#include <my_list.h>
-typedef struct st_list {
- struct st_list *prev,*next;
- void *data;
-} LIST;
-typedef int (*list_walk_action)(void *,void *);
-extern LIST *list_add(LIST *root,LIST *element);
-extern LIST *list_delete(LIST *root,LIST *element);
-extern LIST *list_cons(void *data,LIST *root);
-extern LIST *list_reverse(LIST *root);
-extern void list_free(LIST *root,unsigned int free_data);
-extern unsigned int list_length(LIST *);
-extern int list_walk(LIST *,list_walk_action action,unsigned char * argument);
-struct st_thr_lock;
-extern ulong locks_immediate,locks_waited ;
-enum thr_lock_type { TL_IGNORE=-1,
- TL_UNLOCK,
- TL_READ,
- TL_READ_WITH_SHARED_LOCKS,
- TL_READ_HIGH_PRIORITY,
- TL_READ_NO_INSERT,
- TL_WRITE_ALLOW_WRITE,
- TL_WRITE_ALLOW_READ,
- TL_WRITE_CONCURRENT_INSERT,
- TL_WRITE_DELAYED,
- TL_WRITE_DEFAULT,
- TL_WRITE_LOW_PRIORITY,
- TL_WRITE,
- TL_WRITE_ONLY};
-enum enum_thr_lock_result { THR_LOCK_SUCCESS= 0, THR_LOCK_ABORTED= 1,
- THR_LOCK_WAIT_TIMEOUT= 2, THR_LOCK_DEADLOCK= 3 };
-extern ulong max_write_lock_count;
-extern ulong table_lock_wait_timeout;
-extern my_bool thr_lock_inited;
-extern enum thr_lock_type thr_upgraded_concurrent_insert_lock;
-typedef struct st_thr_lock_info
-{
- pthread_t thread;
- my_thread_id thread_id;
- ulong n_cursors;
-} THR_LOCK_INFO;
-typedef struct st_thr_lock_owner
-{
- THR_LOCK_INFO *info;
-} THR_LOCK_OWNER;
-typedef struct st_thr_lock_data {
- THR_LOCK_OWNER *owner;
- struct st_thr_lock_data *next,**prev;
- struct st_thr_lock *lock;
- pthread_cond_t *cond;
- enum thr_lock_type type;
- void *status_param;
- void *debug_print_param;
-} THR_LOCK_DATA;
-struct st_lock_list {
- THR_LOCK_DATA *data,**last;
-};
-typedef struct st_thr_lock {
- LIST list;
- pthread_mutex_t mutex;
- struct st_lock_list read_wait;
- struct st_lock_list read;
- struct st_lock_list write_wait;
- struct st_lock_list write;
- ulong write_lock_count;
- uint read_no_write_count;
- void (*get_status)(void*, int);
- void (*copy_status)(void*,void*);
- void (*update_status)(void*);
- void (*restore_status)(void*);
- my_bool (*check_status)(void *);
-} THR_LOCK;
-extern LIST *thr_lock_thread_list;
-extern pthread_mutex_t THR_LOCK_lock;
-my_bool init_thr_lock(void);
-void thr_lock_info_init(THR_LOCK_INFO *info);
-void thr_lock_init(THR_LOCK *lock);
-void thr_lock_delete(THR_LOCK *lock);
-void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data,
- void *status_param);
-enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data,
- THR_LOCK_OWNER *owner,
- enum thr_lock_type lock_type);
-void thr_unlock(THR_LOCK_DATA *data);
-enum enum_thr_lock_result thr_multi_lock(THR_LOCK_DATA **data,
- uint count, THR_LOCK_OWNER *owner);
-void thr_multi_unlock(THR_LOCK_DATA **data,uint count);
-void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock);
-my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread);
-void thr_print_locks(void);
-my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data);
-void thr_downgrade_write_lock(THR_LOCK_DATA *data,
- enum thr_lock_type new_lock_type);
-my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data);
-#include <my_base.h>
-#include <my_global.h>
-#include <my_dir.h>
-#include <sys/stat.h>
-typedef struct fileinfo
-{
- char *name;
- struct stat *mystat;
-} FILEINFO;
-typedef struct st_my_dir
-{
- struct fileinfo *dir_entry;
- uint number_off_files;
-} MY_DIR;
-extern MY_DIR *my_dir(const char *path,myf MyFlags);
-extern void my_dirend(MY_DIR *buffer);
-extern struct stat *my_stat(const char *path, struct stat *stat_area, myf my_flags);
-extern int my_fstat(int filenr, struct stat *stat_area, myf MyFlags);
-#include <my_sys.h>
-#include <m_string.h>
-#include <errno.h>
-#include <my_list.h>
-enum ha_rkey_function {
- HA_READ_KEY_EXACT,
- HA_READ_KEY_OR_NEXT,
- HA_READ_KEY_OR_PREV,
- HA_READ_AFTER_KEY,
- HA_READ_BEFORE_KEY,
- HA_READ_PREFIX,
- HA_READ_PREFIX_LAST,
- HA_READ_PREFIX_LAST_OR_PREV,
- HA_READ_MBR_CONTAIN,
- HA_READ_MBR_INTERSECT,
- HA_READ_MBR_WITHIN,
- HA_READ_MBR_DISJOINT,
- HA_READ_MBR_EQUAL
-};
-enum ha_key_alg {
- HA_KEY_ALG_UNDEF= 0,
- HA_KEY_ALG_BTREE= 1,
- HA_KEY_ALG_RTREE= 2,
- HA_KEY_ALG_HASH= 3,
- HA_KEY_ALG_FULLTEXT= 4
-};
-enum ha_storage_media {
- HA_SM_DEFAULT= 0,
- HA_SM_DISK= 1,
- HA_SM_MEMORY= 2
-};
-enum ha_extra_function {
- HA_EXTRA_NORMAL=0,
- HA_EXTRA_QUICK=1,
- HA_EXTRA_NOT_USED=2,
- HA_EXTRA_CACHE=3,
- HA_EXTRA_NO_CACHE=4,
- HA_EXTRA_NO_READCHECK=5,
- HA_EXTRA_READCHECK=6,
- HA_EXTRA_KEYREAD=7,
- HA_EXTRA_NO_KEYREAD=8,
- HA_EXTRA_NO_USER_CHANGE=9,
- HA_EXTRA_KEY_CACHE=10,
- HA_EXTRA_NO_KEY_CACHE=11,
- HA_EXTRA_WAIT_LOCK=12,
- HA_EXTRA_NO_WAIT_LOCK=13,
- HA_EXTRA_WRITE_CACHE=14,
- HA_EXTRA_FLUSH_CACHE=15,
- HA_EXTRA_NO_KEYS=16,
- HA_EXTRA_KEYREAD_CHANGE_POS=17,
- HA_EXTRA_REMEMBER_POS=18,
- HA_EXTRA_RESTORE_POS=19,
- HA_EXTRA_REINIT_CACHE=20,
- HA_EXTRA_FORCE_REOPEN=21,
- HA_EXTRA_FLUSH,
- HA_EXTRA_NO_ROWS,
- HA_EXTRA_RESET_STATE,
- HA_EXTRA_IGNORE_DUP_KEY,
- HA_EXTRA_NO_IGNORE_DUP_KEY,
- HA_EXTRA_PREPARE_FOR_DROP,
- HA_EXTRA_PREPARE_FOR_UPDATE,
- HA_EXTRA_PRELOAD_BUFFER_SIZE,
- HA_EXTRA_CHANGE_KEY_TO_UNIQUE,
- HA_EXTRA_CHANGE_KEY_TO_DUP,
- HA_EXTRA_KEYREAD_PRESERVE_FIELDS,
- HA_EXTRA_MMAP,
- HA_EXTRA_IGNORE_NO_KEY,
- HA_EXTRA_NO_IGNORE_NO_KEY,
- HA_EXTRA_MARK_AS_LOG_TABLE,
- HA_EXTRA_WRITE_CAN_REPLACE,
- HA_EXTRA_WRITE_CANNOT_REPLACE,
- HA_EXTRA_DELETE_CANNOT_BATCH,
- HA_EXTRA_UPDATE_CANNOT_BATCH,
- HA_EXTRA_INSERT_WITH_UPDATE,
- HA_EXTRA_PREPARE_FOR_RENAME,
- HA_EXTRA_ATTACH_CHILDREN,
- HA_EXTRA_DETACH_CHILDREN
-};
-enum ha_panic_function {
- HA_PANIC_CLOSE,
- HA_PANIC_WRITE,
- HA_PANIC_READ
-};
-enum ha_base_keytype {
- HA_KEYTYPE_END=0,
- HA_KEYTYPE_TEXT=1,
- HA_KEYTYPE_BINARY=2,
- HA_KEYTYPE_SHORT_INT=3,
- HA_KEYTYPE_LONG_INT=4,
- HA_KEYTYPE_FLOAT=5,
- HA_KEYTYPE_DOUBLE=6,
- HA_KEYTYPE_NUM=7,
- HA_KEYTYPE_USHORT_INT=8,
- HA_KEYTYPE_ULONG_INT=9,
- HA_KEYTYPE_LONGLONG=10,
- HA_KEYTYPE_ULONGLONG=11,
- HA_KEYTYPE_INT24=12,
- HA_KEYTYPE_UINT24=13,
- HA_KEYTYPE_INT8=14,
- HA_KEYTYPE_VARTEXT1=15,
- HA_KEYTYPE_VARBINARY1=16,
- HA_KEYTYPE_VARTEXT2=17,
- HA_KEYTYPE_VARBINARY2=18,
- HA_KEYTYPE_BIT=19
-};
-typedef ulong key_part_map;
-enum en_fieldtype {
- FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE,
- FIELD_SKIP_ZERO,FIELD_BLOB,FIELD_CONSTANT,FIELD_INTERVALL,FIELD_ZERO,
- FIELD_VARCHAR,FIELD_CHECK,
- FIELD_enum_val_count
-};
-enum data_file_type {
- STATIC_RECORD, DYNAMIC_RECORD, COMPRESSED_RECORD, BLOCK_RECORD
-};
-typedef struct st_key_range
-{
- const uchar *key;
- uint length;
- key_part_map keypart_map;
- enum ha_rkey_function flag;
-} key_range;
-typedef struct st_key_multi_range
-{
- key_range start_key;
- key_range end_key;
- char *ptr;
- uint range_flag;
-} KEY_MULTI_RANGE;
-typedef my_off_t ha_rows;
-typedef void (* invalidator_by_filename)(const char * filename);
-#include <queues.h>
-typedef struct st_queue {
- uchar **root;
- void *first_cmp_arg;
- uint elements;
- uint max_elements;
- uint offset_to_key;
- int max_at_top;
- int (*compare)(void *, uchar *,uchar *);
- uint auto_extent;
-} QUEUE;
-typedef int (*queue_compare)(void *,uchar *, uchar *);
-int init_queue(QUEUE *queue,uint max_elements,uint offset_to_key,
- pbool max_at_top, queue_compare compare,
- void *first_cmp_arg);
-int init_queue_ex(QUEUE *queue,uint max_elements,uint offset_to_key,
- pbool max_at_top, queue_compare compare,
- void *first_cmp_arg, uint auto_extent);
-int reinit_queue(QUEUE *queue,uint max_elements,uint offset_to_key,
- pbool max_at_top, queue_compare compare,
- void *first_cmp_arg);
-int resize_queue(QUEUE *queue, uint max_elements);
-void delete_queue(QUEUE *queue);
-void queue_insert(QUEUE *queue,uchar *element);
-int queue_insert_safe(QUEUE *queue, uchar *element);
-uchar *queue_remove(QUEUE *queue,uint idx);
-void _downheap(QUEUE *queue,uint idx);
-void queue_fix(QUEUE *queue);
-#include "sql_bitmap.h"
-#include <my_bitmap.h>
-#include <m_string.h>
-typedef uint32 my_bitmap_map;
-typedef struct st_bitmap
-{
- my_bitmap_map *bitmap;
- uint n_bits;
- my_bitmap_map last_word_mask;
- my_bitmap_map *last_word_ptr;
- pthread_mutex_t *mutex;
-} MY_BITMAP;
-extern void create_last_word_mask(MY_BITMAP *map);
-extern my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
- my_bool thread_safe);
-extern my_bool bitmap_is_clear_all(const MY_BITMAP *map);
-extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size);
-extern my_bool bitmap_is_set_all(const MY_BITMAP *map);
-extern my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2);
-extern my_bool bitmap_is_overlapping(const MY_BITMAP *map1,
- const MY_BITMAP *map2);
-extern my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit);
-extern my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit);
-extern my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit);
-extern uint bitmap_set_next(MY_BITMAP *map);
-extern uint bitmap_get_first(const MY_BITMAP *map);
-extern uint bitmap_get_first_set(const MY_BITMAP *map);
-extern uint bitmap_bits_set(const MY_BITMAP *map);
-extern void bitmap_free(MY_BITMAP *map);
-extern void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit);
-extern void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size);
-extern void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2);
-extern void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2);
-extern void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2);
-extern void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2);
-extern void bitmap_invert(MY_BITMAP *map);
-extern void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2);
-extern uint bitmap_lock_set_next(MY_BITMAP *map);
-extern void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit);
-static inline void
-bitmap_set_bit(MY_BITMAP *map,uint bit)
-{
- assert(bit < (map)->n_bits);
- (((uchar*)(map)->bitmap)[(bit) / 8] |= (1 << ((bit) & 7)));
-}
-static inline void
-bitmap_flip_bit(MY_BITMAP *map,uint bit)
-{
- assert(bit < (map)->n_bits);
- (((uchar*)(map)->bitmap)[(bit) / 8] ^= (1 << ((bit) & 7)));
-}
-static inline void
-bitmap_clear_bit(MY_BITMAP *map,uint bit)
-{
- assert(bit < (map)->n_bits);
- (((uchar*)(map)->bitmap)[(bit) / 8] &= ~ (1 << ((bit) & 7)));
-}
-static inline uint
-bitmap_is_set(const MY_BITMAP *map,uint bit)
-{
- assert(bit < (map)->n_bits);
- return (uint) (((uchar*)(map)->bitmap)[(bit) / 8] & (1 << ((bit) & 7)));
-}
-static inline my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2)
-{
- *(map1)->last_word_ptr|= (map1)->last_word_mask;
- *(map2)->last_word_ptr|= (map2)->last_word_mask;
- return memcmp((map1)->bitmap, (map2)->bitmap, 4*((((map1))->n_bits + 31)/32))==0;
-}
-template <uint default_width> class Bitmap
-{
- MY_BITMAP map;
- uint32 buffer[(default_width+31)/32];
-public:
- Bitmap() { init(); }
- Bitmap(const Bitmap& from) { *this=from; }
- explicit Bitmap(uint prefix_to_set) { init(prefix_to_set); }
- void init() { bitmap_init(&map, buffer, default_width, 0); }
- void init(uint prefix_to_set) { init(); set_prefix(prefix_to_set); }
- uint length() const { return default_width; }
- Bitmap& operator=(const Bitmap& map2)
- {
- init();
- memcpy(buffer, map2.buffer, sizeof(buffer));
- return *this;
- }
- void set_bit(uint n) { bitmap_set_bit(&map, n); }
- void clear_bit(uint n) { bitmap_clear_bit(&map, n); }
- void set_prefix(uint n) { bitmap_set_prefix(&map, n); }
- void set_all() { (memset((&map)->bitmap, 0xFF, 4*((((&map))->n_bits + 31)/32))); }
- void clear_all() { { memset((&map)->bitmap, 0, 4*((((&map))->n_bits + 31)/32)); }; }
- void intersect(Bitmap& map2) { bitmap_intersect(&map, &map2.map); }
- void intersect(ulonglong map2buff)
- {
- MY_BITMAP map2;
- bitmap_init(&map2, (uint32 *)&map2buff, sizeof(ulonglong)*8, 0);
- bitmap_intersect(&map, &map2);
- }
- void intersect_extended(ulonglong map2buff)
- {
- intersect(map2buff);
- if (map.n_bits > sizeof(ulonglong) * 8)
- bitmap_set_above(&map, sizeof(ulonglong),
- ((map2buff & (1LL << (sizeof(ulonglong) * 8 - 1))) ? 1 : 0));
- }
- void subtract(Bitmap& map2) { bitmap_subtract(&map, &map2.map); }
- void merge(Bitmap& map2) { bitmap_union(&map, &map2.map); }
- my_bool is_set(uint n) const { return bitmap_is_set(&map, n); }
- my_bool is_prefix(uint n) const { return bitmap_is_prefix(&map, n); }
- my_bool is_clear_all() const { return bitmap_is_clear_all(&map); }
- my_bool is_set_all() const { return bitmap_is_set_all(&map); }
- my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset(&map, &map2.map); }
- my_bool is_overlapping(const Bitmap& map2) const { return bitmap_is_overlapping(&map, &map2.map); }
- my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); }
- 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)
- {
- *s++=_dig_vec_upper[*b >> 4];
- *s++=_dig_vec_upper[*b & 15];
- }
- *s=0;
- return buf;
- }
- ulonglong to_ulonglong() const
- {
- if (sizeof(buffer) >= 8)
- return (*((ulonglong *) (buffer)));
- assert(sizeof(buffer) >= 4);
- return (ulonglong) (*((uint32 *) (buffer)));
- }
-};
-template <> class Bitmap<64>
-{
- ulonglong map;
-public:
- Bitmap<64>() { }
- explicit Bitmap<64>(uint prefix_to_set) { set_prefix(prefix_to_set); }
- void init() { }
- 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; }
- my_bool is_set(uint n) const { return ((map & (((ulonglong)1) << n)) ? 1 : 0); }
- my_bool is_prefix(uint n) const { return map == (((ulonglong)1) << n)-1; }
- my_bool is_clear_all() const { return map == (ulonglong)0; }
- my_bool is_set_all() const { return map == ~(ulonglong)0; }
- my_bool is_subset(const Bitmap<64>& map2) const { return !(map & ~map2.map); }
- my_bool is_overlapping(const Bitmap<64>& map2) const { return (map & map2.map)!= 0; }
- my_bool operator==(const Bitmap<64>& map2) const { return map == map2.map; }
- char *print(char *buf) const { longlong2str(map,buf,16); return buf; }
- ulonglong to_ulonglong() const { return map; }
-};
-#include "sql_array.h"
-#include <my_sys.h>
-template <class Elem> class Dynamic_array
-{
- DYNAMIC_ARRAY array;
-public:
- Dynamic_array(uint prealloc=16, uint increment=16)
- {
- init_dynamic_array2(&array,sizeof(Elem),NULL,prealloc,increment );
- }
- Elem& at(int idx)
- {
- return *(((Elem*)array.buffer) + idx);
- }
- Elem *front()
- {
- return (Elem*)array.buffer;
- }
- Elem *back()
- {
- return ((Elem*)array.buffer) + array.elements;
- }
- In_C_you_should_use_my_bool_instead() append(Elem &el)
- {
- return (insert_dynamic(&array, (uchar*)&el));
- }
- int elements()
- {
- return array.elements;
- }
- ~Dynamic_array()
- {
- delete_dynamic(&array);
- }
- typedef int (*CMP_FUNC)(const Elem *el1, const Elem *el2);
- void sort(CMP_FUNC cmp_func)
- {
- my_qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func);
- }
-};
-#include "sql_plugin.h"
-class sys_var;
-#include <mysql/plugin.h>
-typedef struct st_mysql_lex_string MYSQL_LEX_STRING;
-struct st_mysql_xid {
- long formatID;
- long gtrid_length;
- long bqual_length;
- char data[128];
-};
-typedef struct st_mysql_xid MYSQL_XID;
-enum enum_mysql_show_type
-{
- SHOW_UNDEF, SHOW_BOOL, SHOW_INT, SHOW_LONG,
- SHOW_LONGLONG, SHOW_CHAR, SHOW_CHAR_PTR,
- SHOW_ARRAY, SHOW_FUNC, SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_LONGLONG, SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, SHOW_HAVE, SHOW_MY_BOOL, SHOW_HA_ROWS, SHOW_SYS, SHOW_LONG_NOFLUSH, SHOW_LONGLONG_STATUS, SHOW_DOUBLE
-};
-struct st_mysql_show_var {
- const char *name;
- char *value;
- enum enum_mysql_show_type type;
-};
-typedef int (*mysql_show_var_func)(void*, struct st_mysql_show_var*, char *);
-struct st_mysql_sys_var;
-struct st_mysql_value;
-typedef int (*mysql_var_check_func)(void* thd,
- struct st_mysql_sys_var *var,
- void *save, struct st_mysql_value *value);
-typedef void (*mysql_var_update_func)(void* thd,
- struct st_mysql_sys_var *var,
- void *var_ptr, const void *save);
-struct st_mysql_plugin
-{
- int type;
- void *info;
- const char *name;
- const char *author;
- const char *descr;
- int license;
- int (*init)(void *);
- int (*deinit)(void *);
- unsigned int version;
- struct st_mysql_show_var *status_vars;
- struct st_mysql_sys_var **system_vars;
- void * __reserved1;
-};
-enum enum_ftparser_mode
-{
- MYSQL_FTPARSER_SIMPLE_MODE= 0,
- MYSQL_FTPARSER_WITH_STOPWORDS= 1,
- MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2
-};
-enum enum_ft_token_type
-{
- FT_TOKEN_EOF= 0,
- FT_TOKEN_WORD= 1,
- FT_TOKEN_LEFT_PAREN= 2,
- FT_TOKEN_RIGHT_PAREN= 3,
- FT_TOKEN_STOPWORD= 4
-};
-typedef struct st_mysql_ftparser_boolean_info
-{
- enum enum_ft_token_type type;
- int yesno;
- int weight_adjust;
- char wasign;
- char trunc;
- char prev;
- char *quot;
-} MYSQL_FTPARSER_BOOLEAN_INFO;
-typedef struct st_mysql_ftparser_param
-{
- int (*mysql_parse)(struct st_mysql_ftparser_param *,
- char *doc, int doc_len);
- int (*mysql_add_word)(struct st_mysql_ftparser_param *,
- char *word, int word_len,
- MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info);
- void *ftparser_state;
- void *mysql_ftparam;
- struct charset_info_st *cs;
- char *doc;
- int length;
- int flags;
- enum enum_ftparser_mode mode;
-} MYSQL_FTPARSER_PARAM;
-struct st_mysql_ftparser
-{
- int interface_version;
- int (*parse)(MYSQL_FTPARSER_PARAM *param);
- int (*init)(MYSQL_FTPARSER_PARAM *param);
- int (*deinit)(MYSQL_FTPARSER_PARAM *param);
-};
-struct st_mysql_storage_engine
-{
- int interface_version;
-};
-struct handlerton;
-struct st_mysql_daemon
-{
- int interface_version;
-};
-struct st_mysql_information_schema
-{
- int interface_version;
-};
-struct st_mysql_value
-{
- int (*value_type)(struct st_mysql_value *);
- const char *(*val_str)(struct st_mysql_value *, char *buffer, int *length);
- int (*val_real)(struct st_mysql_value *, double *realbuf);
- int (*val_int)(struct st_mysql_value *, long long *intbuf);
-};
-int thd_in_lock_tables(const void* thd);
-int thd_tablespace_op(const void* thd);
-long long thd_test_options(const void* thd, long long test_options);
-int thd_sql_command(const void* thd);
-const char *thd_proc_info(void* thd, const char *info);
-void **thd_ha_data(const void* thd, const struct handlerton *hton);
-int thd_tx_isolation(const void* thd);
-char *thd_security_context(void* thd, char *buffer, unsigned int length,
- unsigned int max_query_len);
-void thd_inc_row_count(void* thd);
-int mysql_tmpfile(const char *prefix);
-int thd_killed(const void* thd);
-unsigned long thd_get_thread_id(const void* thd);
-void *thd_alloc(void* thd, unsigned int size);
-void *thd_calloc(void* thd, unsigned int size);
-char *thd_strdup(void* thd, const char *str);
-char *thd_strmake(void* thd, const char *str, unsigned int size);
-void *thd_memdup(void* thd, const void* str, unsigned int size);
-MYSQL_LEX_STRING *thd_make_lex_string(void* thd, MYSQL_LEX_STRING *lex_str,
- const char *str, unsigned int size,
- int allocate_lex_string);
-void thd_get_xid(const void* thd, MYSQL_XID *xid);
-void mysql_query_cache_invalidate4(void* thd,
- const char *key, unsigned int key_length,
- int using_trx);
-typedef enum enum_mysql_show_type SHOW_TYPE;
-typedef struct st_mysql_show_var SHOW_VAR;
-struct st_plugin_dl
-{
- LEX_STRING dl;
- void *handle;
- struct st_mysql_plugin *plugins;
- int version;
- uint ref_count;
-};
-struct st_plugin_int
-{
- LEX_STRING name;
- struct st_mysql_plugin *plugin;
- struct st_plugin_dl *plugin_dl;
- uint state;
- uint ref_count;
- void *data;
- MEM_ROOT mem_root;
- sys_var *system_vars;
-};
-typedef struct st_plugin_int **plugin_ref;
-typedef int (*plugin_type_init)(struct st_plugin_int *);
-extern char *opt_plugin_load;
-extern char *opt_plugin_dir_ptr;
-extern char opt_plugin_dir[512];
-extern const LEX_STRING plugin_type_names[];
-extern int plugin_init(int *argc, char **argv, int init_flags);
-extern void plugin_shutdown(void);
-extern void my_print_help_inc_plugins(struct my_option *options, uint size);
-extern In_C_you_should_use_my_bool_instead() plugin_is_ready(const LEX_STRING *name, int type);
-extern plugin_ref plugin_lock(THD *thd, plugin_ref *ptr );
-extern plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name,
- int type );
-extern void plugin_unlock(THD *thd, plugin_ref plugin);
-extern void plugin_unlock_list(THD *thd, plugin_ref *list, uint count);
-extern In_C_you_should_use_my_bool_instead() mysql_install_plugin(THD *thd, const LEX_STRING *name,
- const LEX_STRING *dl);
-extern In_C_you_should_use_my_bool_instead() mysql_uninstall_plugin(THD *thd, const LEX_STRING *name);
-extern In_C_you_should_use_my_bool_instead() plugin_register_builtin(struct st_mysql_plugin *plugin);
-extern void plugin_thdvar_init(THD *thd);
-extern void plugin_thdvar_cleanup(THD *thd);
-typedef my_bool (plugin_foreach_func)(THD *thd,
- plugin_ref plugin,
- void *arg);
-extern In_C_you_should_use_my_bool_instead() plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
- int type, uint state_mask, void *arg);
-#include "scheduler.h"
-class THD;
-class scheduler_functions
-{
-public:
- uint max_threads;
- In_C_you_should_use_my_bool_instead() (*init)(void);
- In_C_you_should_use_my_bool_instead() (*init_new_connection_thread)(void);
- void (*add_connection)(THD *thd);
- void (*post_kill_notification)(THD *thd);
- In_C_you_should_use_my_bool_instead() (*end_thread)(THD *thd, In_C_you_should_use_my_bool_instead() cache_thread);
- void (*end)(void);
- scheduler_functions();
-};
-enum scheduler_types
-{
- SCHEDULER_ONE_THREAD_PER_CONNECTION=0,
- SCHEDULER_NO_THREADS,
- SCHEDULER_POOL_OF_THREADS
-};
-void one_thread_per_connection_scheduler(scheduler_functions* func);
-void one_thread_scheduler(scheduler_functions* func);
-enum pool_command_op
-{
- NOT_IN_USE_OP= 0, NORMAL_OP= 1, CONNECT_OP, KILL_OP, DIE_OP
-};
-class thd_scheduler
-{};
-enum enum_query_type
-{
- QT_ORDINARY,
- QT_IS
-};
-typedef ulonglong table_map;
-typedef Bitmap<64> key_map;
-typedef ulong nesting_map;
-typedef ulonglong nested_join_map;
-typedef ulonglong query_id_t;
-extern query_id_t global_query_id;
-inline query_id_t next_query_id() { return global_query_id++; }
-extern const key_map key_map_empty;
-extern key_map key_map_full;
-extern const char *primary_key_name;
-#include "mysql_com.h"
-enum enum_server_command
-{
- COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST,
- COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS,
- COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING,
- COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP,
- COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE,
- COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE,
- COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON,
- COM_END
-};
-struct st_vio;
-typedef struct st_vio Vio;
-typedef struct st_net {
- Vio *vio;
- unsigned char *buff,*buff_end,*write_pos,*read_pos;
- my_socket fd;
- unsigned long remain_in_buf,length, buf_length, where_b;
- unsigned long max_packet,max_packet_size;
- unsigned int pkt_nr,compress_pkt_nr;
- unsigned int write_timeout, read_timeout, retry_count;
- int fcntl;
- unsigned int *return_status;
- unsigned char reading_or_writing;
- char save_char;
- my_bool unused0;
- my_bool unused;
- my_bool compress;
- my_bool unused1;
- unsigned char *query_cache_query;
- unsigned int last_errno;
- unsigned char error;
- my_bool unused2;
- my_bool return_errno;
- char last_error[512];
- char sqlstate[5 +1];
- void *extension;
-} NET;
-enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
- MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG,
- MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE,
- MYSQL_TYPE_NULL, MYSQL_TYPE_TIMESTAMP,
- MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24,
- MYSQL_TYPE_DATE, MYSQL_TYPE_TIME,
- MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
- MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
- MYSQL_TYPE_BIT,
- MYSQL_TYPE_NEWDECIMAL=246,
- MYSQL_TYPE_ENUM=247,
- MYSQL_TYPE_SET=248,
- MYSQL_TYPE_TINY_BLOB=249,
- MYSQL_TYPE_MEDIUM_BLOB=250,
- MYSQL_TYPE_LONG_BLOB=251,
- MYSQL_TYPE_BLOB=252,
- MYSQL_TYPE_VAR_STRING=253,
- MYSQL_TYPE_STRING=254,
- MYSQL_TYPE_GEOMETRY=255
-};
-enum mysql_enum_shutdown_level {
- SHUTDOWN_DEFAULT = 0,
- SHUTDOWN_WAIT_CONNECTIONS= (unsigned char)(1 << 0),
- SHUTDOWN_WAIT_TRANSACTIONS= (unsigned char)(1 << 1),
- SHUTDOWN_WAIT_UPDATES= (unsigned char)(1 << 3),
- SHUTDOWN_WAIT_ALL_BUFFERS= ((unsigned char)(1 << 3) << 1),
- SHUTDOWN_WAIT_CRITICAL_BUFFERS= ((unsigned char)(1 << 3) << 1) + 1,
- KILL_QUERY= 254,
- KILL_CONNECTION= 255
-};
-enum enum_cursor_type
-{
- CURSOR_TYPE_NO_CURSOR= 0,
- CURSOR_TYPE_READ_ONLY= 1,
- CURSOR_TYPE_FOR_UPDATE= 2,
- CURSOR_TYPE_SCROLLABLE= 4
-};
-enum enum_mysql_set_option
-{
- MYSQL_OPTION_MULTI_STATEMENTS_ON,
- MYSQL_OPTION_MULTI_STATEMENTS_OFF
-};
-my_bool my_net_init(NET *net, Vio* vio);
-void my_net_local_init(NET *net);
-void net_end(NET *net);
- void net_clear(NET *net, my_bool clear_buffer);
-my_bool net_realloc(NET *net, size_t length);
-my_bool net_flush(NET *net);
-my_bool my_net_write(NET *net,const unsigned char *packet, size_t len);
-my_bool net_write_command(NET *net,unsigned char command,
- const unsigned char *header, size_t head_len,
- const unsigned char *packet, size_t len);
-int net_real_write(NET *net,const unsigned char *packet, size_t len);
-unsigned long my_net_read(NET *net);
-void my_net_set_write_timeout(NET *net, uint timeout);
-void my_net_set_read_timeout(NET *net, uint timeout);
-struct sockaddr;
-int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen,
- unsigned int timeout);
-struct rand_struct {
- unsigned long seed1,seed2,max_value;
- double max_value_dbl;
-};
-enum Item_result {STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT,
- DECIMAL_RESULT};
-typedef struct st_udf_args
-{
- unsigned int arg_count;
- enum Item_result *arg_type;
- char **args;
- unsigned long *lengths;
- char *maybe_null;
- char **attributes;
- unsigned long *attribute_lengths;
- void *extension;
-} UDF_ARGS;
-typedef struct st_udf_init
-{
- my_bool maybe_null;
- unsigned int decimals;
- unsigned long max_length;
- char *ptr;
- my_bool const_item;
- void *extension;
-} UDF_INIT;
-void randominit(struct rand_struct *, unsigned long seed1,
- unsigned long seed2);
-double my_rnd(struct rand_struct *);
-void create_random_string(char *to, unsigned int length, struct rand_struct *rand_st);
-void hash_password(unsigned long *to, const char *password, unsigned int password_len);
-void make_scrambled_password_323(char *to, const char *password);
-void scramble_323(char *to, const char *message, const char *password);
-my_bool check_scramble_323(const char *, const char *message,
- unsigned long *salt);
-void get_salt_from_password_323(unsigned long *res, const char *password);
-void make_password_from_salt_323(char *to, const unsigned long *salt);
-void make_scrambled_password(char *to, const char *password);
-void scramble(char *to, const char *message, const char *password);
-my_bool check_scramble(const char *reply, const char *message,
- const unsigned char *hash_stage2);
-void get_salt_from_password(unsigned char *res, const char *password);
-void make_password_from_salt(char *to, const unsigned char *hash_stage2);
-char *octet2hex(char *to, const char *str, unsigned int len);
-char *get_tty_password(const char *opt_message);
-const char *mysql_errno_to_sqlstate(unsigned int mysql_errno);
-my_bool my_thread_init(void);
-void my_thread_end(void);
-ulong net_field_length(uchar **packet);
-my_ulonglong net_field_length_ll(uchar **packet);
-uchar *net_store_length(uchar *pkg, ulonglong length);
-#include <violite.h>
-#include "my_net.h"
-#include <errno.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/poll.h>
-#include <sys/ioctl.h>
-#include <netinet/in_systm.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
-void my_inet_ntoa(struct in_addr in, char *buf);
-struct hostent;
-struct hostent *my_gethostbyname_r(const char *name,
- struct hostent *result, char *buffer,
- int buflen, int *h_errnop);
-enum enum_vio_type
-{
- VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET, VIO_TYPE_NAMEDPIPE,
- VIO_TYPE_SSL, VIO_TYPE_SHARED_MEMORY
-};
-Vio* vio_new(my_socket sd, enum enum_vio_type type, uint flags);
-void vio_delete(Vio* vio);
-int vio_close(Vio* vio);
-void vio_reset(Vio* vio, enum enum_vio_type type,
- my_socket sd, void * hPipe, uint flags);
-size_t vio_read(Vio *vio, uchar * buf, size_t size);
-size_t vio_read_buff(Vio *vio, uchar * buf, size_t size);
-size_t vio_write(Vio *vio, const uchar * buf, size_t size);
-int vio_blocking(Vio *vio, my_bool onoff, my_bool *old_mode);
-my_bool vio_is_blocking(Vio *vio);
-int vio_fastsend(Vio *vio);
-int vio_keepalive(Vio *vio, my_bool onoff);
-my_bool vio_should_retry(Vio *vio);
-my_bool vio_was_interrupted(Vio *vio);
-const char* vio_description(Vio *vio);
-enum enum_vio_type vio_type(Vio* vio);
-int vio_errno(Vio*vio);
-my_socket vio_fd(Vio*vio);
-my_bool vio_peer_addr(Vio* vio, char *buf, uint16 *port);
-void vio_in_addr(Vio *vio, struct in_addr *in);
-my_bool vio_poll_read(Vio *vio,uint timeout);
-void vio_end(void);
-enum SSL_type
-{
- SSL_TYPE_NOT_SPECIFIED= -1,
- SSL_TYPE_NONE,
- SSL_TYPE_ANY,
- SSL_TYPE_X509,
- SSL_TYPE_SPECIFIED
-};
-struct st_vio
-{
- my_socket sd;
- void * hPipe;
- my_bool localhost;
- int fcntl_mode;
- struct sockaddr_in local;
- struct sockaddr_in remote;
- enum enum_vio_type type;
- char desc[30];
- char *read_buffer;
- char *read_pos;
- char *read_end;
- void (*viodelete)(Vio*);
- int (*vioerrno)(Vio*);
- size_t (*read)(Vio*, uchar *, size_t);
- size_t (*write)(Vio*, const uchar *, size_t);
- int (*vioblocking)(Vio*, my_bool, my_bool *);
- my_bool (*is_blocking)(Vio*);
- int (*viokeepalive)(Vio*, my_bool);
- int (*fastsend)(Vio*);
- my_bool (*peer_addr)(Vio*, char *, uint16*);
- void (*in_addr)(Vio*, struct in_addr*);
- my_bool (*should_retry)(Vio*);
- my_bool (*was_interrupted)(Vio*);
- int (*vioclose)(Vio*);
- void (*timeout)(Vio*, unsigned int which, unsigned int timeout);
-};
-#include "unireg.h"
-#include "mysqld_error.h"
-#include "structs.h"
-struct st_table;
-class Field;
-typedef struct st_date_time_format {
- uchar positions[8];
- char time_separator;
- uint flag;
- LEX_STRING format;
-} DATE_TIME_FORMAT;
-typedef struct st_keyfile_info {
- uchar ref[8];
- uchar dupp_ref[8];
- uint ref_length;
- uint block_size;
- File filenr;
- ha_rows records;
- ha_rows deleted;
- ulonglong data_file_length;
- ulonglong max_data_file_length;
- ulonglong index_file_length;
- ulonglong max_index_file_length;
- ulonglong delete_length;
- ulonglong auto_increment_value;
- int errkey,sortkey;
- time_t create_time;
- time_t check_time;
- time_t update_time;
- ulong mean_rec_length;
-} KEYFILE_INFO;
-typedef struct st_key_part_info {
- Field *field;
- uint offset;
- uint null_offset;
- uint16 length;
- uint16 store_length;
- uint16 key_type;
- uint16 fieldnr;
- uint16 key_part_flag;
- uint8 type;
- uint8 null_bit;
-} KEY_PART_INFO ;
-typedef struct st_key {
- uint key_length;
- ulong flags;
- uint key_parts;
- uint extra_length;
- uint usable_key_parts;
- uint block_size;
- enum ha_key_alg algorithm;
- union
- {
- plugin_ref parser;
- LEX_STRING *parser_name;
- };
- KEY_PART_INFO *key_part;
- char *name;
- ulong *rec_per_key;
- union {
- int bdb_return_if_eq;
- } handler;
- struct st_table *table;
-} KEY;
-struct st_join_table;
-typedef struct st_reginfo {
- struct st_join_table *join_tab;
- enum thr_lock_type lock_type;
- In_C_you_should_use_my_bool_instead() not_exists_optimize;
- In_C_you_should_use_my_bool_instead() impossible_range;
-} REGINFO;
-struct st_read_record;
-class SQL_SELECT;
-class THD;
-class handler;
-typedef struct st_read_record {
- struct st_table *table;
- handler *file;
- struct st_table **forms;
- int (*read_record)(struct st_read_record *);
- THD *thd;
- SQL_SELECT *select;
- uint cache_records;
- uint ref_length,struct_length,reclength,rec_cache_size,error_offset;
- uint index;
- uchar *ref_pos;
- uchar *record;
- uchar *rec_buf;
- uchar *cache,*cache_pos,*cache_end,*read_positions;
- IO_CACHE *io_cache;
- In_C_you_should_use_my_bool_instead() print_error, ignore_not_found_rows;
-} READ_RECORD;
-typedef enum enum_mysql_timestamp_type timestamp_type;
-typedef struct {
- ulong year,month,day,hour;
- ulonglong minute,second,second_part;
- In_C_you_should_use_my_bool_instead() neg;
-} INTERVAL;
-typedef struct st_known_date_time_format {
- const char *format_name;
- const char *date_format;
- const char *datetime_format;
- const char *time_format;
-} KNOWN_DATE_TIME_FORMAT;
-enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED};
-extern const char *show_comp_option_name[];
-typedef int *(*update_var)(THD *, struct st_mysql_show_var *);
-typedef struct st_lex_user {
- LEX_STRING user, host, password;
-} LEX_USER;
-typedef struct user_resources {
- uint questions;
- uint updates;
- uint conn_per_hour;
- uint user_conn;
- enum {QUERIES_PER_HOUR= 1, UPDATES_PER_HOUR= 2, CONNECTIONS_PER_HOUR= 4,
- USER_CONNECTIONS= 8};
- uint specified_limits;
-} USER_RESOURCES;
-typedef struct user_conn {
- char *user;
- char *host;
- ulonglong reset_utime;
- uint len;
- uint connections;
- uint conn_per_hour, updates, questions;
- USER_RESOURCES user_resources;
-} USER_CONN;
-class Discrete_interval {
-private:
- ulonglong interval_min;
- ulonglong interval_values;
- ulonglong interval_max;
-public:
- Discrete_interval *next;
- void replace(ulonglong start, ulonglong val, ulonglong incr)
- {
- interval_min= start;
- interval_values= val;
- interval_max= (val == ((unsigned long long)(~0ULL))) ? val : start + val * incr;
- }
- Discrete_interval(ulonglong start, ulonglong val, ulonglong incr) :
- next(NULL) { replace(start, val, incr); };
- Discrete_interval() : next(NULL) { replace(0, 0, 0); };
- ulonglong minimum() const { return interval_min; };
- ulonglong values() const { return interval_values; };
- ulonglong maximum() const { return interval_max; };
- In_C_you_should_use_my_bool_instead() merge_if_contiguous(ulonglong start, ulonglong val, ulonglong incr)
- {
- if (interval_max == start)
- {
- if (val == ((unsigned long long)(~0ULL)))
- {
- interval_values= interval_max= val;
- }
- else
- {
- interval_values+= val;
- interval_max= start + val * incr;
- }
- return 0;
- }
- return 1;
- };
-};
-class Discrete_intervals_list {
-private:
- Discrete_interval *head;
- Discrete_interval *tail;
- Discrete_interval *current;
- uint elements;
- void copy_(const Discrete_intervals_list& from)
- {
- for (Discrete_interval *i= from.head; i; i= i->next)
- {
- Discrete_interval j= *i;
- append(&j);
- }
- }
-public:
- Discrete_intervals_list() : head(NULL), current(NULL), elements(0) {};
- Discrete_intervals_list(const Discrete_intervals_list& from)
- {
- copy_(from);
- }
- void operator=(const Discrete_intervals_list& from)
- {
- empty();
- copy_(from);
- }
- void empty_no_free()
- {
- head= current= NULL;
- elements= 0;
- }
- void empty()
- {
- for (Discrete_interval *i= head; i;)
- {
- Discrete_interval *next= i->next;
- delete i;
- i= next;
- }
- empty_no_free();
- }
- const Discrete_interval* get_next()
- {
- Discrete_interval *tmp= current;
- if (current != NULL)
- current= current->next;
- return tmp;
- }
- ~Discrete_intervals_list() { empty(); };
- In_C_you_should_use_my_bool_instead() append(ulonglong start, ulonglong val, ulonglong incr);
- In_C_you_should_use_my_bool_instead() append(Discrete_interval *interval);
- ulonglong minimum() const { return (head ? head->minimum() : 0); };
- ulonglong maximum() const { return (head ? tail->maximum() : 0); };
- uint nb_elements() const { return elements; }
-};
-void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size);
-void *sql_alloc(size_t);
-void *sql_calloc(size_t);
-char *sql_strdup(const char *str);
-char *sql_strmake(const char *str, size_t len);
-void *sql_memdup(const void * ptr, size_t size);
-void sql_element_free(void *ptr);
-char *sql_strmake_with_convert(const char *str, size_t arg_length,
- CHARSET_INFO *from_cs,
- size_t max_res_length,
- CHARSET_INFO *to_cs, size_t *result_length);
-uint kill_one_thread(THD *thd, ulong id, In_C_you_should_use_my_bool_instead() only_kill_query);
-void sql_kill(THD *thd, ulong id, In_C_you_should_use_my_bool_instead() only_kill_query);
-In_C_you_should_use_my_bool_instead() net_request_file(NET* net, const char* fname);
-char* query_table_status(THD *thd,const char *db,const char *table_name);
-extern CHARSET_INFO *system_charset_info, *files_charset_info ;
-extern CHARSET_INFO *national_charset_info, *table_alias_charset;
-enum Derivation
-{
- DERIVATION_IGNORABLE= 5,
- DERIVATION_COERCIBLE= 4,
- DERIVATION_SYSCONST= 3,
- DERIVATION_IMPLICIT= 2,
- DERIVATION_NONE= 1,
- DERIVATION_EXPLICIT= 0
-};
-typedef struct my_locale_st
-{
- uint number;
- const char *name;
- const char *description;
- const In_C_you_should_use_my_bool_instead() is_ascii;
- TYPELIB *month_names;
- TYPELIB *ab_month_names;
- TYPELIB *day_names;
- TYPELIB *ab_day_names;
-} MY_LOCALE;
-extern MY_LOCALE my_locale_en_US;
-extern MY_LOCALE *my_locales[];
-extern MY_LOCALE *my_default_lc_time_names;
-MY_LOCALE *my_locale_by_name(const char *name);
-MY_LOCALE *my_locale_by_number(uint number);
-class Object_creation_ctx
-{
-public:
- Object_creation_ctx *set_n_backup(THD *thd);
- void restore_env(THD *thd, Object_creation_ctx *backup_ctx);
-protected:
- Object_creation_ctx() {}
- virtual Object_creation_ctx *create_backup_ctx(THD *thd) const = 0;
- virtual void change_env(THD *thd) const = 0;
-public:
- virtual ~Object_creation_ctx()
- { }
-};
-class Default_object_creation_ctx : public Object_creation_ctx
-{
-public:
- CHARSET_INFO *get_client_cs()
- {
- return m_client_cs;
- }
- CHARSET_INFO *get_connection_cl()
- {
- return m_connection_cl;
- }
-protected:
- Default_object_creation_ctx(THD *thd);
- Default_object_creation_ctx(CHARSET_INFO *client_cs,
- CHARSET_INFO *connection_cl);
-protected:
- virtual Object_creation_ctx *create_backup_ctx(THD *thd) const;
- virtual void change_env(THD *thd) const;
-protected:
- CHARSET_INFO *m_client_cs;
- CHARSET_INFO *m_connection_cl;
-};
-struct TABLE_LIST;
-class String;
-void view_store_options(THD *thd, TABLE_LIST *table, String *buff);
-enum enum_parsing_place
-{
- NO_MATTER,
- IN_HAVING,
- SELECT_LIST,
- IN_WHERE,
- IN_ON
-};
-struct st_table;
-class THD;
-enum enum_check_fields
-{
- CHECK_FIELD_IGNORE,
- CHECK_FIELD_WARN,
- CHECK_FIELD_ERROR_FOR_NULL
-};
-typedef struct st_sql_list {
- uint elements;
- uchar *first;
- uchar **next;
- st_sql_list() {}
- inline void empty()
- {
- elements=0;
- first=0;
- next= &first;
- }
- inline void link_in_list(uchar *element,uchar **next_ptr)
- {
- elements++;
- (*next)=element;
- next= next_ptr;
- *next=0;
- }
- inline void save_and_clear(struct st_sql_list *save)
- {
- *save= *this;
- empty();
- }
- inline void push_front(struct st_sql_list *save)
- {
- *save->next= first;
- first= save->first;
- elements+= save->elements;
- }
- inline void push_back(struct st_sql_list *save)
- {
- if (save->first)
- {
- *next= save->first;
- next= save->next;
- elements+= save->elements;
- }
- }
-} SQL_LIST;
-extern pthread_key_t THR_THD;
-inline THD *_current_thd(void)
-{
- return ((THD*) pthread_getspecific((THR_THD)));
-}
-extern "C"
-const char *set_thd_proc_info(THD *thd, const char *info,
- const char *calling_func,
- const char *calling_file,
- const unsigned int calling_line);
-enum enum_table_ref_type
-{
- TABLE_REF_NULL= 0,
- TABLE_REF_VIEW,
- TABLE_REF_BASE_TABLE,
- TABLE_REF_I_S_TABLE,
- TABLE_REF_TMP_TABLE
-};
-extern ulong server_id, concurrency;
-typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
- uint key_length,
- ulonglong *engine_data);
-#include "sql_string.h"
-class String;
-int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
-String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
-uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
- const char *from, uint32 from_length,
- CHARSET_INFO *from_cs, uint *errors);
-uint32 well_formed_copy_nchars(CHARSET_INFO *to_cs,
- char *to, uint to_length,
- CHARSET_INFO *from_cs,
- const char *from, uint from_length,
- uint nchars,
- const char **well_formed_error_pos,
- const char **cannot_convert_error_pos,
- const char **from_end_pos);
-size_t my_copy_with_hex_escaping(CHARSET_INFO *cs,
- char *dst, size_t dstlen,
- const char *src, size_t srclen);
-class String
-{
- char *Ptr;
- uint32 str_length,Alloced_length;
- In_C_you_should_use_my_bool_instead() alloced;
- CHARSET_INFO *str_charset;
-public:
- String()
- {
- Ptr=0; str_length=Alloced_length=0; alloced=0;
- str_charset= &my_charset_bin;
- }
- String(uint32 length_arg)
- {
- alloced=0; Alloced_length=0; (void) real_alloc(length_arg);
- str_charset= &my_charset_bin;
- }
- String(const char *str, CHARSET_INFO *cs)
- {
- Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0;
- str_charset=cs;
- }
- String(const char *str,uint32 len, CHARSET_INFO *cs)
- {
- Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;
- str_charset=cs;
- }
- String(char *str,uint32 len, CHARSET_INFO *cs)
- {
- Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;
- str_charset=cs;
- }
- String(const String &str)
- {
- Ptr=str.Ptr ; str_length=str.str_length ;
- Alloced_length=str.Alloced_length; alloced=0;
- str_charset=str.str_charset;
- }
- static void *operator new(size_t size, MEM_ROOT *mem_root)
- { return (void*) alloc_root(mem_root, (uint) size); }
- static void operator delete(void *ptr_arg,size_t size)
- { ; }
- static void operator delete(void *ptr_arg, MEM_ROOT *mem_root)
- { }
- ~String() { free(); }
- inline void set_charset(CHARSET_INFO *charset_arg)
- { str_charset= charset_arg; }
- inline CHARSET_INFO *charset() const { return str_charset; }
- inline uint32 length() const { return str_length;}
- inline uint32 alloced_length() const { return Alloced_length;}
- inline char& operator [] (uint32 i) const { return Ptr[i]; }
- inline void length(uint32 len) { str_length=len ; }
- inline In_C_you_should_use_my_bool_instead() is_empty() { return (str_length == 0); }
- inline void mark_as_const() { Alloced_length= 0;}
- inline const char *ptr() const { return Ptr; }
- inline char *c_ptr()
- {
- if (!Ptr || Ptr[str_length])
- (void) realloc(str_length);
- return Ptr;
- }
- inline char *c_ptr_quick()
- {
- if (Ptr && str_length < Alloced_length)
- Ptr[str_length]=0;
- return Ptr;
- }
- inline char *c_ptr_safe()
- {
- if (Ptr && str_length < Alloced_length)
- Ptr[str_length]=0;
- else
- (void) realloc(str_length);
- return Ptr;
- }
- void set(String &str,uint32 offset,uint32 arg_length)
- {
- assert(&str != this);
- free();
- Ptr=(char*) str.ptr()+offset; str_length=arg_length; alloced=0;
- if (str.Alloced_length)
- Alloced_length=str.Alloced_length-offset;
- else
- Alloced_length=0;
- str_charset=str.str_charset;
- }
- inline void set(char *str,uint32 arg_length, CHARSET_INFO *cs)
- {
- free();
- Ptr=(char*) str; str_length=Alloced_length=arg_length ; alloced=0;
- str_charset=cs;
- }
- inline void set(const char *str,uint32 arg_length, CHARSET_INFO *cs)
- {
- free();
- Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0;
- str_charset=cs;
- }
- In_C_you_should_use_my_bool_instead() set_ascii(const char *str, uint32 arg_length);
- inline void set_quick(char *str,uint32 arg_length, CHARSET_INFO *cs)
- {
- if (!alloced)
- {
- Ptr=(char*) str; str_length=Alloced_length=arg_length;
- }
- str_charset=cs;
- }
- In_C_you_should_use_my_bool_instead() set_int(longlong num, In_C_you_should_use_my_bool_instead() unsigned_flag, CHARSET_INFO *cs);
- In_C_you_should_use_my_bool_instead() set(longlong num, CHARSET_INFO *cs)
- { return set_int(num, false, cs); }
- In_C_you_should_use_my_bool_instead() set(ulonglong num, CHARSET_INFO *cs)
- { return set_int((longlong)num, true, cs); }
- In_C_you_should_use_my_bool_instead() set_real(double num,uint decimals, CHARSET_INFO *cs);
- inline void chop()
- {
- Ptr[str_length--]= '\0';
- }
- inline void free()
- {
- if (alloced)
- {
- alloced=0;
- Alloced_length=0;
- ((void)(myf) (0),my_no_flags_free(Ptr));
- Ptr=0;
- str_length=0;
- }
- }
- inline In_C_you_should_use_my_bool_instead() alloc(uint32 arg_length)
- {
- if (arg_length < Alloced_length)
- return 0;
- return real_alloc(arg_length);
- }
- In_C_you_should_use_my_bool_instead() real_alloc(uint32 arg_length);
- In_C_you_should_use_my_bool_instead() realloc(uint32 arg_length);
- inline void shrink(uint32 arg_length)
- {
- if (arg_length < Alloced_length)
- {
- char *new_ptr;
- if (!(new_ptr=(char*) my_realloc(Ptr,arg_length,(myf) (0))))
- {
- Alloced_length = 0;
- real_alloc(arg_length);
- }
- else
- {
- Ptr=new_ptr;
- Alloced_length=arg_length;
- }
- }
- }
- In_C_you_should_use_my_bool_instead() is_alloced() { return alloced; }
- inline String& operator = (const String &s)
- {
- if (&s != this)
- {
- assert(!s.uses_buffer_owned_by(this));
- free();
- Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length;
- alloced=0;
- }
- return *this;
- }
- In_C_you_should_use_my_bool_instead() copy();
- In_C_you_should_use_my_bool_instead() copy(const String &s);
- In_C_you_should_use_my_bool_instead() copy(const char *s,uint32 arg_length, CHARSET_INFO *cs);
- static In_C_you_should_use_my_bool_instead() needs_conversion(uint32 arg_length,
- CHARSET_INFO *cs_from, CHARSET_INFO *cs_to,
- uint32 *offset);
- In_C_you_should_use_my_bool_instead() copy_aligned(const char *s, uint32 arg_length, uint32 offset,
- CHARSET_INFO *cs);
- In_C_you_should_use_my_bool_instead() set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs);
- In_C_you_should_use_my_bool_instead() copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom,
- CHARSET_INFO *csto, uint *errors);
- In_C_you_should_use_my_bool_instead() append(const String &s);
- In_C_you_should_use_my_bool_instead() append(const char *s);
- In_C_you_should_use_my_bool_instead() append(const char *s,uint32 arg_length);
- In_C_you_should_use_my_bool_instead() append(const char *s,uint32 arg_length, CHARSET_INFO *cs);
- In_C_you_should_use_my_bool_instead() append(IO_CACHE* file, uint32 arg_length);
- In_C_you_should_use_my_bool_instead() append_with_prefill(const char *s, uint32 arg_length,
- uint32 full_length, char fill_char);
- int strstr(const String &search,uint32 offset=0);
- int strrstr(const String &search,uint32 offset=0);
- In_C_you_should_use_my_bool_instead() replace(uint32 offset,uint32 arg_length,const char *to,uint32 length);
- In_C_you_should_use_my_bool_instead() replace(uint32 offset,uint32 arg_length,const String &to);
- inline In_C_you_should_use_my_bool_instead() append(char chr)
- {
- if (str_length < Alloced_length)
- {
- Ptr[str_length++]=chr;
- }
- else
- {
- if (realloc(str_length+1))
- return 1;
- Ptr[str_length++]=chr;
- }
- return 0;
- }
- In_C_you_should_use_my_bool_instead() fill(uint32 max_length,char fill);
- void strip_sp();
- friend int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
- friend int stringcmp(const String *a,const String *b);
- friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
- uint32 numchars();
- int charpos(int i,uint32 offset=0);
- int reserve(uint32 space_needed)
- {
- return realloc(str_length + space_needed);
- }
- int reserve(uint32 space_needed, uint32 grow_by);
- void q_append(const char c)
- {
- Ptr[str_length++] = c;
- }
- void q_append(const uint32 n)
- {
- *((long *) (Ptr + str_length))= (long) (n);
- str_length += 4;
- }
- void q_append(double d)
- {
- do { *((long *) (Ptr + str_length)) = ((doubleget_union *)&(d))->m[0]; *(((long *) (Ptr + str_length))+1) = ((doubleget_union *)&(d))->m[1]; } while (0);
- str_length += 8;
- }
- void q_append(double *d)
- {
- do { *((long *) (Ptr + str_length)) = ((doubleget_union *)&(*d))->m[0]; *(((long *) (Ptr + str_length))+1) = ((doubleget_union *)&(*d))->m[1]; } while (0);
- str_length += 8;
- }
- void q_append(const char *data, uint32 data_len)
- {
- memcpy(Ptr + str_length, data, data_len);
- str_length += data_len;
- }
- void write_at_position(int position, uint32 value)
- {
- *((long *) (Ptr + position))= (long) (value);
- }
- void qs_append(const char *str, uint32 len);
- void qs_append(double d);
- void qs_append(double *d);
- inline void qs_append(const char c)
- {
- Ptr[str_length]= c;
- str_length++;
- }
- void qs_append(int i);
- void qs_append(uint i);
- inline char *prep_append(uint32 arg_length, uint32 step_alloc)
- {
- uint32 new_length= arg_length + str_length;
- if (new_length > Alloced_length)
- {
- if (realloc(new_length + step_alloc))
- return 0;
- }
- uint32 old_length= str_length;
- str_length+= arg_length;
- return Ptr+ old_length;
- }
- inline In_C_you_should_use_my_bool_instead() append(const char *s, uint32 arg_length, uint32 step_alloc)
- {
- uint32 new_length= arg_length + str_length;
- if (new_length > Alloced_length && realloc(new_length + step_alloc))
- return (1);
- memcpy(Ptr+str_length, s, arg_length);
- str_length+= arg_length;
- return (0);
- }
- void print(String *print);
- void swap(String &s);
- inline In_C_you_should_use_my_bool_instead() uses_buffer_owned_by(const String *s) const
- {
- return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->str_length);
- }
-};
-static inline In_C_you_should_use_my_bool_instead() check_if_only_end_space(CHARSET_INFO *cs, char *str,
- char *end)
-{
- return str+ cs->cset->scan(cs, str, end, 2) == end;
-}
-#include "sql_list.h"
-class Sql_alloc
-{
-public:
- static void *operator new(size_t size) throw ()
- {
- return sql_alloc(size);
- }
- static void *operator new[](size_t size)
- {
- return sql_alloc(size);
- }
- static void *operator new[](size_t size, MEM_ROOT *mem_root) throw ()
- { return alloc_root(mem_root, size); }
- static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
- { return alloc_root(mem_root, size); }
- static void operator delete(void *ptr, size_t size) { ; }
- static void operator delete(void *ptr, MEM_ROOT *mem_root)
- { }
- static void operator delete[](void *ptr, MEM_ROOT *mem_root)
- { }
- static void operator delete[](void *ptr, size_t size) { ; }
- inline Sql_alloc() {}
- inline ~Sql_alloc() {}
-};
-struct list_node :public Sql_alloc
-{
- list_node *next;
- void *info;
- list_node(void *info_par,list_node *next_par)
- :next(next_par),info(info_par)
- {}
- list_node()
- {
- info= 0;
- next= this;
- }
-};
-extern list_node end_of_list;
-class base_list :public Sql_alloc
-{
-protected:
- list_node *first,**last;
-public:
- uint elements;
- inline void empty() { elements=0; first= &end_of_list; last=&first;}
- inline base_list() { empty(); }
- inline base_list(const base_list &tmp) :Sql_alloc()
- {
- elements= tmp.elements;
- first= tmp.first;
- last= elements ? tmp.last : &first;
- }
- base_list(const base_list &rhs, MEM_ROOT *mem_root);
- inline base_list(In_C_you_should_use_my_bool_instead() error) { }
- inline In_C_you_should_use_my_bool_instead() push_back(void *info)
- {
- if (((*last)=new list_node(info, &end_of_list)))
- {
- last= &(*last)->next;
- elements++;
- return 0;
- }
- return 1;
- }
- inline In_C_you_should_use_my_bool_instead() push_back(void *info, MEM_ROOT *mem_root)
- {
- if (((*last)=new (mem_root) list_node(info, &end_of_list)))
- {
- last= &(*last)->next;
- elements++;
- return 0;
- }
- return 1;
- }
- inline In_C_you_should_use_my_bool_instead() push_front(void *info)
- {
- list_node *node=new list_node(info,first);
- if (node)
- {
- if (last == &first)
- last= &node->next;
- first=node;
- elements++;
- return 0;
- }
- return 1;
- }
- void remove(list_node **prev)
- {
- list_node *node=(*prev)->next;
- if (!--elements)
- last= &first;
- else if (last == &(*prev)->next)
- last= prev;
- delete *prev;
- *prev=node;
- }
- inline void concat(base_list *list)
- {
- if (!list->is_empty())
- {
- *last= list->first;
- last= list->last;
- elements+= list->elements;
- }
- }
- inline void *pop(void)
- {
- if (first == &end_of_list) return 0;
- list_node *tmp=first;
- first=first->next;
- if (!--elements)
- last= &first;
- return tmp->info;
- }
- inline void disjoin(base_list *list)
- {
- list_node **prev= &first;
- list_node *node= first;
- list_node *list_first= list->first;
- elements=0;
- while (node && node != list_first)
- {
- prev= &node->next;
- node= node->next;
- elements++;
- }
- *prev= *last;
- last= prev;
- }
- inline void prepand(base_list *list)
- {
- if (!list->is_empty())
- {
- *list->last= first;
- first= list->first;
- elements+= list->elements;
- }
- }
- inline void swap(base_list &rhs)
- {
- { list_node * dummy; dummy= first; first= rhs.first; rhs.first= dummy; };
- { list_node ** dummy; dummy= last; last= rhs.last; rhs.last= dummy; };
- { uint dummy; dummy= elements; elements= rhs.elements; rhs.elements= dummy; };
- }
- inline list_node* last_node() { return *last; }
- inline list_node* first_node() { return first;}
- inline void *head() { return first->info; }
- inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
- inline In_C_you_should_use_my_bool_instead() is_empty() { return first == &end_of_list ; }
- inline list_node *last_ref() { return &end_of_list; }
- friend class base_list_iterator;
- friend class error_list;
- friend class error_list_iterator;
-protected:
- void after(void *info,list_node *node)
- {
- list_node *new_node=new list_node(info,node->next);
- node->next=new_node;
- elements++;
- if (last == &(node->next))
- last= &new_node->next;
- }
-};
-class base_list_iterator
-{
-protected:
- base_list *list;
- list_node **el,**prev,*current;
- void sublist(base_list &ls, uint elm)
- {
- ls.first= *el;
- ls.last= list->last;
- ls.elements= elm;
- }
-public:
- base_list_iterator()
- :list(0), el(0), prev(0), current(0)
- {}
- base_list_iterator(base_list &list_par)
- { init(list_par); }
- inline void init(base_list &list_par)
- {
- list= &list_par;
- el= &list_par.first;
- prev= 0;
- current= 0;
- }
- inline void *next(void)
- {
- prev=el;
- current= *el;
- el= &current->next;
- return current->info;
- }
- inline void *next_fast(void)
- {
- list_node *tmp;
- tmp= *el;
- el= &tmp->next;
- return tmp->info;
- }
- inline void rewind(void)
- {
- el= &list->first;
- }
- inline void *replace(void *element)
- {
- void *tmp=current->info;
- assert(current->info != 0);
- current->info=element;
- return tmp;
- }
- void *replace(base_list &new_list)
- {
- void *ret_value=current->info;
- if (!new_list.is_empty())
- {
- *new_list.last=current->next;
- current->info=new_list.first->info;
- current->next=new_list.first->next;
- if ((list->last == &current->next) && (new_list.elements > 1))
- list->last= new_list.last;
- list->elements+=new_list.elements-1;
- }
- return ret_value;
- }
- inline void remove(void)
- {
- list->remove(prev);
- el=prev;
- current=0;
- }
- void after(void *element)
- {
- list->after(element,current);
- current=current->next;
- el= &current->next;
- }
- inline void **ref(void)
- {
- return &current->info;
- }
- inline In_C_you_should_use_my_bool_instead() is_last(void)
- {
- return el == &list->last_ref()->next;
- }
- friend class error_list_iterator;
-};
-template <class T> class List :public base_list
-{
-public:
- inline List() :base_list() {}
- inline List(const List<T> &tmp) :base_list(tmp) {}
- inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
- base_list(tmp, mem_root) {}
- inline In_C_you_should_use_my_bool_instead() push_back(T *a) { return base_list::push_back(a); }
- inline In_C_you_should_use_my_bool_instead() push_back(T *a, MEM_ROOT *mem_root)
- { return base_list::push_back(a, mem_root); }
- inline In_C_you_should_use_my_bool_instead() push_front(T *a) { return base_list::push_front(a); }
- inline T* head() {return (T*) base_list::head(); }
- inline T** head_ref() {return (T**) base_list::head_ref(); }
- inline T* pop() {return (T*) base_list::pop(); }
- inline void concat(List<T> *list) { base_list::concat(list); }
- inline void disjoin(List<T> *list) { base_list::disjoin(list); }
- inline void prepand(List<T> *list) { base_list::prepand(list); }
- void delete_elements(void)
- {
- list_node *element,*next;
- for (element=first; element != &end_of_list; element=next)
- {
- next=element->next;
- delete (T*) element->info;
- }
- empty();
- }
-};
-template <class T> class List_iterator :public base_list_iterator
-{
-public:
- List_iterator(List<T> &a) : base_list_iterator(a) {}
- List_iterator() : base_list_iterator() {}
- inline void init(List<T> &a) { base_list_iterator::init(a); }
- inline T* operator++(int) { return (T*) base_list_iterator::next(); }
- inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
- inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
- inline void rewind(void) { base_list_iterator::rewind(); }
- inline void remove() { base_list_iterator::remove(); }
- inline void after(T *a) { base_list_iterator::after(a); }
- inline T** ref(void) { return (T**) base_list_iterator::ref(); }
-};
-template <class T> class List_iterator_fast :public base_list_iterator
-{
-protected:
- inline T *replace(T *a) { return (T*) 0; }
- inline T *replace(List<T> &a) { return (T*) 0; }
- inline void remove(void) { }
- inline void after(T *a) { }
- inline T** ref(void) { return (T**) 0; }
-public:
- inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
- inline List_iterator_fast() : base_list_iterator() {}
- inline void init(List<T> &a) { base_list_iterator::init(a); }
- inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
- inline void rewind(void) { base_list_iterator::rewind(); }
- void sublist(List<T> &list_arg, uint el_arg)
- {
- base_list_iterator::sublist(list_arg, el_arg);
- }
-};
-struct ilink
-{
- struct ilink **prev,*next;
- static void *operator new(size_t size)
- {
- return (void*)my_malloc((uint)size, (myf) (16 | 8));
- }
- static void operator delete(void* ptr_arg, size_t size)
- {
- ((void)(myf) (16|64),my_no_flags_free((uchar*)ptr_arg));
- }
- inline ilink()
- {
- prev=0; next=0;
- }
- inline void unlink()
- {
- if (prev) *prev= next;
- if (next) next->prev=prev;
- prev=0 ; next=0;
- }
- virtual ~ilink() { unlink(); }
-};
-class i_string: public ilink
-{
-public:
- const char* ptr;
- i_string():ptr(0) { }
- i_string(const char* s) : ptr(s) {}
-};
-class i_string_pair: public ilink
-{
-public:
- const char* key;
- const char* val;
- i_string_pair():key(0),val(0) { }
- i_string_pair(const char* key_arg, const char* val_arg) :
- key(key_arg),val(val_arg) {}
-};
-template <class T> class I_List_iterator;
-class base_ilist
-{
-public:
- struct ilink *first,last;
- inline void empty() { first= &last; last.prev= &first; }
- base_ilist() { empty(); }
- inline In_C_you_should_use_my_bool_instead() is_empty() { return first == &last; }
- inline void append(ilink *a)
- {
- first->prev= &a->next;
- a->next=first; a->prev= &first; first=a;
- }
- inline void push_back(ilink *a)
- {
- *last.prev= a;
- a->next= &last;
- a->prev= last.prev;
- last.prev= &a->next;
- }
- inline struct ilink *get()
- {
- struct ilink *first_link=first;
- if (first_link == &last)
- return 0;
- first_link->unlink();
- return first_link;
- }
- inline struct ilink *head()
- {
- return (first != &last) ? first : 0;
- }
- friend class base_list_iterator;
-};
-class base_ilist_iterator
-{
- base_ilist *list;
- struct ilink **el,*current;
-public:
- base_ilist_iterator(base_ilist &list_par) :list(&list_par),
- el(&list_par.first),current(0) {}
- void *next(void)
- {
- current= *el;
- if (current == &list->last) return 0;
- el= &current->next;
- return current;
- }
-};
-template <class T>
-class I_List :private base_ilist
-{
-public:
- I_List() :base_ilist() {}
- inline void empty() { base_ilist::empty(); }
- inline In_C_you_should_use_my_bool_instead() is_empty() { return base_ilist::is_empty(); }
- inline void append(T* a) { base_ilist::append(a); }
- inline void push_back(T* a) { base_ilist::push_back(a); }
- inline T* get() { return (T*) base_ilist::get(); }
- inline T* head() { return (T*) base_ilist::head(); }
- friend class I_List_iterator<T>;
-};
-template <class T> class I_List_iterator :public base_ilist_iterator
-{
-public:
- I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {}
- inline T* operator++(int) { return (T*) base_ilist_iterator::next(); }
-};
-template <typename T>
-inline
-void
-list_copy_and_replace_each_value(List<T> &list, MEM_ROOT *mem_root)
-{
- List_iterator<T> it(list);
- T *el;
- while ((el= it++))
- it.replace(el->clone(mem_root));
-}
-#include "sql_map.h"
-class mapped_files;
-mapped_files *map_file(const char * name,uchar *magic,uint magic_length);
-void unmap_file(mapped_files *map);
-class mapped_files :public ilink {
- uchar *map;
- ha_rows size;
- char *name;
- File file;
- int error;
- uint use_count;
-public:
- mapped_files(const char * name,uchar *magic,uint magic_length);
- ~mapped_files();
- friend class mapped_file;
- friend mapped_files *map_file(const char * name,uchar *magic,
- uint magic_length);
- friend void unmap_file(mapped_files *map);
-};
-class mapped_file
-{
- mapped_files *file;
-public:
- mapped_file(const char * name,uchar *magic,uint magic_length)
- {
- file=map_file(name,magic,magic_length);
- }
- ~mapped_file()
- {
- unmap_file(file);
- }
- uchar *map()
- {
- return file->map;
- }
-};
-#include "my_decimal.h"
-#include <decimal.h>
-typedef enum
-{TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR}
- decimal_round_mode;
-typedef int32 decimal_digit_t;
-typedef struct st_decimal_t {
- int intg, frac, len;
- my_bool sign;
- decimal_digit_t *buf;
-} decimal_t;
-int internal_str2dec(const char *from, decimal_t *to, char **end,
- my_bool fixed);
-int decimal2string(decimal_t *from, char *to, int *to_len,
- int fixed_precision, int fixed_decimals,
- char filler);
-int decimal2ulonglong(decimal_t *from, ulonglong *to);
-int ulonglong2decimal(ulonglong from, decimal_t *to);
-int decimal2longlong(decimal_t *from, longlong *to);
-int longlong2decimal(longlong from, decimal_t *to);
-int decimal2double(decimal_t *from, double *to);
-int double2decimal(double from, decimal_t *to);
-int decimal_actual_fraction(decimal_t *from);
-int decimal2bin(decimal_t *from, uchar *to, int precision, int scale);
-int bin2decimal(const uchar *from, decimal_t *to, int precision, int scale);
-int decimal_size(int precision, int scale);
-int decimal_bin_size(int precision, int scale);
-int decimal_result_size(decimal_t *from1, decimal_t *from2, char op,
- int param);
-int decimal_intg(decimal_t *from);
-int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to);
-int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to);
-int decimal_cmp(decimal_t *from1, decimal_t *from2);
-int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to);
-int decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to,
- int scale_incr);
-int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to);
-int decimal_round(decimal_t *from, decimal_t *to, int new_scale,
- decimal_round_mode mode);
-int decimal_is_zero(decimal_t *from);
-void max_decimal(int precision, int frac, decimal_t *to);
-inline uint my_decimal_size(uint precision, uint scale)
-{
- return decimal_size(precision, scale) + 1;
-}
-inline int my_decimal_int_part(uint precision, uint decimals)
-{
- return precision - ((decimals == 31) ? 0 : decimals);
-}
-class my_decimal :public decimal_t
-{
- decimal_digit_t buffer[9];
-public:
- void init()
- {
- len= 9;
- buf= buffer;
- for (uint i= 0; i < 9; i++)
- buffer[i]= i;
- }
- my_decimal()
- {
- init();
- }
- void fix_buffer_pointer() { buf= buffer; }
- In_C_you_should_use_my_bool_instead() sign() const { return decimal_t::sign; }
- void sign(In_C_you_should_use_my_bool_instead() s) { decimal_t::sign= s; }
- uint precision() const { return intg + frac; }
- void swap(my_decimal &rhs)
- {
- { my_decimal dummy; dummy= *this; *this= rhs; rhs= dummy; };
- { decimal_digit_t * dummy; dummy= buf; buf= rhs.buf; rhs.buf= dummy; };
- }
-};
-void print_decimal(const my_decimal *dec);
-void print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length);
-const char *dbug_decimal_as_string(char *buff, const my_decimal *val);
-int decimal_operation_results(int result);
-inline
-void max_my_decimal(my_decimal *to, int precision, int frac)
-{
- assert((precision <= ((9 * 9) - 8*2))&& (frac <= 30));
- max_decimal(precision, frac, (decimal_t*) to);
-}
-inline void max_internal_decimal(my_decimal *to)
-{
- max_my_decimal(to, ((9 * 9) - 8*2), 0);
-}
-inline int check_result(uint mask, int result)
-{
- if (result & mask)
- decimal_operation_results(result);
- return result;
-}
-inline int check_result_and_overflow(uint mask, int result, my_decimal *val)
-{
- if (check_result(mask, result) & 2)
- {
- In_C_you_should_use_my_bool_instead() sign= val->sign();
- val->fix_buffer_pointer();
- max_internal_decimal(val);
- val->sign(sign);
- }
- return result;
-}
-inline uint my_decimal_length_to_precision(uint length, uint scale,
- In_C_you_should_use_my_bool_instead() unsigned_flag)
-{
- assert(length || !scale);
- return (uint) (length - (scale>0 ? 1:0) -
- (unsigned_flag || !length ? 0:1));
-}
-inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
- In_C_you_should_use_my_bool_instead() unsigned_flag)
-{
- assert(precision || !scale);
- do { if ((precision) > (((9 * 9) - 8*2))) (precision)=(((9 * 9) - 8*2)); } while(0);
- return (uint32)(precision + (scale>0 ? 1:0) +
- (unsigned_flag || !precision ? 0:1));
-}
-inline
-int my_decimal_string_length(const my_decimal *d)
-{
- return (((d)->intg ? (d)->intg : 1) + (d)->frac + ((d)->frac > 0) + 2);
-}
-inline
-int my_decimal_max_length(const my_decimal *d)
-{
- return (((d)->intg ? (d)->intg : 1) + (d)->frac + ((d)->frac > 0) + 2) - 1;
-}
-inline
-int my_decimal_get_binary_size(uint precision, uint scale)
-{
- return decimal_bin_size((int)precision, (int)scale);
-}
-inline
-void my_decimal2decimal(const my_decimal *from, my_decimal *to)
-{
- *to= *from;
- to->fix_buffer_pointer();
-}
-int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
- int scale);
-inline
-int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec,
- int scale)
-{
- return check_result(mask, bin2decimal(bin, (decimal_t*) d, prec, scale));
-}
-inline
-int my_decimal_set_zero(my_decimal *d)
-{
- do { (((decimal_t*) d))->buf[0]=0; (((decimal_t*) d))->intg=1; (((decimal_t*) d))->frac=0; (((decimal_t*) d))->sign=0; } while(0);
- return 0;
-}
-inline
-In_C_you_should_use_my_bool_instead() my_decimal_is_zero(const my_decimal *decimal_value)
-{
- return decimal_is_zero((decimal_t*) decimal_value);
-}
-inline
-int my_decimal_round(uint mask, const my_decimal *from, int scale,
- In_C_you_should_use_my_bool_instead() truncate, my_decimal *to)
-{
- return check_result(mask, decimal_round((decimal_t*) from, to, scale,
- (truncate ? TRUNCATE : HALF_UP)));
-}
-inline
-int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to)
-{
- return check_result(mask, decimal_round((decimal_t*) from, to, 0, FLOOR));
-}
-inline
-int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
-{
- return check_result(mask, decimal_round((decimal_t*) from, to, 0, CEILING));
-}
-int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
- uint fixed_dec, char filler, String *str);
-inline
-int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag,
- longlong *l)
-{
- my_decimal rounded;
- decimal_round((decimal_t*)d, &rounded, 0, HALF_UP);
- return check_result(mask, (unsigned_flag ?
- decimal2ulonglong(&rounded, (ulonglong *)l) :
- decimal2longlong(&rounded, l)));
-}
-inline
-int my_decimal2double(uint mask, const my_decimal *d, double *result)
-{
- return decimal2double((decimal_t*) d, result);
-}
-inline
-int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end)
-{
- return check_result_and_overflow(mask, internal_str2dec((str), ((decimal_t*)d), (end), 0),
- d);
-}
-int str2my_decimal(uint mask, const char *from, uint length,
- CHARSET_INFO *charset, my_decimal *decimal_value);
-inline
-int double2my_decimal(uint mask, double val, my_decimal *d)
-{
- return check_result_and_overflow(mask, double2decimal(val, (decimal_t*)d), d);
-}
-inline
-int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d)
-{
- return check_result(mask, (unsigned_flag ?
- ulonglong2decimal((ulonglong)i, d) :
- longlong2decimal(i, d)));
-}
-inline
-void my_decimal_neg(decimal_t *arg)
-{
- if (decimal_is_zero(arg))
- {
- arg->sign= 0;
- return;
- }
- do { (arg)->sign^=1; } while(0);
-}
-inline
-int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a,
- const my_decimal *b)
-{
- return check_result_and_overflow(mask,
- decimal_add((decimal_t*)a,(decimal_t*)b,res),
- res);
-}
-inline
-int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a,
- const my_decimal *b)
-{
- return check_result_and_overflow(mask,
- decimal_sub((decimal_t*)a,(decimal_t*)b,res),
- res);
-}
-inline
-int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a,
- const my_decimal *b)
-{
- return check_result_and_overflow(mask,
- decimal_mul((decimal_t*)a,(decimal_t*)b,res),
- res);
-}
-inline
-int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a,
- const my_decimal *b, int div_scale_inc)
-{
- return check_result_and_overflow(mask,
- decimal_div((decimal_t*)a,(decimal_t*)b,res,
- div_scale_inc),
- res);
-}
-inline
-int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a,
- const my_decimal *b)
-{
- return check_result_and_overflow(mask,
- decimal_mod((decimal_t*)a,(decimal_t*)b,res),
- res);
-}
-inline
-int my_decimal_cmp(const my_decimal *a, const my_decimal *b)
-{
- return decimal_cmp((decimal_t*) a, (decimal_t*) b);
-}
-inline
-int my_decimal_intg(const my_decimal *a)
-{
- return decimal_intg((decimal_t*) a);
-}
-void my_decimal_trim(ulong *precision, uint *scale);
-#include "handler.h"
-#include <my_handler.h>
-#include "myisampack.h"
-typedef struct st_HA_KEYSEG
-{
- CHARSET_INFO *charset;
- uint32 start;
- uint32 null_pos;
- uint16 bit_pos;
- uint16 flag;
- uint16 length;
- uint8 type;
- uint8 language;
- uint8 null_bit;
- uint8 bit_start,bit_end;
- uint8 bit_length;
-} HA_KEYSEG;
-extern int ha_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
- my_bool, my_bool);
-extern int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
- register uchar *b, uint key_length, uint nextflag,
- uint *diff_pos);
-extern HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a);
-extern void my_handler_error_register(void);
-extern void my_handler_error_unregister(void);
-#include <ft_global.h>
-typedef struct st_ft_info FT_INFO;
-struct _ft_vft
-{
- int (*read_next)(FT_INFO *, char *);
- float (*find_relevance)(FT_INFO *, uchar *, uint);
- void (*close_search)(FT_INFO *);
- float (*get_relevance)(FT_INFO *);
- void (*reinit_search)(FT_INFO *);
-};
-struct st_ft_info
-{
- struct _ft_vft *please;
-};
-extern const char *ft_stopword_file;
-extern const char *ft_precompiled_stopwords[];
-extern ulong ft_min_word_len;
-extern ulong ft_max_word_len;
-extern ulong ft_query_expansion_limit;
-extern char ft_boolean_syntax[15];
-extern struct st_mysql_ftparser ft_default_parser;
-int ft_init_stopwords(void);
-void ft_free_stopwords(void);
-FT_INFO *ft_init_search(uint,void *, uint, uchar *, uint,CHARSET_INFO *, uchar *);
-my_bool ft_boolean_check_syntax_string(const uchar *);
-#include <keycache.h>
-struct st_block_link;
-typedef struct st_block_link BLOCK_LINK;
-struct st_keycache_page;
-typedef struct st_keycache_page KEYCACHE_PAGE;
-struct st_hash_link;
-typedef struct st_hash_link HASH_LINK;
-typedef struct st_keycache_wqueue
-{
- struct st_my_thread_var *last_thread;
-} KEYCACHE_WQUEUE;
-typedef struct st_key_cache
-{
- my_bool key_cache_inited;
- my_bool in_resize;
- my_bool resize_in_flush;
- my_bool can_be_used;
- size_t key_cache_mem_size;
- uint key_cache_block_size;
- ulong min_warm_blocks;
- ulong age_threshold;
- ulonglong keycache_time;
- uint hash_entries;
- int hash_links;
- int hash_links_used;
- int disk_blocks;
- ulong blocks_used;
- ulong blocks_unused;
- ulong blocks_changed;
- ulong warm_blocks;
- ulong cnt_for_resize_op;
- long blocks_available;
- HASH_LINK **hash_root;
- HASH_LINK *hash_link_root;
- HASH_LINK *free_hash_list;
- BLOCK_LINK *free_block_list;
- BLOCK_LINK *block_root;
- uchar *block_mem;
- BLOCK_LINK *used_last;
- BLOCK_LINK *used_ins;
- pthread_mutex_t cache_lock;
- KEYCACHE_WQUEUE resize_queue;
- KEYCACHE_WQUEUE waiting_for_resize_cnt;
- KEYCACHE_WQUEUE waiting_for_hash_link;
- KEYCACHE_WQUEUE waiting_for_block;
- BLOCK_LINK *changed_blocks[128];
- BLOCK_LINK *file_blocks[128];
- ulonglong param_buff_size;
- ulong param_block_size;
- ulong param_division_limit;
- ulong param_age_threshold;
- ulong global_blocks_changed;
- ulonglong global_cache_w_requests;
- ulonglong global_cache_write;
- ulonglong global_cache_r_requests;
- ulonglong global_cache_read;
- int blocks;
- my_bool in_init;
-} KEY_CACHE;
-extern KEY_CACHE dflt_key_cache_var, *dflt_key_cache;
-extern int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
- size_t use_mem, uint division_limit,
- uint age_threshold);
-extern int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
- size_t use_mem, uint division_limit,
- uint age_threshold);
-extern void change_key_cache_param(KEY_CACHE *keycache, uint division_limit,
- uint age_threshold);
-extern uchar *key_cache_read(KEY_CACHE *keycache,
- File file, my_off_t filepos, int level,
- uchar *buff, uint length,
- uint block_length,int return_buffer);
-extern int key_cache_insert(KEY_CACHE *keycache,
- File file, my_off_t filepos, int level,
- uchar *buff, uint length);
-extern int key_cache_write(KEY_CACHE *keycache,
- File file, my_off_t filepos, int level,
- uchar *buff, uint length,
- uint block_length,int force_write);
-extern int flush_key_blocks(KEY_CACHE *keycache,
- int file, enum flush_type type);
-extern void end_key_cache(KEY_CACHE *keycache, my_bool cleanup);
-extern my_bool multi_keycache_init(void);
-extern void multi_keycache_free(void);
-extern KEY_CACHE *multi_key_cache_search(uchar *key, uint length);
-extern my_bool multi_key_cache_set(const uchar *key, uint length,
- KEY_CACHE *key_cache);
-extern void multi_key_cache_change(KEY_CACHE *old_data,
- KEY_CACHE *new_data);
-extern int reset_key_cache_counters(const char *name,
- KEY_CACHE *key_cache);
-enum legacy_db_type
-{
- DB_TYPE_UNKNOWN=0,DB_TYPE_DIAB_ISAM=1,
- DB_TYPE_HASH,DB_TYPE_MISAM,DB_TYPE_PISAM,
- DB_TYPE_RMS_ISAM, DB_TYPE_HEAP, DB_TYPE_ISAM,
- DB_TYPE_MRG_ISAM, DB_TYPE_MYISAM, DB_TYPE_MRG_MYISAM,
- DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB,
- DB_TYPE_GEMINI, DB_TYPE_NDBCLUSTER,
- DB_TYPE_EXAMPLE_DB, DB_TYPE_ARCHIVE_DB, DB_TYPE_CSV_DB,
- DB_TYPE_FEDERATED_DB,
- DB_TYPE_BLACKHOLE_DB,
- DB_TYPE_PARTITION_DB,
- DB_TYPE_BINLOG,
- DB_TYPE_SOLID,
- DB_TYPE_PBXT,
- DB_TYPE_TABLE_FUNCTION,
- DB_TYPE_MEMCACHE,
- DB_TYPE_FALCON,
- DB_TYPE_MARIA,
- DB_TYPE_FIRST_DYNAMIC=42,
- DB_TYPE_DEFAULT=127
-};
-enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED,
- ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED,
- ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT, ROW_TYPE_PAGE };
-enum enum_binlog_func {
- BFN_RESET_LOGS= 1,
- BFN_RESET_SLAVE= 2,
- BFN_BINLOG_WAIT= 3,
- BFN_BINLOG_END= 4,
- BFN_BINLOG_PURGE_FILE= 5
-};
-enum enum_binlog_command {
- LOGCOM_CREATE_TABLE,
- LOGCOM_ALTER_TABLE,
- LOGCOM_RENAME_TABLE,
- LOGCOM_DROP_TABLE,
- LOGCOM_CREATE_DB,
- LOGCOM_ALTER_DB,
- LOGCOM_DROP_DB
-};
-typedef ulonglong my_xid;
-struct xid_t {
- long formatID;
- long gtrid_length;
- long bqual_length;
- char data[128];
- xid_t() {}
- In_C_you_should_use_my_bool_instead() eq(struct xid_t *xid)
- { return eq(xid->gtrid_length, xid->bqual_length, xid->data); }
- In_C_you_should_use_my_bool_instead() eq(long g, long b, const char *d)
- { return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); }
- void set(struct xid_t *xid)
- { memcpy(this, xid, xid->length()); }
- void set(long f, const char *g, long gl, const char *b, long bl)
- {
- formatID= f;
- memcpy(data, g, gtrid_length= gl);
- memcpy(data+gl, b, bqual_length= bl);
- }
- void set(ulonglong xid)
- {
- my_xid tmp;
- formatID= 1;
- set(8, 0, "MySQLXid");
- memcpy(data+8, &server_id, sizeof(server_id));
- tmp= xid;
- memcpy(data+(8 +sizeof(server_id)), &tmp, sizeof(tmp));
- gtrid_length=((8 +sizeof(server_id))+sizeof(my_xid));
- }
- void set(long g, long b, const char *d)
- {
- formatID= 1;
- gtrid_length= g;
- bqual_length= b;
- memcpy(data, d, g+b);
- }
- In_C_you_should_use_my_bool_instead() is_null() { return formatID == -1; }
- void null() { formatID= -1; }
- my_xid quick_get_my_xid()
- {
- my_xid tmp;
- memcpy(&tmp, data+(8 +sizeof(server_id)), sizeof(tmp));
- return tmp;
- }
- my_xid get_my_xid()
- {
- return gtrid_length == ((8 +sizeof(server_id))+sizeof(my_xid)) && bqual_length == 0 &&
- !memcmp(data+8, &server_id, sizeof(server_id)) &&
- !memcmp(data, "MySQLXid", 8) ?
- quick_get_my_xid() : 0;
- }
- uint length()
- {
- return sizeof(formatID)+sizeof(gtrid_length)+sizeof(bqual_length)+
- gtrid_length+bqual_length;
- }
- uchar *key()
- {
- return (uchar *)&gtrid_length;
- }
- uint key_length()
- {
- return sizeof(gtrid_length)+sizeof(bqual_length)+gtrid_length+bqual_length;
- }
-};
-typedef struct xid_t XID;
-enum ts_command_type
-{
- TS_CMD_NOT_DEFINED = -1,
- CREATE_TABLESPACE = 0,
- ALTER_TABLESPACE = 1,
- CREATE_LOGFILE_GROUP = 2,
- ALTER_LOGFILE_GROUP = 3,
- DROP_TABLESPACE = 4,
- DROP_LOGFILE_GROUP = 5,
- CHANGE_FILE_TABLESPACE = 6,
- ALTER_ACCESS_MODE_TABLESPACE = 7
-};
-enum ts_alter_tablespace_type
-{
- TS_ALTER_TABLESPACE_TYPE_NOT_DEFINED = -1,
- ALTER_TABLESPACE_ADD_FILE = 1,
- ALTER_TABLESPACE_DROP_FILE = 2
-};
-enum tablespace_access_mode
-{
- TS_NOT_DEFINED= -1,
- TS_READ_ONLY = 0,
- TS_READ_WRITE = 1,
- TS_NOT_ACCESSIBLE = 2
-};
-struct handlerton;
-class st_alter_tablespace : public Sql_alloc
-{
- public:
- const char *tablespace_name;
- const char *logfile_group_name;
- enum ts_command_type ts_cmd_type;
- enum ts_alter_tablespace_type ts_alter_tablespace_type;
- const char *data_file_name;
- const char *undo_file_name;
- const char *redo_file_name;
- ulonglong extent_size;
- ulonglong undo_buffer_size;
- ulonglong redo_buffer_size;
- ulonglong initial_size;
- ulonglong autoextend_size;
- ulonglong max_size;
- uint nodegroup_id;
- handlerton *storage_engine;
- In_C_you_should_use_my_bool_instead() wait_until_completed;
- const char *ts_comment;
- enum tablespace_access_mode ts_access_mode;
- st_alter_tablespace()
- {
- tablespace_name= NULL;
- logfile_group_name= "DEFAULT_LG";
- ts_cmd_type= TS_CMD_NOT_DEFINED;
- data_file_name= NULL;
- undo_file_name= NULL;
- redo_file_name= NULL;
- extent_size= 1024*1024;
- undo_buffer_size= 8*1024*1024;
- redo_buffer_size= 8*1024*1024;
- initial_size= 128*1024*1024;
- autoextend_size= 0;
- max_size= 0;
- storage_engine= NULL;
- nodegroup_id= 65535;
- wait_until_completed= (1);
- ts_comment= NULL;
- ts_access_mode= TS_NOT_DEFINED;
- }
-};
-struct st_table;
-typedef struct st_table TABLE;
-typedef struct st_table_share TABLE_SHARE;
-struct st_foreign_key_info;
-typedef struct st_foreign_key_info FOREIGN_KEY_INFO;
-typedef In_C_you_should_use_my_bool_instead() (stat_print_fn)(THD *thd, const char *type, uint type_len,
- const char *file, uint file_len,
- const char *status, uint status_len);
-enum ha_stat_type { HA_ENGINE_STATUS, HA_ENGINE_LOGS, HA_ENGINE_MUTEX };
-extern st_plugin_int *hton2plugin[15];
-enum log_status
-{
- HA_LOG_STATUS_FREE= 0,
- HA_LOG_STATUS_INUSE= 1,
- HA_LOG_STATUS_NOSUCHLOG= 2
-};
-void signal_log_not_needed(struct handlerton, char *log_file);
-struct handler_log_file_data {
- LEX_STRING filename;
- enum log_status status;
-};
-enum handler_iterator_type
-{
- HA_TRANSACTLOG_ITERATOR= 1
-};
-enum handler_create_iterator_result
-{
- HA_ITERATOR_OK,
- HA_ITERATOR_UNSUPPORTED,
- HA_ITERATOR_ERROR
-};
-struct handler_iterator {
- int (*next)(struct handler_iterator *, void *iterator_object);
- void (*destroy)(struct handler_iterator *);
- void *buffer;
-};
-struct handlerton
-{
- SHOW_COMP_OPTION state;
- enum legacy_db_type db_type;
- uint slot;
- uint savepoint_offset;
- int (*close_connection)(handlerton *hton, THD *thd);
- int (*savepoint_set)(handlerton *hton, THD *thd, void *sv);
- int (*savepoint_rollback)(handlerton *hton, THD *thd, void *sv);
- int (*savepoint_release)(handlerton *hton, THD *thd, void *sv);
- int (*commit)(handlerton *hton, THD *thd, In_C_you_should_use_my_bool_instead() all);
- int (*rollback)(handlerton *hton, THD *thd, In_C_you_should_use_my_bool_instead() all);
- int (*prepare)(handlerton *hton, THD *thd, In_C_you_should_use_my_bool_instead() all);
- int (*recover)(handlerton *hton, XID *xid_list, uint len);
- int (*commit_by_xid)(handlerton *hton, XID *xid);
- int (*rollback_by_xid)(handlerton *hton, XID *xid);
- void *(*create_cursor_read_view)(handlerton *hton, THD *thd);
- void (*set_cursor_read_view)(handlerton *hton, THD *thd, void *read_view);
- void (*close_cursor_read_view)(handlerton *hton, THD *thd, void *read_view);
- handler *(*create)(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root);
- void (*drop_database)(handlerton *hton, char* path);
- int (*panic)(handlerton *hton, enum ha_panic_function flag);
- int (*start_consistent_snapshot)(handlerton *hton, THD *thd);
- In_C_you_should_use_my_bool_instead() (*flush_logs)(handlerton *hton);
- In_C_you_should_use_my_bool_instead() (*show_status)(handlerton *hton, THD *thd, stat_print_fn *print, enum ha_stat_type stat);
- uint (*partition_flags)();
- uint (*alter_table_flags)(uint flags);
- int (*alter_tablespace)(handlerton *hton, THD *thd, st_alter_tablespace *ts_info);
- int (*fill_files_table)(handlerton *hton, THD *thd,
- TABLE_LIST *tables,
- class Item *cond);
- uint32 flags;
- int (*binlog_func)(handlerton *hton, THD *thd, enum_binlog_func fn, void *arg);
- void (*binlog_log_query)(handlerton *hton, THD *thd,
- enum_binlog_command binlog_command,
- const char *query, uint query_length,
- const char *db, const char *table_name);
- int (*release_temporary_latches)(handlerton *hton, THD *thd);
- enum log_status (*get_log_status)(handlerton *hton, char *log);
- enum handler_create_iterator_result
- (*create_iterator)(handlerton *hton, enum handler_iterator_type type,
- struct handler_iterator *fill_this_in);
- int (*discover)(handlerton *hton, THD* thd, const char *db,
- const char *name,
- uchar **frmblob,
- size_t *frmlen);
- int (*find_files)(handlerton *hton, THD *thd,
- const char *db,
- const char *path,
- const char *wild, In_C_you_should_use_my_bool_instead() dir, List<LEX_STRING> *files);
- int (*table_exists_in_engine)(handlerton *hton, THD* thd, const char *db,
- const char *name);
- uint32 license;
- void *data;
-};
-class Ha_trx_info;
-struct THD_TRANS
-{
- In_C_you_should_use_my_bool_instead() no_2pc;
- Ha_trx_info *ha_list;
- In_C_you_should_use_my_bool_instead() modified_non_trans_table;
- void reset() { no_2pc= (0); modified_non_trans_table= (0); }
-};
-class Ha_trx_info
-{
-public:
- void register_ha(THD_TRANS *trans, handlerton *ht_arg)
- {
- assert(m_flags == 0);
- assert(m_ht == NULL);
- assert(m_next == NULL);
- m_ht= ht_arg;
- m_flags= (int) TRX_READ_ONLY;
- m_next= trans->ha_list;
- trans->ha_list= this;
- }
- void reset()
- {
- m_next= NULL;
- m_ht= NULL;
- m_flags= 0;
- }
- Ha_trx_info() { reset(); }
- void set_trx_read_write()
- {
- assert(is_started());
- m_flags|= (int) TRX_READ_WRITE;
- }
- In_C_you_should_use_my_bool_instead() is_trx_read_write() const
- {
- assert(is_started());
- return m_flags & (int) TRX_READ_WRITE;
- }
- In_C_you_should_use_my_bool_instead() is_started() const { return m_ht != NULL; }
- void coalesce_trx_with(const Ha_trx_info *stmt_trx)
- {
- assert(is_started());
- if (stmt_trx->is_trx_read_write())
- set_trx_read_write();
- }
- Ha_trx_info *next() const
- {
- assert(is_started());
- return m_next;
- }
- handlerton *ht() const
- {
- assert(is_started());
- return m_ht;
- }
-private:
- enum { TRX_READ_ONLY= 0, TRX_READ_WRITE= 1 };
- Ha_trx_info *m_next;
- handlerton *m_ht;
- uchar m_flags;
-};
-enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
- ISO_REPEATABLE_READ, ISO_SERIALIZABLE};
-enum ndb_distribution { ND_KEYHASH= 0, ND_LINHASH= 1 };
-typedef struct {
- ulonglong data_file_length;
- ulonglong max_data_file_length;
- ulonglong index_file_length;
- ulonglong delete_length;
- ha_rows records;
- ulong mean_rec_length;
- time_t create_time;
- time_t check_time;
- time_t update_time;
- ulonglong check_sum;
-} PARTITION_INFO;
-class Item;
-struct st_table_log_memory_entry;
-class partition_info;
-struct st_partition_iter;
-enum ha_choice { HA_CHOICE_UNDEF, HA_CHOICE_NO, HA_CHOICE_YES };
-typedef struct st_ha_create_information
-{
- CHARSET_INFO *table_charset, *default_table_charset;
- LEX_STRING connect_string;
- const char *password, *tablespace;
- LEX_STRING comment;
- const char *data_file_name, *index_file_name;
- const char *alias;
- ulonglong max_rows,min_rows;
- ulonglong auto_increment_value;
- ulong table_options;
- ulong avg_row_length;
- ulong used_fields;
- ulong key_block_size;
- SQL_LIST merge_list;
- handlerton *db_type;
- enum row_type row_type;
- uint null_bits;
- uint options;
- uint merge_insert_method;
- uint extra_size;
- enum ha_choice transactional;
- In_C_you_should_use_my_bool_instead() table_existed;
- In_C_you_should_use_my_bool_instead() frm_only;
- In_C_you_should_use_my_bool_instead() varchar;
- enum ha_storage_media storage_media;
- enum ha_choice page_checksum;
-} HA_CREATE_INFO;
-typedef struct st_key_create_information
-{
- enum ha_key_alg algorithm;
- ulong block_size;
- LEX_STRING parser_name;
-} KEY_CREATE_INFO;
-class TABLEOP_HOOKS
-{
-public:
- TABLEOP_HOOKS() {}
- virtual ~TABLEOP_HOOKS() {}
- inline void prelock(TABLE **tables, uint count)
- {
- do_prelock(tables, count);
- }
- inline int postlock(TABLE **tables, uint count)
- {
- return do_postlock(tables, count);
- }
-private:
- virtual void do_prelock(TABLE **tables, uint count)
- {
- }
- virtual int do_postlock(TABLE **tables, uint count)
- {
- return 0;
- }
-};
-typedef struct st_savepoint SAVEPOINT;
-extern ulong savepoint_alloc_size;
-extern KEY_CREATE_INFO default_key_create_info;
-typedef class Item COND;
-typedef struct st_ha_check_opt
-{
- st_ha_check_opt() {}
- ulong sort_buffer_size;
- uint flags;
- uint sql_flags;
- KEY_CACHE *key_cache;
- void init();
-} HA_CHECK_OPT;
-typedef struct st_handler_buffer
-{
- const uchar *buffer;
- const uchar *buffer_end;
- uchar *end_of_used_area;
-} HANDLER_BUFFER;
-typedef struct system_status_var SSV;
-class ha_statistics
-{
-public:
- ulonglong data_file_length;
- ulonglong max_data_file_length;
- ulonglong index_file_length;
- ulonglong max_index_file_length;
- ulonglong delete_length;
- ulonglong auto_increment_value;
- ha_rows records;
- ha_rows deleted;
- ulong mean_rec_length;
- time_t create_time;
- time_t check_time;
- time_t update_time;
- uint block_size;
- ha_statistics():
- data_file_length(0), max_data_file_length(0),
- index_file_length(0), delete_length(0), auto_increment_value(0),
- records(0), deleted(0), mean_rec_length(0), create_time(0),
- check_time(0), update_time(0), block_size(0)
- {}
-};
-uint calculate_key_len(TABLE *, uint, const uchar *, key_part_map);
-class handler :public Sql_alloc
-{
-public:
- typedef ulonglong Table_flags;
-protected:
- struct st_table_share *table_share;
- struct st_table *table;
- Table_flags cached_table_flags;
- ha_rows estimation_rows_to_insert;
-public:
- handlerton *ht;
- uchar *ref;
- uchar *dup_ref;
- ha_statistics stats;
- In_C_you_should_use_my_bool_instead() multi_range_sorted;
- KEY_MULTI_RANGE *multi_range_curr;
- KEY_MULTI_RANGE *multi_range_end;
- HANDLER_BUFFER *multi_range_buffer;
- key_range save_end_range, *end_range;
- KEY_PART_INFO *range_key_part;
- int key_compare_result_on_equal;
- In_C_you_should_use_my_bool_instead() eq_range;
- uint errkey;
- uint key_used_on_scan;
- uint active_index;
- uint ref_length;
- FT_INFO *ft_handler;
- enum {NONE=0, INDEX, RND} inited;
- In_C_you_should_use_my_bool_instead() locked;
- In_C_you_should_use_my_bool_instead() implicit_emptied;
- const COND *pushed_cond;
- ulonglong next_insert_id;
- ulonglong insert_id_for_cur_row;
- Discrete_interval auto_inc_interval_for_cur_row;
- handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
- :table_share(share_arg), table(0),
- estimation_rows_to_insert(0), ht(ht_arg),
- ref(0), key_used_on_scan(64), active_index(64),
- ref_length(sizeof(my_off_t)),
- ft_handler(0), inited(NONE),
- locked((0)), implicit_emptied(0),
- pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0)
- {}
- virtual ~handler(void)
- {
- assert(locked == (0));
- }
- virtual handler *clone(MEM_ROOT *mem_root);
- void init()
- {
- cached_table_flags= table_flags();
- }
- int ha_open(TABLE *table, const char *name, int mode, int test_if_locked);
- int ha_index_init(uint idx, In_C_you_should_use_my_bool_instead() sorted)
- {
- int result;
- const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("ha_index_init","./sql/handler.h",1159,&_db_func_,&_db_file_,&_db_level_, &_db_framep_);
- assert(inited==NONE);
- if (!(result= index_init(idx, sorted)))
- inited=INDEX;
- do {_db_return_ (1163, &_db_func_, &_db_file_, &_db_level_); return(result);} while(0);
- }
- int ha_index_end()
- {
- const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("ha_index_end","./sql/handler.h",1167,&_db_func_,&_db_file_,&_db_level_, &_db_framep_);
- assert(inited==INDEX);
- inited=NONE;
- do {_db_return_ (1170, &_db_func_, &_db_file_, &_db_level_); return(index_end());} while(0);
- }
- int ha_rnd_init(In_C_you_should_use_my_bool_instead() scan)
- {
- int result;
- const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("ha_rnd_init","./sql/handler.h",1175,&_db_func_,&_db_file_,&_db_level_, &_db_framep_);
- assert(inited==NONE || (inited==RND && scan));
- inited= (result= rnd_init(scan)) ? NONE: RND;
- do {_db_return_ (1178, &_db_func_, &_db_file_, &_db_level_); return(result);} while(0);
- }
- int ha_rnd_end()
- {
- const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("ha_rnd_end","./sql/handler.h",1182,&_db_func_,&_db_file_,&_db_level_, &_db_framep_);
- assert(inited==RND);
- inited=NONE;
- do {_db_return_ (1185, &_db_func_, &_db_file_, &_db_level_); return(rnd_end());} while(0);
- }
- int ha_reset();
- int ha_index_or_rnd_end()
- {
- return inited == INDEX ? ha_index_end() : inited == RND ? ha_rnd_end() : 0;
- }
- Table_flags ha_table_flags() const { return cached_table_flags; }
- int ha_external_lock(THD *thd, int lock_type);
- int ha_write_row(uchar * buf);
- int ha_update_row(const uchar * old_data, uchar * new_data);
- int ha_delete_row(const uchar * buf);
- void ha_release_auto_increment();
- int ha_check_for_upgrade(HA_CHECK_OPT *check_opt);
- int ha_check(THD *thd, HA_CHECK_OPT *check_opt);
- int ha_repair(THD* thd, HA_CHECK_OPT* check_opt);
- void ha_start_bulk_insert(ha_rows rows)
- {
- estimation_rows_to_insert= rows;
- start_bulk_insert(rows);
- }
- int ha_end_bulk_insert()
- {
- estimation_rows_to_insert= 0;
- return end_bulk_insert();
- }
- int ha_bulk_update_row(const uchar *old_data, uchar *new_data,
- uint *dup_key_found);
- int ha_delete_all_rows();
- int ha_reset_auto_increment(ulonglong value);
- int ha_backup(THD* thd, HA_CHECK_OPT* check_opt);
- int ha_restore(THD* thd, HA_CHECK_OPT* check_opt);
- int ha_optimize(THD* thd, HA_CHECK_OPT* check_opt);
- int ha_analyze(THD* thd, HA_CHECK_OPT* check_opt);
- In_C_you_should_use_my_bool_instead() ha_check_and_repair(THD *thd);
- int ha_disable_indexes(uint mode);
- int ha_enable_indexes(uint mode);
- int ha_discard_or_import_tablespace(my_bool discard);
- void ha_prepare_for_alter();
- int ha_rename_table(const char *from, const char *to);
- int ha_delete_table(const char *name);
- void ha_drop_table(const char *name);
- int ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info);
- int ha_create_handler_files(const char *name, const char *old_name,
- int action_flag, HA_CREATE_INFO *info);
- int ha_change_partitions(HA_CREATE_INFO *create_info,
- const char *path,
- ulonglong *copied,
- ulonglong *deleted,
- const uchar *pack_frm_data,
- size_t pack_frm_len);
- int ha_drop_partitions(const char *path);
- int ha_rename_partitions(const char *path);
- int ha_optimize_partitions(THD *thd);
- int ha_analyze_partitions(THD *thd);
- int ha_check_partitions(THD *thd);
- int ha_repair_partitions(THD *thd);
- void adjust_next_insert_id_after_explicit_value(ulonglong nr);
- int update_auto_increment();
- void print_keydup_error(uint key_nr, const char *msg);
- virtual void print_error(int error, myf errflag);
- virtual In_C_you_should_use_my_bool_instead() get_error_message(int error, String *buf);
- uint get_dup_key(int error);
- virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share)
- {
- table= table_arg;
- table_share= share;
- }
- virtual double scan_time()
- { return ((double) (ulonglong) (stats.data_file_length)) / 4096 + 2; }
- virtual double read_time(uint index, uint ranges, ha_rows rows)
- { return ((double) (ulonglong) (ranges+rows)); }
- virtual const key_map *keys_to_use_for_scanning() { return &key_map_empty; }
- In_C_you_should_use_my_bool_instead() has_transactions()
- { return (ha_table_flags() & (1 << 0)) == 0; }
- virtual uint extra_rec_buf_length() const { return 0; }
- virtual In_C_you_should_use_my_bool_instead() is_fatal_error(int error, uint flags)
- {
- if (!error ||
- ((flags & 1) &&
- (error == 121 ||
- error == 141)))
- return (0);
- return (1);
- }
- virtual ha_rows records() { return stats.records; }
- virtual ha_rows estimate_rows_upper_bound()
- { return stats.records+10; }
- virtual enum row_type get_row_type() const { return ROW_TYPE_NOT_USED; }
- virtual const char *index_type(uint key_number) { assert(0); return "";}
- virtual void column_bitmaps_signal();
- uint get_index(void) const { return active_index; }
- virtual int close(void)=0;
- virtual In_C_you_should_use_my_bool_instead() start_bulk_update() { return 1; }
- virtual In_C_you_should_use_my_bool_instead() start_bulk_delete() { return 1; }
- virtual int exec_bulk_update(uint *dup_key_found)
- {
- assert((0));
- return 131;
- }
- virtual void end_bulk_update() { return; }
- virtual int end_bulk_delete()
- {
- assert((0));
- return 131;
- }
- virtual int index_read_map(uchar * buf, const uchar * key,
- key_part_map keypart_map,
- enum ha_rkey_function find_flag)
- {
- uint key_len= calculate_key_len(table, active_index, key, keypart_map);
- return index_read(buf, key, key_len, find_flag);
- }
- virtual int index_read_idx_map(uchar * buf, uint index, const uchar * key,
- key_part_map keypart_map,
- enum ha_rkey_function find_flag);
- virtual int index_next(uchar * buf)
- { return 131; }
- virtual int index_prev(uchar * buf)
- { return 131; }
- virtual int index_first(uchar * buf)
- { return 131; }
- virtual int index_last(uchar * buf)
- { return 131; }
- virtual int index_next_same(uchar *buf, const uchar *key, uint keylen);
- virtual int index_read_last_map(uchar * buf, const uchar * key,
- key_part_map keypart_map)
- {
- uint key_len= calculate_key_len(table, active_index, key, keypart_map);
- return index_read_last(buf, key, key_len);
- }
- virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
- KEY_MULTI_RANGE *ranges, uint range_count,
- In_C_you_should_use_my_bool_instead() sorted, HANDLER_BUFFER *buffer);
- virtual int read_multi_range_next(KEY_MULTI_RANGE **found_range_p);
- virtual int read_range_first(const key_range *start_key,
- const key_range *end_key,
- In_C_you_should_use_my_bool_instead() eq_range, In_C_you_should_use_my_bool_instead() sorted);
- virtual int read_range_next();
- int compare_key(key_range *range);
- virtual int ft_init() { return 131; }
- void ft_end() { ft_handler=NULL; }
- virtual FT_INFO *ft_init_ext(uint flags, uint inx,String *key)
- { return NULL; }
- virtual int ft_read(uchar *buf) { return 131; }
- virtual int rnd_next(uchar *buf)=0;
- virtual int rnd_pos(uchar * buf, uchar *pos)=0;
- virtual int rnd_pos_by_record(uchar *record)
- {
- position(record);
- return rnd_pos(record, ref);
- }
- virtual int read_first_row(uchar *buf, uint primary_key);
- virtual int restart_rnd_next(uchar *buf, uchar *pos)
- { return 131; }
- virtual int rnd_same(uchar *buf, uint inx)
- { return 131; }
- virtual ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key)
- { return (ha_rows) 10; }
- virtual void position(const uchar *record)=0;
- virtual int info(uint)=0;
- virtual void get_dynamic_partition_info(PARTITION_INFO *stat_info,
- uint part_id);
- virtual int extra(enum ha_extra_function operation)
- { return 0; }
- virtual int extra_opt(enum ha_extra_function operation, ulong cache_size)
- { return extra(operation); }
- virtual In_C_you_should_use_my_bool_instead() was_semi_consistent_read() { return 0; }
- virtual void try_semi_consistent_read(In_C_you_should_use_my_bool_instead()) {}
- virtual void unlock_row() {}
- virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;}
- virtual void get_auto_increment(ulonglong offset, ulonglong increment,
- ulonglong nb_desired_values,
- ulonglong *first_value,
- ulonglong *nb_reserved_values);
- void set_next_insert_id(ulonglong id)
- {
- do {_db_pargs_(1488,"info"); _db_doprnt_ ("auto_increment: next value %lu", (ulong)id);} while(0);
- next_insert_id= id;
- }
- void restore_auto_increment(ulonglong prev_insert_id)
- {
- next_insert_id= (prev_insert_id > 0) ? prev_insert_id :
- insert_id_for_cur_row;
- }
- virtual void update_create_info(HA_CREATE_INFO *create_info) {}
- int check_old_types();
- virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt)
- { return -1; }
- virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt)
- { return -1; }
- virtual int dump(THD* thd, int fd = -1) { return 131; }
- virtual int indexes_are_disabled(void) {return 0;}
- virtual int net_read_dump(NET* net) { return 131; }
- virtual char *update_table_comment(const char * comment)
- { return (char*) comment;}
- virtual void append_create_info(String *packet) {}
- virtual In_C_you_should_use_my_bool_instead() is_fk_defined_on_table_or_index(uint index)
- { return (0); }
- virtual char* get_foreign_key_create_info()
- { return(NULL);}
- virtual char* get_tablespace_name(THD *thd, char *name, uint name_len)
- { return(NULL);}
- virtual In_C_you_should_use_my_bool_instead() can_switch_engines() { return 1; }
- virtual int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
- { return 0; }
- virtual uint referenced_by_foreign_key() { return 0;}
- virtual void init_table_handle_for_HANDLER()
- { return; }
- virtual void free_foreign_key_create_info(char* str) {}
- virtual const char *table_type() const =0;
- virtual const char **bas_ext() const =0;
- virtual int get_default_no_partitions(HA_CREATE_INFO *info) { return 1;}
- virtual void set_auto_partitions(partition_info *part_info) { return; }
- virtual In_C_you_should_use_my_bool_instead() get_no_parts(const char *name,
- uint *no_parts)
- {
- *no_parts= 0;
- return 0;
- }
- virtual void set_part_info(partition_info *part_info) {return;}
- virtual ulong index_flags(uint idx, uint part, In_C_you_should_use_my_bool_instead() all_parts) const =0;
- virtual int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys)
- { return (131); }
- virtual int prepare_drop_index(TABLE *table_arg, uint *key_num,
- uint num_of_keys)
- { return (131); }
- virtual int final_drop_index(TABLE *table_arg)
- { return (131); }
- uint max_record_length() const
- { return ((65535) < (max_supported_record_length()) ? (65535) : (max_supported_record_length())); }
- uint max_keys() const
- { return ((64) < (max_supported_keys()) ? (64) : (max_supported_keys())); }
- uint max_key_parts() const
- { return ((16) < (max_supported_key_parts()) ? (16) : (max_supported_key_parts())); }
- uint max_key_length() const
- { return ((3072) < (max_supported_key_length()) ? (3072) : (max_supported_key_length())); }
- uint max_key_part_length() const
- { return ((3072) < (max_supported_key_part_length()) ? (3072) : (max_supported_key_part_length())); }
- virtual uint max_supported_record_length() const { return 65535; }
- virtual uint max_supported_keys() const { return 0; }
- virtual uint max_supported_key_parts() const { return 16; }
- virtual uint max_supported_key_length() const { return 3072; }
- virtual uint max_supported_key_part_length() const { return 255; }
- virtual uint min_record_length(uint options) const { return 1; }
- virtual In_C_you_should_use_my_bool_instead() low_byte_first() const { return 1; }
- virtual uint checksum() const { return 0; }
- virtual In_C_you_should_use_my_bool_instead() is_crashed() const { return 0; }
- virtual In_C_you_should_use_my_bool_instead() auto_repair() const { return 0; }
- virtual uint lock_count(void) const { return 1; }
- virtual THR_LOCK_DATA **store_lock(THD *thd,
- THR_LOCK_DATA **to,
- enum thr_lock_type lock_type)=0;
- virtual uint8 table_cache_type() { return 0; }
- virtual my_bool register_query_cache_table(THD *thd, char *table_key,
- uint key_length,
- qc_engine_callback
- *engine_callback,
- ulonglong *engine_data)
- {
- *engine_callback= 0;
- return (1);
- }
- virtual In_C_you_should_use_my_bool_instead() primary_key_is_clustered() { return (0); }
- virtual int cmp_ref(const uchar *ref1, const uchar *ref2)
- {
- return memcmp(ref1, ref2, ref_length);
- }
- virtual const COND *cond_push(const COND *cond) { return cond; };
- virtual void cond_pop() { return; };
- virtual In_C_you_should_use_my_bool_instead() check_if_incompatible_data(HA_CREATE_INFO *create_info,
- uint table_changes)
- { return 1; }
- virtual void use_hidden_primary_key();
-protected:
- void ha_statistic_increment(ulong SSV::*offset) const;
- void **ha_data(THD *) const;
- THD *ha_thd(void) const;
- virtual int rename_table(const char *from, const char *to);
- virtual int delete_table(const char *name);
-private:
- inline void mark_trx_read_write();
-private:
- virtual int open(const char *name, int mode, uint test_if_locked)=0;
- virtual int index_init(uint idx, In_C_you_should_use_my_bool_instead() sorted) { active_index= idx; return 0; }
- virtual int index_end() { active_index= 64; return 0; }
- virtual int rnd_init(In_C_you_should_use_my_bool_instead() scan)= 0;
- virtual int rnd_end() { return 0; }
- virtual int write_row(uchar *buf __attribute__((unused)))
- {
- return 131;
- }
- virtual int update_row(const uchar *old_data __attribute__((unused)),
- uchar *new_data __attribute__((unused)))
- {
- return 131;
- }
- virtual int delete_row(const uchar *buf __attribute__((unused)))
- {
- return 131;
- }
- virtual int reset() { return 0; }
- virtual Table_flags table_flags(void) const= 0;
- virtual int external_lock(THD *thd __attribute__((unused)),
- int lock_type __attribute__((unused)))
- {
- return 0;
- }
- virtual void release_auto_increment() { return; };
- virtual int check_for_upgrade(HA_CHECK_OPT *check_opt)
- { return 0; }
- virtual int check(THD* thd, HA_CHECK_OPT* check_opt)
- { return -1; }
- virtual int repair(THD* thd, HA_CHECK_OPT* check_opt)
- { return -1; }
- virtual void start_bulk_insert(ha_rows rows) {}
- virtual int end_bulk_insert() { return 0; }
- virtual int index_read(uchar * buf, const uchar * key, uint key_len,
- enum ha_rkey_function find_flag)
- { return 131; }
- virtual int index_read_last(uchar * buf, const uchar * key, uint key_len)
- { return ((_my_thread_var())->thr_errno= 131); }
- virtual int bulk_update_row(const uchar *old_data, uchar *new_data,
- uint *dup_key_found)
- {
- assert((0));
- return 131;
- }
- virtual int delete_all_rows()
- { return ((_my_thread_var())->thr_errno=131); }
- virtual int reset_auto_increment(ulonglong value)
- { return 131; }
- virtual int backup(THD* thd, HA_CHECK_OPT* check_opt)
- { return -1; }
- virtual int restore(THD* thd, HA_CHECK_OPT* check_opt)
- { return -1; }
- virtual int optimize(THD* thd, HA_CHECK_OPT* check_opt)
- { return -1; }
- virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt)
- { return -1; }
- virtual In_C_you_should_use_my_bool_instead() check_and_repair(THD *thd) { return (1); }
- virtual int disable_indexes(uint mode) { return 131; }
- virtual int enable_indexes(uint mode) { return 131; }
- virtual int discard_or_import_tablespace(my_bool discard)
- { return ((_my_thread_var())->thr_errno=131); }
- virtual void prepare_for_alter() { return; }
- virtual void drop_table(const char *name);
- virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0;
- virtual int create_handler_files(const char *name, const char *old_name,
- int action_flag, HA_CREATE_INFO *info)
- { return (0); }
- virtual int change_partitions(HA_CREATE_INFO *create_info,
- const char *path,
- ulonglong *copied,
- ulonglong *deleted,
- const uchar *pack_frm_data,
- size_t pack_frm_len)
- { return 131; }
- virtual int drop_partitions(const char *path)
- { return 131; }
- virtual int rename_partitions(const char *path)
- { return 131; }
- virtual int optimize_partitions(THD *thd)
- { return 131; }
- virtual int analyze_partitions(THD *thd)
- { return 131; }
- virtual int check_partitions(THD *thd)
- { return 131; }
- virtual int repair_partitions(THD *thd)
- { return 131; }
-};
-extern const char *ha_row_type[];
-extern const char *tx_isolation_names[];
-extern const char *binlog_format_names[];
-extern TYPELIB tx_isolation_typelib;
-extern TYPELIB myisam_stats_method_typelib;
-extern ulong total_ha, total_ha_2pc;
-handlerton *ha_default_handlerton(THD *thd);
-plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name);
-plugin_ref ha_lock_engine(THD *thd, handlerton *hton);
-handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type);
-handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
- handlerton *db_type);
-handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
- In_C_you_should_use_my_bool_instead() no_substitute, In_C_you_should_use_my_bool_instead() report_error);
-static inline enum legacy_db_type ha_legacy_type(const handlerton *db_type)
-{
- return (db_type == NULL) ? DB_TYPE_UNKNOWN : db_type->db_type;
-}
-static inline const char *ha_resolve_storage_engine_name(const handlerton *db_type)
-{
- return db_type == NULL ? "UNKNOWN" : hton2plugin[db_type->slot]->name.str;
-}
-static inline In_C_you_should_use_my_bool_instead() ha_check_storage_engine_flag(const handlerton *db_type, uint32 flag)
-{
- return db_type == NULL ? (0) : ((db_type->flags & flag) ? 1 : 0);
-}
-static inline In_C_you_should_use_my_bool_instead() ha_storage_engine_is_enabled(const handlerton *db_type)
-{
- return (db_type && db_type->create) ?
- (db_type->state == SHOW_OPTION_YES) : (0);
-}
-int ha_init_errors(void);
-int ha_init(void);
-int ha_end(void);
-int ha_initialize_handlerton(st_plugin_int *plugin);
-int ha_finalize_handlerton(st_plugin_int *plugin);
-TYPELIB *ha_known_exts(void);
-int ha_panic(enum ha_panic_function flag);
-void ha_close_connection(THD* thd);
-In_C_you_should_use_my_bool_instead() ha_flush_logs(handlerton *db_type);
-void ha_drop_database(char* path);
-int ha_create_table(THD *thd, const char *path,
- const char *db, const char *table_name,
- HA_CREATE_INFO *create_info,
- In_C_you_should_use_my_bool_instead() update_create_info);
-int ha_delete_table(THD *thd, handlerton *db_type, const char *path,
- const char *db, const char *alias, In_C_you_should_use_my_bool_instead() generate_warning);
-In_C_you_should_use_my_bool_instead() ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat);
-int ha_create_table_from_engine(THD* thd, const char *db, const char *name);
-int ha_discover(THD* thd, const char* dbname, const char* name,
- uchar** frmblob, size_t* frmlen);
-int ha_find_files(THD *thd,const char *db,const char *path,
- const char *wild, In_C_you_should_use_my_bool_instead() dir, List<LEX_STRING>* files);
-int ha_table_exists_in_engine(THD* thd, const char* db, const char* name);
-extern "C" int ha_init_key_cache(const char *name, KEY_CACHE *key_cache);
-int ha_resize_key_cache(KEY_CACHE *key_cache);
-int ha_change_key_cache_param(KEY_CACHE *key_cache);
-int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache);
-int ha_end_key_cache(KEY_CACHE *key_cache);
-int ha_release_temporary_latches(THD *thd);
-int ha_start_consistent_snapshot(THD *thd);
-int ha_commit_or_rollback_by_xid(XID *xid, In_C_you_should_use_my_bool_instead() commit);
-int ha_commit_one_phase(THD *thd, In_C_you_should_use_my_bool_instead() all);
-int ha_rollback_trans(THD *thd, In_C_you_should_use_my_bool_instead() all);
-int ha_prepare(THD *thd);
-int ha_recover(HASH *commit_list);
-int ha_commit_trans(THD *thd, In_C_you_should_use_my_bool_instead() all);
-int ha_autocommit_or_rollback(THD *thd, int error);
-int ha_enable_transaction(THD *thd, In_C_you_should_use_my_bool_instead() on);
-int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv);
-int ha_savepoint(THD *thd, SAVEPOINT *sv);
-int ha_release_savepoint(THD *thd, SAVEPOINT *sv);
-void trans_register_ha(THD *thd, In_C_you_should_use_my_bool_instead() all, handlerton *ht);
-#include "parse_file.h"
-enum file_opt_type {
- FILE_OPTIONS_STRING,
- FILE_OPTIONS_ESTRING,
- FILE_OPTIONS_ULONGLONG,
- FILE_OPTIONS_REV,
- FILE_OPTIONS_TIMESTAMP,
- FILE_OPTIONS_STRLIST,
- FILE_OPTIONS_ULLLIST
-};
-struct File_option
-{
- LEX_STRING name;
- int offset;
- file_opt_type type;
-};
-class Unknown_key_hook
-{
-public:
- Unknown_key_hook() {}
- virtual ~Unknown_key_hook() {}
- virtual In_C_you_should_use_my_bool_instead() process_unknown_string(char *&unknown_key, uchar* base,
- MEM_ROOT *mem_root, char *end)= 0;
-};
-class File_parser_dummy_hook: public Unknown_key_hook
-{
-public:
- File_parser_dummy_hook() {}
- virtual In_C_you_should_use_my_bool_instead() process_unknown_string(char *&unknown_key, uchar* base,
- MEM_ROOT *mem_root, char *end);
-};
-extern File_parser_dummy_hook file_parser_dummy_hook;
-In_C_you_should_use_my_bool_instead() get_file_options_ulllist(char *&ptr, char *end, char *line,
- uchar* base, File_option *parameter,
- MEM_ROOT *mem_root);
-char *
-parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str);
-class File_parser;
-File_parser *sql_parse_prepare(const LEX_STRING *file_name,
- MEM_ROOT *mem_root, In_C_you_should_use_my_bool_instead() bad_format_errors);
-my_bool
-sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
- const LEX_STRING *type,
- uchar* base, File_option *parameters, uint versions);
-my_bool rename_in_schema_file(const char *schema, const char *old_name,
- const char *new_name, ulonglong revision,
- uint num_view_backups);
-class File_parser: public Sql_alloc
-{
- char *buff, *start, *end;
- LEX_STRING file_type;
- my_bool content_ok;
-public:
- File_parser() :buff(0), start(0), end(0), content_ok(0)
- { file_type.str= 0; file_type.length= 0; }
- my_bool ok() { return content_ok; }
- LEX_STRING *type() { return &file_type; }
- my_bool parse(uchar* base, MEM_ROOT *mem_root,
- struct File_option *parameters, uint required,
- Unknown_key_hook *hook);
- friend File_parser *sql_parse_prepare(const LEX_STRING *file_name,
- MEM_ROOT *mem_root,
- In_C_you_should_use_my_bool_instead() bad_format_errors);
-};
-#include "table.h"
-class Item;
-class Item_subselect;
-class GRANT_TABLE;
-class st_select_lex_unit;
-class st_select_lex;
-class partition_info;
-class COND_EQUAL;
-class Security_context;
-class View_creation_ctx : public Default_object_creation_ctx,
- public Sql_alloc
-{
-public:
- static View_creation_ctx *create(THD *thd);
- static View_creation_ctx *create(THD *thd,
- TABLE_LIST *view);
-private:
- View_creation_ctx(THD *thd)
- : Default_object_creation_ctx(thd)
- { }
-};
-typedef struct st_order {
- struct st_order *next;
- Item **item;
- Item *item_ptr;
- Item **item_copy;
- int counter;
- In_C_you_should_use_my_bool_instead() asc;
- In_C_you_should_use_my_bool_instead() free_me;
- In_C_you_should_use_my_bool_instead() in_field_list;
- In_C_you_should_use_my_bool_instead() counter_used;
- Field *field;
- char *buff;
- table_map used, depend_map;
-} ORDER;
-typedef struct st_grant_info
-{
- GRANT_TABLE *grant_table;
- uint version;
- ulong privilege;
- ulong want_privilege;
- ulong orig_want_privilege;
-} GRANT_INFO;
-enum tmp_table_type
-{
- NO_TMP_TABLE, NON_TRANSACTIONAL_TMP_TABLE, TRANSACTIONAL_TMP_TABLE,
- INTERNAL_TMP_TABLE, SYSTEM_TMP_TABLE
-};
-enum trg_event_type
-{
- TRG_EVENT_INSERT= 0,
- TRG_EVENT_UPDATE= 1,
- TRG_EVENT_DELETE= 2,
- TRG_EVENT_MAX
-};
-enum frm_type_enum
-{
- FRMTYPE_ERROR= 0,
- FRMTYPE_TABLE,
- FRMTYPE_VIEW
-};
-enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP };
-typedef struct st_filesort_info
-{
- IO_CACHE *io_cache;
- uchar **sort_keys;
- uchar *buffpek;
- uint buffpek_len;
- uchar *addon_buf;
- size_t addon_length;
- struct st_sort_addon_field *addon_field;
- void (*unpack)(struct st_sort_addon_field *, uchar *);
- uchar *record_pointers;
- ha_rows found_records;
-} FILESORT_INFO;
-enum timestamp_auto_set_type
-{
- TIMESTAMP_NO_AUTO_SET= 0, TIMESTAMP_AUTO_SET_ON_INSERT= 1,
- TIMESTAMP_AUTO_SET_ON_UPDATE= 2, TIMESTAMP_AUTO_SET_ON_BOTH= 3
-};
-class Field_timestamp;
-class Field_blob;
-class Table_triggers_list;
-enum enum_table_category
-{
- TABLE_UNKNOWN_CATEGORY=0,
- TABLE_CATEGORY_TEMPORARY=1,
- TABLE_CATEGORY_USER=2,
- TABLE_CATEGORY_SYSTEM=3,
- TABLE_CATEGORY_INFORMATION=4,
- TABLE_CATEGORY_PERFORMANCE=5
-};
-typedef enum enum_table_category TABLE_CATEGORY;
-TABLE_CATEGORY get_table_category(const LEX_STRING *db,
- const LEX_STRING *name);
-typedef struct st_table_share
-{
- st_table_share() {}
- TABLE_CATEGORY table_category;
- HASH name_hash;
- MEM_ROOT mem_root;
- TYPELIB keynames;
- TYPELIB fieldnames;
- TYPELIB *intervals;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- struct st_table_share *next,
- **prev;
- Field **field;
- Field **found_next_number_field;
- Field *timestamp_field;
- KEY *key_info;
- uint *blob_field;
- uchar *default_values;
- LEX_STRING comment;
- CHARSET_INFO *table_charset;
- MY_BITMAP all_set;
- LEX_STRING table_cache_key;
- LEX_STRING db;
- LEX_STRING table_name;
- LEX_STRING path;
- LEX_STRING normalized_path;
- LEX_STRING connect_string;
- key_map keys_in_use;
- key_map keys_for_keyread;
- ha_rows min_rows, max_rows;
- ulong avg_row_length;
- ulong raid_chunksize;
- ulong version, mysql_version;
- ulong timestamp_offset;
- ulong reclength;
- plugin_ref db_plugin;
- inline handlerton *db_type() const
- {
- return db_plugin ? ((handlerton*)((db_plugin)[0]->data)) : NULL;
- }
- enum row_type row_type;
- enum tmp_table_type tmp_table;
- enum ha_choice transactional;
- enum ha_choice page_checksum;
- uint ref_count;
- uint open_count;
- uint blob_ptr_size;
- uint key_block_size;
- uint null_bytes, last_null_bit_pos;
- uint fields;
- uint rec_buff_length;
- uint keys, key_parts;
- uint max_key_length, max_unique_length, total_key_length;
- uint uniques;
- uint null_fields;
- uint blob_fields;
- uint timestamp_field_offset;
- uint varchar_fields;
- uint db_create_options;
- uint db_options_in_use;
- uint db_record_offset;
- uint raid_type, raid_chunks;
- uint rowid_field_offset;
- uint primary_key;
- uint next_number_index;
- uint next_number_key_offset;
- uint next_number_keypart;
- uint error, open_errno, errarg;
- uint column_bitmap_size;
- uchar frm_version;
- In_C_you_should_use_my_bool_instead() null_field_first;
- In_C_you_should_use_my_bool_instead() system;
- In_C_you_should_use_my_bool_instead() crypted;
- In_C_you_should_use_my_bool_instead() db_low_byte_first;
- In_C_you_should_use_my_bool_instead() crashed;
- In_C_you_should_use_my_bool_instead() is_view;
- In_C_you_should_use_my_bool_instead() name_lock, replace_with_name_lock;
- In_C_you_should_use_my_bool_instead() waiting_on_cond;
- ulong table_map_id;
- ulonglong table_map_version;
- int cached_row_logging_check;
- void set_table_cache_key(char *key_buff, uint key_length)
- {
- table_cache_key.str= key_buff;
- table_cache_key.length= key_length;
- db.str= table_cache_key.str;
- db.length= strlen(db.str);
- table_name.str= db.str + db.length + 1;
- table_name.length= strlen(table_name.str);
- }
- void set_table_cache_key(char *key_buff, const char *key, uint key_length)
- {
- memcpy(key_buff, key, key_length);
- set_table_cache_key(key_buff, key_length);
- }
- inline In_C_you_should_use_my_bool_instead() honor_global_locks()
- {
- return ((table_category == TABLE_CATEGORY_USER)
- || (table_category == TABLE_CATEGORY_SYSTEM));
- }
- inline In_C_you_should_use_my_bool_instead() require_write_privileges()
- {
- return (table_category == TABLE_CATEGORY_PERFORMANCE);
- }
- inline ulong get_table_def_version()
- {
- return table_map_id;
- }
- enum enum_table_ref_type get_table_ref_type() const
- {
- if (is_view)
- return TABLE_REF_VIEW;
- switch (tmp_table) {
- case NO_TMP_TABLE:
- return TABLE_REF_BASE_TABLE;
- case SYSTEM_TMP_TABLE:
- return TABLE_REF_I_S_TABLE;
- default:
- return TABLE_REF_TMP_TABLE;
- }
- }
- ulong get_table_ref_version() const
- {
- return (tmp_table == SYSTEM_TMP_TABLE || is_view) ? 0 : table_map_id;
- }
-} TABLE_SHARE;
-extern ulong refresh_version;
-enum index_hint_type
-{
- INDEX_HINT_IGNORE,
- INDEX_HINT_USE,
- INDEX_HINT_FORCE
-};
-struct st_table {
- st_table() {}
- TABLE_SHARE *s;
- handler *file;
- struct st_table *next, *prev;
- struct st_table *parent;
- TABLE_LIST *child_l;
- TABLE_LIST **child_last_l;
- THD *in_use;
- Field **field;
- uchar *record[2];
- uchar *write_row_record;
- uchar *insert_values;
- key_map covering_keys;
- key_map quick_keys, merge_keys;
- key_map keys_in_use_for_query;
- key_map keys_in_use_for_group_by;
- key_map keys_in_use_for_order_by;
- KEY *key_info;
- Field *next_number_field;
- Field *found_next_number_field;
- Field_timestamp *timestamp_field;
- Table_triggers_list *triggers;
- TABLE_LIST *pos_in_table_list;
- ORDER *group;
- const char *alias;
- uchar *null_flags;
- my_bitmap_map *bitmap_init_value;
- MY_BITMAP def_read_set, def_write_set, tmp_set;
- MY_BITMAP *read_set, *write_set;
- query_id_t query_id;
- ha_rows quick_rows[64];
- key_part_map const_key_parts[64];
- uint quick_key_parts[64];
- uint quick_n_ranges[64];
- ha_rows quick_condition_rows;
- timestamp_auto_set_type timestamp_field_type;
- table_map map;
- uint lock_position;
- uint lock_data_start;
- uint lock_count;
- uint tablenr,used_fields;
- uint temp_pool_slot;
- uint status;
- uint db_stat;
- uint derived_select_number;
- int current_lock;
- my_bool copy_blobs;
- uint maybe_null;
- my_bool null_row;
- my_bool force_index;
- my_bool distinct,const_table,no_rows;
- my_bool key_read, no_keyread;
- my_bool open_placeholder;
- my_bool locked_by_logger;
- my_bool no_replicate;
- my_bool locked_by_name;
- my_bool fulltext_searched;
- my_bool no_cache;
- my_bool open_by_handler;
- my_bool auto_increment_field_not_null;
- my_bool insert_or_update;
- my_bool alias_name_used;
- my_bool get_fields_in_item_tree;
- my_bool children_attached;
- REGINFO reginfo;
- MEM_ROOT mem_root;
- GRANT_INFO grant;
- FILESORT_INFO sort;
- In_C_you_should_use_my_bool_instead() fill_item_list(List<Item> *item_list) const;
- void reset_item_list(List<Item> *item_list) const;
- void clear_column_bitmaps(void);
- void prepare_for_position(void);
- void mark_columns_used_by_index_no_reset(uint index, MY_BITMAP *map);
- void mark_columns_used_by_index(uint index);
- void restore_column_maps_after_mark_index();
- void mark_auto_increment_column(void);
- void mark_columns_needed_for_update(void);
- void mark_columns_needed_for_delete(void);
- void mark_columns_needed_for_insert(void);
- inline void column_bitmaps_set(MY_BITMAP *read_set_arg,
- MY_BITMAP *write_set_arg)
- {
- read_set= read_set_arg;
- write_set= write_set_arg;
- if (file)
- file->column_bitmaps_signal();
- }
- inline void column_bitmaps_set_no_signal(MY_BITMAP *read_set_arg,
- MY_BITMAP *write_set_arg)
- {
- read_set= read_set_arg;
- write_set= write_set_arg;
- }
- inline void use_all_columns()
- {
- column_bitmaps_set(&s->all_set, &s->all_set);
- }
- inline void default_column_bitmaps()
- {
- read_set= &def_read_set;
- write_set= &def_write_set;
- }
- inline In_C_you_should_use_my_bool_instead() is_name_opened() { return db_stat || open_placeholder; }
- inline In_C_you_should_use_my_bool_instead() needs_reopen_or_name_lock()
- { return s->version != refresh_version; }
- In_C_you_should_use_my_bool_instead() is_children_attached(void);
-};
-enum enum_schema_table_state
-{
- NOT_PROCESSED= 0,
- PROCESSED_BY_CREATE_SORT_INDEX,
- PROCESSED_BY_JOIN_EXEC
-};
-typedef struct st_foreign_key_info
-{
- LEX_STRING *forein_id;
- LEX_STRING *referenced_db;
- LEX_STRING *referenced_table;
- LEX_STRING *update_method;
- LEX_STRING *delete_method;
- LEX_STRING *referenced_key_name;
- List<LEX_STRING> foreign_fields;
- List<LEX_STRING> referenced_fields;
-} FOREIGN_KEY_INFO;
-enum enum_schema_tables
-{
- SCH_CHARSETS= 0,
- SCH_COLLATIONS,
- SCH_COLLATION_CHARACTER_SET_APPLICABILITY,
- SCH_COLUMNS,
- SCH_COLUMN_PRIVILEGES,
- SCH_ENGINES,
- SCH_EVENTS,
- SCH_FILES,
- SCH_GLOBAL_STATUS,
- SCH_GLOBAL_VARIABLES,
- SCH_KEY_COLUMN_USAGE,
- SCH_OPEN_TABLES,
- SCH_PARTITIONS,
- SCH_PLUGINS,
- SCH_PROCESSLIST,
- SCH_PROFILES,
- SCH_REFERENTIAL_CONSTRAINTS,
- SCH_PROCEDURES,
- SCH_SCHEMATA,
- SCH_SCHEMA_PRIVILEGES,
- SCH_SESSION_STATUS,
- SCH_SESSION_VARIABLES,
- SCH_STATISTICS,
- SCH_STATUS,
- SCH_TABLES,
- SCH_TABLE_CONSTRAINTS,
- SCH_TABLE_NAMES,
- SCH_TABLE_PRIVILEGES,
- SCH_TRIGGERS,
- SCH_USER_PRIVILEGES,
- SCH_VARIABLES,
- SCH_VIEWS
-};
-typedef struct st_field_info
-{
- const char* field_name;
- uint field_length;
- enum enum_field_types field_type;
- int value;
- uint field_flags;
- const char* old_name;
- 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;
- TABLE *(*create_table) (THD *thd, TABLE_LIST *table_list);
- int (*fill_table) (THD *thd, TABLE_LIST *tables, COND *cond);
- int (*old_format) (THD *thd, struct st_schema_table *schema_table);
- int (*process_table) (THD *thd, TABLE_LIST *tables, TABLE *table,
- In_C_you_should_use_my_bool_instead() res, LEX_STRING *db_name, LEX_STRING *table_name);
- int idx_field1, idx_field2;
- In_C_you_should_use_my_bool_instead() hidden;
- uint i_s_requested_object;
-} ST_SCHEMA_TABLE;
-struct st_lex;
-class select_union;
-class TMP_TABLE_PARAM;
-Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
- const char *name);
-struct Field_translator
-{
- Item *item;
- const char *name;
-};
-class Natural_join_column: public Sql_alloc
-{
-public:
- Field_translator *view_field;
- Field *table_field;
- TABLE_LIST *table_ref;
- In_C_you_should_use_my_bool_instead() is_common;
-public:
- Natural_join_column(Field_translator *field_param, TABLE_LIST *tab);
- Natural_join_column(Field *field_param, TABLE_LIST *tab);
- const char *name();
- Item *create_item(THD *thd);
- Field *field();
- const char *table_name();
- const char *db_name();
- GRANT_INFO *grant();
-};
-class Index_hint;
-struct TABLE_LIST
-{
- TABLE_LIST() {}
- inline void init_one_table(const char *db_name_arg,
- const char *table_name_arg,
- enum thr_lock_type lock_type_arg)
- {
- bzero((char*) this, sizeof(*this));
- db= (char*) db_name_arg;
- table_name= alias= (char*) table_name_arg;
- lock_type= lock_type_arg;
- }
- TABLE_LIST *next_local;
- TABLE_LIST *next_global, **prev_global;
- char *db, *alias, *table_name, *schema_table_name;
- char *option;
- Item *on_expr;
- Item *prep_on_expr;
- COND_EQUAL *cond_equal;
- TABLE_LIST *natural_join;
- In_C_you_should_use_my_bool_instead() is_natural_join;
- List<String> *join_using_fields;
- List<Natural_join_column> *join_columns;
- In_C_you_should_use_my_bool_instead() is_join_columns_complete;
- TABLE_LIST *next_name_resolution_table;
- List<Index_hint> *index_hints;
- TABLE *table;
- uint table_id;
- select_union *derived_result;
- TABLE_LIST *correspondent_table;
- st_select_lex_unit *derived;
- ST_SCHEMA_TABLE *schema_table;
- st_select_lex *schema_select_lex;
- In_C_you_should_use_my_bool_instead() schema_table_reformed;
- TMP_TABLE_PARAM *schema_table_param;
- st_select_lex *select_lex;
- st_lex *view;
- Field_translator *field_translation;
- Field_translator *field_translation_end;
- TABLE_LIST *merge_underlying_list;
- List<TABLE_LIST> *view_tables;
- TABLE_LIST *belong_to_view;
- TABLE_LIST *referencing_view;
- TABLE_LIST *parent_l;
- Security_context *security_ctx;
- Security_context *view_sctx;
- In_C_you_should_use_my_bool_instead() allowed_show;
- TABLE_LIST *next_leaf;
- Item *where;
- Item *check_option;
- LEX_STRING select_stmt;
- LEX_STRING md5;
- LEX_STRING source;
- LEX_STRING view_db;
- LEX_STRING view_name;
- LEX_STRING timestamp;
- st_lex_user definer;
- ulonglong file_version;
- ulonglong updatable_view;
- ulonglong revision;
- ulonglong algorithm;
- ulonglong view_suid;
- ulonglong with_check;
- uint8 effective_with_check;
- uint8 effective_algorithm;
- GRANT_INFO grant;
- ulonglong engine_data;
- qc_engine_callback callback_func;
- thr_lock_type lock_type;
- uint outer_join;
- uint shared;
- size_t db_length;
- size_t table_name_length;
- In_C_you_should_use_my_bool_instead() updatable;
- In_C_you_should_use_my_bool_instead() straight;
- In_C_you_should_use_my_bool_instead() updating;
- In_C_you_should_use_my_bool_instead() force_index;
- In_C_you_should_use_my_bool_instead() ignore_leaves;
- table_map dep_tables;
- table_map on_expr_dep_tables;
- struct st_nested_join *nested_join;
- TABLE_LIST *embedding;
- List<TABLE_LIST> *join_list;
- In_C_you_should_use_my_bool_instead() cacheable_table;
- In_C_you_should_use_my_bool_instead() table_in_first_from_clause;
- In_C_you_should_use_my_bool_instead() skip_temporary;
- In_C_you_should_use_my_bool_instead() contain_auto_increment;
- In_C_you_should_use_my_bool_instead() multitable_view;
- In_C_you_should_use_my_bool_instead() compact_view_format;
- In_C_you_should_use_my_bool_instead() where_processed;
- In_C_you_should_use_my_bool_instead() check_option_processed;
- enum frm_type_enum required_type;
- handlerton *db_type;
- char timestamp_buffer[20];
- In_C_you_should_use_my_bool_instead() prelocking_placeholder;
- In_C_you_should_use_my_bool_instead() create;
- In_C_you_should_use_my_bool_instead() internal_tmp_table;
- View_creation_ctx *view_creation_ctx;
- LEX_STRING view_client_cs_name;
- LEX_STRING view_connection_cl_name;
- LEX_STRING view_body_utf8;
- uint8 trg_event_map;
- uint i_s_requested_object;
- In_C_you_should_use_my_bool_instead() has_db_lookup_value;
- In_C_you_should_use_my_bool_instead() has_table_lookup_value;
- uint table_open_method;
- enum enum_schema_table_state schema_table_state;
- void calc_md5(char *buffer);
- void set_underlying_merge();
- int view_check_option(THD *thd, In_C_you_should_use_my_bool_instead() ignore_failure);
- In_C_you_should_use_my_bool_instead() setup_underlying(THD *thd);
- void cleanup_items();
- In_C_you_should_use_my_bool_instead() placeholder()
- {
- return derived || view || schema_table || create && !table->db_stat ||
- !table;
- }
- void print(THD *thd, String *str, enum_query_type query_type);
- In_C_you_should_use_my_bool_instead() check_single_table(TABLE_LIST **table, table_map map,
- TABLE_LIST *view);
- In_C_you_should_use_my_bool_instead() set_insert_values(MEM_ROOT *mem_root);
- void hide_view_error(THD *thd);
- TABLE_LIST *find_underlying_table(TABLE *table);
- TABLE_LIST *first_leaf_for_name_resolution();
- TABLE_LIST *last_leaf_for_name_resolution();
- In_C_you_should_use_my_bool_instead() is_leaf_for_name_resolution();
- inline TABLE_LIST *top_table()
- { return belong_to_view ? belong_to_view : this; }
- inline In_C_you_should_use_my_bool_instead() prepare_check_option(THD *thd)
- {
- In_C_you_should_use_my_bool_instead() res= (0);
- if (effective_with_check)
- res= prep_check_option(thd, effective_with_check);
- return res;
- }
- inline In_C_you_should_use_my_bool_instead() prepare_where(THD *thd, Item **conds,
- In_C_you_should_use_my_bool_instead() no_where_clause)
- {
- if (effective_algorithm == 2)
- return prep_where(thd, conds, no_where_clause);
- return (0);
- }
- void register_want_access(ulong want_access);
- In_C_you_should_use_my_bool_instead() prepare_security(THD *thd);
- Security_context *find_view_security_context(THD *thd);
- In_C_you_should_use_my_bool_instead() prepare_view_securety_context(THD *thd);
- void reinit_before_use(THD *thd);
- Item_subselect *containing_subselect();
- In_C_you_should_use_my_bool_instead() process_index_hints(TABLE *table);
- inline ulong get_child_def_version()
- {
- return child_def_version;
- }
- inline void set_child_def_version(ulong version)
- {
- child_def_version= version;
- }
- inline void init_child_def_version()
- {
- child_def_version= ~0UL;
- }
- inline
- In_C_you_should_use_my_bool_instead() is_table_ref_id_equal(TABLE_SHARE *s) const
- {
- return (m_table_ref_type == s->get_table_ref_type() &&
- m_table_ref_version == s->get_table_ref_version());
- }
- inline
- void set_table_ref_id(TABLE_SHARE *s)
- {
- m_table_ref_type= s->get_table_ref_type();
- m_table_ref_version= s->get_table_ref_version();
- }
-private:
- In_C_you_should_use_my_bool_instead() prep_check_option(THD *thd, uint8 check_opt_type);
- In_C_you_should_use_my_bool_instead() prep_where(THD *thd, Item **conds, In_C_you_should_use_my_bool_instead() no_where_clause);
- ulong child_def_version;
- enum enum_table_ref_type m_table_ref_type;
- ulong m_table_ref_version;
-};
-class Item;
-class Field_iterator: public Sql_alloc
-{
-public:
- Field_iterator() {}
- virtual ~Field_iterator() {}
- virtual void set(TABLE_LIST *)= 0;
- virtual void next()= 0;
- virtual In_C_you_should_use_my_bool_instead() end_of_fields()= 0;
- virtual const char *name()= 0;
- virtual Item *create_item(THD *)= 0;
- virtual Field *field()= 0;
-};
-class Field_iterator_table: public Field_iterator
-{
- Field **ptr;
-public:
- Field_iterator_table() :ptr(0) {}
- void set(TABLE_LIST *table) { ptr= table->table->field; }
- void set_table(TABLE *table) { ptr= table->field; }
- void next() { ptr++; }
- In_C_you_should_use_my_bool_instead() end_of_fields() { return *ptr == 0; }
- const char *name();
- Item *create_item(THD *thd);
- Field *field() { return *ptr; }
-};
-class Field_iterator_view: public Field_iterator
-{
- Field_translator *ptr, *array_end;
- TABLE_LIST *view;
-public:
- Field_iterator_view() :ptr(0), array_end(0) {}
- void set(TABLE_LIST *table);
- void next() { ptr++; }
- In_C_you_should_use_my_bool_instead() end_of_fields() { return ptr == array_end; }
- const char *name();
- Item *create_item(THD *thd);
- Item **item_ptr() {return &ptr->item; }
- Field *field() { return 0; }
- inline Item *item() { return ptr->item; }
- Field_translator *field_translator() { return ptr; }
-};
-class Field_iterator_natural_join: public Field_iterator
-{
- List_iterator_fast<Natural_join_column> column_ref_it;
- Natural_join_column *cur_column_ref;
-public:
- Field_iterator_natural_join() :cur_column_ref(NULL) {}
- ~Field_iterator_natural_join() {}
- void set(TABLE_LIST *table);
- void next();
- In_C_you_should_use_my_bool_instead() end_of_fields() { return !cur_column_ref; }
- const char *name() { return cur_column_ref->name(); }
- Item *create_item(THD *thd) { return cur_column_ref->create_item(thd); }
- Field *field() { return cur_column_ref->field(); }
- Natural_join_column *column_ref() { return cur_column_ref; }
-};
-class Field_iterator_table_ref: public Field_iterator
-{
- TABLE_LIST *table_ref, *first_leaf, *last_leaf;
- Field_iterator_table table_field_it;
- Field_iterator_view view_field_it;
- Field_iterator_natural_join natural_join_it;
- Field_iterator *field_it;
- void set_field_iterator();
-public:
- Field_iterator_table_ref() :field_it(NULL) {}
- void set(TABLE_LIST *table);
- void next();
- In_C_you_should_use_my_bool_instead() end_of_fields()
- { return (table_ref == last_leaf && field_it->end_of_fields()); }
- const char *name() { return field_it->name(); }
- const char *table_name();
- const char *db_name();
- GRANT_INFO *grant();
- Item *create_item(THD *thd) { return field_it->create_item(thd); }
- Field *field() { return field_it->field(); }
- Natural_join_column *get_or_create_column_ref(TABLE_LIST *parent_table_ref);
- Natural_join_column *get_natural_column_ref();
-};
-typedef struct st_nested_join
-{
- List<TABLE_LIST> join_list;
- table_map used_tables;
- table_map not_null_tables;
- struct st_join_table *first_nested;
- uint counter;
- nested_join_map nj_map;
-} NESTED_JOIN;
-typedef struct st_changed_table_list
-{
- struct st_changed_table_list *next;
- char *key;
- uint32 key_length;
-} CHANGED_TABLE_LIST;
-typedef struct st_open_table_list{
- struct st_open_table_list *next;
- char *db,*table;
- uint32 in_use,locked;
-} OPEN_TABLE_LIST;
-typedef struct st_table_field_w_type
-{
- LEX_STRING name;
- LEX_STRING type;
- LEX_STRING cset;
-} TABLE_FIELD_W_TYPE;
-my_bool
-table_check_intact(TABLE *table, const uint table_f_count,
- const TABLE_FIELD_W_TYPE *table_def);
-static inline my_bitmap_map *tmp_use_all_columns(TABLE *table,
- MY_BITMAP *bitmap)
-{
- my_bitmap_map *old= bitmap->bitmap;
- bitmap->bitmap= table->s->all_set.bitmap;
- return old;
-}
-static inline void tmp_restore_column_map(MY_BITMAP *bitmap,
- my_bitmap_map *old)
-{
- bitmap->bitmap= old;
-}
-static inline my_bitmap_map *dbug_tmp_use_all_columns(TABLE *table,
- MY_BITMAP *bitmap)
-{
- return tmp_use_all_columns(table, bitmap);
-}
-static inline void dbug_tmp_restore_column_map(MY_BITMAP *bitmap,
- my_bitmap_map *old)
-{
- tmp_restore_column_map(bitmap, old);
-}
-size_t max_row_length(TABLE *table, const uchar *data);
-#include "sql_error.h"
-class MYSQL_ERROR: public Sql_alloc
-{
-public:
- enum enum_warning_level
- { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END};
- uint code;
- enum_warning_level level;
- char *msg;
- MYSQL_ERROR(THD *thd, uint code_arg, enum_warning_level level_arg,
- const char *msg_arg)
- :code(code_arg), level(level_arg)
- {
- if (msg_arg)
- set_msg(thd, msg_arg);
- }
- void set_msg(THD *thd, const char *msg_arg);
-};
-MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
- uint code, const char *msg);
-void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
- uint code, const char *format, ...);
-void mysql_reset_errors(THD *thd, In_C_you_should_use_my_bool_instead() force);
-In_C_you_should_use_my_bool_instead() mysqld_show_warnings(THD *thd, ulong levels_to_show);
-extern const LEX_STRING warning_level_names[];
-#include "field.h"
-const uint32 max_field_size= (uint32) 4294967295U;
-class Send_field;
-class Protocol;
-class Create_field;
-struct st_cache_field;
-int field_conv(Field *to,Field *from);
-inline uint get_enum_pack_length(int elements)
-{
- return elements < 256 ? 1 : 2;
-}
-inline uint get_set_pack_length(int elements)
-{
- uint len= (elements + 7) / 8;
- return len > 4 ? 8 : len;
-}
-class Field
-{
- Field(const Item &);
- void operator=(Field &);
-public:
- static void *operator new(size_t size) {return sql_alloc(size); }
- static void operator delete(void *ptr_arg, size_t size) { ; }
- uchar *ptr;
- uchar *null_ptr;
- struct st_table *table;
- struct st_table *orig_table;
- const char **table_name, *field_name;
- LEX_STRING comment;
- key_map key_start, part_of_key, part_of_key_not_clustered;
- key_map part_of_sortkey;
- enum utype { NONE,DATE,SHIELD,NOEMPTY,CASEUP,PNR,BGNR,PGNR,YES,NO,REL,
- CHECK,EMPTY,UNKNOWN_FIELD,CASEDN,NEXT_NUMBER,INTERVAL_FIELD,
- BIT_FIELD, TIMESTAMP_OLD_FIELD, CAPITALIZE, BLOB_FIELD,
- TIMESTAMP_DN_FIELD, TIMESTAMP_UN_FIELD, TIMESTAMP_DNUN_FIELD};
- 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;
- uint32 field_length;
- uint32 flags;
- uint16 field_index;
- uchar null_bit;
- In_C_you_should_use_my_bool_instead() is_created_from_null_item;
- Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
- uchar null_bit_arg, utype unireg_check_arg,
- const char *field_name_arg);
- virtual ~Field() {}
- virtual int store(const char *to, uint length,CHARSET_INFO *cs)=0;
- virtual int store(double nr)=0;
- virtual int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val)=0;
- virtual int store_decimal(const my_decimal *d)=0;
- virtual int store_time(MYSQL_TIME *ltime, timestamp_type t_type);
- int store(const char *to, uint length, CHARSET_INFO *cs,
- enum_check_fields check_level);
- virtual double val_real(void)=0;
- virtual longlong val_int(void)=0;
- virtual my_decimal *val_decimal(my_decimal *);
- inline String *val_str(String *str) { return val_str(str, str); }
- virtual String *val_str(String*,String *)=0;
- String *val_int_as_str(String *val_buffer, my_bool unsigned_flag);
- virtual In_C_you_should_use_my_bool_instead() str_needs_quotes() { return (0); }
- virtual Item_result result_type () const=0;
- virtual Item_result cmp_type () const { return result_type(); }
- virtual Item_result cast_to_int_type () const { return result_type(); }
- static In_C_you_should_use_my_bool_instead() type_can_have_key_part(enum_field_types);
- static enum_field_types field_type_merge(enum_field_types, enum_field_types);
- static Item_result result_merge_type(enum_field_types);
- virtual In_C_you_should_use_my_bool_instead() eq(Field *field)
- {
- return (ptr == field->ptr && null_ptr == field->null_ptr &&
- null_bit == field->null_bit);
- }
- virtual In_C_you_should_use_my_bool_instead() eq_def(Field *field);
- virtual uint32 pack_length() const { return (uint32) field_length; }
- virtual uint32 pack_length_in_rec() const { return pack_length(); }
- virtual int compatible_field_size(uint field_metadata);
- virtual uint pack_length_from_metadata(uint field_metadata)
- { return field_metadata; }
- virtual uint row_pack_length() { return 0; }
- virtual int save_field_metadata(uchar *first_byte)
- { return do_save_field_metadata(first_byte); }
- virtual uint32 data_length() { return pack_length(); }
- virtual uint32 sort_length() const { return pack_length(); }
- virtual uint32 max_data_length() const {
- return pack_length();
- };
- virtual int reset(void) { bzero(ptr,pack_length()); return 0; }
- virtual void reset_fields() {}
- virtual void set_default()
- {
- my_ptrdiff_t l_offset= (my_ptrdiff_t) (table->s->default_values -
- table->record[0]);
- memcpy(ptr, ptr + l_offset, pack_length());
- if (null_ptr)
- *null_ptr= ((*null_ptr & (uchar) ~null_bit) |
- null_ptr[l_offset] & null_bit);
- }
- virtual In_C_you_should_use_my_bool_instead() binary() const { return 1; }
- virtual In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; }
- virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- virtual uint32 key_length() const { return pack_length(); }
- virtual enum_field_types type() const =0;
- virtual enum_field_types real_type() const { return type(); }
- inline int cmp(const uchar *str) { return cmp(ptr,str); }
- virtual int cmp_max(const uchar *a, const uchar *b, uint max_len)
- { 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=~0L)
- { return memcmp(a,b,pack_length()); }
- virtual int cmp_offset(uint 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)
- { return cmp(a, b); }
- virtual int key_cmp(const uchar *str, uint length)
- { return cmp(ptr,str); }
- virtual uint decimals() const { return 0; }
- virtual void sql_type(String &str) const =0;
- virtual uint size_of() const =0;
- inline In_C_you_should_use_my_bool_instead() is_null(my_ptrdiff_t row_offset= 0)
- { return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : table->null_row; }
- inline In_C_you_should_use_my_bool_instead() is_real_null(my_ptrdiff_t row_offset= 0)
- { return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : 0; }
- inline In_C_you_should_use_my_bool_instead() is_null_in_record(const uchar *record)
- {
- if (!null_ptr)
- return 0;
- return ((record[(uint) (null_ptr -table->record[0])] & null_bit) ? 1 : 0);
- }
- inline In_C_you_should_use_my_bool_instead() is_null_in_record_with_offset(my_ptrdiff_t offset)
- {
- if (!null_ptr)
- return 0;
- return ((null_ptr[offset] & null_bit) ? 1 : 0);
- }
- inline void set_null(my_ptrdiff_t row_offset= 0)
- { if (null_ptr) null_ptr[row_offset]|= null_bit; }
- inline void set_notnull(my_ptrdiff_t row_offset= 0)
- { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; }
- inline In_C_you_should_use_my_bool_instead() maybe_null(void) { return null_ptr != 0 || table->maybe_null; }
- inline In_C_you_should_use_my_bool_instead() real_maybe_null(void) { return null_ptr != 0; }
- enum {
- LAST_NULL_BYTE_UNDEF= 0
- };
- size_t last_null_byte() const {
- size_t bytes= do_last_null_byte();
- do {_db_pargs_(284,"debug"); _db_doprnt_ ("last_null_byte() ==> %ld", (long) bytes);} while(0);
- assert(bytes <= table->s->null_bytes);
- return bytes;
- }
- virtual void make_field(Send_field *);
- virtual void sort_string(uchar *buff,uint length)=0;
- virtual In_C_you_should_use_my_bool_instead() optimize_range(uint idx, uint part);
- virtual In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (0); }
- virtual void free() {}
- virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table,
- In_C_you_should_use_my_bool_instead() keep_type);
- virtual Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
- uchar *new_ptr, uchar *new_null_ptr,
- uint new_null_bit);
- Field *clone(MEM_ROOT *mem_root, struct st_table *new_table);
- inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
- {
- ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
- }
- inline void move_field(uchar *ptr_arg) { ptr=ptr_arg; }
- virtual void move_field_offset(my_ptrdiff_t ptr_diff)
- {
- ptr=(uchar*) ((uchar*) (ptr)+ptr_diff);
- if (null_ptr)
- null_ptr=(uchar*) ((uchar*) (null_ptr)+ptr_diff);
- }
- virtual void get_image(uchar *buff, uint length, CHARSET_INFO *cs)
- { memcpy(buff,ptr,length); }
- virtual void set_image(const uchar *buff,uint length, CHARSET_INFO *cs)
- { memcpy(ptr,buff,length); }
- virtual uint get_key_image(uchar *buff, uint length, imagetype type)
- {
- get_image(buff, length, &my_charset_bin);
- return length;
- }
- virtual void set_key_image(const uchar *buff,uint length)
- { set_image(buff,length, &my_charset_bin); }
- inline longlong val_int_offset(uint row_offset)
- {
- ptr+=row_offset;
- longlong tmp=val_int();
- ptr-=row_offset;
- return tmp;
- }
- inline longlong val_int(const uchar *new_ptr)
- {
- uchar *old_ptr= ptr;
- longlong return_value;
- ptr= (uchar*) new_ptr;
- return_value= val_int();
- ptr= old_ptr;
- return return_value;
- }
- inline String *val_str(String *str, const uchar *new_ptr)
- {
- uchar *old_ptr= ptr;
- ptr= (uchar*) new_ptr;
- val_str(str);
- ptr= old_ptr;
- return str;
- }
- virtual In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- virtual uchar *pack(uchar *to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- uchar *pack(uchar *to, const uchar *from)
- {
- const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("Field::pack","./sql/field.h",390,&_db_func_,&_db_file_,&_db_level_, &_db_framep_);
- uchar *result= this->pack(to, from, UINT_MAX, table->s->db_low_byte_first);
- do {_db_return_ (392, &_db_func_, &_db_file_, &_db_level_); return(result);} while(0);
- }
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first);
- const uchar *unpack(uchar* to, const uchar *from)
- {
- const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("Field::unpack","./sql/field.h",402,&_db_func_,&_db_file_,&_db_level_, &_db_framep_);
- const uchar *result= unpack(to, from, 0U, table->s->db_low_byte_first);
- do {_db_return_ (404, &_db_func_, &_db_file_, &_db_level_); return(result);} while(0);
- }
- virtual uchar *pack_key(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- return pack(to, from, max_length, low_byte_first);
- }
- virtual uchar *pack_key_from_key_image(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- return pack(to, from, max_length, low_byte_first);
- }
- virtual const uchar *unpack_key(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- return unpack(to, from, max_length, low_byte_first);
- }
- virtual uint packed_col_length(const uchar *to, uint length)
- { return length;}
- virtual uint max_packed_col_length(uint max_length)
- { return max_length;}
- virtual int pack_cmp(const uchar *a,const uchar *b, uint key_length_arg,
- my_bool insert_or_update)
- { return cmp(a,b); }
- virtual int pack_cmp(const uchar *b, uint key_length_arg,
- my_bool insert_or_update)
- { return cmp(ptr,b); }
- uint offset(uchar *record)
- {
- return (uint) (ptr - record);
- }
- void copy_from_tmp(int offset);
- uint fill_cache_field(struct st_cache_field *copy);
- virtual In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate);
- virtual In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime);
- virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
- virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
- virtual In_C_you_should_use_my_bool_instead() has_charset(void) const { return (0); }
- virtual void set_charset(CHARSET_INFO *charset_arg) { }
- virtual enum Derivation derivation(void) const
- { return DERIVATION_IMPLICIT; }
- virtual void set_derivation(enum Derivation derivation_arg) { }
- In_C_you_should_use_my_bool_instead() set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
- int cuted_increment);
- void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code,
- const char *str, uint str_len,
- timestamp_type ts_type, int cuted_increment);
- void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code,
- longlong nr, timestamp_type ts_type,
- int cuted_increment);
- void set_datetime_warning(MYSQL_ERROR::enum_warning_level, const uint code,
- double nr, timestamp_type ts_type);
- inline In_C_you_should_use_my_bool_instead() check_overflow(int op_result)
- {
- return (op_result == 2);
- }
- int warn_if_overflow(int op_result);
- void init(TABLE *table_arg)
- {
- orig_table= table= table_arg;
- table_name= &table_arg->alias;
- }
- virtual uint32 max_display_length()= 0;
- virtual uint is_equal(Create_field *new_field);
- longlong convert_decimal2longlong(const my_decimal *val, In_C_you_should_use_my_bool_instead() unsigned_flag,
- int *err);
- inline uint32 char_length() const
- {
- return field_length / charset()->mbmaxlen;
- }
- virtual geometry_type get_geometry_type()
- {
- assert(0);
- return GEOM_GEOMETRY;
- }
- virtual void hash(ulong *nr, ulong *nr2);
- friend In_C_you_should_use_my_bool_instead() reopen_table(THD *,struct st_table *,In_C_you_should_use_my_bool_instead());
- friend int cre_myisam(char * name, register TABLE *form, uint options,
- ulonglong auto_increment_value);
- friend class Copy_field;
- friend class Item_avg_field;
- friend class Item_std_field;
- friend class Item_sum_num;
- friend class Item_sum_sum;
- friend class Item_sum_str;
- friend class Item_sum_count;
- friend class Item_sum_avg;
- friend class Item_sum_std;
- friend class Item_sum_min;
- friend class Item_sum_max;
- friend class Item_func_group_concat;
-private:
- virtual size_t do_last_null_byte() const;
- virtual int do_save_field_metadata(uchar *metadata_ptr)
- { return 0; }
-};
-class Field_num :public Field {
-public:
- const uint8 dec;
- In_C_you_should_use_my_bool_instead() zerofill,unsigned_flag;
- Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg, utype unireg_check_arg,
- const char *field_name_arg,
- uint8 dec_arg, In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg);
- Item_result result_type () const { return REAL_RESULT; }
- void prepend_zeros(String *value);
- void add_zerofill_and_unsigned(String &res) const;
- friend class Create_field;
- void make_field(Send_field *);
- uint decimals() const { return (uint) dec; }
- uint size_of() const { return sizeof(*this); }
- In_C_you_should_use_my_bool_instead() eq_def(Field *field);
- int store_decimal(const my_decimal *);
- my_decimal *val_decimal(my_decimal *);
- uint is_equal(Create_field *new_field);
- int check_int(CHARSET_INFO *cs, const char *str, int length,
- const char *int_end, int error);
- In_C_you_should_use_my_bool_instead() get_int(CHARSET_INFO *cs, const char *from, uint len,
- longlong *rnd, ulonglong unsigned_max,
- longlong signed_min, longlong signed_max);
-};
-class Field_str :public Field {
-protected:
- CHARSET_INFO *field_charset;
- enum Derivation field_derivation;
-public:
- Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg, utype unireg_check_arg,
- const char *field_name_arg, CHARSET_INFO *charset);
- Item_result result_type () const { return STRING_RESULT; }
- uint decimals() const { return 31; }
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val)=0;
- int store_decimal(const my_decimal *);
- int store(const char *to,uint length,CHARSET_INFO *cs)=0;
- uint size_of() const { return sizeof(*this); }
- CHARSET_INFO *charset(void) const { return field_charset; }
- void set_charset(CHARSET_INFO *charset_arg) { field_charset= charset_arg; }
- enum Derivation derivation(void) const { return field_derivation; }
- virtual void set_derivation(enum Derivation derivation_arg)
- { field_derivation= derivation_arg; }
- In_C_you_should_use_my_bool_instead() binary() const { return field_charset == &my_charset_bin; }
- uint32 max_display_length() { return field_length; }
- friend class Create_field;
- my_decimal *val_decimal(my_decimal *);
- virtual In_C_you_should_use_my_bool_instead() str_needs_quotes() { return (1); }
- In_C_you_should_use_my_bool_instead() compare_str_field_flags(Create_field *new_field, uint32 flags);
- uint is_equal(Create_field *new_field);
-};
-class Field_longstr :public Field_str
-{
-protected:
- int report_if_important_data(const char *ptr, const char *end,
- In_C_you_should_use_my_bool_instead() count_spaces);
-public:
- Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg, utype unireg_check_arg,
- const char *field_name_arg, CHARSET_INFO *charset_arg)
- :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
- field_name_arg, charset_arg)
- {}
- int store_decimal(const my_decimal *d);
- uint32 max_data_length() const;
-};
-class Field_real :public Field_num {
-public:
- my_bool not_fixed;
- Field_real(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg, utype unireg_check_arg,
- const char *field_name_arg,
- uint8 dec_arg, In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
- field_name_arg, dec_arg, zero_arg, unsigned_arg),
- not_fixed(dec_arg >= 31)
- {}
- int store_decimal(const my_decimal *);
- my_decimal *val_decimal(my_decimal *);
- int truncate(double *nr, double max_length);
- uint32 max_display_length() { return field_length; }
- uint size_of() const { return sizeof(*this); }
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first);
- virtual uchar *pack(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
-};
-class Field_decimal :public Field_real {
-public:
- Field_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- uint8 dec_arg,In_C_you_should_use_my_bool_instead() zero_arg,In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg,
- dec_arg, zero_arg, unsigned_arg)
- {}
- enum_field_types type() const { return MYSQL_TYPE_DECIMAL;}
- enum ha_base_keytype key_type() const
- { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; }
- int reset(void);
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- void overflow(In_C_you_should_use_my_bool_instead() negative);
- In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; }
- void sql_type(String &str) const;
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- return Field::unpack(to, from, param_data, low_byte_first);
- }
- virtual uchar *pack(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- return Field::pack(to, from, max_length, low_byte_first);
- }
-};
-class Field_new_decimal :public Field_num {
-private:
- int do_save_field_metadata(uchar *first_byte);
-public:
- uint precision;
- uint bin_size;
- Field_new_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- uint8 dec_arg, In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg);
- Field_new_decimal(uint32 len_arg, In_C_you_should_use_my_bool_instead() maybe_null_arg,
- const char *field_name_arg, uint8 dec_arg,
- In_C_you_should_use_my_bool_instead() unsigned_arg);
- enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;}
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- Item_result result_type () const { return DECIMAL_RESULT; }
- int reset(void);
- In_C_you_should_use_my_bool_instead() store_value(const my_decimal *decimal_value);
- void set_value_on_overflow(my_decimal *decimal_value, In_C_you_should_use_my_bool_instead() sign);
- int store(const char *to, uint length, CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int store_time(MYSQL_TIME *ltime, timestamp_type t_type);
- int store_decimal(const my_decimal *);
- double val_real(void);
- longlong val_int(void);
- my_decimal *val_decimal(my_decimal *);
- String *val_str(String*, String *);
- int cmp(const uchar *, const uchar *);
- void sort_string(uchar *buff, uint length);
- In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; }
- void sql_type(String &str) const;
- uint32 max_display_length() { return field_length; }
- uint size_of() const { return sizeof(*this); }
- uint32 pack_length() const { return (uint32) bin_size; }
- uint pack_length_from_metadata(uint field_metadata);
- uint row_pack_length() { return pack_length(); }
- int compatible_field_size(uint field_metadata);
- uint is_equal(Create_field *new_field);
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first);
-};
-class Field_tiny :public Field_num {
-public:
- Field_tiny(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg,
- 0, zero_arg,unsigned_arg)
- {}
- enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types type() const { return MYSQL_TYPE_TINY;}
- enum ha_base_keytype key_type() const
- { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int reset(void) { ptr[0]=0; return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 1; }
- void sql_type(String &str) const;
- uint32 max_display_length() { return 4; }
- virtual uchar *pack(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- *to= *from;
- return to + 1;
- }
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- *to= *from;
- return from + 1;
- }
-};
-class Field_short :public Field_num {
-public:
- Field_short(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg,
- 0, zero_arg,unsigned_arg)
- {}
- Field_short(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, 0, 0, unsigned_arg)
- {}
- enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types type() const { return MYSQL_TYPE_SHORT;}
- enum ha_base_keytype key_type() const
- { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;}
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int reset(void) { ptr[0]=ptr[1]=0; return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 2; }
- void sql_type(String &str) const;
- uint32 max_display_length() { return 6; }
- virtual uchar *pack(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- int16 val;
- do { val = (*((int16 *) (from))); } while(0);
- *((uint16*) (to))= (uint16) (val);
- return to + sizeof(val);
- }
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- int16 val;
- do { val = (*((int16 *) (from))); } while(0);
- *((uint16*) (to))= (uint16) (val);
- return from + sizeof(val);
- }
-};
-class Field_medium :public Field_num {
-public:
- Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg,
- 0, zero_arg,unsigned_arg)
- {}
- enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types type() const { return MYSQL_TYPE_INT24;}
- enum ha_base_keytype key_type() const
- { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- 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 *);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 3; }
- void sql_type(String &str) const;
- uint32 max_display_length() { return 8; }
- virtual uchar *pack(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- return Field::pack(to, from, max_length, low_byte_first);
- }
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- return Field::unpack(to, from, param_data, low_byte_first);
- }
-};
-class Field_long :public Field_num {
-public:
- Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg,
- 0, zero_arg,unsigned_arg)
- {}
- Field_long(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg,0,0,unsigned_arg)
- {}
- enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types type() const { return MYSQL_TYPE_LONG;}
- enum ha_base_keytype key_type() const
- { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
- double val_real(void);
- longlong val_int(void);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- String *val_str(String*,String *);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 4; }
- void sql_type(String &str) const;
- uint32 max_display_length() { return 11; }
- virtual uchar *pack(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- int32 val;
- do { val = (*((long *) (from))); } while(0);
- *((long *) (to))= (long) (val);
- return to + sizeof(val);
- }
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- int32 val;
- do { val = (*((long *) (from))); } while(0);
- *((long *) (to))= (long) (val);
- return from + sizeof(val);
- }
-};
-class Field_longlong :public Field_num {
-public:
- Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg,
- 0, zero_arg,unsigned_arg)
- {}
- Field_longlong(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg,
- const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg,0,0,unsigned_arg)
- {}
- enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types type() const { return MYSQL_TYPE_LONGLONG;}
- enum ha_base_keytype key_type() const
- { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int reset(void)
- {
- ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0;
- return 0;
- }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 8; }
- void sql_type(String &str) const;
- In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); }
- uint32 max_display_length() { return 20; }
- virtual uchar *pack(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- int64 val;
- memcpy(((uchar*) &val),((uchar*) (from)),(sizeof(ulonglong)));
- memcpy(((uchar*) (to)),((uchar*) &val),(sizeof(ulonglong)));
- return to + sizeof(val);
- }
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first)
- {
- int64 val;
- memcpy(((uchar*) &val),((uchar*) (from)),(sizeof(ulonglong)));
- memcpy(((uchar*) (to)),((uchar*) &val),(sizeof(ulonglong)));
- return from + sizeof(val);
- }
-};
-class Field_float :public Field_real {
-public:
- Field_float(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- uint8 dec_arg,In_C_you_should_use_my_bool_instead() zero_arg,In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg,
- dec_arg, zero_arg, unsigned_arg)
- {}
- Field_float(uint32 len_arg, In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- uint8 dec_arg)
- :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
- NONE, field_name_arg, dec_arg, 0, 0)
- {}
- enum_field_types type() const { return MYSQL_TYPE_FLOAT;}
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int reset(void) { bzero(ptr,sizeof(float)); return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return sizeof(float); }
- uint row_pack_length() { return pack_length(); }
- void sql_type(String &str) const;
-private:
- int do_save_field_metadata(uchar *first_byte);
-};
-class Field_double :public Field_real {
-public:
- Field_double(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- uint8 dec_arg,In_C_you_should_use_my_bool_instead() zero_arg,In_C_you_should_use_my_bool_instead() unsigned_arg)
- :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg,
- dec_arg, zero_arg, unsigned_arg)
- {}
- Field_double(uint32 len_arg, In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- uint8 dec_arg)
- :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
- NONE, field_name_arg, dec_arg, 0, 0)
- {}
- Field_double(uint32 len_arg, In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- uint8 dec_arg, my_bool not_fixed_arg)
- :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
- NONE, field_name_arg, dec_arg, 0, 0)
- {not_fixed= not_fixed_arg; }
- enum_field_types type() const { return MYSQL_TYPE_DOUBLE;}
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int reset(void) { bzero(ptr,sizeof(double)); return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return sizeof(double); }
- uint row_pack_length() { return pack_length(); }
- void sql_type(String &str) const;
-private:
- int do_save_field_metadata(uchar *first_byte);
-};
-class Field_null :public Field_str {
- static uchar null[1];
-public:
- Field_null(uchar *ptr_arg, uint32 len_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str(ptr_arg, len_arg, null, 1,
- unireg_check_arg, field_name_arg, cs)
- {}
- enum_field_types type() const { return MYSQL_TYPE_NULL;}
- int store(const char *to, uint length, CHARSET_INFO *cs)
- { null[0]=1; return 0; }
- int store(double nr) { null[0]=1; return 0; }
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val) { null[0]=1; return 0; }
- int store_decimal(const my_decimal *d) { null[0]=1; return 0; }
- int reset(void) { return 0; }
- double val_real(void) { return 0.0;}
- longlong val_int(void) { return 0;}
- my_decimal *val_decimal(my_decimal *) { return 0; }
- String *val_str(String *value,String *value2)
- { value2->length(0); return value2;}
- int cmp(const uchar *a, const uchar *b) { return 0;}
- void sort_string(uchar *buff, uint length) {}
- uint32 pack_length() const { return 0; }
- void sql_type(String &str) const;
- uint size_of() const { return sizeof(*this); }
- uint32 max_display_length() { return 4; }
-};
-class Field_timestamp :public Field_str {
-public:
- Field_timestamp(uchar *ptr_arg, uint32 len_arg,
- uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- TABLE_SHARE *share, CHARSET_INFO *cs);
- Field_timestamp(In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs);
- enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;}
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
- enum Item_result cmp_type () const { return INT_RESULT; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 4; }
- void sql_type(String &str) const;
- In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); }
- In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; }
- void set_time();
- virtual void set_default()
- {
- if (table->timestamp_field == this &&
- unireg_check != TIMESTAMP_UN_FIELD)
- set_time();
- else
- Field::set_default();
- }
- inline long get_timestamp(my_bool *null_value)
- {
- if ((*null_value= is_null()))
- return 0;
- long tmp;
- do { tmp = (*((long *) (ptr))); } while(0);
- return tmp;
- }
- inline void store_timestamp(my_time_t timestamp)
- {
- *((long *) (ptr))= (long) ((uint32) timestamp);
- }
- In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate);
- In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime);
- timestamp_auto_set_type get_auto_set_type() const;
-};
-class Field_year :public Field_tiny {
-public:
- Field_year(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg)
- :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, 1, 1)
- {}
- enum_field_types type() const { return MYSQL_TYPE_YEAR;}
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- void sql_type(String &str) const;
- In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); }
-};
-class Field_date :public Field_str {
-public:
- Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
- {}
- Field_date(In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str((uchar*) 0,10, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
- enum_field_types type() const { return MYSQL_TYPE_DATE;}
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
- enum Item_result cmp_type () const { return INT_RESULT; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 4; }
- void sql_type(String &str) const;
- In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); }
- In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; }
-};
-class Field_newdate :public Field_str {
-public:
- Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
- {}
- Field_newdate(In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str((uchar*) 0,10, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
- enum_field_types type() const { return MYSQL_TYPE_DATE;}
- enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; }
- enum Item_result cmp_type () const { return INT_RESULT; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int store_time(MYSQL_TIME *ltime, timestamp_type type);
- 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 *);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 3; }
- void sql_type(String &str) const;
- In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); }
- In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; }
- In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate);
- In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime);
-};
-class Field_time :public Field_str {
-public:
- Field_time(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
- {}
- Field_time(In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str((uchar*) 0,8, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
- enum_field_types type() const { return MYSQL_TYPE_TIME;}
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
- enum Item_result cmp_type () const { return INT_RESULT; }
- int store_time(MYSQL_TIME *ltime, timestamp_type type);
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- 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 *);
- In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime, uint fuzzydate);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 3; }
- void sql_type(String &str) const;
- In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); }
- In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; }
-};
-class Field_datetime :public Field_str {
-public:
- Field_datetime(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
- {}
- Field_datetime(In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str((uchar*) 0,19, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
- enum_field_types type() const { return MYSQL_TYPE_DATETIME;}
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
- enum Item_result cmp_type () const { return INT_RESULT; }
- uint decimals() const { return 6; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int store_time(MYSQL_TIME *ltime, timestamp_type type);
- int reset(void)
- {
- ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0;
- return 0;
- }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 8; }
- void sql_type(String &str) const;
- In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); }
- In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; }
- In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate);
- In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime);
-};
-class Field_string :public Field_longstr {
-public:
- In_C_you_should_use_my_bool_instead() can_alter_field_type;
- Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs),
- can_alter_field_type(1) {};
- Field_string(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
- NONE, field_name_arg, cs),
- can_alter_field_type(1) {};
- enum_field_types type() const
- {
- return ((can_alter_field_type && orig_table &&
- orig_table->s->db_create_options & 1 &&
- field_length >= 4) &&
- orig_table->s->frm_version < (6 +4) ?
- MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING);
- }
- enum ha_base_keytype key_type() const
- { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
- In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; }
- int reset(void)
- {
- charset()->cset->fill(charset(),(char*) ptr, field_length,
- (has_charset() ? ' ' : 0));
- return 0;
- }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int store(double nr) { return Field_str::store(nr); }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- my_decimal *val_decimal(my_decimal *);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- void sql_type(String &str) const;
- virtual uchar *pack(uchar *to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first);
- uint pack_length_from_metadata(uint field_metadata)
- { return (field_metadata & 0x00ff); }
- uint row_pack_length() { return (field_length + 1); }
- int pack_cmp(const uchar *a,const uchar *b,uint key_length,
- my_bool insert_or_update);
- int pack_cmp(const uchar *b,uint key_length,my_bool insert_or_update);
- uint packed_col_length(const uchar *to, uint length);
- uint max_packed_col_length(uint max_length);
- uint size_of() const { return sizeof(*this); }
- enum_field_types real_type() const { return MYSQL_TYPE_STRING; }
- In_C_you_should_use_my_bool_instead() has_charset(void) const
- { return charset() == &my_charset_bin ? (0) : (1); }
- Field *new_field(MEM_ROOT *root, struct st_table *new_table, In_C_you_should_use_my_bool_instead() keep_type);
- virtual uint get_key_image(uchar *buff,uint length, imagetype type);
-private:
- int do_save_field_metadata(uchar *first_byte);
-};
-class Field_varstring :public Field_longstr {
-public:
- static const uint MAX_SIZE;
- uint32 length_bytes;
- Field_varstring(uchar *ptr_arg,
- uint32 len_arg, uint length_bytes_arg,
- uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- TABLE_SHARE *share, CHARSET_INFO *cs)
- :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs),
- length_bytes(length_bytes_arg)
- {
- share->varchar_fields++;
- }
- Field_varstring(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg,
- const char *field_name_arg,
- TABLE_SHARE *share, CHARSET_INFO *cs)
- :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
- NONE, field_name_arg, cs),
- length_bytes(len_arg < 256 ? 1 :2)
- {
- share->varchar_fields++;
- }
- enum_field_types type() const { return MYSQL_TYPE_VARCHAR; }
- enum ha_base_keytype key_type() const;
- uint row_pack_length() { return field_length; }
- In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; }
- int reset(void) { bzero(ptr,field_length+length_bytes); return 0; }
- uint32 pack_length() const { return (uint32) field_length+length_bytes; }
- uint32 key_length() const { return (uint32) field_length; }
- uint32 sort_length() const
- {
- return (uint32) field_length + (field_charset == &my_charset_bin ?
- length_bytes : 0);
- }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int store(double nr) { return Field_str::store(nr); }
- double val_real(void);
- 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)
- {
- return cmp_max(a, b, ~0L);
- }
- void sort_string(uchar *buff,uint length);
- uint get_key_image(uchar *buff,uint length, imagetype type);
- void set_key_image(const uchar *buff,uint length);
- void sql_type(String &str) const;
- virtual uchar *pack(uchar *to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- uchar *pack_key(uchar *to, const uchar *from, uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- uchar *pack_key_from_key_image(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- virtual const uchar *unpack(uchar* to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first);
- const uchar *unpack_key(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- int pack_cmp(const uchar *a, const uchar *b, uint key_length,
- my_bool insert_or_update);
- int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update);
- int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0L);
- int key_cmp(const uchar *,const uchar*);
- int key_cmp(const uchar *str, uint length);
- uint packed_col_length(const uchar *to, uint length);
- uint max_packed_col_length(uint max_length);
- uint32 data_length();
- uint size_of() const { return sizeof(*this); }
- enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; }
- In_C_you_should_use_my_bool_instead() has_charset(void) const
- { return charset() == &my_charset_bin ? (0) : (1); }
- Field *new_field(MEM_ROOT *root, struct st_table *new_table, In_C_you_should_use_my_bool_instead() keep_type);
- Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
- uchar *new_ptr, uchar *new_null_ptr,
- uint new_null_bit);
- uint is_equal(Create_field *new_field);
- void hash(ulong *nr, ulong *nr2);
-private:
- int do_save_field_metadata(uchar *first_byte);
-};
-class Field_blob :public Field_longstr {
-protected:
- uint packlength;
- String value;
-public:
- Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- TABLE_SHARE *share, uint blob_pack_length, CHARSET_INFO *cs);
- Field_blob(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
- NONE, field_name_arg, cs),
- packlength(4)
- {
- flags|= 16;
- }
- Field_blob(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs, In_C_you_should_use_my_bool_instead() set_packlength)
- :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
- NONE, field_name_arg, cs)
- {
- flags|= 16;
- packlength= 4;
- if (set_packlength)
- {
- uint32 l_char_length= len_arg/cs->mbmaxlen;
- packlength= l_char_length <= 255 ? 1 :
- l_char_length <= 65535 ? 2 :
- l_char_length <= 16777215 ? 3 : 4;
- }
- }
- Field_blob(uint32 packlength_arg)
- :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, "temp", system_charset_info),
- packlength(packlength_arg) {}
- enum_field_types type() const { return MYSQL_TYPE_BLOB;}
- enum ha_base_keytype key_type() const
- { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- double val_real(void);
- 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)
- { return cmp_max(a, b, ~0L); }
- 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=~0L);
- int key_cmp(const uchar *,const uchar*);
- int key_cmp(const uchar *str, uint length);
- uint32 key_length() const { return 0; }
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const
- { return (uint32) (packlength+table->s->blob_ptr_size); }
- uint32 pack_length_no_ptr() const
- { return (uint32) (packlength); }
- uint row_pack_length() { return pack_length_no_ptr(); }
- uint32 sort_length() const;
- virtual uint32 max_data_length() const
- {
- return (uint32) (((ulonglong) 1 << (packlength*8)) -1);
- }
- int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; }
- void reset_fields() { bzero((uchar*) &value,sizeof(value)); }
- static
- void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number, In_C_you_should_use_my_bool_instead() low_byte_first);
- void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number)
- {
- store_length(i_ptr, i_packlength, i_number, table->s->db_low_byte_first);
- }
- inline void store_length(uint32 number)
- {
- store_length(ptr, packlength, number);
- }
- uint32 get_packed_size(const uchar *ptr_arg, In_C_you_should_use_my_bool_instead() low_byte_first)
- {return packlength + get_length(ptr_arg, packlength, low_byte_first);}
- inline uint32 get_length(uint row_offset= 0)
- { return get_length(ptr+row_offset, this->packlength, table->s->db_low_byte_first); }
- uint32 get_length(const uchar *ptr, uint packlength, In_C_you_should_use_my_bool_instead() low_byte_first);
- uint32 get_length(const uchar *ptr_arg)
- { return get_length(ptr_arg, this->packlength, table->s->db_low_byte_first); }
- void put_length(uchar *pos, uint32 length);
- inline void get_ptr(uchar **str)
- {
- memcpy(((uchar*) str),(ptr+packlength),(sizeof(uchar*)));
- }
- inline void get_ptr(uchar **str, uint row_offset)
- {
- memcpy(((uchar*) str),(ptr+packlength+row_offset),(sizeof(char*)));
- }
- inline void set_ptr(uchar *length, uchar *data)
- {
- memcpy(ptr,length,packlength);
- memcpy((ptr+packlength),(&data),(sizeof(char*)));
- }
- void set_ptr_offset(my_ptrdiff_t ptr_diff, uint32 length, uchar *data)
- {
- uchar *ptr_ofs= (uchar*) ((uchar*) (ptr)+ptr_diff);
- store_length(ptr_ofs, packlength, length);
- memcpy((ptr_ofs+packlength),(&data),(sizeof(char*)));
- }
- inline void set_ptr(uint32 length, uchar *data)
- {
- set_ptr_offset(0, length, data);
- }
- uint get_key_image(uchar *buff,uint length, imagetype type);
- void set_key_image(const uchar *buff,uint length);
- void sql_type(String &str) const;
- inline In_C_you_should_use_my_bool_instead() copy()
- {
- uchar *tmp;
- get_ptr(&tmp);
- if (value.copy((char*) tmp, get_length(), charset()))
- {
- Field_blob::reset();
- return 1;
- }
- tmp=(uchar*) value.ptr();
- memcpy((ptr+packlength),(&tmp),(sizeof(char*)));
- return 0;
- }
- virtual uchar *pack(uchar *to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- uchar *pack_key(uchar *to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- uchar *pack_key_from_key_image(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- virtual const uchar *unpack(uchar *to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first);
- const uchar *unpack_key(uchar* to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- int pack_cmp(const uchar *a, const uchar *b, uint key_length,
- my_bool insert_or_update);
- int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update);
- uint packed_col_length(const uchar *col_ptr, uint length);
- uint max_packed_col_length(uint max_length);
- void free() { value.free(); }
- inline void clear_temporary() { bzero((uchar*) &value,sizeof(value)); }
- friend int field_conv(Field *to,Field *from);
- uint size_of() const { return sizeof(*this); }
- In_C_you_should_use_my_bool_instead() has_charset(void) const
- { return charset() == &my_charset_bin ? (0) : (1); }
- uint32 max_display_length();
- uint is_equal(Create_field *new_field);
- inline In_C_you_should_use_my_bool_instead() in_read_set() { return bitmap_is_set(table->read_set, field_index); }
- inline In_C_you_should_use_my_bool_instead() in_write_set() { return bitmap_is_set(table->write_set, field_index); }
-private:
- int do_save_field_metadata(uchar *first_byte);
-};
-class Field_geom :public Field_blob {
-public:
- enum geometry_type geom_type;
- Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- TABLE_SHARE *share, uint blob_pack_length,
- enum geometry_type geom_type_arg)
- :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; }
- Field_geom(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg,
- TABLE_SHARE *share, enum geometry_type geom_type_arg)
- :Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin)
- { geom_type= geom_type_arg; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; }
- enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; }
- void sql_type(String &str) const;
- int store(const char *to, uint length, CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int store_decimal(const my_decimal *);
- uint size_of() const { return sizeof(*this); }
- int reset(void) { return !maybe_null() || Field_blob::reset(); }
- geometry_type get_geometry_type() { return geom_type; };
-};
-class Field_enum :public Field_str {
-protected:
- uint packlength;
-public:
- TYPELIB *typelib;
- Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- uint packlength_arg,
- TYPELIB *typelib_arg,
- CHARSET_INFO *charset_arg)
- :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, charset_arg),
- packlength(packlength_arg),typelib(typelib_arg)
- {
- flags|=256;
- }
- Field *new_field(MEM_ROOT *root, struct st_table *new_table, In_C_you_should_use_my_bool_instead() keep_type);
- enum_field_types type() const { return MYSQL_TYPE_STRING; }
- enum Item_result cmp_type () const { return INT_RESULT; }
- enum Item_result cast_to_int_type () const { return INT_RESULT; }
- enum ha_base_keytype key_type() const;
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- int cmp(const uchar *,const uchar *);
- 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); }
- enum_field_types real_type() const { return MYSQL_TYPE_ENUM; }
- uint pack_length_from_metadata(uint field_metadata)
- { return (field_metadata & 0x00ff); }
- uint row_pack_length() { return pack_length(); }
- virtual In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; }
- In_C_you_should_use_my_bool_instead() optimize_range(uint idx, uint part) { return 0; }
- In_C_you_should_use_my_bool_instead() eq_def(Field *field);
- In_C_you_should_use_my_bool_instead() has_charset(void) const { return (1); }
- CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
-private:
- int do_save_field_metadata(uchar *first_byte);
-};
-class Field_set :public Field_enum {
-public:
- Field_set(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- uint32 packlength_arg,
- TYPELIB *typelib_arg, CHARSET_INFO *charset_arg)
- :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg,
- packlength_arg,
- typelib_arg,charset_arg)
- {
- flags=(flags & ~256) | 2048;
- }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr) { return Field_set::store((longlong) nr, (0)); }
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- virtual In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; }
- String *val_str(String*,String *);
- void sql_type(String &str) const;
- enum_field_types real_type() const { return MYSQL_TYPE_SET; }
- In_C_you_should_use_my_bool_instead() has_charset(void) const { return (1); }
-};
-class Field_bit :public Field {
-public:
- uchar *bit_ptr;
- uchar bit_ofs;
- uint bit_len;
- uint bytes_in_rec;
- Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
- enum utype unireg_check_arg, const char *field_name_arg);
- enum_field_types type() const { return MYSQL_TYPE_BIT; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
- uint32 key_length() const { return (uint32) (field_length + 7) / 8; }
- uint32 max_data_length() const { return (field_length + 7) / 8; }
- uint32 max_display_length() { return field_length; }
- uint size_of() const { return sizeof(*this); }
- Item_result result_type () const { return INT_RESULT; }
- int reset(void) { bzero(ptr, bytes_in_rec); return 0; }
- int store(const char *to, uint length, CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val);
- int store_decimal(const my_decimal *);
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*, String *);
- virtual In_C_you_should_use_my_bool_instead() str_needs_quotes() { return (1); }
- my_decimal *val_decimal(my_decimal *);
- int cmp(const uchar *a, const uchar *b)
- {
- assert(ptr == a);
- return Field_bit::key_cmp(b, bytes_in_rec+((bit_len) ? 1 : 0));
- }
- 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)
- { return cmp_binary((uchar *) a, (uchar *) b); }
- int key_cmp(const uchar *str, uint length);
- int cmp_offset(uint row_offset);
- void get_image(uchar *buff, uint length, CHARSET_INFO *cs)
- { get_key_image(buff, length, itRAW); }
- void set_image(const uchar *buff,uint length, CHARSET_INFO *cs)
- { Field_bit::store((char *) buff, length, cs); }
- uint get_key_image(uchar *buff, uint length, imagetype type);
- void set_key_image(const uchar *buff, uint length)
- { Field_bit::store((char*) buff, length, &my_charset_bin); }
- void sort_string(uchar *buff, uint length)
- { 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 row_pack_length()
- { return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); }
- int compatible_field_size(uint field_metadata);
- void sql_type(String &str) const;
- virtual uchar *pack(uchar *to, const uchar *from,
- uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first);
- virtual const uchar *unpack(uchar *to, const uchar *from,
- uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first);
- virtual void set_default();
- Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
- uchar *new_ptr, uchar *new_null_ptr,
- uint new_null_bit);
- void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg)
- {
- bit_ptr= bit_ptr_arg;
- bit_ofs= bit_ofs_arg;
- }
- In_C_you_should_use_my_bool_instead() eq(Field *field)
- {
- return (Field::eq(field) &&
- field->type() == type() &&
- bit_ptr == ((Field_bit *)field)->bit_ptr &&
- bit_ofs == ((Field_bit *)field)->bit_ofs);
- }
- uint is_equal(Create_field *new_field);
- void move_field_offset(my_ptrdiff_t ptr_diff)
- {
- Field::move_field_offset(ptr_diff);
- bit_ptr= (uchar*) ((uchar*) (bit_ptr)+ptr_diff);
- }
- void hash(ulong *nr, ulong *nr2);
-private:
- virtual size_t do_last_null_byte() const;
- int do_save_field_metadata(uchar *first_byte);
-};
-class Field_bit_as_char: public Field_bit {
-public:
- Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg);
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- uint size_of() const { return sizeof(*this); }
- int store(const char *to, uint length, CHARSET_INFO *charset);
- int store(double nr) { return Field_bit::store(nr); }
- int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val)
- { return Field_bit::store(nr, unsigned_val); }
- void sql_type(String &str) const;
-};
-class Create_field :public Sql_alloc
-{
-public:
- const char *field_name;
- const char *change;
- const char *after;
- LEX_STRING comment;
- Item *def;
- enum enum_field_types sql_type;
- ulong length;
- uint32 char_length;
- uint decimals, flags, pack_length, key_length;
- Field::utype unireg_check;
- TYPELIB *interval;
- TYPELIB *save_interval;
- List<String> interval_list;
- CHARSET_INFO *charset;
- Field::geometry_type geom_type;
- Field *field;
- uint8 row,col,sc_length,interval_id;
- uint offset,pack_flag;
- Create_field() :after(0) {}
- Create_field(Field *field, Field *orig_field);
- Create_field *clone(MEM_ROOT *mem_root) const
- { return new (mem_root) Create_field(*this); }
- void create_length_to_internal_length(void);
- void init_for_tmp_table(enum_field_types sql_type_arg,
- uint32 max_length, uint32 decimals,
- In_C_you_should_use_my_bool_instead() maybe_null, In_C_you_should_use_my_bool_instead() is_unsigned);
- In_C_you_should_use_my_bool_instead() init(THD *thd, char *field_name, enum_field_types type, char *length,
- char *decimals, uint type_modifier, Item *default_value,
- Item *on_update_value, LEX_STRING *comment, char *change,
- List<String> *interval_list, CHARSET_INFO *cs,
- uint uint_geom_type);
-};
-class Send_field {
- public:
- const char *db_name;
- const char *table_name,*org_table_name;
- const char *col_name,*org_col_name;
- ulong length;
- uint charsetnr, flags, decimals;
- enum_field_types type;
- Send_field() {}
-};
-class Copy_field :public Sql_alloc {
- typedef void Copy_func(Copy_field*);
- Copy_func *get_copy_func(Field *to, Field *from);
-public:
- uchar *from_ptr,*to_ptr;
- uchar *from_null_ptr,*to_null_ptr;
- my_bool *null_row;
- uint from_bit,to_bit;
- uint from_length,to_length;
- Field *from_field,*to_field;
- String tmp;
- Copy_field() {}
- ~Copy_field() {}
- void set(Field *to,Field *from,In_C_you_should_use_my_bool_instead() save);
- void set(uchar *to,Field *from);
- void (*do_copy)(Copy_field *);
- void (*do_copy2)(Copy_field *);
-};
-Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
- uchar *null_pos, uchar null_bit,
- uint pack_flag, enum_field_types field_type,
- CHARSET_INFO *cs,
- Field::geometry_type geom_type,
- Field::utype unireg_check,
- TYPELIB *interval, const char *field_name);
-uint pack_length_to_packflag(uint type);
-enum_field_types get_blob_type_from_length(ulong length);
-uint32 calc_pack_length(enum_field_types type,uint32 length);
-int set_field_to_null(Field *field);
-int set_field_to_null_with_conversions(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
-#include "protocol.h"
-class i_string;
-class THD;
-typedef struct st_mysql_field MYSQL_FIELD;
-typedef struct st_mysql_rows MYSQL_ROWS;
-class Protocol
-{
-protected:
- THD *thd;
- String *packet;
- String *convert;
- uint field_pos;
- enum enum_field_types *field_types;
- uint field_count;
- In_C_you_should_use_my_bool_instead() net_store_data(const uchar *from, size_t length);
- In_C_you_should_use_my_bool_instead() store_string_aux(const char *from, size_t length,
- CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
-public:
- Protocol() {}
- Protocol(THD *thd_arg) { init(thd_arg); }
- virtual ~Protocol() {}
- void init(THD* thd_arg);
- enum { SEND_NUM_ROWS= 1, SEND_DEFAULTS= 2, SEND_EOF= 4 };
- virtual In_C_you_should_use_my_bool_instead() send_fields(List<Item> *list, uint flags);
- In_C_you_should_use_my_bool_instead() store(I_List<i_string> *str_list);
- In_C_you_should_use_my_bool_instead() store(const char *from, CHARSET_INFO *cs);
- String *storage_packet() { return packet; }
- inline void free() { packet->free(); }
- virtual In_C_you_should_use_my_bool_instead() write();
- inline In_C_you_should_use_my_bool_instead() store(int from)
- { return store_long((longlong) from); }
- inline In_C_you_should_use_my_bool_instead() store(uint32 from)
- { return store_long((longlong) from); }
- inline In_C_you_should_use_my_bool_instead() store(longlong from)
- { return store_longlong((longlong) from, 0); }
- inline In_C_you_should_use_my_bool_instead() store(ulonglong from)
- { return store_longlong((longlong) from, 1); }
- inline In_C_you_should_use_my_bool_instead() store(String *str)
- { return store((char*) str->ptr(), str->length(), str->charset()); }
- virtual In_C_you_should_use_my_bool_instead() prepare_for_send(List<Item> *item_list)
- {
- field_count=item_list->elements;
- return 0;
- }
- virtual In_C_you_should_use_my_bool_instead() flush();
- virtual void end_partial_result_set(THD *thd);
- virtual void prepare_for_resend()=0;
- virtual In_C_you_should_use_my_bool_instead() store_null()=0;
- virtual In_C_you_should_use_my_bool_instead() store_tiny(longlong from)=0;
- virtual In_C_you_should_use_my_bool_instead() store_short(longlong from)=0;
- virtual In_C_you_should_use_my_bool_instead() store_long(longlong from)=0;
- virtual In_C_you_should_use_my_bool_instead() store_longlong(longlong from, In_C_you_should_use_my_bool_instead() unsigned_flag)=0;
- virtual In_C_you_should_use_my_bool_instead() store_decimal(const my_decimal *)=0;
- virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length, CHARSET_INFO *cs)=0;
- virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length,
- CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0;
- virtual In_C_you_should_use_my_bool_instead() store(float from, uint32 decimals, String *buffer)=0;
- virtual In_C_you_should_use_my_bool_instead() store(double from, uint32 decimals, String *buffer)=0;
- virtual In_C_you_should_use_my_bool_instead() store(MYSQL_TIME *time)=0;
- virtual In_C_you_should_use_my_bool_instead() store_date(MYSQL_TIME *time)=0;
- virtual In_C_you_should_use_my_bool_instead() store_time(MYSQL_TIME *time)=0;
- virtual In_C_you_should_use_my_bool_instead() store(Field *field)=0;
- void remove_last_row() {}
- enum enum_protocol_type
- {
- PROTOCOL_TEXT= 0, PROTOCOL_BINARY= 1
- };
- virtual enum enum_protocol_type type()= 0;
-};
-class Protocol_text :public Protocol
-{
-public:
- Protocol_text() {}
- Protocol_text(THD *thd_arg) :Protocol(thd_arg) {}
- virtual void prepare_for_resend();
- virtual In_C_you_should_use_my_bool_instead() store_null();
- virtual In_C_you_should_use_my_bool_instead() store_tiny(longlong from);
- virtual In_C_you_should_use_my_bool_instead() store_short(longlong from);
- virtual In_C_you_should_use_my_bool_instead() store_long(longlong from);
- virtual In_C_you_should_use_my_bool_instead() store_longlong(longlong from, In_C_you_should_use_my_bool_instead() unsigned_flag);
- virtual In_C_you_should_use_my_bool_instead() store_decimal(const my_decimal *);
- virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length, CHARSET_INFO *cs);
- virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length,
- CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
- virtual In_C_you_should_use_my_bool_instead() store(MYSQL_TIME *time);
- virtual In_C_you_should_use_my_bool_instead() store_date(MYSQL_TIME *time);
- virtual In_C_you_should_use_my_bool_instead() store_time(MYSQL_TIME *time);
- virtual In_C_you_should_use_my_bool_instead() store(float nr, uint32 decimals, String *buffer);
- virtual In_C_you_should_use_my_bool_instead() store(double from, uint32 decimals, String *buffer);
- virtual In_C_you_should_use_my_bool_instead() store(Field *field);
- virtual enum enum_protocol_type type() { return PROTOCOL_TEXT; };
-};
-class Protocol_binary :public Protocol
-{
-private:
- uint bit_fields;
-public:
- Protocol_binary() {}
- Protocol_binary(THD *thd_arg) :Protocol(thd_arg) {}
- virtual In_C_you_should_use_my_bool_instead() prepare_for_send(List<Item> *item_list);
- virtual void prepare_for_resend();
- virtual In_C_you_should_use_my_bool_instead() store_null();
- virtual In_C_you_should_use_my_bool_instead() store_tiny(longlong from);
- virtual In_C_you_should_use_my_bool_instead() store_short(longlong from);
- virtual In_C_you_should_use_my_bool_instead() store_long(longlong from);
- virtual In_C_you_should_use_my_bool_instead() store_longlong(longlong from, In_C_you_should_use_my_bool_instead() unsigned_flag);
- virtual In_C_you_should_use_my_bool_instead() store_decimal(const my_decimal *);
- virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length, CHARSET_INFO *cs);
- virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length,
- CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
- virtual In_C_you_should_use_my_bool_instead() store(MYSQL_TIME *time);
- virtual In_C_you_should_use_my_bool_instead() store_date(MYSQL_TIME *time);
- virtual In_C_you_should_use_my_bool_instead() store_time(MYSQL_TIME *time);
- virtual In_C_you_should_use_my_bool_instead() store(float nr, uint32 decimals, String *buffer);
- virtual In_C_you_should_use_my_bool_instead() store(double from, uint32 decimals, String *buffer);
- virtual In_C_you_should_use_my_bool_instead() store(Field *field);
- virtual enum enum_protocol_type type() { return PROTOCOL_BINARY; };
-};
-void send_warning(THD *thd, uint sql_errno, const char *err=0);
-void net_send_error(THD *thd, uint sql_errno=0, const char *err=0);
-void net_end_statement(THD *thd);
-In_C_you_should_use_my_bool_instead() send_old_password_request(THD *thd);
-uchar *net_store_data(uchar *to,const uchar *from, size_t length);
-uchar *net_store_data(uchar *to,int32 from);
-uchar *net_store_data(uchar *to,longlong from);
-#include "sql_udf.h"
-enum Item_udftype {UDFTYPE_FUNCTION=1,UDFTYPE_AGGREGATE};
-typedef void (*Udf_func_clear)(UDF_INIT *, uchar *, uchar *);
-typedef void (*Udf_func_add)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *);
-typedef void (*Udf_func_deinit)(UDF_INIT*);
-typedef my_bool (*Udf_func_init)(UDF_INIT *, UDF_ARGS *, char *);
-typedef void (*Udf_func_any)();
-typedef double (*Udf_func_double)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *);
-typedef longlong (*Udf_func_longlong)(UDF_INIT *, UDF_ARGS *, uchar *,
- uchar *);
-typedef struct st_udf_func
-{
- LEX_STRING name;
- Item_result returns;
- Item_udftype type;
- char *dl;
- void *dlhandle;
- Udf_func_any func;
- Udf_func_init func_init;
- Udf_func_deinit func_deinit;
- Udf_func_clear func_clear;
- Udf_func_add func_add;
- ulong usage_count;
-} udf_func;
-class Item_result_field;
-class udf_handler :public Sql_alloc
-{
- protected:
- udf_func *u_d;
- String *buffers;
- UDF_ARGS f_args;
- UDF_INIT initid;
- char *num_buffer;
- uchar error, is_null;
- In_C_you_should_use_my_bool_instead() initialized;
- Item **args;
- public:
- table_map used_tables_cache;
- In_C_you_should_use_my_bool_instead() const_item_cache;
- In_C_you_should_use_my_bool_instead() not_original;
- udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0),
- is_null(0), initialized(0), not_original(0)
- {}
- ~udf_handler();
- const char *name() const { return u_d ? u_d->name.str : "?"; }
- Item_result result_type () const
- { return u_d ? u_d->returns : STRING_RESULT;}
- In_C_you_should_use_my_bool_instead() get_arguments();
- In_C_you_should_use_my_bool_instead() fix_fields(THD *thd, Item_result_field *item,
- uint arg_count, Item **args);
- void cleanup();
- double val(my_bool *null_value)
- {
- is_null= 0;
- if (get_arguments())
- {
- *null_value=1;
- return 0.0;
- }
- Udf_func_double func= (Udf_func_double) u_d->func;
- double tmp=func(&initid, &f_args, &is_null, &error);
- if (is_null || error)
- {
- *null_value=1;
- return 0.0;
- }
- *null_value=0;
- return tmp;
- }
- longlong val_int(my_bool *null_value)
- {
- is_null= 0;
- if (get_arguments())
- {
- *null_value=1;
- return 0LL;
- }
- Udf_func_longlong func= (Udf_func_longlong) u_d->func;
- longlong tmp=func(&initid, &f_args, &is_null, &error);
- if (is_null || error)
- {
- *null_value=1;
- return 0LL;
- }
- *null_value=0;
- return tmp;
- }
- my_decimal *val_decimal(my_bool *null_value, my_decimal *dec_buf);
- void clear()
- {
- is_null= 0;
- Udf_func_clear func= u_d->func_clear;
- func(&initid, &is_null, &error);
- }
- void add(my_bool *null_value)
- {
- if (get_arguments())
- {
- *null_value=1;
- return;
- }
- Udf_func_add func= u_d->func_add;
- func(&initid, &f_args, &is_null, &error);
- *null_value= (my_bool) (is_null || error);
- }
- String *val_str(String *str,String *save_str);
-};
-void udf_init(void),udf_free(void);
-udf_func *find_udf(const char *name, uint len=0,In_C_you_should_use_my_bool_instead() mark_used=0);
-void free_udf(udf_func *udf);
-int mysql_create_function(THD *thd,udf_func *udf);
-int mysql_drop_function(THD *thd,const LEX_STRING *name);
-#include "sql_profile.h"
-extern ST_FIELD_INFO query_profile_statistics_info[];
-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);
-#include "sql_partition.h"
-#pragma interface
-typedef struct {
- longlong list_value;
- uint32 partition_id;
-} LIST_PART_ENTRY;
-typedef struct {
- uint32 start_part;
- uint32 end_part;
-} part_id_range;
-struct st_partition_iter;
-In_C_you_should_use_my_bool_instead() is_partition_in_list(char *part_name, List<char> list_part_names);
-char *are_partitions_in_table(partition_info *new_part_info,
- partition_info *old_part_info);
-In_C_you_should_use_my_bool_instead() check_reorganise_list(partition_info *new_part_info,
- partition_info *old_part_info,
- List<char> list_part_names);
-handler *get_ha_partition(partition_info *part_info);
-int get_parts_for_update(const uchar *old_data, uchar *new_data,
- const uchar *rec0, partition_info *part_info,
- uint32 *old_part_id, uint32 *new_part_id,
- longlong *func_value);
-int get_part_for_delete(const uchar *buf, const uchar *rec0,
- partition_info *part_info, uint32 *part_id);
-void prune_partition_set(const TABLE *table, part_id_range *part_spec);
-In_C_you_should_use_my_bool_instead() check_partition_info(partition_info *part_info,handlerton **eng_type,
- TABLE *table, handler *file, HA_CREATE_INFO *info);
-void set_linear_hash_mask(partition_info *part_info, uint no_parts);
-In_C_you_should_use_my_bool_instead() fix_partition_func(THD *thd, TABLE *table, In_C_you_should_use_my_bool_instead() create_table_ind);
-char *generate_partition_syntax(partition_info *part_info,
- uint *buf_length, In_C_you_should_use_my_bool_instead() use_sql_alloc,
- In_C_you_should_use_my_bool_instead() show_partition_options);
-In_C_you_should_use_my_bool_instead() partition_key_modified(TABLE *table, const MY_BITMAP *fields);
-void get_partition_set(const TABLE *table, uchar *buf, const uint index,
- const key_range *key_spec,
- part_id_range *part_spec);
-void get_full_part_id_from_key(const TABLE *table, uchar *buf,
- KEY *key_info,
- const key_range *key_spec,
- part_id_range *part_spec);
-In_C_you_should_use_my_bool_instead() mysql_unpack_partition(THD *thd, const char *part_buf,
- uint part_info_len,
- const char *part_state, uint part_state_len,
- TABLE *table, In_C_you_should_use_my_bool_instead() is_create_table_ind,
- handlerton *default_db_type,
- In_C_you_should_use_my_bool_instead() *work_part_info_used);
-void make_used_partitions_str(partition_info *part_info, String *parts_str);
-uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
- In_C_you_should_use_my_bool_instead() left_endpoint,
- In_C_you_should_use_my_bool_instead() include_endpoint);
-uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
- In_C_you_should_use_my_bool_instead() left_endpoint,
- In_C_you_should_use_my_bool_instead() include_endpoint);
-In_C_you_should_use_my_bool_instead() fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
- In_C_you_should_use_my_bool_instead() is_sub_part, In_C_you_should_use_my_bool_instead() is_field_to_be_setup);
-In_C_you_should_use_my_bool_instead() check_part_func_fields(Field **ptr, In_C_you_should_use_my_bool_instead() ok_with_charsets);
-In_C_you_should_use_my_bool_instead() field_is_partition_charset(Field *field);
-typedef uint32 (*partition_iter_func)(st_partition_iter* part_iter);
-typedef struct st_partition_iter
-{
- partition_iter_func get_next;
- In_C_you_should_use_my_bool_instead() ret_null_part, ret_null_part_orig;
- struct st_part_num_range
- {
- uint32 start;
- uint32 cur;
- uint32 end;
- };
- struct st_field_value_range
- {
- longlong start;
- longlong cur;
- longlong end;
- };
- union
- {
- struct st_part_num_range part_nums;
- struct st_field_value_range field_vals;
- };
- partition_info *part_info;
-} PARTITION_ITERATOR;
-typedef int (*get_partitions_in_range_iter)(partition_info *part_info,
- In_C_you_should_use_my_bool_instead() is_subpart,
- uchar *min_val, uchar *max_val,
- uint flags,
- PARTITION_ITERATOR *part_iter);
-#include "partition_info.h"
-#include "partition_element.h"
-enum partition_type {
- NOT_A_PARTITION= 0,
- RANGE_PARTITION,
- HASH_PARTITION,
- LIST_PARTITION
-};
-enum partition_state {
- PART_NORMAL= 0,
- PART_IS_DROPPED= 1,
- PART_TO_BE_DROPPED= 2,
- PART_TO_BE_ADDED= 3,
- PART_TO_BE_REORGED= 4,
- PART_REORGED_DROPPED= 5,
- PART_CHANGED= 6,
- PART_IS_CHANGED= 7,
- PART_IS_ADDED= 8
-};
-typedef struct p_elem_val
-{
- longlong value;
- In_C_you_should_use_my_bool_instead() null_value;
- In_C_you_should_use_my_bool_instead() unsigned_flag;
-} part_elem_value;
-struct st_ddl_log_memory_entry;
-class partition_element :public Sql_alloc {
-public:
- List<partition_element> subpartitions;
- List<part_elem_value> list_val_list;
- ha_rows part_max_rows;
- ha_rows part_min_rows;
- longlong range_value;
- char *partition_name;
- char *tablespace_name;
- struct st_ddl_log_memory_entry *log_entry;
- char* part_comment;
- char* data_file_name;
- char* index_file_name;
- handlerton *engine_type;
- enum partition_state part_state;
- uint16 nodegroup_id;
- In_C_you_should_use_my_bool_instead() has_null_value;
- In_C_you_should_use_my_bool_instead() signed_flag;
- In_C_you_should_use_my_bool_instead() max_value;
- partition_element()
- : part_max_rows(0), part_min_rows(0), range_value(0),
- partition_name(NULL), tablespace_name(NULL),
- log_entry(NULL), part_comment(NULL),
- data_file_name(NULL), index_file_name(NULL),
- engine_type(NULL), part_state(PART_NORMAL),
- nodegroup_id(65535), has_null_value((0)),
- signed_flag((0)), max_value((0))
- {
- }
- partition_element(partition_element *part_elem)
- : part_max_rows(part_elem->part_max_rows),
- part_min_rows(part_elem->part_min_rows),
- range_value(0), partition_name(NULL),
- tablespace_name(part_elem->tablespace_name),
- part_comment(part_elem->part_comment),
- data_file_name(part_elem->data_file_name),
- index_file_name(part_elem->index_file_name),
- engine_type(part_elem->engine_type),
- part_state(part_elem->part_state),
- nodegroup_id(part_elem->nodegroup_id),
- has_null_value((0))
- {
- }
- ~partition_element() {}
-};
-class partition_info;
-typedef int (*get_part_id_func)(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-typedef uint32 (*get_subpart_id_func)(partition_info *part_info);
-struct st_ddl_log_memory_entry;
-class partition_info : public Sql_alloc
-{
-public:
- List<partition_element> partitions;
- List<partition_element> temp_partitions;
- List<char> part_field_list;
- List<char> subpart_field_list;
- get_part_id_func get_partition_id;
- get_part_id_func get_part_partition_id;
- get_subpart_id_func get_subpartition_id;
- get_part_id_func get_partition_id_charset;
- get_part_id_func get_part_partition_id_charset;
- get_subpart_id_func get_subpartition_id_charset;
- Field **part_field_array;
- Field **subpart_field_array;
- Field **part_charset_field_array;
- Field **subpart_charset_field_array;
- Field **full_part_field_array;
- Field **full_part_charset_field_array;
- MY_BITMAP full_part_field_set;
- uchar **part_field_buffers;
- uchar **subpart_field_buffers;
- uchar **full_part_field_buffers;
- uchar **restore_part_field_ptrs;
- uchar **restore_subpart_field_ptrs;
- uchar **restore_full_part_field_ptrs;
- Item *part_expr;
- Item *subpart_expr;
- Item *item_free_list;
- struct st_ddl_log_memory_entry *first_log_entry;
- struct st_ddl_log_memory_entry *exec_log_entry;
- struct st_ddl_log_memory_entry *frm_log_entry;
- MY_BITMAP used_partitions;
- union {
- longlong *range_int_array;
- LIST_PART_ENTRY *list_array;
- };
- get_partitions_in_range_iter get_part_iter_for_interval;
- get_partitions_in_range_iter get_subpart_iter_for_interval;
- longlong err_value;
- char* part_info_string;
- char *part_func_string;
- char *subpart_func_string;
- const char *part_state;
- partition_element *curr_part_elem;
- partition_element *current_partition;
- key_map all_fields_in_PF, all_fields_in_PPF, all_fields_in_SPF;
- key_map some_fields_in_PF;
- handlerton *default_engine_type;
- Item_result part_result_type;
- partition_type part_type;
- partition_type subpart_type;
- uint part_info_len;
- uint part_state_len;
- uint part_func_len;
- uint subpart_func_len;
- uint no_parts;
- uint no_subparts;
- uint count_curr_subparts;
- uint part_error_code;
- uint no_list_values;
- uint no_part_fields;
- uint no_subpart_fields;
- uint no_full_part_fields;
- uint has_null_part_id;
- uint16 linear_hash_mask;
- In_C_you_should_use_my_bool_instead() use_default_partitions;
- In_C_you_should_use_my_bool_instead() use_default_no_partitions;
- In_C_you_should_use_my_bool_instead() use_default_subpartitions;
- In_C_you_should_use_my_bool_instead() use_default_no_subpartitions;
- In_C_you_should_use_my_bool_instead() default_partitions_setup;
- In_C_you_should_use_my_bool_instead() defined_max_value;
- In_C_you_should_use_my_bool_instead() list_of_part_fields;
- In_C_you_should_use_my_bool_instead() list_of_subpart_fields;
- In_C_you_should_use_my_bool_instead() linear_hash_ind;
- In_C_you_should_use_my_bool_instead() fixed;
- In_C_you_should_use_my_bool_instead() is_auto_partitioned;
- In_C_you_should_use_my_bool_instead() from_openfrm;
- In_C_you_should_use_my_bool_instead() has_null_value;
- partition_info()
- : get_partition_id(NULL), get_part_partition_id(NULL),
- get_subpartition_id(NULL),
- part_field_array(NULL), subpart_field_array(NULL),
- part_charset_field_array(NULL),
- subpart_charset_field_array(NULL),
- full_part_field_array(NULL),
- full_part_charset_field_array(NULL),
- part_field_buffers(NULL), subpart_field_buffers(NULL),
- full_part_field_buffers(NULL),
- restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL),
- restore_full_part_field_ptrs(NULL),
- part_expr(NULL), subpart_expr(NULL), item_free_list(NULL),
- first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL),
- list_array(NULL), err_value(0),
- part_info_string(NULL),
- part_func_string(NULL), subpart_func_string(NULL),
- part_state(NULL),
- curr_part_elem(NULL), current_partition(NULL),
- default_engine_type(NULL),
- part_result_type(INT_RESULT),
- part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION),
- part_info_len(0), part_state_len(0),
- part_func_len(0), subpart_func_len(0),
- no_parts(0), no_subparts(0),
- count_curr_subparts(0), part_error_code(0),
- no_list_values(0), no_part_fields(0), no_subpart_fields(0),
- no_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0),
- use_default_partitions((1)), use_default_no_partitions((1)),
- use_default_subpartitions((1)), use_default_no_subpartitions((1)),
- default_partitions_setup((0)), defined_max_value((0)),
- list_of_part_fields((0)), list_of_subpart_fields((0)),
- linear_hash_ind((0)), fixed((0)),
- is_auto_partitioned((0)), from_openfrm((0)),
- has_null_value((0))
- {
- all_fields_in_PF.clear_all();
- all_fields_in_PPF.clear_all();
- all_fields_in_SPF.clear_all();
- some_fields_in_PF.clear_all();
- partitions.empty();
- temp_partitions.empty();
- part_field_list.empty();
- subpart_field_list.empty();
- }
- ~partition_info() {}
- partition_info *get_clone();
- In_C_you_should_use_my_bool_instead() is_sub_partitioned()
- {
- return (subpart_type == NOT_A_PARTITION ? (0) : (1));
- }
- uint get_tot_partitions()
- {
- return no_parts * (is_sub_partitioned() ? no_subparts : 1);
- }
- In_C_you_should_use_my_bool_instead() set_up_defaults_for_partitioning(handler *file, HA_CREATE_INFO *info,
- uint start_no);
- char *has_unique_names();
- In_C_you_should_use_my_bool_instead() check_engine_mix(handlerton *engine_type, In_C_you_should_use_my_bool_instead() default_engine);
- In_C_you_should_use_my_bool_instead() check_range_constants();
- In_C_you_should_use_my_bool_instead() check_list_constants();
- In_C_you_should_use_my_bool_instead() check_partition_info(THD *thd, handlerton **eng_type,
- handler *file, HA_CREATE_INFO *info,
- In_C_you_should_use_my_bool_instead() check_partition_function);
- void print_no_partition_found(TABLE *table);
- In_C_you_should_use_my_bool_instead() set_up_charset_field_preps();
-private:
- static int list_part_cmp(const void* a, const void* b);
- static int list_part_cmp_unsigned(const void* a, const void* b);
- In_C_you_should_use_my_bool_instead() set_up_default_partitions(handler *file, HA_CREATE_INFO *info,
- uint start_no);
- In_C_you_should_use_my_bool_instead() set_up_default_subpartitions(handler *file, HA_CREATE_INFO *info);
- char *create_default_partition_names(uint part_no, uint no_parts,
- uint start_no);
- char *create_subpartition_name(uint subpart_no, const char *part_name);
- In_C_you_should_use_my_bool_instead() has_unique_name(partition_element *element);
-};
-uint32 get_next_partition_id_range(struct st_partition_iter* part_iter);
-In_C_you_should_use_my_bool_instead() check_partition_dirs(partition_info *part_info);
-static inline void init_single_partition_iterator(uint32 part_id,
- PARTITION_ITERATOR *part_iter)
-{
- part_iter->part_nums.start= part_iter->part_nums.cur= part_id;
- part_iter->part_nums.end= part_id+1;
- part_iter->get_next= get_next_partition_id_range;
-}
-static inline
-void init_all_partitions_iterator(partition_info *part_info,
- PARTITION_ITERATOR *part_iter)
-{
- part_iter->part_nums.start= part_iter->part_nums.cur= 0;
- part_iter->part_nums.end= part_info->no_parts;
- part_iter->get_next= get_next_partition_id_range;
-}
-class user_var_entry;
-class Security_context;
-enum enum_var_type
-{
- OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
-};
-class sys_var;
-#include "item.h"
-class Protocol;
-struct TABLE_LIST;
-void item_init(void);
-class Item_field;
-class DTCollation {
-public:
- CHARSET_INFO *collation;
- enum Derivation derivation;
- uint repertoire;
- void set_repertoire_from_charset(CHARSET_INFO *cs)
- {
- repertoire= cs->state & 4096 ?
- 1 : 3;
- }
- DTCollation()
- {
- collation= &my_charset_bin;
- derivation= DERIVATION_NONE;
- repertoire= 3;
- }
- DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg)
- {
- collation= collation_arg;
- derivation= derivation_arg;
- set_repertoire_from_charset(collation_arg);
- }
- void set(DTCollation &dt)
- {
- collation= dt.collation;
- derivation= dt.derivation;
- repertoire= dt.repertoire;
- }
- void set(CHARSET_INFO *collation_arg, Derivation derivation_arg)
- {
- collation= collation_arg;
- derivation= derivation_arg;
- set_repertoire_from_charset(collation_arg);
- }
- void set(CHARSET_INFO *collation_arg,
- Derivation derivation_arg,
- uint repertoire_arg)
- {
- collation= collation_arg;
- derivation= derivation_arg;
- repertoire= repertoire_arg;
- }
- void set(CHARSET_INFO *collation_arg)
- {
- collation= collation_arg;
- set_repertoire_from_charset(collation_arg);
- }
- void set(Derivation derivation_arg)
- { derivation= derivation_arg; }
- In_C_you_should_use_my_bool_instead() aggregate(DTCollation &dt, uint flags= 0);
- In_C_you_should_use_my_bool_instead() set(DTCollation &dt1, DTCollation &dt2, uint flags= 0)
- { set(dt1); return aggregate(dt2, flags); }
- const char *derivation_name() const
- {
- switch(derivation)
- {
- case DERIVATION_IGNORABLE: return "IGNORABLE";
- case DERIVATION_COERCIBLE: return "COERCIBLE";
- case DERIVATION_IMPLICIT: return "IMPLICIT";
- case DERIVATION_SYSCONST: return "SYSCONST";
- case DERIVATION_EXPLICIT: return "EXPLICIT";
- case DERIVATION_NONE: return "NONE";
- default: return "UNKNOWN";
- }
- }
-};
-struct Hybrid_type_traits;
-struct Hybrid_type
-{
- longlong integer;
- double real;
- my_decimal dec_buf[3];
- int used_dec_buf_no;
- const Hybrid_type_traits *traits;
- Hybrid_type() {}
- Hybrid_type(const Hybrid_type &rhs) :traits(rhs.traits) {}
-};
-struct Hybrid_type_traits
-{
- virtual Item_result type() const { return REAL_RESULT; }
- virtual void
- fix_length_and_dec(Item *item, Item *arg) const;
- virtual void set_zero(Hybrid_type *val) const { val->real= 0.0; }
- virtual void add(Hybrid_type *val, Field *f) const
- { val->real+= f->val_real(); }
- virtual void div(Hybrid_type *val, ulonglong u) const
- { val->real/= ((double) (ulonglong) (u)); }
- virtual longlong val_int(Hybrid_type *val, In_C_you_should_use_my_bool_instead() unsigned_flag) const
- { return (longlong) rint(val->real); }
- virtual double val_real(Hybrid_type *val) const { return val->real; }
- virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const;
- virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
- static const Hybrid_type_traits *instance();
- Hybrid_type_traits() {}
- virtual ~Hybrid_type_traits() {}
-};
-struct Hybrid_type_traits_decimal: public Hybrid_type_traits
-{
- virtual Item_result type() const { return DECIMAL_RESULT; }
- virtual void
- fix_length_and_dec(Item *arg, Item *item) const;
- virtual void set_zero(Hybrid_type *val) const;
- virtual void add(Hybrid_type *val, Field *f) const;
- virtual void div(Hybrid_type *val, ulonglong u) const;
- virtual longlong val_int(Hybrid_type *val, In_C_you_should_use_my_bool_instead() unsigned_flag) const;
- virtual double val_real(Hybrid_type *val) const;
- virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const
- { return &val->dec_buf[val->used_dec_buf_no]; }
- virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
- static const Hybrid_type_traits_decimal *instance();
- Hybrid_type_traits_decimal() {};
-};
-struct Hybrid_type_traits_integer: public Hybrid_type_traits
-{
- virtual Item_result type() const { return INT_RESULT; }
- virtual void
- fix_length_and_dec(Item *arg, Item *item) const;
- virtual void set_zero(Hybrid_type *val) const
- { val->integer= 0; }
- virtual void add(Hybrid_type *val, Field *f) const
- { val->integer+= f->val_int(); }
- virtual void div(Hybrid_type *val, ulonglong u) const
- { val->integer/= (longlong) u; }
- virtual longlong val_int(Hybrid_type *val, In_C_you_should_use_my_bool_instead() unsigned_flag) const
- { return val->integer; }
- virtual double val_real(Hybrid_type *val) const
- { return (double) val->integer; }
- virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const
- {
- int2my_decimal(30, val->integer, 0, &val->dec_buf[2]);
- return &val->dec_buf[2];
- }
- virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const
- { buf->set(val->integer, &my_charset_bin); return buf;}
- static const Hybrid_type_traits_integer *instance();
- Hybrid_type_traits_integer() {};
-};
-void dummy_error_processor(THD *thd, void *data);
-void view_error_processor(THD *thd, void *data);
-struct Name_resolution_context: Sql_alloc
-{
- Name_resolution_context *outer_context;
- TABLE_LIST *table_list;
- TABLE_LIST *first_name_resolution_table;
- TABLE_LIST *last_name_resolution_table;
- st_select_lex *select_lex;
- void (*error_processor)(THD *, void *);
- void *error_processor_data;
- In_C_you_should_use_my_bool_instead() resolve_in_select_list;
- Security_context *security_ctx;
- Name_resolution_context()
- :outer_context(0), table_list(0), select_lex(0),
- error_processor_data(0),
- security_ctx(0)
- {}
- void init()
- {
- resolve_in_select_list= (0);
- error_processor= &dummy_error_processor;
- first_name_resolution_table= NULL;
- last_name_resolution_table= NULL;
- }
- void resolve_in_table_list_only(TABLE_LIST *tables)
- {
- table_list= first_name_resolution_table= tables;
- resolve_in_select_list= (0);
- }
- void process_error(THD *thd)
- {
- (*error_processor)(thd, error_processor_data);
- }
-};
-class Name_resolution_context_state
-{
-private:
- TABLE_LIST *save_table_list;
- TABLE_LIST *save_first_name_resolution_table;
- TABLE_LIST *save_next_name_resolution_table;
- In_C_you_should_use_my_bool_instead() save_resolve_in_select_list;
- TABLE_LIST *save_next_local;
-public:
- Name_resolution_context_state() {}
-public:
- void save_state(Name_resolution_context *context, TABLE_LIST *table_list)
- {
- save_table_list= context->table_list;
- save_first_name_resolution_table= context->first_name_resolution_table;
- save_resolve_in_select_list= context->resolve_in_select_list;
- save_next_local= table_list->next_local;
- save_next_name_resolution_table= table_list->next_name_resolution_table;
- }
- void restore_state(Name_resolution_context *context, TABLE_LIST *table_list)
- {
- table_list->next_local= save_next_local;
- table_list->next_name_resolution_table= save_next_name_resolution_table;
- context->table_list= save_table_list;
- context->first_name_resolution_table= save_first_name_resolution_table;
- context->resolve_in_select_list= save_resolve_in_select_list;
- }
- TABLE_LIST *get_first_name_resolution_table()
- {
- return save_first_name_resolution_table;
- }
-};
-typedef enum monotonicity_info
-{
- NON_MONOTONIC,
- MONOTONIC_INCREASING,
- MONOTONIC_STRICT_INCREASING
-} enum_monotonicity_info;
-class sp_rcontext;
-class Settable_routine_parameter
-{
-public:
- Settable_routine_parameter() {}
- virtual ~Settable_routine_parameter() {}
- virtual void set_required_privilege(In_C_you_should_use_my_bool_instead() rw) {};
- virtual In_C_you_should_use_my_bool_instead() set_value(THD *thd, sp_rcontext *ctx, Item **it)= 0;
-};
-typedef In_C_you_should_use_my_bool_instead() (Item::*Item_processor) (uchar *arg);
-typedef In_C_you_should_use_my_bool_instead() (Item::*Item_analyzer) (uchar **argp);
-typedef Item* (Item::*Item_transformer) (uchar *arg);
-typedef void (*Cond_traverser) (const Item *item, void *arg);
-class Item {
- Item(const Item &);
- void operator=(Item &);
-public:
- static void *operator new(size_t size)
- { return sql_alloc(size); }
- static void *operator new(size_t size, MEM_ROOT *mem_root)
- { return alloc_root(mem_root, size); }
- static void operator delete(void *ptr,size_t size) { ; }
- static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
- enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM,
- INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM,
- COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM,
- PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
- FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,
- SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,
- PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM,
- XPATH_NODESET, XPATH_NODESET_CMP,
- VIEW_FIXER_ITEM};
- enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
- enum traverse_order { POSTFIX, PREFIX };
- uint rsize;
- String str_value;
- char * name;
- char * orig_name;
- Item *next;
- uint32 max_length;
- uint name_length;
- int8 marker;
- uint8 decimals;
- my_bool maybe_null;
- my_bool null_value;
- my_bool unsigned_flag;
- my_bool with_sum_func;
- my_bool fixed;
- my_bool is_autogenerated_name;
- DTCollation collation;
- my_bool with_subselect;
- Item_result cmp_context;
- Item();
- Item(THD *thd, Item *item);
- virtual ~Item()
- {
- }
- void set_name(const char *str, uint length, CHARSET_INFO *cs);
- void rename(char *new_name);
- void init_make_field(Send_field *tmp_field,enum enum_field_types type);
- virtual void cleanup();
- virtual void make_field(Send_field *field);
- Field *make_string_field(TABLE *table);
- virtual In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **);
- inline void quick_fix_field() { fixed= 1; }
- int save_in_field_no_warnings(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- virtual int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- virtual void save_org_in_field(Field *field)
- { (void) save_in_field(field, 1); }
- virtual int save_safe_in_field(Field *field)
- { return save_in_field(field, 1); }
- virtual In_C_you_should_use_my_bool_instead() send(Protocol *protocol, String *str);
- virtual In_C_you_should_use_my_bool_instead() eq(const Item *, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- virtual Item_result result_type() const { return REAL_RESULT; }
- virtual Item_result cast_to_int_type() const { return result_type(); }
- virtual enum_field_types string_field_type() const;
- virtual enum_field_types field_type() const;
- virtual enum Type type() const =0;
- virtual enum_monotonicity_info get_monotonicity_info() const
- { return NON_MONOTONIC; }
- virtual longlong val_int_endpoint(In_C_you_should_use_my_bool_instead() left_endp, In_C_you_should_use_my_bool_instead() *incl_endp)
- { assert(0); return 0; }
- virtual double val_real()=0;
- virtual longlong val_int()=0;
- inline ulonglong val_uint() { return (ulonglong) val_int(); }
- virtual String *val_str(String *str)=0;
- virtual my_decimal *val_decimal(my_decimal *decimal_buffer)= 0;
- virtual In_C_you_should_use_my_bool_instead() val_bool();
- virtual String *val_nodeset(String*) { return 0; }
- String *val_string_from_real(String *str);
- String *val_string_from_int(String *str);
- String *val_string_from_decimal(String *str);
- my_decimal *val_decimal_from_real(my_decimal *decimal_value);
- my_decimal *val_decimal_from_int(my_decimal *decimal_value);
- my_decimal *val_decimal_from_string(my_decimal *decimal_value);
- my_decimal *val_decimal_from_date(my_decimal *decimal_value);
- my_decimal *val_decimal_from_time(my_decimal *decimal_value);
- longlong val_int_from_decimal();
- double val_real_from_decimal();
- int save_time_in_field(Field *field);
- int save_date_in_field(Field *field);
- int save_str_value_in_field(Field *field, String *result);
- virtual Field *get_tmp_table_field() { return 0; }
- virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
- virtual const char *full_name() const { return name ? name : "???"; }
- virtual double val_result() { return val_real(); }
- virtual longlong val_int_result() { return val_int(); }
- virtual String *str_result(String* tmp) { return val_str(tmp); }
- virtual my_decimal *val_decimal_result(my_decimal *val)
- { return val_decimal(val); }
- virtual In_C_you_should_use_my_bool_instead() val_bool_result() { return val_bool(); }
- virtual table_map used_tables() const { return (table_map) 0L; }
- virtual table_map not_null_tables() const { return used_tables(); }
- virtual In_C_you_should_use_my_bool_instead() basic_const_item() const { return 0; }
- virtual Item *clone_item() { return 0; }
- virtual cond_result eq_cmp_result() const { return COND_OK; }
- inline uint float_length(uint decimals_par) const
- { return decimals != 31 ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}
- virtual uint decimal_precision() const;
- inline int decimal_int_part() const
- { return my_decimal_int_part(decimal_precision(), decimals); }
- virtual In_C_you_should_use_my_bool_instead() const_item() const { return used_tables() == 0; }
- virtual In_C_you_should_use_my_bool_instead() const_during_execution() const
- { return (used_tables() & ~(((table_map) 1) << (sizeof(table_map)*8-3))) == 0; }
- virtual inline void print(String *str, enum_query_type query_type)
- {
- str->append(full_name());
- }
- void print_item_w_name(String *, enum_query_type query_type);
- virtual void update_used_tables() {}
- virtual void split_sum_func(THD *thd, Item **ref_pointer_array,
- List<Item> &fields) {}
- void split_sum_func2(THD *thd, Item **ref_pointer_array, List<Item> &fields,
- Item **ref, In_C_you_should_use_my_bool_instead() skip_registered);
- virtual In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate);
- virtual In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime);
- virtual In_C_you_should_use_my_bool_instead() get_date_result(MYSQL_TIME *ltime,uint fuzzydate)
- { return get_date(ltime,fuzzydate); }
- virtual In_C_you_should_use_my_bool_instead() is_null() { return 0; }
- virtual void update_null_value () { (void) val_int(); }
- virtual void top_level_item() {}
- virtual void set_result_field(Field *field) {}
- virtual In_C_you_should_use_my_bool_instead() is_result_field() { return 0; }
- virtual In_C_you_should_use_my_bool_instead() is_bool_func() { return 0; }
- virtual void save_in_result_field(In_C_you_should_use_my_bool_instead() no_conversions) {}
- virtual void no_rows_in_result() {}
- virtual Item *copy_or_same(THD *thd) { return this; }
- virtual Item *copy_andor_structure(THD *thd) { return this; }
- virtual Item *real_item() { return this; }
- virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
- static CHARSET_INFO *default_charset();
- virtual CHARSET_INFO *compare_collation() { return NULL; }
- virtual In_C_you_should_use_my_bool_instead() walk(Item_processor processor, In_C_you_should_use_my_bool_instead() walk_subquery, uchar *arg)
- {
- return (this->*processor)(arg);
- }
- virtual Item* transform(Item_transformer transformer, uchar *arg);
- virtual Item* compile(Item_analyzer analyzer, uchar **arg_p,
- Item_transformer transformer, uchar *arg_t)
- {
- if ((this->*analyzer) (arg_p))
- return ((this->*transformer) (arg_t));
- return 0;
- }
- virtual void traverse_cond(Cond_traverser traverser,
- void *arg, traverse_order order)
- {
- (*traverser)(this, arg);
- }
- virtual In_C_you_should_use_my_bool_instead() remove_dependence_processor(uchar * arg) { return 0; }
- virtual In_C_you_should_use_my_bool_instead() remove_fixed(uchar * arg) { fixed= 0; return 0; }
- virtual In_C_you_should_use_my_bool_instead() cleanup_processor(uchar *arg);
- virtual In_C_you_should_use_my_bool_instead() collect_item_field_processor(uchar * arg) { return 0; }
- virtual In_C_you_should_use_my_bool_instead() find_item_in_field_list_processor(uchar *arg) { return 0; }
- virtual In_C_you_should_use_my_bool_instead() change_context_processor(uchar *context) { return 0; }
- virtual In_C_you_should_use_my_bool_instead() reset_query_id_processor(uchar *query_id_arg) { return 0; }
- virtual In_C_you_should_use_my_bool_instead() is_expensive_processor(uchar *arg) { return 0; }
- virtual In_C_you_should_use_my_bool_instead() register_field_in_read_map(uchar *arg) { return 0; }
- virtual In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *bool_arg) { return (1);}
- virtual In_C_you_should_use_my_bool_instead() subst_argument_checker(uchar **arg)
- {
- if (*arg)
- *arg= NULL;
- return (1);
- }
- virtual Item *equal_fields_propagator(uchar * arg) { return this; }
- virtual In_C_you_should_use_my_bool_instead() set_no_const_sub(uchar *arg) { return (0); }
- virtual Item *replace_equal_field(uchar * arg) { return this; }
- virtual Item *this_item() { return this; }
- virtual const Item *this_item() const { return this; }
- virtual Item **this_item_addr(THD *thd, Item **addr_arg) { return addr_arg; }
- virtual uint cols() { return 1; }
- virtual Item* element_index(uint i) { return this; }
- virtual Item** addr(uint i) { return 0; }
- virtual In_C_you_should_use_my_bool_instead() check_cols(uint c);
- virtual In_C_you_should_use_my_bool_instead() null_inside() { return 0; }
- virtual void bring_value() {}
- Field *tmp_table_field_from_field_type(TABLE *table, In_C_you_should_use_my_bool_instead() fixed_length);
- virtual Item_field *filed_for_view_update() { return 0; }
- virtual Item *neg_transformer(THD *thd) { return NULL; }
- virtual Item *update_value_transformer(uchar *select_arg) { return this; }
- virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
- void delete_self()
- {
- cleanup();
- delete this;
- }
- virtual In_C_you_should_use_my_bool_instead() is_splocal() { return 0; }
- virtual Settable_routine_parameter *get_settable_routine_parameter()
- {
- return 0;
- }
- virtual In_C_you_should_use_my_bool_instead() result_as_longlong() { return (0); }
- In_C_you_should_use_my_bool_instead() is_datetime();
- virtual Field::geometry_type get_geometry_type() const
- { return Field::GEOM_GEOMETRY; };
- String *check_well_formed_result(String *str, In_C_you_should_use_my_bool_instead() send_error= 0);
- In_C_you_should_use_my_bool_instead() eq_by_collation(Item *item, In_C_you_should_use_my_bool_instead() binary_cmp, CHARSET_INFO *cs);
-};
-class sp_head;
-class Item_basic_constant :public Item
-{
-public:
- void cleanup()
- {
- if (orig_name)
- name= orig_name;
- }
-};
-class Item_sp_variable :public Item
-{
-protected:
- THD *m_thd;
-public:
- LEX_STRING m_name;
-public:
- sp_head *m_sp;
-public:
- Item_sp_variable(char *sp_var_name_str, uint sp_var_name_length);
-public:
- In_C_you_should_use_my_bool_instead() fix_fields(THD *thd, Item **);
- double val_real();
- longlong val_int();
- String *val_str(String *sp);
- my_decimal *val_decimal(my_decimal *decimal_value);
- In_C_you_should_use_my_bool_instead() is_null();
-public:
- inline void make_field(Send_field *field);
- inline In_C_you_should_use_my_bool_instead() const_item() const;
- inline int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- inline In_C_you_should_use_my_bool_instead() send(Protocol *protocol, String *str);
-};
-inline void Item_sp_variable::make_field(Send_field *field)
-{
- Item *it= this_item();
- if (name)
- it->set_name(name, (uint) strlen(name), system_charset_info);
- else
- it->set_name(m_name.str, m_name.length, system_charset_info);
- it->make_field(field);
-}
-inline In_C_you_should_use_my_bool_instead() Item_sp_variable::const_item() const
-{
- return (1);
-}
-inline int Item_sp_variable::save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions)
-{
- return this_item()->save_in_field(field, no_conversions);
-}
-inline In_C_you_should_use_my_bool_instead() Item_sp_variable::send(Protocol *protocol, String *str)
-{
- return this_item()->send(protocol, str);
-}
-class Item_splocal :public Item_sp_variable,
- private Settable_routine_parameter
-{
- uint m_var_idx;
- Type m_type;
- Item_result m_result_type;
- enum_field_types m_field_type;
-public:
- uint pos_in_query;
- uint len_in_query;
- Item_splocal(const LEX_STRING &sp_var_name, uint sp_var_idx,
- enum_field_types sp_var_type,
- uint pos_in_q= 0, uint len_in_q= 0);
- In_C_you_should_use_my_bool_instead() is_splocal() { return 1; }
- Item *this_item();
- const Item *this_item() const;
- Item **this_item_addr(THD *thd, Item **);
- virtual void print(String *str, enum_query_type query_type);
-public:
- inline const LEX_STRING *my_name() const;
- inline uint get_var_idx() const;
- inline enum Type type() const;
- inline Item_result result_type() const;
- inline enum_field_types field_type() const { return m_field_type; }
-private:
- In_C_you_should_use_my_bool_instead() set_value(THD *thd, sp_rcontext *ctx, Item **it);
-public:
- Settable_routine_parameter *get_settable_routine_parameter()
- {
- return this;
- }
-};
-inline const LEX_STRING *Item_splocal::my_name() const
-{
- return &m_name;
-}
-inline uint Item_splocal::get_var_idx() const
-{
- return m_var_idx;
-}
-inline enum Item::Type Item_splocal::type() const
-{
- return m_type;
-}
-inline Item_result Item_splocal::result_type() const
-{
- return m_result_type;
-}
-class Item_case_expr :public Item_sp_variable
-{
-public:
- Item_case_expr(uint case_expr_id);
-public:
- Item *this_item();
- const Item *this_item() const;
- Item **this_item_addr(THD *thd, Item **);
- inline enum Type type() const;
- inline Item_result result_type() const;
-public:
- virtual void print(String *str, enum_query_type query_type);
-private:
- uint m_case_expr_id;
-};
-inline enum Item::Type Item_case_expr::type() const
-{
- return this_item()->type();
-}
-inline Item_result Item_case_expr::result_type() const
-{
- return this_item()->result_type();
-}
-class Item_name_const : public Item
-{
- Item *value_item;
- Item *name_item;
- In_C_you_should_use_my_bool_instead() valid_args;
-public:
- Item_name_const(Item *name_arg, Item *val);
- In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **);
- enum Type type() const;
- double val_real();
- longlong val_int();
- String *val_str(String *sp);
- my_decimal *val_decimal(my_decimal *);
- In_C_you_should_use_my_bool_instead() is_null();
- virtual void print(String *str, enum_query_type query_type);
- Item_result result_type() const
- {
- return value_item->result_type();
- }
- In_C_you_should_use_my_bool_instead() const_item() const
- {
- return (1);
- }
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions)
- {
- return value_item->save_in_field(field, no_conversions);
- }
- In_C_you_should_use_my_bool_instead() send(Protocol *protocol, String *str)
- {
- return value_item->send(protocol, str);
- }
-};
-In_C_you_should_use_my_bool_instead() agg_item_collations(DTCollation &c, const char *name,
- Item **items, uint nitems, uint flags, int item_sep);
-In_C_you_should_use_my_bool_instead() agg_item_collations_for_comparison(DTCollation &c, const char *name,
- Item **items, uint nitems, uint flags);
-In_C_you_should_use_my_bool_instead() agg_item_charsets(DTCollation &c, const char *name,
- Item **items, uint nitems, uint flags, int item_sep);
-class Item_num: public Item_basic_constant
-{
-public:
- Item_num() {}
- virtual Item_num *neg()= 0;
- Item *safe_charset_converter(CHARSET_INFO *tocs);
- In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) { return (0);}
-};
-class st_select_lex;
-class Item_ident :public Item
-{
-protected:
- const char *orig_db_name;
- const char *orig_table_name;
- const char *orig_field_name;
-public:
- Name_resolution_context *context;
- const char *db_name;
- const char *table_name;
- const char *field_name;
- In_C_you_should_use_my_bool_instead() alias_name_used;
- uint cached_field_index;
- TABLE_LIST *cached_table;
- st_select_lex *depended_from;
- Item_ident(Name_resolution_context *context_arg,
- const char *db_name_arg, const char *table_name_arg,
- const char *field_name_arg);
- Item_ident(THD *thd, Item_ident *item);
- const char *full_name() const;
- void cleanup();
- In_C_you_should_use_my_bool_instead() remove_dependence_processor(uchar * arg);
- virtual void print(String *str, enum_query_type query_type);
- virtual In_C_you_should_use_my_bool_instead() change_context_processor(uchar *cntx)
- { context= (Name_resolution_context *)cntx; return (0); }
- friend In_C_you_should_use_my_bool_instead() insert_fields(THD *thd, Name_resolution_context *context,
- const char *db_name,
- const char *table_name, List_iterator<Item> *it,
- In_C_you_should_use_my_bool_instead() any_privileges);
-};
-class Item_ident_for_show :public Item
-{
-public:
- Field *field;
- const char *db_name;
- const char *table_name;
- Item_ident_for_show(Field *par_field, const char *db_arg,
- const char *table_name_arg)
- :field(par_field), db_name(db_arg), table_name(table_name_arg)
- {}
- enum Type type() const { return FIELD_ITEM; }
- double val_real() { return field->val_real(); }
- longlong val_int() { return field->val_int(); }
- String *val_str(String *str) { return field->val_str(str); }
- my_decimal *val_decimal(my_decimal *dec) { return field->val_decimal(dec); }
- void make_field(Send_field *tmp_field);
-};
-class Item_equal;
-class COND_EQUAL;
-class Item_field :public Item_ident
-{
-protected:
- void set_field(Field *field);
-public:
- Field *field,*result_field;
- Item_equal *item_equal;
- In_C_you_should_use_my_bool_instead() no_const_subst;
- uint have_privileges;
- In_C_you_should_use_my_bool_instead() any_privileges;
- Item_field(Name_resolution_context *context_arg,
- const char *db_arg,const char *table_name_arg,
- const char *field_name_arg);
- Item_field(THD *thd, Item_field *item);
- Item_field(THD *thd, Name_resolution_context *context_arg, Field *field);
- Item_field(Field *field);
- enum Type type() const { return FIELD_ITEM; }
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- double val_real();
- longlong val_int();
- my_decimal *val_decimal(my_decimal *);
- String *val_str(String*);
- double val_result();
- longlong val_int_result();
- String *str_result(String* tmp);
- my_decimal *val_decimal_result(my_decimal *);
- In_C_you_should_use_my_bool_instead() val_bool_result();
- In_C_you_should_use_my_bool_instead() send(Protocol *protocol, String *str_arg);
- void reset_field(Field *f);
- In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **);
- void make_field(Send_field *tmp_field);
- int save_in_field(Field *field,In_C_you_should_use_my_bool_instead() no_conversions);
- void save_org_in_field(Field *field);
- table_map used_tables() const;
- enum Item_result result_type () const
- {
- return field->result_type();
- }
- Item_result cast_to_int_type() const
- {
- return field->cast_to_int_type();
- }
- enum_field_types field_type() const
- {
- return field->type();
- }
- enum_monotonicity_info get_monotonicity_info() const
- {
- return MONOTONIC_STRICT_INCREASING;
- }
- longlong val_int_endpoint(In_C_you_should_use_my_bool_instead() left_endp, In_C_you_should_use_my_bool_instead() *incl_endp);
- Field *get_tmp_table_field() { return result_field; }
- Field *tmp_table_field(TABLE *t_arg) { return result_field; }
- In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate);
- In_C_you_should_use_my_bool_instead() get_date_result(MYSQL_TIME *ltime,uint fuzzydate);
- In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime);
- In_C_you_should_use_my_bool_instead() is_null() { return field->is_null(); }
- void update_null_value();
- Item *get_tmp_table_item(THD *thd);
- In_C_you_should_use_my_bool_instead() collect_item_field_processor(uchar * arg);
- In_C_you_should_use_my_bool_instead() find_item_in_field_list_processor(uchar *arg);
- In_C_you_should_use_my_bool_instead() register_field_in_read_map(uchar *arg);
- In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (0);}
- void cleanup();
- In_C_you_should_use_my_bool_instead() result_as_longlong()
- {
- return field->can_be_compared_as_longlong();
- }
- Item_equal *find_item_equal(COND_EQUAL *cond_equal);
- In_C_you_should_use_my_bool_instead() subst_argument_checker(uchar **arg);
- Item *equal_fields_propagator(uchar *arg);
- In_C_you_should_use_my_bool_instead() set_no_const_sub(uchar *arg);
- Item *replace_equal_field(uchar *arg);
- inline uint32 max_disp_length() { return field->max_display_length(); }
- Item_field *filed_for_view_update() { return this; }
- Item *safe_charset_converter(CHARSET_INFO *tocs);
- int fix_outer_field(THD *thd, Field **field, Item **reference);
- virtual Item *update_value_transformer(uchar *select_arg);
- virtual void print(String *str, enum_query_type query_type);
- Field::geometry_type get_geometry_type() const
- {
- assert(field_type() == MYSQL_TYPE_GEOMETRY);
- return field->get_geometry_type();
- }
- friend class Item_default_value;
- friend class Item_insert_value;
- friend class st_select_lex_unit;
-};
-class Item_null :public Item_basic_constant
-{
-public:
- Item_null(char *name_par=0)
- {
- maybe_null= null_value= (1);
- max_length= 0;
- name= name_par ? name_par : (char*) "NULL";
- fixed= 1;
- collation.set(&my_charset_bin, DERIVATION_IGNORABLE);
- }
- enum Type type() const { return NULL_ITEM; }
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- double val_real();
- longlong val_int();
- String *val_str(String *str);
- my_decimal *val_decimal(my_decimal *);
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- int save_safe_in_field(Field *field);
- In_C_you_should_use_my_bool_instead() send(Protocol *protocol, String *str);
- enum Item_result result_type () const { return STRING_RESULT; }
- enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
- In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; }
- Item *clone_item() { return new Item_null(name); }
- In_C_you_should_use_my_bool_instead() is_null() { return 1; }
- virtual inline void print(String *str, enum_query_type query_type)
- {
- str->append(("NULL"), ((size_t) (sizeof("NULL") - 1)));
- }
- Item *safe_charset_converter(CHARSET_INFO *tocs);
- In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (0);}
-};
-class Item_null_result :public Item_null
-{
-public:
- Field *result_field;
- Item_null_result() : Item_null(), result_field(0) {}
- In_C_you_should_use_my_bool_instead() is_result_field() { return result_field != 0; }
- void save_in_result_field(In_C_you_should_use_my_bool_instead() no_conversions)
- {
- save_in_field(result_field, no_conversions);
- }
- In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (1);}
-};
-class Item_param :public Item
-{
- char cnvbuf[(255*3 +1)];
- String cnvstr;
- Item *cnvitem;
-public:
- enum enum_item_param_state
- {
- NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE,
- STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE,
- DECIMAL_VALUE
- } state;
- String str_value_ptr;
- my_decimal decimal_value;
- union
- {
- longlong integer;
- double real;
- struct CONVERSION_INFO
- {
- CHARSET_INFO *character_set_client;
- CHARSET_INFO *character_set_of_placeholder;
- CHARSET_INFO *final_character_set_of_str_value;
- } cs_info;
- MYSQL_TIME time;
- } value;
- enum Item_result item_result_type;
- enum Type item_type;
- enum enum_field_types param_type;
- uint pos_in_query;
- Item_param(uint pos_in_query_arg);
- enum Item_result result_type () const { return item_result_type; }
- enum Type type() const { return item_type; }
- enum_field_types field_type() const { return param_type; }
- double val_real();
- longlong val_int();
- my_decimal *val_decimal(my_decimal*);
- String *val_str(String*);
- In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *tm);
- In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *tm, uint fuzzydate);
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- void set_null();
- void set_int(longlong i, uint32 max_length_arg);
- void set_double(double i);
- void set_decimal(const char *str, ulong length);
- In_C_you_should_use_my_bool_instead() set_str(const char *str, ulong length);
- In_C_you_should_use_my_bool_instead() set_longdata(const char *str, ulong length);
- void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg);
- In_C_you_should_use_my_bool_instead() set_from_user_var(THD *thd, const user_var_entry *entry);
- void reset();
- void (*set_param_func)(Item_param *param, uchar **pos, ulong len);
- const String *query_val_str(String *str) const;
- In_C_you_should_use_my_bool_instead() convert_str_value(THD *thd);
- virtual table_map used_tables() const
- { return state != NO_VALUE ? (table_map)0 : (((table_map) 1) << (sizeof(table_map)*8-3)); }
- virtual void print(String *str, enum_query_type query_type);
- In_C_you_should_use_my_bool_instead() is_null()
- { assert(state != NO_VALUE); return state == NULL_VALUE; }
- In_C_you_should_use_my_bool_instead() basic_const_item() const;
- Item *safe_charset_converter(CHARSET_INFO *tocs);
- Item *clone_item();
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- In_C_you_should_use_my_bool_instead() limit_clause_param;
- void set_param_type_and_swap_value(Item_param *from);
-};
-class Item_int :public Item_num
-{
-public:
- longlong value;
- Item_int(int32 i,uint length= 11)
- :value((longlong) i)
- { max_length=length; fixed= 1; }
- Item_int(longlong i,uint length= 21)
- :value(i)
- { max_length=length; fixed= 1; }
- Item_int(ulonglong i, uint length= 21)
- :value((longlong)i)
- { max_length=length; fixed= 1; unsigned_flag= 1; }
- Item_int(const char *str_arg,longlong i,uint length) :value(i)
- { max_length=length; name=(char*) str_arg; fixed= 1; }
- Item_int(const char *str_arg, uint length=64);
- enum Type type() const { return INT_ITEM; }
- enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
- longlong val_int() { assert(fixed == 1); return value; }
- double val_real() { assert(fixed == 1); return (double) value; }
- my_decimal *val_decimal(my_decimal *);
- String *val_str(String*);
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; }
- Item *clone_item() { return new Item_int(name,value,max_length); }
- virtual void print(String *str, enum_query_type query_type);
- Item_num *neg() { value= -value; return this; }
- uint decimal_precision() const
- { return (uint)(max_length - ((value < 0) ? 1 : 0)); }
- In_C_you_should_use_my_bool_instead() eq(const Item *, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *bool_arg) { return (0);}
-};
-class Item_uint :public Item_int
-{
-public:
- Item_uint(const char *str_arg, uint length);
- Item_uint(ulonglong i) :Item_int((ulonglong) i, 10) {}
- Item_uint(const char *str_arg, longlong i, uint length);
- double val_real()
- { assert(fixed == 1); return ((double) (ulonglong) ((ulonglong)value)); }
- String *val_str(String*);
- Item *clone_item() { return new Item_uint(name, value, max_length); }
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- virtual void print(String *str, enum_query_type query_type);
- Item_num *neg ();
- uint decimal_precision() const { return max_length; }
- In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *bool_arg) { return (0);}
-};
-class Item_decimal :public Item_num
-{
-protected:
- my_decimal decimal_value;
-public:
- Item_decimal(const char *str_arg, uint length, CHARSET_INFO *charset);
- Item_decimal(const char *str, const my_decimal *val_arg,
- uint decimal_par, uint length);
- Item_decimal(my_decimal *value_par);
- Item_decimal(longlong val, In_C_you_should_use_my_bool_instead() unsig);
- Item_decimal(double val, int precision, int scale);
- Item_decimal(const uchar *bin, int precision, int scale);
- enum Type type() const { return DECIMAL_ITEM; }
- enum Item_result result_type () const { return DECIMAL_RESULT; }
- enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
- longlong val_int();
- double val_real();
- String *val_str(String*);
- my_decimal *val_decimal(my_decimal *val) { return &decimal_value; }
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; }
- Item *clone_item()
- {
- return new Item_decimal(name, &decimal_value, decimals, max_length);
- }
- virtual void print(String *str, enum_query_type query_type);
- Item_num *neg()
- {
- my_decimal_neg(&decimal_value);
- unsigned_flag= !decimal_value.sign();
- return this;
- }
- uint decimal_precision() const { return decimal_value.precision(); }
- In_C_you_should_use_my_bool_instead() eq(const Item *, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- void set_decimal_value(my_decimal *value_par);
- In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *bool_arg) { return (0);}
-};
-class Item_float :public Item_num
-{
- char *presentation;
-public:
- double value;
- Item_float(const char *str_arg, uint length);
- Item_float(const char *str,double val_arg,uint decimal_par,uint length)
- :value(val_arg)
- {
- presentation= name=(char*) str;
- decimals=(uint8) decimal_par;
- max_length=length;
- fixed= 1;
- }
- Item_float(double value_par, uint decimal_par) :presentation(0), value(value_par)
- {
- decimals= (uint8) decimal_par;
- fixed= 1;
- }
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- enum Type type() const { return REAL_ITEM; }
- enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
- double val_real() { assert(fixed == 1); return value; }
- longlong val_int()
- {
- assert(fixed == 1);
- if (value <= (double) ((long long) 0x8000000000000000LL))
- {
- return ((long long) 0x8000000000000000LL);
- }
- else if (value >= (double) (ulonglong) ((long long) 0x7FFFFFFFFFFFFFFFLL))
- {
- return ((long long) 0x7FFFFFFFFFFFFFFFLL);
- }
- return (longlong) rint(value);
- }
- String *val_str(String*);
- my_decimal *val_decimal(my_decimal *);
- In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; }
- Item *clone_item()
- { return new Item_float(name, value, decimals, max_length); }
- Item_num *neg() { value= -value; return this; }
- virtual void print(String *str, enum_query_type query_type);
- In_C_you_should_use_my_bool_instead() eq(const Item *, In_C_you_should_use_my_bool_instead() binary_cmp) const;
-};
-class Item_static_float_func :public Item_float
-{
- const char *func_name;
-public:
- Item_static_float_func(const char *str, double val_arg, uint decimal_par,
- uint length)
- :Item_float((char *) 0, val_arg, decimal_par, length), func_name(str)
- {}
- virtual inline void print(String *str, enum_query_type query_type)
- {
- str->append(func_name);
- }
- Item *safe_charset_converter(CHARSET_INFO *tocs);
-};
-class Item_string :public Item_basic_constant
-{
-public:
- Item_string(const char *str,uint length,
- CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE,
- uint repertoire= 3)
- : m_cs_specified((0))
- {
- str_value.set_or_copy_aligned(str, length, cs);
- collation.set(cs, dv, repertoire);
- max_length= str_value.numchars()*cs->mbmaxlen;
- set_name(str, length, cs);
- decimals=31;
- fixed= 1;
- }
- Item_string(CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
- : m_cs_specified((0))
- {
- collation.set(cs, dv);
- max_length= 0;
- set_name(NULL, 0, cs);
- decimals= 31;
- fixed= 1;
- }
- Item_string(const char *name_par, const char *str, uint length,
- CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE,
- uint repertoire= 3)
- : m_cs_specified((0))
- {
- str_value.set_or_copy_aligned(str, length, cs);
- collation.set(cs, dv, repertoire);
- max_length= str_value.numchars()*cs->mbmaxlen;
- set_name(name_par, 0, cs);
- decimals=31;
- fixed= 1;
- }
- void set_str_with_copy(const char *str_arg, uint length_arg)
- {
- str_value.copy(str_arg, length_arg, collation.collation);
- max_length= str_value.numchars() * collation.collation->mbmaxlen;
- }
- void set_repertoire_from_value()
- {
- collation.repertoire= my_string_repertoire(str_value.charset(),
- str_value.ptr(),
- str_value.length());
- }
- enum Type type() const { return STRING_ITEM; }
- double val_real();
- longlong val_int();
- String *val_str(String*)
- {
- assert(fixed == 1);
- return (String*) &str_value;
- }
- my_decimal *val_decimal(my_decimal *);
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- enum Item_result result_type () const { return STRING_RESULT; }
- enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
- In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; }
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- Item *clone_item()
- {
- return new Item_string(name, str_value.ptr(),
- str_value.length(), collation.collation);
- }
- Item *safe_charset_converter(CHARSET_INFO *tocs);
- inline void append(char *str, uint length)
- {
- str_value.append(str, length);
- max_length= str_value.numchars() * collation.collation->mbmaxlen;
- }
- virtual void print(String *str, enum_query_type query_type);
- In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (0);}
- inline In_C_you_should_use_my_bool_instead() is_cs_specified() const
- {
- return m_cs_specified;
- }
- inline void set_cs_specified(In_C_you_should_use_my_bool_instead() cs_specified)
- {
- m_cs_specified= cs_specified;
- }
-private:
- In_C_you_should_use_my_bool_instead() m_cs_specified;
-};
-class Item_static_string_func :public Item_string
-{
- const char *func_name;
-public:
- Item_static_string_func(const char *name_par, const char *str, uint length,
- CHARSET_INFO *cs,
- Derivation dv= DERIVATION_COERCIBLE)
- :Item_string((char *) 0, str, length, cs, dv), func_name(name_par)
- {}
- Item *safe_charset_converter(CHARSET_INFO *tocs);
- virtual inline void print(String *str, enum_query_type query_type)
- {
- str->append(func_name);
- }
- In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (1);}
-};
-class Item_partition_func_safe_string: public Item_string
-{
-public:
- Item_partition_func_safe_string(const char *name, uint length,
- CHARSET_INFO *cs= NULL):
- Item_string(name, length, cs)
- {}
-};
-class Item_return_date_time :public Item_partition_func_safe_string
-{
- enum_field_types date_time_field_type;
-public:
- Item_return_date_time(const char *name_arg, enum_field_types field_type_arg)
- :Item_partition_func_safe_string(name_arg, 0, &my_charset_bin),
- date_time_field_type(field_type_arg)
- { }
- enum_field_types field_type() const { return date_time_field_type; }
-};
-class Item_blob :public Item_partition_func_safe_string
-{
-public:
- Item_blob(const char *name, uint length) :
- Item_partition_func_safe_string(name, length, &my_charset_bin)
- { max_length= length; }
- enum Type type() const { return TYPE_HOLDER; }
- enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
-};
-class Item_empty_string :public Item_partition_func_safe_string
-{
-public:
- Item_empty_string(const char *header,uint length, CHARSET_INFO *cs= NULL) :
- Item_partition_func_safe_string("",0, cs ? cs : &my_charset_utf8_general_ci)
- { name=(char*) header; max_length= cs ? length * cs->mbmaxlen : length; }
- void make_field(Send_field *field);
-};
-class Item_return_int :public Item_int
-{
- enum_field_types int_field_type;
-public:
- Item_return_int(const char *name_arg, uint length,
- enum_field_types field_type_arg, longlong value= 0)
- :Item_int(name_arg, value, length), int_field_type(field_type_arg)
- {
- unsigned_flag=1;
- }
- enum_field_types field_type() const { return int_field_type; }
-};
-class Item_hex_string: public Item_basic_constant
-{
-public:
- Item_hex_string() {}
- Item_hex_string(const char *str,uint str_length);
- enum Type type() const { return VARBIN_ITEM; }
- double val_real()
- {
- assert(fixed == 1);
- return (double) (ulonglong) Item_hex_string::val_int();
- }
- longlong val_int();
- In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; }
- String *val_str(String*) { assert(fixed == 1); return &str_value; }
- my_decimal *val_decimal(my_decimal *);
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- enum Item_result result_type () const { return STRING_RESULT; }
- enum Item_result cast_to_int_type() const { return INT_RESULT; }
- enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
- virtual void print(String *str, enum_query_type query_type);
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
- In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (0);}
-};
-class Item_bin_string: public Item_hex_string
-{
-public:
- Item_bin_string(const char *str,uint str_length);
-};
-class Item_result_field :public Item
-{
-public:
- Field *result_field;
- Item_result_field() :result_field(0) {}
- Item_result_field(THD *thd, Item_result_field *item):
- Item(thd, item), result_field(item->result_field)
- {}
- ~Item_result_field() {}
- Field *get_tmp_table_field() { return result_field; }
- Field *tmp_table_field(TABLE *t_arg) { return result_field; }
- table_map used_tables() const { return 1; }
- virtual void fix_length_and_dec()=0;
- void set_result_field(Field *field) { result_field= field; }
- In_C_you_should_use_my_bool_instead() is_result_field() { return 1; }
- void save_in_result_field(In_C_you_should_use_my_bool_instead() no_conversions)
- {
- save_in_field(result_field, no_conversions);
- }
- void cleanup();
-};
-class Item_ref :public Item_ident
-{
-protected:
- void set_properties();
-public:
- enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF };
- Field *result_field;
- Item **ref;
- Item_ref(Name_resolution_context *context_arg,
- const char *db_arg, const char *table_name_arg,
- const char *field_name_arg)
- :Item_ident(context_arg, db_arg, table_name_arg, field_name_arg),
- result_field(0), ref(0) {}
- Item_ref(Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg, const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() alias_name_used_arg= (0));
- Item_ref(THD *thd, Item_ref *item)
- :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {}
- enum Type type() const { return REF_ITEM; }
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const
- {
- Item *it= ((Item *) item)->real_item();
- return ref && (*ref)->eq(it, binary_cmp);
- }
- double val_real();
- longlong val_int();
- my_decimal *val_decimal(my_decimal *);
- In_C_you_should_use_my_bool_instead() val_bool();
- String *val_str(String* tmp);
- In_C_you_should_use_my_bool_instead() is_null();
- In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate);
- double val_result();
- longlong val_int_result();
- String *str_result(String* tmp);
- my_decimal *val_decimal_result(my_decimal *);
- In_C_you_should_use_my_bool_instead() val_bool_result();
- In_C_you_should_use_my_bool_instead() send(Protocol *prot, String *tmp);
- void make_field(Send_field *field);
- In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **);
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
- void save_org_in_field(Field *field);
- enum Item_result result_type () const { return (*ref)->result_type(); }
- enum_field_types field_type() const { return (*ref)->field_type(); }
- Field *get_tmp_table_field()
- { return result_field ? result_field : (*ref)->get_tmp_table_field(); }
- Item *get_tmp_table_item(THD *thd);
- table_map used_tables() const
- {
- return depended_from ? (((table_map) 1) << (sizeof(table_map)*8-2)) : (*ref)->used_tables();
- }
- void update_used_tables()
- {
- if (!depended_from)
- (*ref)->update_used_tables();
- }
- table_map not_null_tables() const { return (*ref)->not_null_tables(); }
- void set_result_field(Field *field) { result_field= field; }
- In_C_you_should_use_my_bool_instead() is_result_field() { return 1; }
- void save_in_result_field(In_C_you_should_use_my_bool_instead() no_conversions)
- {
- (*ref)->save_in_field(result_field, no_conversions);
- }
- Item *real_item()
- {
- return ref ? (*ref)->real_item() : this;
- }
- In_C_you_should_use_my_bool_instead() walk(Item_processor processor, In_C_you_should_use_my_bool_instead() walk_subquery, uchar *arg)
- { return (*ref)->walk(processor, walk_subquery, arg); }
- virtual void print(String *str, enum_query_type query_type);
- In_C_you_should_use_my_bool_instead() result_as_longlong()
- {
- return (*ref)->result_as_longlong();
- }
- void cleanup();
- Item_field *filed_for_view_update()
- { return (*ref)->filed_for_view_update(); }
- virtual Ref_Type ref_type() { return REF; }
- uint cols()
- {
- return ref && result_type() == ROW_RESULT ? (*ref)->cols() : 1;
- }
- Item* element_index(uint i)
- {
- return ref && result_type() == ROW_RESULT ? (*ref)->element_index(i) : this;
- }
- Item** addr(uint i)
- {
- return ref && result_type() == ROW_RESULT ? (*ref)->addr(i) : 0;
- }
- In_C_you_should_use_my_bool_instead() check_cols(uint c)
- {
- return ref && result_type() == ROW_RESULT ? (*ref)->check_cols(c)
- : Item::check_cols(c);
- }
- In_C_you_should_use_my_bool_instead() null_inside()
- {
- return ref && result_type() == ROW_RESULT ? (*ref)->null_inside() : 0;
- }
- void bring_value()
- {
- if (ref && result_type() == ROW_RESULT)
- (*ref)->bring_value();
- }
-};
-class Item_direct_ref :public Item_ref
-{
-public:
- Item_direct_ref(Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg,
- const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() alias_name_used_arg= (0))
- :Item_ref(context_arg, item, table_name_arg,
- field_name_arg, alias_name_used_arg)
- {}
- Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
- double val_real();
- longlong val_int();
- String *val_str(String* tmp);
- my_decimal *val_decimal(my_decimal *);
- In_C_you_should_use_my_bool_instead() val_bool();
- In_C_you_should_use_my_bool_instead() is_null();
- In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate);
- virtual Ref_Type ref_type() { return DIRECT_REF; }
-};
-class Item_direct_view_ref :public Item_direct_ref
-{
-public:
- Item_direct_view_ref(Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg,
- const char *field_name_arg)
- :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg) {}
- Item_direct_view_ref(THD *thd, Item_direct_ref *item)
- :Item_direct_ref(thd, item) {}
- In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **);
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- Item *get_tmp_table_item(THD *thd)
- {
- Item *item= Item_ref::get_tmp_table_item(thd);
- item->name= name;
- return item;
- }
- virtual Ref_Type ref_type() { return VIEW_REF; }
-};
-class Item_sum;
-class Item_outer_ref :public Item_direct_ref
-{
-public:
- Item *outer_ref;
- Item_sum *in_sum_func;
- In_C_you_should_use_my_bool_instead() found_in_select_list;
- Item_outer_ref(Name_resolution_context *context_arg,
- Item_field *outer_field_arg)
- :Item_direct_ref(context_arg, 0, outer_field_arg->table_name,
- outer_field_arg->field_name),
- outer_ref(outer_field_arg), in_sum_func(0),
- found_in_select_list(0)
- {
- ref= &outer_ref;
- set_properties();
- fixed= 0;
- }
- Item_outer_ref(Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg, const char *field_name_arg,
- In_C_you_should_use_my_bool_instead() alias_name_used_arg)
- :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg,
- alias_name_used_arg),
- outer_ref(0), in_sum_func(0), found_in_select_list(1)
- {}
- void save_in_result_field(In_C_you_should_use_my_bool_instead() no_conversions)
- {
- outer_ref->save_org_in_field(result_field);
- }
- In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **);
- table_map used_tables() const
- {
- return (*ref)->const_item() ? 0 : (((table_map) 1) << (sizeof(table_map)*8-2));
- }
- virtual Ref_Type ref_type() { return OUTER_REF; }
-};
-class Item_in_subselect;
-class Item_ref_null_helper: public Item_ref
-{
-protected:
- Item_in_subselect* owner;
-public:
- Item_ref_null_helper(Name_resolution_context *context_arg,
- Item_in_subselect* master, Item **item,
- const char *table_name_arg, const char *field_name_arg)
- :Item_ref(context_arg, item, table_name_arg, field_name_arg),
- owner(master) {}
- double val_real();
- longlong val_int();
- String* val_str(String* s);
- my_decimal *val_decimal(my_decimal *);
- In_C_you_should_use_my_bool_instead() val_bool();
- In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime, uint fuzzydate);
- virtual void print(String *str, enum_query_type query_type);
- table_map used_tables() const
- {
- return (depended_from ?
- (((table_map) 1) << (sizeof(table_map)*8-2)) :
- (*ref)->used_tables() | (((table_map) 1) << (sizeof(table_map)*8-1)));
- }
-};
-class Item_int_with_ref :public Item_int
-{
- Item *ref;
-public:
- Item_int_with_ref(longlong i, Item *ref_arg, my_bool unsigned_arg) :
- Item_int(i), ref(ref_arg)
- {
- unsigned_flag= unsigned_arg;
- }
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions)
- {
- return ref->save_in_field(field, no_conversions);
- }
- Item *clone_item();
- virtual Item *real_item() { return ref; }
-};
-class Item_copy_string :public Item
-{
- enum enum_field_types cached_field_type;
-public:
- Item *item;
- Item_copy_string(Item *i) :item(i)
- {
- null_value=maybe_null=item->maybe_null;
- decimals=item->decimals;
- max_length=item->max_length;
- name=item->name;
- cached_field_type= item->field_type();
- }
- enum Type type() const { return COPY_STR_ITEM; }
- enum Item_result result_type () const { return STRING_RESULT; }
- enum_field_types field_type() const { return cached_field_type; }
- double val_real()
- {
- int err_not_used;
- char *end_not_used;
- return (null_value ? 0.0 :
- ((str_value.charset())->cset->strntod((str_value.charset()),((char*) str_value.ptr()),(str_value.length()),(&end_not_used),(&err_not_used))));
- }
- longlong val_int()
- {
- int err;
- return null_value ? 0LL : ((str_value.charset())->cset->strntoll((str_value.charset()),(str_value.ptr()),(str_value.length()),(10),((char**) 0),(&err)));
- }
- String *val_str(String*);
- my_decimal *val_decimal(my_decimal *);
- void make_field(Send_field *field) { item->make_field(field); }
- void copy();
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions)
- {
- return save_str_value_in_field(field, &str_value);
- }
- table_map used_tables() const { return (table_map) 1L; }
- In_C_you_should_use_my_bool_instead() const_item() const { return 0; }
- In_C_you_should_use_my_bool_instead() is_null() { return null_value; }
-};
-class Cached_item :public Sql_alloc
-{
-public:
- my_bool null_value;
- Cached_item() :null_value(0) {}
- virtual In_C_you_should_use_my_bool_instead() cmp(void)=0;
- virtual ~Cached_item();
-};
-class Cached_item_str :public Cached_item
-{
- Item *item;
- String value,tmp_value;
-public:
- Cached_item_str(THD *thd, Item *arg);
- In_C_you_should_use_my_bool_instead() cmp(void);
- ~Cached_item_str();
-};
-class Cached_item_real :public Cached_item
-{
- Item *item;
- double value;
-public:
- Cached_item_real(Item *item_par) :item(item_par),value(0.0) {}
- In_C_you_should_use_my_bool_instead() cmp(void);
-};
-class Cached_item_int :public Cached_item
-{
- Item *item;
- longlong value;
-public:
- Cached_item_int(Item *item_par) :item(item_par),value(0) {}
- In_C_you_should_use_my_bool_instead() cmp(void);
-};
-class Cached_item_decimal :public Cached_item
-{
- Item *item;
- my_decimal value;
-public:
- Cached_item_decimal(Item *item_par);
- In_C_you_should_use_my_bool_instead() cmp(void);
-};
-class Cached_item_field :public Cached_item
-{
- uchar *buff;
- Field *field;
- uint length;
-public:
- Cached_item_field(Item_field *item)
- {
- field= item->field;
- buff= (uchar*) sql_calloc(length=field->pack_length());
- }
- In_C_you_should_use_my_bool_instead() cmp(void);
-};
-class Item_default_value : public Item_field
-{
-public:
- Item *arg;
- Item_default_value(Name_resolution_context *context_arg)
- :Item_field(context_arg, (const char *)NULL, (const char *)NULL,
- (const char *)NULL),
- arg(NULL) {}
- Item_default_value(Name_resolution_context *context_arg, Item *a)
- :Item_field(context_arg, (const char *)NULL, (const char *)NULL,
- (const char *)NULL),
- arg(a) {}
- enum Type type() const { return DEFAULT_VALUE_ITEM; }
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **);
- virtual void print(String *str, enum_query_type query_type);
- int save_in_field(Field *field_arg, In_C_you_should_use_my_bool_instead() no_conversions);
- table_map used_tables() const { return (table_map)0L; }
- In_C_you_should_use_my_bool_instead() walk(Item_processor processor, In_C_you_should_use_my_bool_instead() walk_subquery, uchar *args)
- {
- return arg->walk(processor, walk_subquery, args) ||
- (this->*processor)(args);
- }
- Item *transform(Item_transformer transformer, uchar *args);
-};
-class Item_insert_value : public Item_field
-{
-public:
- Item *arg;
- Item_insert_value(Name_resolution_context *context_arg, Item *a)
- :Item_field(context_arg, (const char *)NULL, (const char *)NULL,
- (const char *)NULL),
- arg(a) {}
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **);
- virtual void print(String *str, enum_query_type query_type);
- int save_in_field(Field *field_arg, In_C_you_should_use_my_bool_instead() no_conversions)
- {
- return Item_field::save_in_field(field_arg, no_conversions);
- }
- table_map used_tables() const { return (((table_map) 1) << (sizeof(table_map)*8-1)); }
- In_C_you_should_use_my_bool_instead() walk(Item_processor processor, In_C_you_should_use_my_bool_instead() walk_subquery, uchar *args)
- {
- return arg->walk(processor, walk_subquery, args) ||
- (this->*processor)(args);
- }
-};
-enum trg_action_time_type
-{
- TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX
-};
-class Table_triggers_list;
-class Item_trigger_field : public Item_field,
- private Settable_routine_parameter
-{
-public:
- enum row_version_type {OLD_ROW, NEW_ROW};
- row_version_type row_version;
- Item_trigger_field *next_trg_field;
- uint field_idx;
- Table_triggers_list *triggers;
- Item_trigger_field(Name_resolution_context *context_arg,
- row_version_type row_ver_arg,
- const char *field_name_arg,
- ulong priv, const In_C_you_should_use_my_bool_instead() ro)
- :Item_field(context_arg,
- (const char *)NULL, (const char *)NULL, field_name_arg),
- row_version(row_ver_arg), field_idx((uint)-1), original_privilege(priv),
- want_privilege(priv), table_grants(NULL), read_only (ro)
- {}
- void setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info);
- enum Type type() const { return TRIGGER_FIELD_ITEM; }
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const;
- In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **);
- virtual void print(String *str, enum_query_type query_type);
- table_map used_tables() const { return (table_map)0L; }
- Field *get_tmp_table_field() { return 0; }
- Item *copy_or_same(THD *thd) { return this; }
- Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
- void cleanup();
-private:
- void set_required_privilege(In_C_you_should_use_my_bool_instead() rw);
- In_C_you_should_use_my_bool_instead() set_value(THD *thd, sp_rcontext *ctx, Item **it);
-public:
- Settable_routine_parameter *get_settable_routine_parameter()
- {
- return (read_only ? 0 : this);
- }
- In_C_you_should_use_my_bool_instead() set_value(THD *thd, Item **it)
- {
- return set_value(thd, NULL, it);
- }
-private:
- ulong original_privilege;
- ulong want_privilege;
- GRANT_INFO *table_grants;
- In_C_you_should_use_my_bool_instead() read_only;
-};
-class Item_cache: public Item_basic_constant
-{
-protected:
- Item *example;
- table_map used_table_map;
- Field *cached_field;
- enum enum_field_types cached_field_type;
-public:
- Item_cache():
- example(0), used_table_map(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING)
- {
- fixed= 1;
- null_value= 1;
- }
- Item_cache(enum_field_types field_type_arg):
- example(0), used_table_map(0), cached_field(0), cached_field_type(field_type_arg)
- {
- fixed= 1;
- null_value= 1;
- }
- void set_used_tables(table_map map) { used_table_map= map; }
- virtual In_C_you_should_use_my_bool_instead() allocate(uint i) { return 0; }
- virtual In_C_you_should_use_my_bool_instead() setup(Item *item)
- {
- example= item;
- max_length= item->max_length;
- decimals= item->decimals;
- collation.set(item->collation);
- unsigned_flag= item->unsigned_flag;
- if (item->type() == FIELD_ITEM)
- cached_field= ((Item_field *)item)->field;
- return 0;
- };
- virtual void store(Item *)= 0;
- enum Type type() const { return CACHE_ITEM; }
- enum_field_types field_type() const { return cached_field_type; }
- static Item_cache* get_cache(const Item *item);
- table_map used_tables() const { return used_table_map; }
- virtual void keep_array() {}
- virtual void print(String *str, enum_query_type query_type);
- In_C_you_should_use_my_bool_instead() eq_def(Field *field)
- {
- return cached_field ? cached_field->eq_def (field) : (0);
- }
- In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const
- {
- return this == item;
- }
-};
-class Item_cache_int: public Item_cache
-{
-protected:
- longlong value;
-public:
- Item_cache_int(): Item_cache(), value(0) {}
- Item_cache_int(enum_field_types field_type_arg):
- Item_cache(field_type_arg), value(0) {}
- void store(Item *item);
- void store(Item *item, longlong val_arg);
- double val_real() { assert(fixed == 1); return (double) value; }
- longlong val_int() { assert(fixed == 1); return value; }
- String* val_str(String *str);
- my_decimal *val_decimal(my_decimal *);
- enum Item_result result_type() const { return INT_RESULT; }
- In_C_you_should_use_my_bool_instead() result_as_longlong() { return (1); }
-};
-class Item_cache_real: public Item_cache
-{
- double value;
-public:
- Item_cache_real(): Item_cache(), value(0) {}
- void store(Item *item);
- double val_real() { assert(fixed == 1); return value; }
- longlong val_int();
- String* val_str(String *str);
- my_decimal *val_decimal(my_decimal *);
- enum Item_result result_type() const { return REAL_RESULT; }
-};
-class Item_cache_decimal: public Item_cache
-{
-protected:
- my_decimal decimal_value;
-public:
- Item_cache_decimal(): Item_cache() {}
- void store(Item *item);
- double val_real();
- longlong val_int();
- String* val_str(String *str);
- my_decimal *val_decimal(my_decimal *);
- enum Item_result result_type() const { return DECIMAL_RESULT; }
-};
-class Item_cache_str: public Item_cache
-{
- char buffer[80];
- String *value, value_buff;
- In_C_you_should_use_my_bool_instead() is_varbinary;
-public:
- Item_cache_str(const Item *item) :
- Item_cache(), value(0),
- is_varbinary(item->type() == FIELD_ITEM &&
- ((const Item_field *) item)->field->type() ==
- MYSQL_TYPE_VARCHAR &&
- !((const Item_field *) item)->field->has_charset())
- {}
- void store(Item *item);
- double val_real();
- longlong val_int();
- String* val_str(String *) { assert(fixed == 1); return value; }
- my_decimal *val_decimal(my_decimal *);
- enum Item_result result_type() const { return STRING_RESULT; }
- CHARSET_INFO *charset() const { return value->charset(); };
- int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions);
-};
-class Item_cache_row: public Item_cache
-{
- Item_cache **values;
- uint item_count;
- In_C_you_should_use_my_bool_instead() save_array;
-public:
- Item_cache_row()
- :Item_cache(), values(0), item_count(2), save_array(0) {}
- In_C_you_should_use_my_bool_instead() allocate(uint num);
- In_C_you_should_use_my_bool_instead() setup(Item *item);
- void store(Item *item);
- void illegal_method_call(const char *);
- void make_field(Send_field *)
- {
- illegal_method_call((const char*)"make_field");
- };
- double val_real()
- {
- illegal_method_call((const char*)"val");
- return 0;
- };
- longlong val_int()
- {
- illegal_method_call((const char*)"val_int");
- return 0;
- };
- String *val_str(String *)
- {
- illegal_method_call((const char*)"val_str");
- return 0;
- };
- my_decimal *val_decimal(my_decimal *val)
- {
- illegal_method_call((const char*)"val_decimal");
- return 0;
- };
- enum Item_result result_type() const { return ROW_RESULT; }
- uint cols() { return item_count; }
- Item *element_index(uint i) { return values[i]; }
- Item **addr(uint i) { return (Item **) (values + i); }
- In_C_you_should_use_my_bool_instead() check_cols(uint c);
- In_C_you_should_use_my_bool_instead() null_inside();
- void bring_value();
- void keep_array() { save_array= 1; }
- void cleanup()
- {
- const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("Item_cache_row::cleanup","./sql/item.h",2898,&_db_func_,&_db_file_,&_db_level_, &_db_framep_);
- Item_cache::cleanup();
- if (save_array)
- bzero(values, item_count*sizeof(Item**));
- else
- values= 0;
- do {_db_return_ (2904, &_db_func_, &_db_file_, &_db_level_); return;} while(0);
- }
-};
-class Item_type_holder: public Item
-{
-protected:
- TYPELIB *enum_set_typelib;
- enum_field_types fld_type;
- Field::geometry_type geometry_type;
- void get_full_info(Item *item);
- int prev_decimal_int_part;
-public:
- Item_type_holder(THD*, Item*);
- Item_result result_type() const;
- enum_field_types field_type() const { return fld_type; };
- enum Type type() const { return TYPE_HOLDER; }
- double val_real();
- longlong val_int();
- my_decimal *val_decimal(my_decimal *);
- String *val_str(String*);
- In_C_you_should_use_my_bool_instead() join_types(THD *thd, Item *);
- Field *make_field_by_type(TABLE *table);
- static uint32 display_length(Item *item);
- static enum_field_types get_real_type(Item *);
- Field::geometry_type get_geometry_type() const { return geometry_type; };
-};
-class st_select_lex;
-void mark_select_range_as_dependent(THD *thd,
- st_select_lex *last_select,
- st_select_lex *current_sel,
- Field *found_field, Item *found_item,
- Item_ident *resolved_item);
-extern Cached_item *new_Cached_item(THD *thd, Item *item);
-extern Item_result item_cmp_type(Item_result a,Item_result b);
-extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item);
-extern In_C_you_should_use_my_bool_instead() field_is_equal_to_item(Field *field,Item *item);
-extern my_decimal decimal_zero;
-void free_items(Item *item);
-void cleanup_items(Item *item);
-class THD;
-void close_thread_tables(THD *thd);
-In_C_you_should_use_my_bool_instead() check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables);
-In_C_you_should_use_my_bool_instead() check_single_table_access(THD *thd, ulong privilege,
- TABLE_LIST *tables, In_C_you_should_use_my_bool_instead() no_errors);
-In_C_you_should_use_my_bool_instead() check_routine_access(THD *thd,ulong want_access,char *db,char *name,
- In_C_you_should_use_my_bool_instead() is_proc, In_C_you_should_use_my_bool_instead() no_errors);
-In_C_you_should_use_my_bool_instead() check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
-In_C_you_should_use_my_bool_instead() check_some_routine_access(THD *thd, const char *db, const char *name, In_C_you_should_use_my_bool_instead() is_proc);
-In_C_you_should_use_my_bool_instead() multi_update_precheck(THD *thd, TABLE_LIST *tables);
-In_C_you_should_use_my_bool_instead() multi_delete_precheck(THD *thd, TABLE_LIST *tables);
-int mysql_multi_update_prepare(THD *thd);
-int mysql_multi_delete_prepare(THD *thd);
-In_C_you_should_use_my_bool_instead() mysql_insert_select_prepare(THD *thd);
-In_C_you_should_use_my_bool_instead() update_precheck(THD *thd, TABLE_LIST *tables);
-In_C_you_should_use_my_bool_instead() delete_precheck(THD *thd, TABLE_LIST *tables);
-In_C_you_should_use_my_bool_instead() insert_precheck(THD *thd, TABLE_LIST *tables);
-In_C_you_should_use_my_bool_instead() create_table_precheck(THD *thd, TABLE_LIST *tables,
- TABLE_LIST *create_table);
-int append_query_string(CHARSET_INFO *csinfo,
- String const *from, String *to);
-void get_default_definer(THD *thd, LEX_USER *definer);
-LEX_USER *create_default_definer(THD *thd);
-LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
-LEX_USER *get_current_user(THD *thd, LEX_USER *user);
-In_C_you_should_use_my_bool_instead() check_string_byte_length(LEX_STRING *str, const char *err_msg,
- uint max_byte_length);
-In_C_you_should_use_my_bool_instead() check_string_char_length(LEX_STRING *str, const char *err_msg,
- uint max_char_length, CHARSET_INFO *cs,
- In_C_you_should_use_my_bool_instead() no_error);
-In_C_you_should_use_my_bool_instead() test_if_data_home_dir(const char *dir);
-In_C_you_should_use_my_bool_instead() parse_sql(THD *thd,
- class Lex_input_stream *lip,
- class Object_creation_ctx *creation_ctx);
-enum enum_mysql_completiontype {
- ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
- COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6
-};
-In_C_you_should_use_my_bool_instead() begin_trans(THD *thd);
-In_C_you_should_use_my_bool_instead() end_active_trans(THD *thd);
-int end_trans(THD *thd, enum enum_mysql_completiontype completion);
-Item *negate_expression(THD *thd, Item *expr);
-int vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
-void sql_print_error(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void sql_print_warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void sql_print_information(const char *format, ...)
- __attribute__((format(printf, 1, 2)));
-typedef void (*sql_print_message_func)(const char *format, ...)
- __attribute__((format(printf, 1, 2)));
-extern sql_print_message_func sql_print_message_handlers[];
-int error_log_print(enum loglevel level, const char *format,
- va_list args);
-In_C_you_should_use_my_bool_instead() slow_log_print(THD *thd, const char *query, uint query_length,
- ulonglong current_utime);
-In_C_you_should_use_my_bool_instead() general_log_print(THD *thd, enum enum_server_command command,
- const char *format,...);
-In_C_you_should_use_my_bool_instead() general_log_write(THD *thd, enum enum_server_command command,
- const char *query, uint query_length);
-#include "sql_class.h"
-#include "log.h"
-class Relay_log_info;
-class Format_description_log_event;
-class TC_LOG
-{
- public:
- int using_heuristic_recover();
- TC_LOG() {}
- virtual ~TC_LOG() {}
- virtual int open(const char *opt_name)=0;
- virtual void close()=0;
- virtual int log_xid(THD *thd, my_xid xid)=0;
- virtual void unlog(ulong cookie, my_xid xid)=0;
-};
-class TC_LOG_DUMMY: public TC_LOG
-{
-public:
- TC_LOG_DUMMY() {}
- int open(const char *opt_name) { return 0; }
- void close() { }
- int log_xid(THD *thd, my_xid xid) { return 1; }
- void unlog(ulong cookie, my_xid xid) { }
-};
-class TC_LOG_MMAP: public TC_LOG
-{
- public:
- typedef enum {
- POOL,
- ERROR,
- DIRTY
- } PAGE_STATE;
- private:
- typedef struct st_page {
- struct st_page *next;
- my_xid *start, *end;
- my_xid *ptr;
- int size, free;
- int waiters;
- PAGE_STATE state;
- pthread_mutex_t lock;
- pthread_cond_t cond;
- } PAGE;
- char logname[512];
- File fd;
- my_off_t file_length;
- uint npages, inited;
- uchar *data;
- struct st_page *pages, *syncing, *active, *pool, *pool_last;
- pthread_mutex_t LOCK_active, LOCK_pool, LOCK_sync;
- pthread_cond_t COND_pool, COND_active;
- public:
- TC_LOG_MMAP(): inited(0) {}
- int open(const char *opt_name);
- void close();
- int log_xid(THD *thd, my_xid xid);
- void unlog(ulong cookie, my_xid xid);
- int recover();
- private:
- void get_active_from_pool();
- int sync();
- int overflow();
-};
-extern TC_LOG *tc_log;
-extern TC_LOG_MMAP tc_log_mmap;
-extern TC_LOG_DUMMY tc_log_dummy;
-class Relay_log_info;
-typedef struct st_log_info
-{
- char log_file_name[512];
- my_off_t index_file_offset, index_file_start_offset;
- my_off_t pos;
- In_C_you_should_use_my_bool_instead() fatal;
- pthread_mutex_t lock;
- st_log_info()
- : index_file_offset(0), index_file_start_offset(0),
- pos(0), fatal(0)
- {
- log_file_name[0] = '\0';
- pthread_mutex_init(&lock, NULL);
- }
- ~st_log_info() { pthread_mutex_destroy(&lock);}
-} LOG_INFO;
-class Log_event;
-class Rows_log_event;
-enum enum_log_type { LOG_UNKNOWN, LOG_NORMAL, LOG_BIN };
-enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED };
-class MYSQL_LOG
-{
-public:
- MYSQL_LOG();
- void init_pthread_objects();
- void cleanup();
- In_C_you_should_use_my_bool_instead() open(const char *log_name,
- enum_log_type log_type,
- const char *new_name,
- enum cache_type io_cache_type_arg);
- void init(enum_log_type log_type_arg,
- enum cache_type io_cache_type_arg);
- void close(uint exiting);
- inline In_C_you_should_use_my_bool_instead() is_open() { return log_state != LOG_CLOSED; }
- const char *generate_name(const char *log_name, const char *suffix,
- In_C_you_should_use_my_bool_instead() strip_ext, char *buff);
- int generate_new_name(char *new_name, const char *log_name);
- protected:
- pthread_mutex_t LOCK_log;
- char *name;
- char log_file_name[512];
- char time_buff[20], db[(64*3) + 1];
- In_C_you_should_use_my_bool_instead() write_error, inited;
- IO_CACHE log_file;
- enum_log_type log_type;
- volatile enum_log_state log_state;
- enum cache_type io_cache_type;
- friend class Log_event;
-};
-class MYSQL_QUERY_LOG: public MYSQL_LOG
-{
-public:
- MYSQL_QUERY_LOG() : last_time(0) {}
- void reopen_file();
- In_C_you_should_use_my_bool_instead() write(time_t event_time, const char *user_host,
- uint user_host_len, int thread_id,
- const char *command_type, uint command_type_len,
- const char *sql_text, uint sql_text_len);
- In_C_you_should_use_my_bool_instead() write(THD *thd, time_t current_time, time_t query_start_arg,
- const char *user_host, uint user_host_len,
- ulonglong query_utime, ulonglong lock_utime, In_C_you_should_use_my_bool_instead() is_command,
- const char *sql_text, uint sql_text_len);
- In_C_you_should_use_my_bool_instead() open_slow_log(const char *log_name)
- {
- char buf[512];
- return open(generate_name(log_name, "-slow.log", 0, buf), LOG_NORMAL, 0,
- WRITE_CACHE);
- }
- In_C_you_should_use_my_bool_instead() open_query_log(const char *log_name)
- {
- char buf[512];
- return open(generate_name(log_name, ".log", 0, buf), LOG_NORMAL, 0,
- WRITE_CACHE);
- }
-private:
- time_t last_time;
-};
-class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
-{
- private:
- pthread_mutex_t LOCK_index;
- pthread_mutex_t LOCK_prep_xids;
- pthread_cond_t COND_prep_xids;
- pthread_cond_t update_cond;
- ulonglong bytes_written;
- IO_CACHE index_file;
- char index_file_name[512];
- ulong max_size;
- long prepared_xids;
- uint file_id;
- uint open_count;
- int readers_count;
- In_C_you_should_use_my_bool_instead() need_start_event;
- In_C_you_should_use_my_bool_instead() no_auto_events;
- ulonglong m_table_map_version;
- int write_to_file(IO_CACHE *cache);
- void new_file_without_locking();
- void new_file_impl(In_C_you_should_use_my_bool_instead() need_lock);
-public:
- MYSQL_LOG::generate_name;
- MYSQL_LOG::is_open;
- Format_description_log_event *description_event_for_exec,
- *description_event_for_queue;
- MYSQL_BIN_LOG();
- int open(const char *opt_name);
- void close();
- int log_xid(THD *thd, my_xid xid);
- void unlog(ulong cookie, my_xid xid);
- int recover(IO_CACHE *log, Format_description_log_event *fdle);
- In_C_you_should_use_my_bool_instead() is_table_mapped(TABLE *table) const
- {
- return table->s->table_map_version == table_map_version();
- }
- ulonglong table_map_version() const { return m_table_map_version; }
- void update_table_map_version() { ++m_table_map_version; }
- int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event);
- void reset_bytes_written()
- {
- bytes_written = 0;
- }
- void harvest_bytes_written(ulonglong* counter)
- {
- char buf1[22],buf2[22];
- const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("harvest_bytes_written","./sql/log.h",321,&_db_func_,&_db_file_,&_db_level_, &_db_framep_);
- (*counter)+=bytes_written;
- do {_db_pargs_(324,"info"); _db_doprnt_ ("counter: %s bytes_written: %s", llstr(*counter,buf1), llstr(bytes_written,buf2));} while(0);
- bytes_written=0;
- do {_db_return_ (326, &_db_func_, &_db_file_, &_db_level_); return;} while(0);
- }
- void set_max_size(ulong max_size_arg);
- void signal_update();
- void wait_for_update(THD* thd, In_C_you_should_use_my_bool_instead() master_or_slave);
- void set_need_start_event() { need_start_event = 1; }
- void init(In_C_you_should_use_my_bool_instead() no_auto_events_arg, ulong max_size);
- void init_pthread_objects();
- void cleanup();
- In_C_you_should_use_my_bool_instead() open(const char *log_name,
- enum_log_type log_type,
- const char *new_name,
- enum cache_type io_cache_type_arg,
- In_C_you_should_use_my_bool_instead() no_auto_events_arg, ulong max_size,
- In_C_you_should_use_my_bool_instead() null_created);
- In_C_you_should_use_my_bool_instead() open_index_file(const char *index_file_name_arg,
- const char *log_name);
- void new_file();
- In_C_you_should_use_my_bool_instead() write(Log_event* event_info);
- In_C_you_should_use_my_bool_instead() write(THD *thd, IO_CACHE *cache, Log_event *commit_event);
- int write_cache(IO_CACHE *cache, In_C_you_should_use_my_bool_instead() lock_log, In_C_you_should_use_my_bool_instead() flush_and_sync);
- void start_union_events(THD *thd, query_id_t query_id_param);
- void stop_union_events(THD *thd);
- In_C_you_should_use_my_bool_instead() is_query_in_union(THD *thd, query_id_t query_id_param);
- In_C_you_should_use_my_bool_instead() appendv(const char* buf,uint len,...);
- In_C_you_should_use_my_bool_instead() append(Log_event* ev);
- void make_log_name(char* buf, const char* log_ident);
- In_C_you_should_use_my_bool_instead() is_active(const char* log_file_name);
- int update_log_index(LOG_INFO* linfo, In_C_you_should_use_my_bool_instead() need_update_threads);
- void rotate_and_purge(uint flags);
- In_C_you_should_use_my_bool_instead() flush_and_sync();
- int purge_logs(const char *to_log, In_C_you_should_use_my_bool_instead() included,
- In_C_you_should_use_my_bool_instead() need_mutex, In_C_you_should_use_my_bool_instead() need_update_threads,
- ulonglong *decrease_log_space);
- int purge_logs_before_date(time_t purge_time);
- int purge_first_log(Relay_log_info* rli, In_C_you_should_use_my_bool_instead() included);
- In_C_you_should_use_my_bool_instead() reset_logs(THD* thd);
- void close(uint exiting);
- int find_log_pos(LOG_INFO* linfo, const char* log_name,
- In_C_you_should_use_my_bool_instead() need_mutex);
- int find_next_log(LOG_INFO* linfo, In_C_you_should_use_my_bool_instead() need_mutex);
- int get_current_log(LOG_INFO* linfo);
- int raw_get_current_log(LOG_INFO* linfo);
- uint next_file_id();
- inline char* get_index_fname() { return index_file_name;}
- inline char* get_log_fname() { return log_file_name; }
- inline char* get_name() { return name; }
- inline pthread_mutex_t* get_log_lock() { return &LOCK_log; }
- inline IO_CACHE* get_log_file() { return &log_file; }
- inline void lock_index() { pthread_mutex_lock(&LOCK_index);}
- inline void unlock_index() { pthread_mutex_unlock(&LOCK_index);}
- inline IO_CACHE *get_index_file() { return &index_file;}
- inline uint32 get_open_count() { return open_count; }
-};
-class Log_event_handler
-{
-public:
- Log_event_handler() {}
- virtual In_C_you_should_use_my_bool_instead() init()= 0;
- virtual void cleanup()= 0;
- virtual In_C_you_should_use_my_bool_instead() log_slow(THD *thd, time_t current_time,
- time_t query_start_arg, const char *user_host,
- uint user_host_len, ulonglong query_utime,
- ulonglong lock_utime, In_C_you_should_use_my_bool_instead() is_command,
- const char *sql_text, uint sql_text_len)= 0;
- virtual In_C_you_should_use_my_bool_instead() log_error(enum loglevel level, const char *format,
- va_list args)= 0;
- virtual In_C_you_should_use_my_bool_instead() log_general(THD *thd, time_t event_time, const char *user_host,
- uint user_host_len, int thread_id,
- const char *command_type, uint command_type_len,
- const char *sql_text, uint sql_text_len,
- CHARSET_INFO *client_cs)= 0;
- virtual ~Log_event_handler() {}
-};
-int check_if_log_table(uint db_len, const char *db, uint table_name_len,
- const char *table_name, uint check_if_opened);
-class Log_to_csv_event_handler: public Log_event_handler
-{
- friend class LOGGER;
-public:
- Log_to_csv_event_handler();
- ~Log_to_csv_event_handler();
- virtual In_C_you_should_use_my_bool_instead() init();
- virtual void cleanup();
- virtual In_C_you_should_use_my_bool_instead() log_slow(THD *thd, time_t current_time,
- time_t query_start_arg, const char *user_host,
- uint user_host_len, ulonglong query_utime,
- ulonglong lock_utime, In_C_you_should_use_my_bool_instead() is_command,
- const char *sql_text, uint sql_text_len);
- virtual In_C_you_should_use_my_bool_instead() log_error(enum loglevel level, const char *format,
- va_list args);
- virtual In_C_you_should_use_my_bool_instead() log_general(THD *thd, time_t event_time, const char *user_host,
- uint user_host_len, int thread_id,
- const char *command_type, uint command_type_len,
- const char *sql_text, uint sql_text_len,
- CHARSET_INFO *client_cs);
- int activate_log(THD *thd, uint log_type);
-};
-class Log_to_file_event_handler: public Log_event_handler
-{
- MYSQL_QUERY_LOG mysql_log;
- MYSQL_QUERY_LOG mysql_slow_log;
- In_C_you_should_use_my_bool_instead() is_initialized;
-public:
- Log_to_file_event_handler(): is_initialized((0))
- {}
- virtual In_C_you_should_use_my_bool_instead() init();
- virtual void cleanup();
- virtual In_C_you_should_use_my_bool_instead() log_slow(THD *thd, time_t current_time,
- time_t query_start_arg, const char *user_host,
- uint user_host_len, ulonglong query_utime,
- ulonglong lock_utime, In_C_you_should_use_my_bool_instead() is_command,
- const char *sql_text, uint sql_text_len);
- virtual In_C_you_should_use_my_bool_instead() log_error(enum loglevel level, const char *format,
- va_list args);
- virtual In_C_you_should_use_my_bool_instead() log_general(THD *thd, time_t event_time, const char *user_host,
- uint user_host_len, int thread_id,
- const char *command_type, uint command_type_len,
- const char *sql_text, uint sql_text_len,
- CHARSET_INFO *client_cs);
- void flush();
- void init_pthread_objects();
- MYSQL_QUERY_LOG *get_mysql_slow_log() { return &mysql_slow_log; }
- MYSQL_QUERY_LOG *get_mysql_log() { return &mysql_log; }
-};
-class LOGGER
-{
- pthread_rwlock_t LOCK_logger;
- uint inited;
- Log_to_csv_event_handler *table_log_handler;
- Log_to_file_event_handler *file_log_handler;
- Log_event_handler *error_log_handler_list[3 + 1];
- Log_event_handler *slow_log_handler_list[3 + 1];
- Log_event_handler *general_log_handler_list[3 + 1];
-public:
- In_C_you_should_use_my_bool_instead() is_log_tables_initialized;
- LOGGER() : inited(0), table_log_handler(NULL),
- file_log_handler(NULL), is_log_tables_initialized((0))
- {}
- void lock_shared() { pthread_rwlock_rdlock(&LOCK_logger); }
- void lock_exclusive() { pthread_rwlock_wrlock(&LOCK_logger); }
- void unlock() { pthread_rwlock_unlock(&LOCK_logger); }
- In_C_you_should_use_my_bool_instead() is_log_table_enabled(uint log_table_type);
- In_C_you_should_use_my_bool_instead() log_command(THD *thd, enum enum_server_command command);
- void init_base();
- void init_log_tables();
- In_C_you_should_use_my_bool_instead() flush_logs(THD *thd);
- void cleanup_base();
- void cleanup_end();
- In_C_you_should_use_my_bool_instead() error_log_print(enum loglevel level, const char *format,
- va_list args);
- In_C_you_should_use_my_bool_instead() slow_log_print(THD *thd, const char *query, uint query_length,
- ulonglong current_utime);
- In_C_you_should_use_my_bool_instead() general_log_print(THD *thd,enum enum_server_command command,
- const char *format, va_list args);
- In_C_you_should_use_my_bool_instead() general_log_write(THD *thd, enum enum_server_command command,
- const char *query, uint query_length);
- int set_handlers(uint error_log_printer,
- uint slow_log_printer,
- uint general_log_printer);
- void init_error_log(uint error_log_printer);
- void init_slow_log(uint slow_log_printer);
- void init_general_log(uint general_log_printer);
- void deactivate_log_handler(THD* thd, uint log_type);
- In_C_you_should_use_my_bool_instead() activate_log_handler(THD* thd, uint log_type);
- MYSQL_QUERY_LOG *get_slow_log_file_handler()
- {
- if (file_log_handler)
- return file_log_handler->get_mysql_slow_log();
- return NULL;
- }
- MYSQL_QUERY_LOG *get_log_file_handler()
- {
- if (file_log_handler)
- return file_log_handler->get_mysql_log();
- return NULL;
- }
-};
-enum enum_binlog_format {
- BINLOG_FORMAT_MIXED= 0,
- BINLOG_FORMAT_STMT= 1,
- BINLOG_FORMAT_ROW= 2,
- BINLOG_FORMAT_UNSPEC= 3
-};
-extern TYPELIB binlog_format_typelib;
-#include "rpl_tblmap.h"
-struct st_table;
-typedef st_table TABLE;
-class table_mapping {
-private:
- MEM_ROOT m_mem_root;
-public:
- enum enum_error {
- ERR_NO_ERROR = 0,
- ERR_LIMIT_EXCEEDED,
- ERR_MEMORY_ALLOCATION
- };
- table_mapping();
- ~table_mapping();
- TABLE* get_table(ulong table_id);
- int set_table(ulong table_id, TABLE* table);
- int remove_table(ulong table_id);
- void clear_tables();
- ulong count() const { return m_table_ids.records; }
-private:
- struct entry {
- ulong table_id;
- union {
- TABLE *table;
- entry *next;
- };
- };
- entry *find_entry(ulong table_id)
- {
- return (entry *)hash_search(&m_table_ids,
- (uchar*)&table_id,
- sizeof(table_id));
- }
- int expand();
- entry *m_free;
- HASH m_table_ids;
-};
-class Reprepare_observer
-{
-public:
- In_C_you_should_use_my_bool_instead() report_error(THD *thd);
- In_C_you_should_use_my_bool_instead() is_invalidated() const { return m_invalidated; }
- void reset_reprepare_observer() { m_invalidated= (0); }
-private:
- In_C_you_should_use_my_bool_instead() m_invalidated;
-};
-class Relay_log_info;
-class Query_log_event;
-class Load_log_event;
-class Slave_log_event;
-class sp_rcontext;
-class sp_cache;
-class Lex_input_stream;
-class Rows_log_event;
-enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
-enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
-enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE };
-enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
- DELAY_KEY_WRITE_ALL };
-enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT,
- SLAVE_EXEC_MODE_IDEMPOTENT,
- SLAVE_EXEC_MODE_LAST_BIT};
-enum enum_mark_columns
-{ MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE};
-extern char internal_table_name[2];
-extern char empty_c_string[1];
-extern const char **errmesg;
-extern uint tc_heuristic_recover;
-typedef struct st_user_var_events
-{
- user_var_entry *user_var_event;
- char *value;
- ulong length;
- Item_result type;
- uint charset_number;
-} BINLOG_USER_VAR_EVENT;
-typedef struct st_copy_info {
- ha_rows records;
- ha_rows deleted;
- ha_rows updated;
- ha_rows copied;
- ha_rows error_count;
- ha_rows touched;
- enum enum_duplicates handle_duplicates;
- int escape_char, last_errno;
- In_C_you_should_use_my_bool_instead() ignore;
- List<Item> *update_fields;
- List<Item> *update_values;
- TABLE_LIST *view;
-} COPY_INFO;
-class Key_part_spec :public Sql_alloc {
-public:
- const char *field_name;
- uint length;
- Key_part_spec(const char *name,uint len=0) :field_name(name), length(len) {}
- In_C_you_should_use_my_bool_instead() operator==(const Key_part_spec& other) const;
- Key_part_spec *clone(MEM_ROOT *mem_root) const
- { return new (mem_root) Key_part_spec(*this); }
-};
-class Alter_drop :public Sql_alloc {
-public:
- enum drop_type {KEY, COLUMN };
- const char *name;
- enum drop_type type;
- Alter_drop(enum drop_type par_type,const char *par_name)
- :name(par_name), type(par_type) {}
- Alter_drop *clone(MEM_ROOT *mem_root) const
- { return new (mem_root) Alter_drop(*this); }
-};
-class Alter_column :public Sql_alloc {
-public:
- const char *name;
- Item *def;
- Alter_column(const char *par_name,Item *literal)
- :name(par_name), def(literal) {}
- Alter_column *clone(MEM_ROOT *mem_root) const
- { return new (mem_root) Alter_column(*this); }
-};
-class Key :public Sql_alloc {
-public:
- enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY};
- enum Keytype type;
- KEY_CREATE_INFO key_create_info;
- List<Key_part_spec> columns;
- const char *name;
- In_C_you_should_use_my_bool_instead() generated;
- Key(enum Keytype type_par, const char *name_arg,
- KEY_CREATE_INFO *key_info_arg,
- In_C_you_should_use_my_bool_instead() generated_arg, List<Key_part_spec> &cols)
- :type(type_par), key_create_info(*key_info_arg), columns(cols),
- name(name_arg), generated(generated_arg)
- {}
- Key(const Key &rhs, MEM_ROOT *mem_root);
- virtual ~Key() {}
- friend In_C_you_should_use_my_bool_instead() foreign_key_prefix(Key *a, Key *b);
- virtual Key *clone(MEM_ROOT *mem_root) const
- { return new (mem_root) Key(*this, mem_root); }
-};
-class Table_ident;
-class Foreign_key: public Key {
-public:
- enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL,
- FK_MATCH_PARTIAL, FK_MATCH_SIMPLE};
- enum fk_option { FK_OPTION_UNDEF, FK_OPTION_RESTRICT, FK_OPTION_CASCADE,
- FK_OPTION_SET_NULL, FK_OPTION_NO_ACTION, FK_OPTION_DEFAULT};
- Table_ident *ref_table;
- List<Key_part_spec> ref_columns;
- uint delete_opt, update_opt, match_opt;
- Foreign_key(const char *name_arg, List<Key_part_spec> &cols,
- Table_ident *table, List<Key_part_spec> &ref_cols,
- uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg)
- :Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols),
- ref_table(table), ref_columns(ref_cols),
- delete_opt(delete_opt_arg), update_opt(update_opt_arg),
- match_opt(match_opt_arg)
- {}
- Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root);
- virtual Key *clone(MEM_ROOT *mem_root) const
- { return new (mem_root) Foreign_key(*this, mem_root); }
-};
-typedef struct st_mysql_lock
-{
- TABLE **table;
- uint table_count,lock_count;
- THR_LOCK_DATA **locks;
-} MYSQL_LOCK;
-class LEX_COLUMN : public Sql_alloc
-{
-public:
- String column;
- uint rights;
- LEX_COLUMN (const String& x,const uint& y ): column (x),rights (y) {}
-};
-#include "sql_lex.h"
-class Table_ident;
-class sql_exchange;
-class LEX_COLUMN;
-class sp_head;
-class sp_name;
-class sp_instr;
-class sp_pcontext;
-class st_alter_tablespace;
-class partition_info;
-class Event_parse_data;
-enum enum_sql_command {
- SQLCOM_SELECT, SQLCOM_CREATE_TABLE, SQLCOM_CREATE_INDEX, SQLCOM_ALTER_TABLE,
- SQLCOM_UPDATE, SQLCOM_INSERT, SQLCOM_INSERT_SELECT,
- SQLCOM_DELETE, SQLCOM_TRUNCATE, SQLCOM_DROP_TABLE, SQLCOM_DROP_INDEX,
- SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS,
- SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_STATUS,
- SQLCOM_SHOW_ENGINE_LOGS, SQLCOM_SHOW_ENGINE_STATUS, SQLCOM_SHOW_ENGINE_MUTEX,
- SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
- SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS,
- SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS,
- SQLCOM_SHOW_TRIGGERS,
- SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES,
- SQLCOM_GRANT,
- SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB,
- SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT,
- SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION,
- SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK,
- SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS,
- SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE,
- SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT,
- SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT,
- SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
- SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER,
- SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE,
- SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS,
- SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA,
- SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
- SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI,
- SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
- SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
- SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES,
- SQLCOM_HELP, SQLCOM_CREATE_USER, SQLCOM_DROP_USER, SQLCOM_RENAME_USER,
- SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM,
- SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL,
- SQLCOM_DROP_PROCEDURE, SQLCOM_ALTER_PROCEDURE,SQLCOM_ALTER_FUNCTION,
- SQLCOM_SHOW_CREATE_PROC, SQLCOM_SHOW_CREATE_FUNC,
- SQLCOM_SHOW_STATUS_PROC, SQLCOM_SHOW_STATUS_FUNC,
- SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE,
- SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW,
- SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER,
- SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE,
- SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER,
- SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE,
- SQLCOM_ALTER_TABLESPACE,
- SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN,
- SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT,
- SQLCOM_SHOW_PLUGINS,
- SQLCOM_SHOW_CONTRIBUTORS,
- SQLCOM_CREATE_SERVER, SQLCOM_DROP_SERVER, SQLCOM_ALTER_SERVER,
- SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT,
- SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS,
- SQLCOM_SHOW_CREATE_TRIGGER,
- SQLCOM_ALTER_DB_UPGRADE,
- SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES,
- SQLCOM_END
-};
-class Delayed_insert;
-class select_result;
-class Time_zone;
-struct system_variables
-{
- ulong dynamic_variables_version;
- char* dynamic_variables_ptr;
- uint dynamic_variables_head;
- uint dynamic_variables_size;
- ulonglong myisam_max_extra_sort_file_size;
- ulonglong myisam_max_sort_file_size;
- ulonglong max_heap_table_size;
- ulonglong tmp_table_size;
- ulonglong long_query_time;
- ha_rows select_limit;
- ha_rows max_join_size;
- ulong auto_increment_increment, auto_increment_offset;
- ulong bulk_insert_buff_size;
- ulong join_buff_size;
- ulong max_allowed_packet;
- ulong max_error_count;
- ulong max_length_for_sort_data;
- ulong max_sort_length;
- ulong max_tmp_tables;
- ulong max_insert_delayed_threads;
- ulong min_examined_row_limit;
- ulong multi_range_count;
- ulong myisam_repair_threads;
- ulong myisam_sort_buff_size;
- ulong myisam_stats_method;
- ulong net_buffer_length;
- ulong net_interactive_timeout;
- ulong net_read_timeout;
- ulong net_retry_count;
- ulong net_wait_timeout;
- ulong net_write_timeout;
- ulong optimizer_prune_level;
- ulong optimizer_search_depth;
- ulong preload_buff_size;
- ulong profiling_history_size;
- ulong query_cache_type;
- ulong read_buff_size;
- ulong read_rnd_buff_size;
- ulong div_precincrement;
- ulong sortbuff_size;
- ulong thread_handling;
- ulong tx_isolation;
- ulong completion_type;
- ulong sql_mode;
- ulong max_sp_recursion_depth;
- ulong updatable_views_with_limit;
- ulong default_week_format;
- ulong max_seeks_for_key;
- ulong range_alloc_block_size;
- ulong query_alloc_block_size;
- ulong query_prealloc_size;
- ulong trans_alloc_block_size;
- ulong trans_prealloc_size;
- ulong log_warnings;
- ulong group_concat_max_len;
- ulong ndb_autoincrement_prefetch_sz;
- ulong ndb_index_stat_cache_entries;
- ulong ndb_index_stat_update_freq;
- ulong binlog_format;
- my_thread_id pseudo_thread_id;
- my_bool low_priority_updates;
- my_bool new_mode;
- my_bool old_mode;
- my_bool query_cache_wlock_invalidate;
- my_bool engine_condition_pushdown;
- my_bool keep_files_on_create;
- my_bool ndb_force_send;
- my_bool ndb_use_copying_alter_table;
- my_bool ndb_use_exact_count;
- my_bool ndb_use_transactions;
- my_bool ndb_index_stat_enable;
- my_bool old_alter_table;
- my_bool old_passwords;
- plugin_ref table_plugin;
- CHARSET_INFO *character_set_filesystem;
- CHARSET_INFO *character_set_client;
- CHARSET_INFO *character_set_results;
- CHARSET_INFO *collation_server;
- CHARSET_INFO *collation_database;
- CHARSET_INFO *collation_connection;
- MY_LOCALE *lc_time_names;
- Time_zone *time_zone;
- DATE_TIME_FORMAT *date_format;
- DATE_TIME_FORMAT *datetime_format;
- DATE_TIME_FORMAT *time_format;
- my_bool sysdate_is_now;
-};
-typedef struct system_status_var
-{
- ulonglong bytes_received;
- ulonglong bytes_sent;
- ulong com_other;
- ulong com_stat[(uint) SQLCOM_END];
- ulong created_tmp_disk_tables;
- ulong created_tmp_tables;
- ulong ha_commit_count;
- ulong ha_delete_count;
- ulong ha_read_first_count;
- ulong ha_read_last_count;
- ulong ha_read_key_count;
- ulong ha_read_next_count;
- ulong ha_read_prev_count;
- ulong ha_read_rnd_count;
- ulong ha_read_rnd_next_count;
- ulong ha_rollback_count;
- ulong ha_update_count;
- ulong ha_write_count;
- ulong ha_prepare_count;
- ulong ha_discover_count;
- ulong ha_savepoint_count;
- ulong ha_savepoint_rollback_count;
- ulong key_blocks_changed;
- ulong key_blocks_used;
- ulong key_cache_r_requests;
- ulong key_cache_read;
- ulong key_cache_w_requests;
- ulong key_cache_write;
- ulong net_big_packet_count;
- ulong opened_tables;
- ulong opened_shares;
- ulong select_full_join_count;
- ulong select_full_range_join_count;
- ulong select_range_count;
- ulong select_range_check_count;
- ulong select_scan_count;
- ulong long_query_count;
- ulong filesort_merge_passes;
- ulong filesort_range_count;
- ulong filesort_rows;
- ulong filesort_scan_count;
- ulong com_stmt_prepare;
- ulong com_stmt_reprepare;
- ulong com_stmt_execute;
- ulong com_stmt_send_long_data;
- ulong com_stmt_fetch;
- ulong com_stmt_reset;
- ulong com_stmt_close;
- double last_query_cost;
-} STATUS_VAR;
-void mark_transaction_to_rollback(THD *thd, In_C_you_should_use_my_bool_instead() all);
-#include "sql_acl.h"
-#include "slave.h"
-#include "log.h"
-#include "my_list.h"
-#include "rpl_filter.h"
-#include "mysql.h"
-#include "mysql_version.h"
-#include "mysql_com.h"
-#include "mysql_time.h"
-#include "my_list.h"
-extern unsigned int mysql_port;
-extern char *mysql_unix_port;
-typedef struct st_mysql_field {
- char *name;
- char *org_name;
- char *table;
- char *org_table;
- char *db;
- char *catalog;
- char *def;
- unsigned long length;
- unsigned long max_length;
- unsigned int name_length;
- unsigned int org_name_length;
- unsigned int table_length;
- unsigned int org_table_length;
- unsigned int db_length;
- unsigned int catalog_length;
- unsigned int def_length;
- unsigned int flags;
- unsigned int decimals;
- unsigned int charsetnr;
- enum enum_field_types type;
- void *extension;
-} MYSQL_FIELD;
-typedef char **MYSQL_ROW;
-typedef unsigned int MYSQL_FIELD_OFFSET;
-#include "typelib.h"
-typedef struct st_mysql_rows {
- struct st_mysql_rows *next;
- MYSQL_ROW data;
- unsigned long length;
-} MYSQL_ROWS;
-typedef MYSQL_ROWS *MYSQL_ROW_OFFSET;
-#include "my_alloc.h"
-typedef struct embedded_query_result EMBEDDED_QUERY_RESULT;
-typedef struct st_mysql_data {
- MYSQL_ROWS *data;
- struct embedded_query_result *embedded_info;
- MEM_ROOT alloc;
- my_ulonglong rows;
- unsigned int fields;
- void *extension;
-} MYSQL_DATA;
-enum mysql_option
-{
- MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE,
- MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP,
- MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE,
- MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT,
- MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT,
- MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
- MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
- MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
- MYSQL_OPT_SSL_VERIFY_SERVER_CERT
-};
-struct st_mysql_options {
- unsigned int connect_timeout, read_timeout, write_timeout;
- unsigned int port, protocol;
- unsigned long client_flag;
- char *host,*user,*password,*unix_socket,*db;
- struct st_dynamic_array *init_commands;
- char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name;
- char *ssl_key;
- char *ssl_cert;
- char *ssl_ca;
- char *ssl_capath;
- char *ssl_cipher;
- char *shared_memory_base_name;
- unsigned long max_allowed_packet;
- my_bool use_ssl;
- my_bool compress,named_pipe;
- my_bool rpl_probe;
- my_bool rpl_parse;
- my_bool no_master_reads;
- my_bool separate_thread;
- enum mysql_option methods_to_use;
- char *client_ip;
- my_bool secure_auth;
- my_bool report_data_truncation;
- int (*local_infile_init)(void **, const char *, void *);
- int (*local_infile_read)(void *, char *, unsigned int);
- void (*local_infile_end)(void *);
- int (*local_infile_error)(void *, char *, unsigned int);
- void *local_infile_userdata;
- void *extension;
-};
-enum mysql_status
-{
- MYSQL_STATUS_READY,MYSQL_STATUS_GET_RESULT,MYSQL_STATUS_USE_RESULT
-};
-enum mysql_protocol_type
-{
- MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET,
- MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY
-};
-enum mysql_rpl_type
-{
- MYSQL_RPL_MASTER, MYSQL_RPL_SLAVE, MYSQL_RPL_ADMIN
-};
-typedef struct character_set
-{
- unsigned int number;
- unsigned int state;
- const char *csname;
- const char *name;
- const char *comment;
- const char *dir;
- unsigned int mbminlen;
- unsigned int mbmaxlen;
-} MY_CHARSET_INFO;
-struct st_mysql_methods;
-struct st_mysql_stmt;
-typedef struct st_mysql
-{
- NET net;
- unsigned char *connector_fd;
- char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
- char *info, *db;
- struct charset_info_st *charset;
- MYSQL_FIELD *fields;
- MEM_ROOT field_alloc;
- my_ulonglong affected_rows;
- my_ulonglong insert_id;
- my_ulonglong extra_info;
- unsigned long thread_id;
- unsigned long packet_length;
- unsigned int port;
- unsigned long client_flag,server_capabilities;
- unsigned int protocol_version;
- unsigned int field_count;
- unsigned int server_status;
- unsigned int server_language;
- unsigned int warning_count;
- struct st_mysql_options options;
- enum mysql_status status;
- my_bool free_me;
- my_bool reconnect;
- char scramble[20 +1];
- my_bool rpl_pivot;
- struct st_mysql* master, *next_slave;
- struct st_mysql* last_used_slave;
- struct st_mysql* last_used_con;
- LIST *stmts;
- const struct st_mysql_methods *methods;
- void *thd;
- my_bool *unbuffered_fetch_owner;
- char *info_buffer;
- void *extension;
-} MYSQL;
-typedef struct st_mysql_res {
- my_ulonglong row_count;
- MYSQL_FIELD *fields;
- MYSQL_DATA *data;
- MYSQL_ROWS *data_cursor;
- unsigned long *lengths;
- MYSQL *handle;
- const struct st_mysql_methods *methods;
- MYSQL_ROW row;
- MYSQL_ROW current_row;
- MEM_ROOT field_alloc;
- unsigned int field_count, current_field;
- my_bool eof;
- my_bool unbuffered_fetch_cancelled;
- void *extension;
-} MYSQL_RES;
-typedef struct st_mysql_manager
-{
- NET net;
- char *host, *user, *passwd;
- char *net_buf, *net_buf_pos, *net_data_end;
- unsigned int port;
- int cmd_status;
- int last_errno;
- int net_buf_size;
- my_bool free_me;
- my_bool eof;
- char last_error[256];
- void *extension;
-} MYSQL_MANAGER;
-typedef struct st_mysql_parameters
-{
- unsigned long *p_max_allowed_packet;
- unsigned long *p_net_buffer_length;
- void *extension;
-} MYSQL_PARAMETERS;
-int mysql_server_init(int argc, char **argv, char **groups);
-void mysql_server_end(void);
-MYSQL_PARAMETERS * mysql_get_parameters(void);
-my_bool mysql_thread_init(void);
-void mysql_thread_end(void);
-my_ulonglong mysql_num_rows(MYSQL_RES *res);
-unsigned int mysql_num_fields(MYSQL_RES *res);
-my_bool mysql_eof(MYSQL_RES *res);
-MYSQL_FIELD * mysql_fetch_field_direct(MYSQL_RES *res,
- unsigned int fieldnr);
-MYSQL_FIELD * mysql_fetch_fields(MYSQL_RES *res);
-MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *res);
-MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES *res);
-unsigned int mysql_field_count(MYSQL *mysql);
-my_ulonglong mysql_affected_rows(MYSQL *mysql);
-my_ulonglong mysql_insert_id(MYSQL *mysql);
-unsigned int mysql_errno(MYSQL *mysql);
-const char * mysql_error(MYSQL *mysql);
-const char * mysql_sqlstate(MYSQL *mysql);
-unsigned int mysql_warning_count(MYSQL *mysql);
-const char * mysql_info(MYSQL *mysql);
-unsigned long mysql_thread_id(MYSQL *mysql);
-const char * mysql_character_set_name(MYSQL *mysql);
-int mysql_set_character_set(MYSQL *mysql, const char *csname);
-MYSQL * mysql_init(MYSQL *mysql);
-my_bool mysql_ssl_set(MYSQL *mysql, const char *key,
- const char *cert, const char *ca,
- const char *capath, const char *cipher);
-const char * mysql_get_ssl_cipher(MYSQL *mysql);
-my_bool mysql_change_user(MYSQL *mysql, const char *user,
- const char *passwd, const char *db);
-MYSQL * mysql_real_connect(MYSQL *mysql, const char *host,
- const char *user,
- const char *passwd,
- const char *db,
- unsigned int port,
- const char *unix_socket,
- unsigned long clientflag);
-int mysql_select_db(MYSQL *mysql, const char *db);
-int mysql_query(MYSQL *mysql, const char *q);
-int mysql_send_query(MYSQL *mysql, const char *q,
- unsigned long length);
-int mysql_real_query(MYSQL *mysql, const char *q,
- unsigned long length);
-MYSQL_RES * mysql_store_result(MYSQL *mysql);
-MYSQL_RES * mysql_use_result(MYSQL *mysql);
-my_bool mysql_master_query(MYSQL *mysql, const char *q,
- unsigned long length);
-my_bool mysql_master_send_query(MYSQL *mysql, const char *q,
- unsigned long length);
-my_bool mysql_slave_query(MYSQL *mysql, const char *q,
- unsigned long length);
-my_bool mysql_slave_send_query(MYSQL *mysql, const char *q,
- unsigned long length);
-void mysql_get_character_set_info(MYSQL *mysql,
- MY_CHARSET_INFO *charset);
-void
-mysql_set_local_infile_handler(MYSQL *mysql,
- int (*local_infile_init)(void **, const char *,
- void *),
- int (*local_infile_read)(void *, char *,
- unsigned int),
- void (*local_infile_end)(void *),
- int (*local_infile_error)(void *, char*,
- unsigned int),
- void *);
-void
-mysql_set_local_infile_default(MYSQL *mysql);
-void mysql_enable_rpl_parse(MYSQL* mysql);
-void mysql_disable_rpl_parse(MYSQL* mysql);
-int mysql_rpl_parse_enabled(MYSQL* mysql);
-void mysql_enable_reads_from_master(MYSQL* mysql);
-void mysql_disable_reads_from_master(MYSQL* mysql);
-my_bool mysql_reads_from_master_enabled(MYSQL* mysql);
-enum mysql_rpl_type mysql_rpl_query_type(const char* q, int len);
-my_bool mysql_rpl_probe(MYSQL* mysql);
-int mysql_set_master(MYSQL* mysql, const char* host,
- unsigned int port,
- const char* user,
- const char* passwd);
-int mysql_add_slave(MYSQL* mysql, const char* host,
- unsigned int port,
- const char* user,
- const char* passwd);
-int mysql_shutdown(MYSQL *mysql,
- enum mysql_enum_shutdown_level
- shutdown_level);
-int mysql_dump_debug_info(MYSQL *mysql);
-int mysql_refresh(MYSQL *mysql,
- unsigned int refresh_options);
-int mysql_kill(MYSQL *mysql,unsigned long pid);
-int mysql_set_server_option(MYSQL *mysql,
- enum enum_mysql_set_option
- option);
-int mysql_ping(MYSQL *mysql);
-const char * mysql_stat(MYSQL *mysql);
-const char * mysql_get_server_info(MYSQL *mysql);
-const char * mysql_get_client_info(void);
-unsigned long mysql_get_client_version(void);
-const char * mysql_get_host_info(MYSQL *mysql);
-unsigned long mysql_get_server_version(MYSQL *mysql);
-unsigned int mysql_get_proto_info(MYSQL *mysql);
-MYSQL_RES * mysql_list_dbs(MYSQL *mysql,const char *wild);
-MYSQL_RES * mysql_list_tables(MYSQL *mysql,const char *wild);
-MYSQL_RES * mysql_list_processes(MYSQL *mysql);
-int mysql_options(MYSQL *mysql,enum mysql_option option,
- const void *arg);
-void mysql_free_result(MYSQL_RES *result);
-void mysql_data_seek(MYSQL_RES *result,
- my_ulonglong offset);
-MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result,
- MYSQL_ROW_OFFSET offset);
-MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result,
- MYSQL_FIELD_OFFSET offset);
-MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
-unsigned long * mysql_fetch_lengths(MYSQL_RES *result);
-MYSQL_FIELD * mysql_fetch_field(MYSQL_RES *result);
-MYSQL_RES * mysql_list_fields(MYSQL *mysql, const char *table,
- const char *wild);
-unsigned long mysql_escape_string(char *to,const char *from,
- unsigned long from_length);
-unsigned long mysql_hex_string(char *to,const char *from,
- unsigned long from_length);
-unsigned long mysql_real_escape_string(MYSQL *mysql,
- char *to,const char *from,
- unsigned long length);
-void mysql_debug(const char *debug);
-void myodbc_remove_escape(MYSQL *mysql,char *name);
-unsigned int mysql_thread_safe(void);
-my_bool mysql_embedded(void);
-MYSQL_MANAGER* mysql_manager_init(MYSQL_MANAGER* con);
-MYSQL_MANAGER* mysql_manager_connect(MYSQL_MANAGER* con,
- const char* host,
- const char* user,
- const char* passwd,
- unsigned int port);
-void mysql_manager_close(MYSQL_MANAGER* con);
-int mysql_manager_command(MYSQL_MANAGER* con,
- const char* cmd, int cmd_len);
-int mysql_manager_fetch_line(MYSQL_MANAGER* con,
- char* res_buf,
- int res_buf_size);
-my_bool mysql_read_query_result(MYSQL *mysql);
-enum enum_mysql_stmt_state
-{
- MYSQL_STMT_INIT_DONE= 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE,
- MYSQL_STMT_FETCH_DONE
-};
-typedef struct st_mysql_bind
-{
- unsigned long *length;
- my_bool *is_null;
- void *buffer;
- my_bool *error;
- unsigned char *row_ptr;
- void (*store_param_func)(NET *net, struct st_mysql_bind *param);
- void (*fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *,
- unsigned char **row);
- void (*skip_result)(struct st_mysql_bind *, MYSQL_FIELD *,
- unsigned char **row);
- unsigned long buffer_length;
- unsigned long offset;
- unsigned long length_value;
- unsigned int param_number;
- unsigned int pack_length;
- enum enum_field_types buffer_type;
- my_bool error_value;
- my_bool is_unsigned;
- my_bool long_data_used;
- my_bool is_null_value;
- void *extension;
-} MYSQL_BIND;
-typedef struct st_mysql_stmt
-{
- MEM_ROOT mem_root;
- LIST list;
- MYSQL *mysql;
- MYSQL_BIND *params;
- MYSQL_BIND *bind;
- MYSQL_FIELD *fields;
- MYSQL_DATA result;
- MYSQL_ROWS *data_cursor;
- int (*read_row_func)(struct st_mysql_stmt *stmt,
- unsigned char **row);
- my_ulonglong affected_rows;
- my_ulonglong insert_id;
- unsigned long stmt_id;
- unsigned long flags;
- unsigned long prefetch_rows;
- unsigned int server_status;
- unsigned int last_errno;
- unsigned int param_count;
- unsigned int field_count;
- enum enum_mysql_stmt_state state;
- char last_error[512];
- char sqlstate[5 +1];
- my_bool send_types_to_server;
- my_bool bind_param_done;
- unsigned char bind_result_done;
- my_bool unbuffered_fetch_cancelled;
- my_bool update_max_length;
- void *extension;
-} MYSQL_STMT;
-enum enum_stmt_attr_type
-{
- STMT_ATTR_UPDATE_MAX_LENGTH,
- STMT_ATTR_CURSOR_TYPE,
- STMT_ATTR_PREFETCH_ROWS
-};
-typedef struct st_mysql_methods
-{
- my_bool (*read_query_result)(MYSQL *mysql);
- my_bool (*advanced_command)(MYSQL *mysql,
- enum enum_server_command command,
- const unsigned char *header,
- unsigned long header_length,
- const unsigned char *arg,
- unsigned long arg_length,
- my_bool skip_check,
- MYSQL_STMT *stmt);
- MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
- unsigned int fields);
- MYSQL_RES * (*use_result)(MYSQL *mysql);
- void (*fetch_lengths)(unsigned long *to,
- MYSQL_ROW column, unsigned int field_count);
- void (*flush_use_result)(MYSQL *mysql);
- MYSQL_FIELD * (*list_fields)(MYSQL *mysql);
- my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt);
- int (*stmt_execute)(MYSQL_STMT *stmt);
- int (*read_binary_rows)(MYSQL_STMT *stmt);
- int (*unbuffered_fetch)(MYSQL *mysql, char **row);
- void (*free_embedded_thd)(MYSQL *mysql);
- const char *(*read_statistics)(MYSQL *mysql);
- my_bool (*next_result)(MYSQL *mysql);
- int (*read_change_user_result)(MYSQL *mysql, char *buff, const char *passwd);
- int (*read_rows_from_cursor)(MYSQL_STMT *stmt);
-} MYSQL_METHODS;
-MYSQL_STMT * mysql_stmt_init(MYSQL *mysql);
-int mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query,
- unsigned long length);
-int mysql_stmt_execute(MYSQL_STMT *stmt);
-int mysql_stmt_fetch(MYSQL_STMT *stmt);
-int mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg,
- unsigned int column,
- unsigned long offset);
-int mysql_stmt_store_result(MYSQL_STMT *stmt);
-unsigned long mysql_stmt_param_count(MYSQL_STMT * stmt);
-my_bool mysql_stmt_attr_set(MYSQL_STMT *stmt,
- enum enum_stmt_attr_type attr_type,
- const void *attr);
-my_bool mysql_stmt_attr_get(MYSQL_STMT *stmt,
- enum enum_stmt_attr_type attr_type,
- void *attr);
-my_bool mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd);
-my_bool mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd);
-my_bool mysql_stmt_close(MYSQL_STMT * stmt);
-my_bool mysql_stmt_reset(MYSQL_STMT * stmt);
-my_bool mysql_stmt_free_result(MYSQL_STMT *stmt);
-my_bool mysql_stmt_send_long_data(MYSQL_STMT *stmt,
- unsigned int param_number,
- const char *data,
- unsigned long length);
-MYSQL_RES * mysql_stmt_result_metadata(MYSQL_STMT *stmt);
-MYSQL_RES * mysql_stmt_param_metadata(MYSQL_STMT *stmt);
-unsigned int mysql_stmt_errno(MYSQL_STMT * stmt);
-const char * mysql_stmt_error(MYSQL_STMT * stmt);
-const char * mysql_stmt_sqlstate(MYSQL_STMT * stmt);
-MYSQL_ROW_OFFSET mysql_stmt_row_seek(MYSQL_STMT *stmt,
- MYSQL_ROW_OFFSET offset);
-MYSQL_ROW_OFFSET mysql_stmt_row_tell(MYSQL_STMT *stmt);
-void mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong offset);
-my_ulonglong mysql_stmt_num_rows(MYSQL_STMT *stmt);
-my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT *stmt);
-my_ulonglong mysql_stmt_insert_id(MYSQL_STMT *stmt);
-unsigned int mysql_stmt_field_count(MYSQL_STMT *stmt);
-my_bool mysql_commit(MYSQL * mysql);
-my_bool mysql_rollback(MYSQL * mysql);
-my_bool mysql_autocommit(MYSQL * mysql, my_bool auto_mode);
-my_bool mysql_more_results(MYSQL *mysql);
-int mysql_next_result(MYSQL *mysql);
-void mysql_close(MYSQL *sock);
-typedef struct st_table_rule_ent
-{
- char* db;
- char* tbl_name;
- uint key_len;
-} TABLE_RULE_ENT;
-class Rpl_filter
-{
-public:
- Rpl_filter();
- ~Rpl_filter();
- Rpl_filter(Rpl_filter const&);
- Rpl_filter& operator=(Rpl_filter const&);
- In_C_you_should_use_my_bool_instead() tables_ok(const char* db, TABLE_LIST* tables);
- In_C_you_should_use_my_bool_instead() db_ok(const char* db);
- In_C_you_should_use_my_bool_instead() db_ok_with_wild_table(const char *db);
- In_C_you_should_use_my_bool_instead() is_on();
- int add_do_table(const char* table_spec);
- int add_ignore_table(const char* table_spec);
- int add_wild_do_table(const char* table_spec);
- int add_wild_ignore_table(const char* table_spec);
- void add_do_db(const char* db_spec);
- void add_ignore_db(const char* db_spec);
- void add_db_rewrite(const char* from_db, const char* to_db);
- void get_do_table(String* str);
- void get_ignore_table(String* str);
- void get_wild_do_table(String* str);
- void get_wild_ignore_table(String* str);
- const char* get_rewrite_db(const char* db, size_t *new_len);
- I_List<i_string>* get_do_db();
- I_List<i_string>* get_ignore_db();
-private:
- In_C_you_should_use_my_bool_instead() table_rules_on;
- void init_table_rule_hash(HASH* h, In_C_you_should_use_my_bool_instead()* h_inited);
- void init_table_rule_array(DYNAMIC_ARRAY* a, In_C_you_should_use_my_bool_instead()* a_inited);
- int add_table_rule(HASH* h, const char* table_spec);
- int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
- void free_string_array(DYNAMIC_ARRAY *a);
- void table_rule_ent_hash_to_str(String* s, HASH* h, In_C_you_should_use_my_bool_instead() inited);
- void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a,
- In_C_you_should_use_my_bool_instead() inited);
- TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len);
- HASH do_table;
- HASH ignore_table;
- DYNAMIC_ARRAY wild_do_table;
- DYNAMIC_ARRAY wild_ignore_table;
- In_C_you_should_use_my_bool_instead() do_table_inited;
- In_C_you_should_use_my_bool_instead() ignore_table_inited;
- In_C_you_should_use_my_bool_instead() wild_do_table_inited;
- In_C_you_should_use_my_bool_instead() wild_ignore_table_inited;
- I_List<i_string> do_db;
- I_List<i_string> ignore_db;
- I_List<i_string_pair> rewrite_db;
-};
-extern Rpl_filter *rpl_filter;
-extern Rpl_filter *binlog_filter;
-#include "rpl_tblmap.h"
-class Relay_log_info;
-class Master_info;
-extern ulong master_retry_count;
-extern MY_BITMAP slave_error_mask;
-extern In_C_you_should_use_my_bool_instead() use_slave_mask;
-extern char *slave_load_tmpdir;
-extern char *master_info_file, *relay_log_info_file;
-extern char *opt_relay_logname, *opt_relaylog_index_name;
-extern my_bool opt_skip_slave_start, opt_reckless_slave;
-extern my_bool opt_log_slave_updates;
-extern ulonglong relay_log_space_limit;
-int init_slave();
-void init_slave_skip_errors(const char* arg);
-In_C_you_should_use_my_bool_instead() flush_relay_log_info(Relay_log_info* rli);
-int register_slave_on_master(MYSQL* mysql);
-int terminate_slave_threads(Master_info* mi, int thread_mask,
- In_C_you_should_use_my_bool_instead() skip_lock = 0);
-int start_slave_threads(In_C_you_should_use_my_bool_instead() need_slave_mutex, In_C_you_should_use_my_bool_instead() wait_for_start,
- Master_info* mi, const char* master_info_fname,
- const char* slave_info_fname, int thread_mask);
-int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
- pthread_mutex_t *cond_lock,
- pthread_cond_t* start_cond,
- volatile uint *slave_running,
- volatile ulong *slave_run_id,
- Master_info* mi,
- In_C_you_should_use_my_bool_instead() high_priority);
-int mysql_table_dump(THD* thd, const char* db,
- const char* tbl_name, int fd = -1);
-int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
- Master_info* mi, MYSQL* mysql, In_C_you_should_use_my_bool_instead() overwrite);
-In_C_you_should_use_my_bool_instead() show_master_info(THD* thd, Master_info* mi);
-In_C_you_should_use_my_bool_instead() show_binlog_info(THD* thd);
-In_C_you_should_use_my_bool_instead() rpl_master_has_bug(Relay_log_info *rli, uint bug_id, In_C_you_should_use_my_bool_instead() report=(1));
-In_C_you_should_use_my_bool_instead() rpl_master_erroneous_autoinc(THD* thd);
-const char *print_slave_db_safe(const char *db);
-int check_expected_error(THD* thd, Relay_log_info const *rli, int error_code);
-void skip_load_data_infile(NET* net);
-void end_slave();
-void clear_until_condition(Relay_log_info* rli);
-void clear_slave_error(Relay_log_info* rli);
-void end_relay_log_info(Relay_log_info* rli);
-void lock_slave_threads(Master_info* mi);
-void unlock_slave_threads(Master_info* mi);
-void init_thread_mask(int* mask,Master_info* mi,In_C_you_should_use_my_bool_instead() inverse);
-int init_relay_log_pos(Relay_log_info* rli,const char* log,ulonglong pos,
- In_C_you_should_use_my_bool_instead() need_data_lock, const char** errmsg,
- In_C_you_should_use_my_bool_instead() look_for_description_event);
-int purge_relay_logs(Relay_log_info* rli, THD *thd, In_C_you_should_use_my_bool_instead() just_reset,
- const char** errmsg);
-void set_slave_thread_options(THD* thd);
-void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli);
-void rotate_relay_log(Master_info* mi);
-int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli,
- In_C_you_should_use_my_bool_instead() skip);
- void * handle_slave_io(void *arg);
- void * handle_slave_sql(void *arg);
-extern In_C_you_should_use_my_bool_instead() volatile abort_loop;
-extern Master_info main_mi, *active_mi;
-extern LIST master_list;
-extern my_bool replicate_same_server_id;
-extern int disconnect_slave_event_count, abort_slave_event_count ;
-extern uint master_port, master_connect_retry, report_port;
-extern char * master_user, *master_password, *master_host;
-extern char *master_info_file, *relay_log_info_file, *report_user;
-extern char *report_host, *report_password;
-extern my_bool master_ssl;
-extern char *master_ssl_ca, *master_ssl_capath, *master_ssl_cert;
-extern char *master_ssl_cipher, *master_ssl_key;
-extern I_List<THD> threads;
-enum mysql_db_table_field
-{
- MYSQL_DB_FIELD_HOST = 0,
- MYSQL_DB_FIELD_DB,
- MYSQL_DB_FIELD_USER,
- MYSQL_DB_FIELD_SELECT_PRIV,
- MYSQL_DB_FIELD_INSERT_PRIV,
- MYSQL_DB_FIELD_UPDATE_PRIV,
- MYSQL_DB_FIELD_DELETE_PRIV,
- MYSQL_DB_FIELD_CREATE_PRIV,
- MYSQL_DB_FIELD_DROP_PRIV,
- MYSQL_DB_FIELD_GRANT_PRIV,
- MYSQL_DB_FIELD_REFERENCES_PRIV,
- MYSQL_DB_FIELD_INDEX_PRIV,
- MYSQL_DB_FIELD_ALTER_PRIV,
- MYSQL_DB_FIELD_CREATE_TMP_TABLE_PRIV,
- MYSQL_DB_FIELD_LOCK_TABLES_PRIV,
- MYSQL_DB_FIELD_CREATE_VIEW_PRIV,
- MYSQL_DB_FIELD_SHOW_VIEW_PRIV,
- MYSQL_DB_FIELD_CREATE_ROUTINE_PRIV,
- MYSQL_DB_FIELD_ALTER_ROUTINE_PRIV,
- MYSQL_DB_FIELD_EXECUTE_PRIV,
- MYSQL_DB_FIELD_EVENT_PRIV,
- MYSQL_DB_FIELD_TRIGGER_PRIV,
- MYSQL_DB_FIELD_COUNT
-};
-extern TABLE_FIELD_W_TYPE mysql_db_table_fields[];
-extern time_t mysql_db_table_last_check;
-struct acl_host_and_ip
-{
- char *hostname;
- long ip,ip_mask;
-};
-class ACL_ACCESS {
-public:
- ulong sort;
- ulong access;
-};
-class ACL_HOST :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- char *db;
-};
-class ACL_USER :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- uint hostname_length;
- USER_RESOURCES user_resource;
- char *user;
- uint8 salt[20 +1];
- uint8 salt_len;
- enum SSL_type ssl_type;
- const char *ssl_cipher, *x509_issuer, *x509_subject;
-};
-class ACL_DB :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- char *user,*db;
-};
-In_C_you_should_use_my_bool_instead() hostname_requires_resolving(const char *hostname);
-my_bool acl_init(In_C_you_should_use_my_bool_instead() dont_read_acl_tables);
-my_bool acl_reload(THD *thd);
-void acl_free(In_C_you_should_use_my_bool_instead() end=0);
-ulong acl_get(const char *host, const char *ip,
- const char *user, const char *db, my_bool db_is_pattern);
-int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
- uint passwd_len);
-In_C_you_should_use_my_bool_instead() acl_getroot_no_password(Security_context *sctx, char *user, char *host,
- char *ip, char *db);
-In_C_you_should_use_my_bool_instead() acl_check_host(const char *host, const char *ip);
-int check_change_password(THD *thd, const char *host, const char *user,
- char *password, uint password_len);
-In_C_you_should_use_my_bool_instead() change_password(THD *thd, const char *host, const char *user,
- char *password);
-In_C_you_should_use_my_bool_instead() mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
- ulong rights, In_C_you_should_use_my_bool_instead() revoke);
-int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
- List <LEX_COLUMN> &column_list, ulong rights,
- In_C_you_should_use_my_bool_instead() revoke);
-In_C_you_should_use_my_bool_instead() mysql_routine_grant(THD *thd, TABLE_LIST *table, In_C_you_should_use_my_bool_instead() is_proc,
- List <LEX_USER> &user_list, ulong rights,
- In_C_you_should_use_my_bool_instead() revoke, In_C_you_should_use_my_bool_instead() no_error);
-my_bool grant_init();
-void grant_free(void);
-my_bool grant_reload(THD *thd);
-In_C_you_should_use_my_bool_instead() check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
- uint show_command, uint number, In_C_you_should_use_my_bool_instead() dont_print_error);
-In_C_you_should_use_my_bool_instead() check_grant_column (THD *thd, GRANT_INFO *grant,
- const char *db_name, const char *table_name,
- const char *name, uint length, Security_context *sctx);
-In_C_you_should_use_my_bool_instead() check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
- const char *name, uint length);
-In_C_you_should_use_my_bool_instead() check_grant_all_columns(THD *thd, ulong want_access,
- Field_iterator_table_ref *fields);
-In_C_you_should_use_my_bool_instead() check_grant_routine(THD *thd, ulong want_access,
- TABLE_LIST *procs, In_C_you_should_use_my_bool_instead() is_proc, In_C_you_should_use_my_bool_instead() no_error);
-In_C_you_should_use_my_bool_instead() check_grant_db(THD *thd,const char *db);
-ulong get_table_grant(THD *thd, TABLE_LIST *table);
-ulong get_column_grant(THD *thd, GRANT_INFO *grant,
- const char *db_name, const char *table_name,
- const char *field_name);
-In_C_you_should_use_my_bool_instead() mysql_show_grants(THD *thd, LEX_USER *user);
-void get_privilege_desc(char *to, uint max_length, ulong access);
-void get_mqh(const char *user, const char *host, USER_CONN *uc);
-In_C_you_should_use_my_bool_instead() mysql_create_user(THD *thd, List <LEX_USER> &list);
-In_C_you_should_use_my_bool_instead() mysql_drop_user(THD *thd, List <LEX_USER> &list);
-In_C_you_should_use_my_bool_instead() mysql_rename_user(THD *thd, List <LEX_USER> &list);
-In_C_you_should_use_my_bool_instead() mysql_revoke_all(THD *thd, List <LEX_USER> &list);
-void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
- const char *db, const char *table);
-In_C_you_should_use_my_bool_instead() sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
- In_C_you_should_use_my_bool_instead() is_proc);
-int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
- In_C_you_should_use_my_bool_instead() is_proc);
-In_C_you_should_use_my_bool_instead() check_routine_level_acl(THD *thd, const char *db, const char *name,
- In_C_you_should_use_my_bool_instead() is_proc);
-In_C_you_should_use_my_bool_instead() is_acl_user(const char *host, const char *user);
-#include "tztime.h"
-class Time_zone: public Sql_alloc
-{
-public:
- Time_zone() {}
- virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
- my_bool *in_dst_time_gap) const = 0;
- virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const = 0;
- virtual const String * get_name() const = 0;
- virtual ~Time_zone() {};
-};
-extern Time_zone * my_tz_UTC;
-extern Time_zone * my_tz_SYSTEM;
-extern Time_zone * my_tz_OFFSET0;
-extern Time_zone * my_tz_find(THD *thd, const String *name);
-extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
-extern void my_tz_free();
-extern my_time_t sec_since_epoch_TIME(MYSQL_TIME *t);
-static const int MY_TZ_TABLES_COUNT= 4;
-In_C_you_should_use_my_bool_instead() check_global_access(THD *thd, ulong want_access);
-int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
-void sql_perror(const char *message);
-In_C_you_should_use_my_bool_instead() fn_format_relative_to_data_home(char * to, const char *name,
- const char *dir, const char *extension);
-extern uint mysql_data_home_len;
-extern char *mysql_data_home,server_version[60],
- mysql_real_data_home[], mysql_unpacked_real_data_home[];
-extern CHARSET_INFO *character_set_filesystem;
-extern char reg_ext[20];
-extern uint reg_ext_length;
-extern ulong specialflag;
-extern uint lower_case_table_names;
-extern In_C_you_should_use_my_bool_instead() mysqld_embedded;
-extern my_bool opt_large_pages;
-extern uint opt_large_page_size;
-extern struct system_variables global_system_variables;
-uint strconvert(CHARSET_INFO *from_cs, const char *from,
- CHARSET_INFO *to_cs, char *to, uint to_length, uint *errors);
-uint filename_to_tablename(const char *from, char *to, uint to_length);
-uint tablename_to_filename(const char *from, char *to, uint to_length);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 1a3a0886c1f..a307836f2bd 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -13,7 +13,43 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h"
+#include <signal.h>
+#ifndef __WIN__
+#include <netdb.h> // getservbyname, servent
+#endif
+#include "sql_parse.h" // test_if_data_home_dir
+#include "sql_cache.h" // query_cache, query_cache_*
+#include "sql_locale.h" // MY_LOCALES, my_locales, my_locale_by_name
+#include "sql_show.h" // free_status_vars, add_status_vars,
+ // reset_status_vars
+#include "strfunc.h" // find_set_from_flags
+#include "parse_file.h" // File_parser_dummy_hook
+#include "sql_db.h" // my_dboptions_cache_free
+ // my_dboptions_cache_init
+#include "sql_table.h" // release_ddl_log, execute_ddl_log_recovery
+#include "sql_connect.h" // free_max_user_conn, init_max_user_conn,
+ // handle_one_connection
+#include "sql_time.h" // known_date_time_formats,
+ // get_date_time_format_str,
+ // date_time_format_make
+#include "tztime.h" // my_tz_free, my_tz_init, my_tz_SYSTEM
+#include "hostname.h" // hostname_cache_free, hostname_cache_init
+#include "sql_acl.h" // acl_free, grant_free, acl_init,
+ // grant_init
+#include "sql_base.h" // table_def_free, table_def_init,
+ // cached_open_tables,
+ // cached_table_definitions
+#include "sql_test.h" // mysql_print_status
+#include "item_create.h" // item_create_cleanup, item_create_init
+#include "sql_servers.h" // servers_free, servers_init
+#include "init.h" // unireg_init
+#include "derror.h" // init_errmessage
+#include "derror.h" // init_errmessage
+#include "des_key_file.h" // load_des_key_file
+#include "sql_manager.h" // stop_handle_manager, start_handle_manager
#include <m_ctype.h>
#include <my_dir.h>
#include <my_bit.h>
@@ -22,57 +58,45 @@
#include "sql_repl.h"
#include "rpl_filter.h"
#include "repl_failsafe.h"
+#include <sql_common.h>
#include <my_stacktrace.h>
#include "mysqld_suffix.h"
#include "mysys_err.h"
#include "events.h"
+#include "sql_audit.h"
+#include "probes_mysql.h"
+#include "scheduler.h"
#include "debug_sync.h"
+#include "sql_callback.h"
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+#include "../storage/perfschema/pfs_server.h"
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+#include "keycaches.h"
#include "../storage/myisam/ha_myisam.h"
+#include "set_var.h"
#include "rpl_injector.h"
+#include "rpl_handler.h"
+
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
-#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
-#if defined(NOT_ENOUGH_TESTED) \
- && defined(NDB_SHM_TRANSPORTER) && MYSQL_VERSION_ID >= 50000
-#define OPT_NDB_SHM_DEFAULT 1
-#else
-#define OPT_NDB_SHM_DEFAULT 0
-#endif
-#endif
-
-#ifndef DEFAULT_SKIP_THREAD_PRIORITY
-#define DEFAULT_SKIP_THREAD_PRIORITY 0
-#endif
-
#include <thr_alarm.h>
#include <ft_global.h>
#include <errmsg.h>
#include "sp_rcontext.h"
#include "sp_cache.h"
+#include "sql_reload.h" // reload_acl_and_cache
-#define mysqld_charset &my_charset_latin1
-
-#ifdef HAVE_purify
-#define IF_PURIFY(A,B) (A)
-#else
-#define IF_PURIFY(A,B) (B)
-#endif
-
-#if SIZEOF_CHARP == 4
-#define MAX_MEM_TABLE_SIZE ~(ulong) 0
-#else
-#define MAX_MEM_TABLE_SIZE ~(ulonglong) 0
+#ifdef HAVE_POLL_H
+#include <poll.h>
#endif
-/* stack traces are only supported on linux intel */
-#if defined(__linux__) && defined(__i386__)
-#define HAVE_STACK_TRACE_ON_SEGV
-#endif /* __linux__ */
+#define mysqld_charset &my_charset_latin1
/* We have HAVE_purify below as this speeds up the shutdown of MySQL */
@@ -99,15 +123,12 @@ extern "C" { // Because of SCO 3.2V4.2
#include <my_net.h>
#if !defined(__WIN__)
-# ifndef __NETWARE__
#include <sys/resource.h>
-# endif /* __NETWARE__ */
#ifdef HAVE_SYS_UN_H
-# include <sys/un.h>
+#include <sys/un.h>
#endif
-#include <netdb.h>
#ifdef HAVE_SELECT_H
-# include <select.h>
+#include <select.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
@@ -128,44 +149,15 @@ extern "C" { // Because of SCO 3.2V4.2
#define SIGNAL_FMT "signal %d"
#endif
-#ifdef __NETWARE__
-#define zVOLSTATE_ACTIVE 6
-#define zVOLSTATE_DEACTIVE 2
-#define zVOLSTATE_MAINTENANCE 3
-
-#undef __event_h__
-#include <../include/event.h>
-/*
- This #undef exists here because both libc of NetWare and MySQL have
- files named event.h which causes compilation errors.
-*/
-
-#include <nks/netware.h>
-#include <nks/vm.h>
-#include <library.h>
-#include <monitor.h>
-#include <zOmni.h> //For NEB
-#include <neb.h> //For NEB
-#include <nebpub.h> //For NEB
-#include <zEvent.h> //For NSS event structures
-#include <zPublics.h>
-
-static void *neb_consumer_id= NULL; //For storing NEB consumer id
-static char datavolname[256]= {0};
-static VolumeID_t datavolid;
-static event_handle_t eh;
-static Report_t ref;
-static void *refneb= NULL;
-my_bool event_flag= FALSE;
-static int volumeid= -1;
-
- /* NEB event callback */
-unsigned long neb_event_callback(struct EventBlock *eblock);
-static void registerwithneb();
-static void getvolumename();
-static void getvolumeID(BYTE *volumeName);
-#endif /* __NETWARE__ */
-
+#ifdef HAVE_SOLARIS_LARGE_PAGES
+#include <sys/mman.h>
+#if defined(__sun__) && defined(__GNUC__) && defined(__cplusplus) \
+ && defined(_XOPEN_SOURCE)
+extern int getpagesizes(size_t *, int);
+extern int getpagesizes2(size_t *, int);
+extern int memcntl(caddr_t, size_t, int, caddr_t, int, int);
+#endif /* __sun__ ... */
+#endif /* HAVE_SOLARIS_LARGE_PAGES */
#ifdef _AIX41
int initgroups(const char *,unsigned int);
@@ -273,86 +265,9 @@ extern "C" sig_handler handle_segfault(int sig);
/* Constants */
-const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"};
-/*
- WARNING: When adding new SQL modes don't forget to update the
- tables definitions that stores it's value.
- (ie: mysql.event, mysql.proc)
-*/
-static const char *sql_mode_names[]=
-{
- "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
- "?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
- "NO_DIR_IN_CREATE",
- "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "MAXDB", "NO_KEY_OPTIONS",
- "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI",
- "NO_AUTO_VALUE_ON_ZERO", "NO_BACKSLASH_ESCAPES", "STRICT_TRANS_TABLES",
- "STRICT_ALL_TABLES",
- "NO_ZERO_IN_DATE", "NO_ZERO_DATE", "ALLOW_INVALID_DATES",
- "ERROR_FOR_DIVISION_BY_ZERO",
- "TRADITIONAL", "NO_AUTO_CREATE_USER", "HIGH_NOT_PRECEDENCE",
- "NO_ENGINE_SUBSTITUTION",
- "PAD_CHAR_TO_FULL_LENGTH",
- NullS
-};
-
-static const unsigned int sql_mode_names_len[]=
-{
- /*REAL_AS_FLOAT*/ 13,
- /*PIPES_AS_CONCAT*/ 15,
- /*ANSI_QUOTES*/ 11,
- /*IGNORE_SPACE*/ 12,
- /*?*/ 1,
- /*ONLY_FULL_GROUP_BY*/ 18,
- /*NO_UNSIGNED_SUBTRACTION*/ 23,
- /*NO_DIR_IN_CREATE*/ 16,
- /*POSTGRESQL*/ 10,
- /*ORACLE*/ 6,
- /*MSSQL*/ 5,
- /*DB2*/ 3,
- /*MAXDB*/ 5,
- /*NO_KEY_OPTIONS*/ 14,
- /*NO_TABLE_OPTIONS*/ 16,
- /*NO_FIELD_OPTIONS*/ 16,
- /*MYSQL323*/ 8,
- /*MYSQL40*/ 7,
- /*ANSI*/ 4,
- /*NO_AUTO_VALUE_ON_ZERO*/ 21,
- /*NO_BACKSLASH_ESCAPES*/ 20,
- /*STRICT_TRANS_TABLES*/ 19,
- /*STRICT_ALL_TABLES*/ 17,
- /*NO_ZERO_IN_DATE*/ 15,
- /*NO_ZERO_DATE*/ 12,
- /*ALLOW_INVALID_DATES*/ 19,
- /*ERROR_FOR_DIVISION_BY_ZERO*/ 26,
- /*TRADITIONAL*/ 11,
- /*NO_AUTO_CREATE_USER*/ 19,
- /*HIGH_NOT_PRECEDENCE*/ 19,
- /*NO_ENGINE_SUBSTITUTION*/ 22,
- /*PAD_CHAR_TO_FULL_LENGTH*/ 23
-};
-
-TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
- sql_mode_names,
- (unsigned int *)sql_mode_names_len };
+#include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE
-static const char *optimizer_switch_names[]=
-{
- "index_merge","index_merge_union","index_merge_sort_union",
- "index_merge_intersection", "default", NullS
-};
-/* Corresponding defines are named OPTIMIZER_SWITCH_XXX */
-static const unsigned int optimizer_switch_names_len[]=
-{
- sizeof("index_merge") - 1,
- sizeof("index_merge_union") - 1,
- sizeof("index_merge_sort_union") - 1,
- sizeof("index_merge_intersection") - 1,
- sizeof("default") - 1
-};
-TYPELIB optimizer_switch_typelib= { array_elements(optimizer_switch_names)-1,"",
- optimizer_switch_names,
- (unsigned int *)optimizer_switch_names_len };
+const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"};
static const char *tc_heuristic_recover_names[]=
{
@@ -364,26 +279,8 @@ static TYPELIB tc_heuristic_recover_typelib=
tc_heuristic_recover_names, NULL
};
-static const char *thread_handling_names[]=
-{ "one-thread-per-connection", "no-threads",
-#if HAVE_POOL_OF_THREADS == 1
- "pool-of-threads",
-#endif
- NullS};
-
-TYPELIB thread_handling_typelib=
-{
- array_elements(thread_handling_names) - 1, "",
- thread_handling_names, NULL
-};
-
const char *first_keyword= "first", *binary_keyword= "BINARY";
const char *my_localhost= "localhost", *delayed_user= "DELAYED";
-#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
-#define GET_HA_ROWS GET_ULL
-#else
-#define GET_HA_ROWS GET_ULONG
-#endif
bool opt_large_files= sizeof(my_off_t) > 4;
@@ -399,49 +296,63 @@ arg_cmp_func Arg_comparator::comparator_matrix[5][2] =
{&Arg_comparator::compare_row, &Arg_comparator::compare_e_row},
{&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal}};
-const char *log_output_names[] = { "NONE", "FILE", "TABLE", NullS};
-static const unsigned int log_output_names_len[]= { 4, 4, 5, 0 };
-TYPELIB log_output_typelib= {array_elements(log_output_names)-1,"",
- log_output_names,
- (unsigned int *) log_output_names_len};
-
/* static variables */
+#ifdef HAVE_PSI_INTERFACE
+#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
+static PSI_thread_key key_thread_handle_con_namedpipes;
+static PSI_cond_key key_COND_handler_count;
+#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
+
+#if defined(HAVE_SMEM) && !defined(EMBEDDED_LIBRARY)
+static PSI_thread_key key_thread_handle_con_sharedmem;
+#endif /* HAVE_SMEM && !EMBEDDED_LIBRARY */
+
+#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
+static PSI_thread_key key_thread_handle_con_sockets;
+#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
+
+#ifdef __WIN__
+static PSI_thread_key key_thread_handle_shutdown;
+#endif /* __WIN__ */
+
+#if defined (HAVE_OPENSSL) && !defined(HAVE_YASSL)
+static PSI_rwlock_key key_rwlock_openssl;
+#endif
+#endif /* HAVE_PSI_INTERFACE */
+
/* the default log output is log tables */
static bool lower_case_table_names_used= 0;
static bool volatile select_thread_in_use, signal_thread_in_use;
-static bool volatile ready_to_exit;
+/* See Bug#56666 and Bug#56760 */;
+volatile bool ready_to_exit;
static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
static my_bool opt_short_log_format= 0;
static uint kill_cached_threads, wake_thread;
-static ulong killed_threads, thread_created;
+static ulong killed_threads;
static ulong max_used_connections;
-static ulong my_bind_addr; /**< the address we bind to */
static volatile ulong cached_thread_count= 0;
-static const char *sql_mode_str= "OFF";
-/* Text representation for OPTIMIZER_SWITCH_DEFAULT */
-static const char *optimizer_switch_str="index_merge=on,index_merge_union=on,"
- "index_merge_sort_union=on,"
- "index_merge_intersection=on";
-static char *mysqld_user, *mysqld_chroot, *log_error_file_ptr;
-static char *opt_init_slave, *language_ptr, *opt_init_connect;
+static char *mysqld_user, *mysqld_chroot;
static char *default_character_set_name;
static char *character_set_filesystem_name;
+static char *lc_messages;
static char *lc_time_names_name;
static char *my_bind_addr_str;
-static char *default_collation_name;
-static char *default_storage_engine_str;
+static char *default_collation_name;
+char *default_storage_engine;
static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME;
static I_List<THD> thread_cache;
-static double long_query_time;
+static bool binlog_format_used= false;
+
+LEX_STRING opt_init_connect, opt_init_slave;
-static pthread_cond_t COND_thread_cache, COND_flush_thread_cache;
+static mysql_cond_t COND_thread_cache, COND_flush_thread_cache;
/* Global variables */
-bool opt_update_log, opt_bin_log, opt_ignore_builtin_innodb= 0;
+bool opt_bin_log, opt_ignore_builtin_innodb= 0;
my_bool opt_log, opt_slow_log;
-ulong log_output_options;
+ulonglong log_output_options;
my_bool opt_log_queries_not_using_indexes= 0;
bool opt_error_log= IF_WIN(1,0);
bool opt_disable_networking=0, opt_skip_show_db=0;
@@ -481,10 +392,16 @@ my_bool opt_skip_slave_start = 0; ///< If set, slave is not autostarted
my_bool opt_reckless_slave = 0;
my_bool opt_enable_named_pipe= 0;
my_bool opt_local_infile, opt_slave_compressed_protocol;
-my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
-my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
+my_bool opt_safe_user_create = 0;
+my_bool opt_show_slave_auth_info;
my_bool opt_log_slave_updates= 0;
-bool slave_warning_issued = false;
+char *opt_slave_skip_errors;
+
+/**
+ compatibility option:
+ - index usage hints (USE INDEX without a FOR clause) behave as in 5.0
+*/
+my_bool old_mode;
/*
Legacy global handlerton. These will be removed (please do not add more).
@@ -493,36 +410,18 @@ handlerton *heap_hton;
handlerton *myisam_hton;
handlerton *partition_hton;
-#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
-const char *opt_ndbcluster_connectstring= 0;
-const char *opt_ndb_connectstring= 0;
-char opt_ndb_constrbuf[1024]= {0};
-unsigned opt_ndb_constrbuf_len= 0;
-my_bool opt_ndb_shm, opt_ndb_optimized_node_selection;
-ulong opt_ndb_cache_check_time;
-const char *opt_ndb_mgmd;
-ulong opt_ndb_nodeid;
-ulong ndb_extra_logging;
-#ifdef HAVE_NDB_BINLOG
-ulong ndb_report_thresh_binlog_epoch_slip;
-ulong ndb_report_thresh_binlog_mem_usage;
-#endif
-
-extern const char *ndb_distribution_names[];
-extern TYPELIB ndb_distribution_typelib;
-extern const char *opt_ndb_distribution;
-extern enum ndb_distribution opt_ndb_distribution_id;
-#endif
-my_bool opt_readonly, use_temp_pool, relay_log_purge;
+my_bool opt_readonly= 0, use_temp_pool, relay_log_purge;
+my_bool relay_log_recovery;
my_bool opt_sync_frm, opt_allow_suspicious_udfs;
my_bool opt_secure_auth= 0;
-char* opt_secure_file_priv= 0;
+char* opt_secure_file_priv;
my_bool opt_log_slow_admin_statements= 0;
my_bool opt_log_slow_slave_statements= 0;
my_bool lower_case_file_system= 0;
my_bool opt_large_pages= 0;
+my_bool opt_super_large_pages= 0;
my_bool opt_myisam_use_mmap= 0;
-uint opt_large_page_size= 0;
+uint opt_large_page_size= 0;
#if defined(ENABLED_DEBUG_SYNC)
uint opt_debug_sync_timeout= 0;
#endif /* defined(ENABLED_DEBUG_SYNC) */
@@ -538,43 +437,45 @@ my_bool sp_automatic_privileges= 1;
ulong opt_binlog_rows_event_max_size;
const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS};
-TYPELIB binlog_format_typelib=
- { array_elements(binlog_format_names) - 1, "",
- binlog_format_names, NULL };
-ulong opt_binlog_format_id= (ulong) BINLOG_FORMAT_UNSPEC;
-const char *opt_binlog_format= binlog_format_names[opt_binlog_format_id];
#ifdef HAVE_INITGROUPS
static bool calling_initgroups= FALSE; /**< Used in SIGSEGV handler. */
#endif
uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
uint mysqld_port_timeout;
-uint delay_key_write_options, protocol_version;
+ulong delay_key_write_options;
+uint protocol_version;
uint lower_case_table_names;
-uint tc_heuristic_recover= 0;
-uint volatile thread_count, thread_running;
-ulonglong thd_startup_options;
+ulong tc_heuristic_recover= 0;
+uint volatile thread_count;
+int32 thread_running;
+ulong thread_created;
ulong back_log, connect_timeout, concurrency, server_id;
ulong table_cache_size, table_def_size;
ulong what_to_log;
-ulong query_buff_size, slow_launch_time, slave_open_temp_tables;
+ulong slow_launch_time, slave_open_temp_tables;
ulong open_files_limit, max_binlog_size, max_relay_log_size;
-ulong slave_net_timeout, slave_trans_retries;
+ulong slave_trans_retries;
+uint slave_net_timeout;
ulong slave_exec_mode_options;
-static const char *slave_exec_mode_str= "STRICT";
-ulong thread_cache_size=0, thread_pool_size= 0;
+ulonglong slave_type_conversions_options;
+ulong thread_cache_size=0;
ulong binlog_cache_size=0;
ulonglong max_binlog_cache_size=0;
+ulong binlog_stmt_cache_size=0;
+ulonglong max_binlog_stmt_cache_size=0;
ulong query_cache_size=0;
ulong refresh_version; /* Increments on each reload */
query_id_t global_query_id;
+my_atomic_rwlock_t global_query_id_lock;
+my_atomic_rwlock_t thread_running_lock;
ulong aborted_threads, aborted_connects;
ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size;
ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use;
ulong delayed_insert_errors,flush_time;
ulong specialflag=0;
ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
+ulong binlog_stmt_cache_use= 0, binlog_stmt_cache_disk_use= 0;
ulong max_connections, max_connect_errors;
-uint max_user_connections= 0;
/**
Limit of the total number of prepared statements in the server.
Is necessary to protect the server against out-of-memory attacks.
@@ -592,37 +493,74 @@ ulong max_prepared_stmt_count;
*/
ulong prepared_stmt_count=0;
ulong thread_id=1L,current_pid;
-ulong slow_launch_threads = 0, sync_binlog_period;
+ulong slow_launch_threads = 0;
+uint sync_binlog_period= 0, sync_relaylog_period= 0,
+ sync_relayloginfo_period= 0, sync_masterinfo_period= 0;
ulong expire_logs_days = 0;
ulong rpl_recovery_rank=0;
-const char *log_output_str= "FILE";
+
+const double log_10[] = {
+ 1e000, 1e001, 1e002, 1e003, 1e004, 1e005, 1e006, 1e007, 1e008, 1e009,
+ 1e010, 1e011, 1e012, 1e013, 1e014, 1e015, 1e016, 1e017, 1e018, 1e019,
+ 1e020, 1e021, 1e022, 1e023, 1e024, 1e025, 1e026, 1e027, 1e028, 1e029,
+ 1e030, 1e031, 1e032, 1e033, 1e034, 1e035, 1e036, 1e037, 1e038, 1e039,
+ 1e040, 1e041, 1e042, 1e043, 1e044, 1e045, 1e046, 1e047, 1e048, 1e049,
+ 1e050, 1e051, 1e052, 1e053, 1e054, 1e055, 1e056, 1e057, 1e058, 1e059,
+ 1e060, 1e061, 1e062, 1e063, 1e064, 1e065, 1e066, 1e067, 1e068, 1e069,
+ 1e070, 1e071, 1e072, 1e073, 1e074, 1e075, 1e076, 1e077, 1e078, 1e079,
+ 1e080, 1e081, 1e082, 1e083, 1e084, 1e085, 1e086, 1e087, 1e088, 1e089,
+ 1e090, 1e091, 1e092, 1e093, 1e094, 1e095, 1e096, 1e097, 1e098, 1e099,
+ 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
+ 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
+ 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
+ 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
+ 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
+ 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
+ 1e160, 1e161, 1e162, 1e163, 1e164, 1e165, 1e166, 1e167, 1e168, 1e169,
+ 1e170, 1e171, 1e172, 1e173, 1e174, 1e175, 1e176, 1e177, 1e178, 1e179,
+ 1e180, 1e181, 1e182, 1e183, 1e184, 1e185, 1e186, 1e187, 1e188, 1e189,
+ 1e190, 1e191, 1e192, 1e193, 1e194, 1e195, 1e196, 1e197, 1e198, 1e199,
+ 1e200, 1e201, 1e202, 1e203, 1e204, 1e205, 1e206, 1e207, 1e208, 1e209,
+ 1e210, 1e211, 1e212, 1e213, 1e214, 1e215, 1e216, 1e217, 1e218, 1e219,
+ 1e220, 1e221, 1e222, 1e223, 1e224, 1e225, 1e226, 1e227, 1e228, 1e229,
+ 1e230, 1e231, 1e232, 1e233, 1e234, 1e235, 1e236, 1e237, 1e238, 1e239,
+ 1e240, 1e241, 1e242, 1e243, 1e244, 1e245, 1e246, 1e247, 1e248, 1e249,
+ 1e250, 1e251, 1e252, 1e253, 1e254, 1e255, 1e256, 1e257, 1e258, 1e259,
+ 1e260, 1e261, 1e262, 1e263, 1e264, 1e265, 1e266, 1e267, 1e268, 1e269,
+ 1e270, 1e271, 1e272, 1e273, 1e274, 1e275, 1e276, 1e277, 1e278, 1e279,
+ 1e280, 1e281, 1e282, 1e283, 1e284, 1e285, 1e286, 1e287, 1e288, 1e289,
+ 1e290, 1e291, 1e292, 1e293, 1e294, 1e295, 1e296, 1e297, 1e298, 1e299,
+ 1e300, 1e301, 1e302, 1e303, 1e304, 1e305, 1e306, 1e307, 1e308
+};
time_t server_start_time, flush_status_time;
char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30];
+char default_logfile_name[FN_REFLEN];
char *default_tz_name;
char log_error_file[FN_REFLEN], glob_hostname[FN_REFLEN];
char mysql_real_data_home[FN_REFLEN],
- language[FN_REFLEN], reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN],
- *opt_init_file, *opt_tc_log_file,
- def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
+ lc_messages_dir[FN_REFLEN], reg_ext[FN_EXTLEN],
+ mysql_charsets_dir[FN_REFLEN],
+ *opt_init_file, *opt_tc_log_file;
+char *lc_messages_dir_ptr, *log_error_file_ptr;
char mysql_unpacked_real_data_home[FN_REFLEN];
int mysql_unpacked_real_data_home_len;
+uint mysql_real_data_home_len, mysql_data_home_len= 1;
uint reg_ext_length;
const key_map key_map_empty(0);
key_map key_map_full(0); // Will be initialized later
-const char *opt_date_time_formats[3];
+DATE_TIME_FORMAT global_date_format, global_datetime_format, global_time_format;
+Time_zone *default_tz;
-uint mysql_data_home_len;
-char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home;
+char *mysql_data_home= const_cast<char*>(".");
+const char *mysql_real_data_home_ptr= mysql_real_data_home;
char server_version[SERVER_VERSION_LENGTH];
char *mysqld_unix_port, *opt_mysql_tmpdir;
-const char **errmesg; /**< Error messages */
-const char *myisam_recover_options_str="OFF";
-const char *myisam_stats_method_str="nulls_unequal";
+ulong thread_handling;
-/** name of reference on left espression in rewritten IN subquery */
+/** name of reference on left expression in rewritten IN subquery */
const char *in_left_expr_name= "<left expr>";
/** name of additional condition */
const char *in_additional_cond= "<IN COND>";
@@ -637,12 +575,10 @@ Lt_creator lt_creator;
Ge_creator ge_creator;
Le_creator le_creator;
-FILE *bootstrap_file;
+MYSQL_FILE *bootstrap_file;
int bootstrap_error;
-FILE *stderror_file=0;
I_List<THD> threads;
-I_List<NAMED_LIST> key_caches;
Rpl_filter* rpl_filter;
Rpl_filter* binlog_filter;
@@ -656,26 +592,28 @@ MY_BITMAP temp_pool;
CHARSET_INFO *system_charset_info, *files_charset_info ;
CHARSET_INFO *national_charset_info, *table_alias_charset;
CHARSET_INFO *character_set_filesystem;
+CHARSET_INFO *error_message_charset_info;
+MY_LOCALE *my_default_lc_messages;
MY_LOCALE *my_default_lc_time_names;
SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen, have_query_cache;
SHOW_COMP_OPTION have_geometry, have_rtree_keys;
SHOW_COMP_OPTION have_crypt, have_compress;
-SHOW_COMP_OPTION have_community_features;
+SHOW_COMP_OPTION have_profiling;
/* Thread specific variables */
pthread_key(MEM_ROOT**,THR_MALLOC);
pthread_key(THD*, THR_THD);
-pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
- LOCK_mapped_file, LOCK_status, LOCK_global_read_lock,
- LOCK_error_log, LOCK_uuid_generator,
- LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
- LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
- LOCK_global_system_variables,
- LOCK_user_conn, LOCK_slave_list, LOCK_active_mi,
- LOCK_connection_count;
+mysql_mutex_t LOCK_thread_count;
+mysql_mutex_t
+ LOCK_status, LOCK_error_log, LOCK_uuid_generator,
+ LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
+ LOCK_crypt,
+ LOCK_global_system_variables,
+ LOCK_user_conn, LOCK_slave_list, LOCK_active_mi,
+ LOCK_connection_count, LOCK_error_messages;
/**
The below lock protects access to two global server variables:
max_prepared_stmt_count and prepared_stmt_count. These variables
@@ -683,53 +621,221 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
in the server, respectively. As PREPARE/DEALLOCATE rate in a loaded
server may be fairly high, we need a dedicated lock.
*/
-pthread_mutex_t LOCK_prepared_stmt_count;
+mysql_mutex_t LOCK_prepared_stmt_count;
#ifdef HAVE_OPENSSL
-pthread_mutex_t LOCK_des_key_file;
+mysql_mutex_t LOCK_des_key_file;
#endif
-rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
-rw_lock_t LOCK_system_variables_hash;
-pthread_cond_t COND_refresh, COND_thread_count, COND_global_read_lock;
+mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
+mysql_rwlock_t LOCK_system_variables_hash;
+mysql_cond_t COND_thread_count;
pthread_t signal_thread;
pthread_attr_t connection_attrib;
-pthread_mutex_t LOCK_server_started;
-pthread_cond_t COND_server_started;
+mysql_mutex_t LOCK_server_started;
+mysql_cond_t COND_server_started;
int mysqld_server_started= 0;
File_parser_dummy_hook file_parser_dummy_hook;
/* replication parameters, if master_host is not NULL, we are a slave */
-uint master_port= MYSQL_PORT, master_connect_retry = 60;
uint report_port= MYSQL_PORT;
ulong master_retry_count=0;
-char *master_user, *master_password, *master_host, *master_info_file;
+char *master_info_file;
char *relay_log_info_file, *report_user, *report_password, *report_host;
char *opt_relay_logname = 0, *opt_relaylog_index_name=0;
-my_bool master_ssl;
-char *master_ssl_key, *master_ssl_cert;
-char *master_ssl_ca, *master_ssl_capath, *master_ssl_cipher;
char *opt_logname, *opt_slow_logname;
/* Static variables */
static bool kill_in_progress, segfaulted;
-#ifdef HAVE_STACK_TRACE_ON_SEGV
-static my_bool opt_do_pstack;
-#endif /* HAVE_STACK_TRACE_ON_SEGV */
static my_bool opt_bootstrap, opt_myisam_log;
static int cleanup_done;
-static ulong opt_specialflag, opt_myisam_block_size;
+static ulong opt_specialflag;
static char *opt_update_logname, *opt_binlog_index_name;
-static char *opt_tc_heuristic_recover;
-static char *mysql_home_ptr, *pidfile_name_ptr;
+char *mysql_home_ptr, *pidfile_name_ptr;
+/** Initial command line arguments (count), after load_defaults().*/
static int defaults_argc;
+/**
+ Initial command line arguments (arguments), after load_defaults().
+ This memory is allocated by @c load_defaults() and should be freed
+ using @c free_defaults().
+ Do not modify defaults_argc / defaults_argv,
+ use remaining_argc / remaining_argv instead to parse the command
+ line arguments in multiple steps.
+*/
static char **defaults_argv;
+/** Remaining command line arguments (count), filtered by handle_options().*/
+static int remaining_argc;
+/** Remaining command line arguments (arguments), filtered by handle_options().*/
+static char **remaining_argv;
static char *opt_bin_logname;
int orig_argc;
char **orig_argv;
+/*
+ Since buffered_option_error_reporter is only used currently
+ for parsing performance schema options, this code is not needed
+ when the performance schema is not compiled in.
+*/
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+/**
+ A log message for the error log, buffered in memory.
+ Log messages are temporarily buffered when generated before the error log
+ is initialized, and then printed once the error log is ready.
+*/
+class Buffered_log : public Sql_alloc
+{
+public:
+ Buffered_log(enum loglevel level, const char *message);
+
+ ~Buffered_log()
+ {}
+
+ void print(void);
+
+private:
+ /** Log message level. */
+ enum loglevel m_level;
+ /** Log message text. */
+ String m_message;
+};
+
+/**
+ Constructor.
+ @param level the message log level
+ @param message the message text
+*/
+Buffered_log::Buffered_log(enum loglevel level, const char *message)
+ : m_level(level), m_message()
+{
+ m_message.copy(message, strlen(message), &my_charset_latin1);
+}
+
+/**
+ Print a buffered log to the real log file.
+*/
+void Buffered_log::print()
+{
+ /*
+ Since messages are buffered, they can be printed out
+ of order with other entries in the log.
+ Add "Buffered xxx" to the message text to prevent confusion.
+ */
+ switch(m_level)
+ {
+ case ERROR_LEVEL:
+ sql_print_error("Buffered error: %s\n", m_message.c_ptr_safe());
+ break;
+ case WARNING_LEVEL:
+ sql_print_warning("Buffered warning: %s\n", m_message.c_ptr_safe());
+ break;
+ case INFORMATION_LEVEL:
+ /*
+ Messages printed as "information" still end up in the mysqld *error* log,
+ but with a [Note] tag instead of an [ERROR] tag.
+ While this is probably fine for a human reading the log,
+ it is upsetting existing automated scripts used to parse logs,
+ because such scripts are likely to not already handle [Note] properly.
+ INFORMATION_LEVEL messages are simply silenced, on purpose,
+ to avoid un needed verbosity.
+ */
+ break;
+ }
+}
+
+/**
+ Collection of all the buffered log messages.
+*/
+class Buffered_logs
+{
+public:
+ Buffered_logs()
+ {}
+
+ ~Buffered_logs()
+ {}
+
+ void init();
+ void cleanup();
+
+ void buffer(enum loglevel m_level, const char *msg);
+ void print();
+private:
+ /**
+ Memory root to use to store buffered logs.
+ This memory root lifespan is between init and cleanup.
+ Once the buffered logs are printed, they are not needed anymore,
+ and all the memory used is reclaimed.
+ */
+ MEM_ROOT m_root;
+ /** List of buffered log messages. */
+ List<Buffered_log> m_list;
+};
+
+void Buffered_logs::init()
+{
+ init_alloc_root(&m_root, 1024, 0);
+}
+
+void Buffered_logs::cleanup()
+{
+ m_list.delete_elements();
+ free_root(&m_root, MYF(0));
+}
+
+/**
+ Add a log message to the buffer.
+*/
+void Buffered_logs::buffer(enum loglevel level, const char *msg)
+{
+ /*
+ Do not let Sql_alloc::operator new(size_t) allocate memory,
+ there is no memory root associated with the main() thread.
+ Give explicitly the proper memory root to use to
+ Sql_alloc::operator new(size_t, MEM_ROOT *) instead.
+ */
+ Buffered_log *log= new (&m_root) Buffered_log(level, msg);
+ if (log)
+ m_list.push_back(log, &m_root);
+}
+
+/**
+ Print buffered log messages.
+*/
+void Buffered_logs::print()
+{
+ Buffered_log *log;
+ List_iterator_fast<Buffered_log> it(m_list);
+ while ((log= it++))
+ log->print();
+}
+
+/** Logs reported before a logger is available. */
+static Buffered_logs buffered_logs;
+
+#ifndef EMBEDDED_LIBRARY
+/**
+ Error reporter that buffer log messages.
+ @param level log message level
+ @param format log message format string
+*/
+C_MODE_START
+static void buffered_option_error_reporter(enum loglevel level,
+ const char *format, ...)
+{
+ va_list args;
+ char buffer[1024];
+
+ va_start(args, format);
+ my_vsnprintf(buffer, sizeof(buffer), format, args);
+ va_end(args);
+ buffered_logs.buffer(level, buffer);
+}
+C_MODE_END
+#endif /* !EMBEDDED_LIBRARY */
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
static my_socket unix_sock,ip_sock;
struct rand_struct sql_rand; ///< used by sql_class.cc:THD::THD()
@@ -745,7 +851,7 @@ static uint thr_kill_signal;
#undef getpid
#include <process.h>
-static pthread_cond_t COND_handler_count;
+static mysql_cond_t COND_handler_count;
static uint handler_count;
static bool start_mode=0, use_opt_args;
static int opt_argc;
@@ -759,7 +865,7 @@ static NTService Service; ///< Service object for WinNT
#endif /* EMBEDDED_LIBRARY */
#endif /* __WIN__ */
-#ifdef __NT__
+#ifdef _WIN32
static char pipe_name[512];
static SECURITY_ATTRIBUTES saPipeSecurity;
static SECURITY_DESCRIPTOR sdPipeDescriptor;
@@ -783,7 +889,6 @@ int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;
#endif
#ifdef HAVE_QUERY_CACHE
-static ulong query_cache_limit= 0;
ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE;
Query_cache query_cache;
#endif
@@ -793,16 +898,16 @@ my_bool opt_enable_shared_memory;
HANDLE smem_event_connect_request= 0;
#endif
-scheduler_functions thread_scheduler;
+my_bool opt_use_ssl = 0;
+char *opt_ssl_ca= NULL, *opt_ssl_capath= NULL, *opt_ssl_cert= NULL,
+ *opt_ssl_cipher= NULL, *opt_ssl_key= NULL;
-#define SSL_VARS_NOT_STATIC
-#include "sslopt-vars.h"
#ifdef HAVE_OPENSSL
#include <openssl/crypto.h>
#ifndef HAVE_YASSL
typedef struct CRYPTO_dynlock_value
{
- rw_lock_t lock;
+ mysql_rwlock_t lock;
} openssl_lock_t;
static openssl_lock_t *openssl_stdlocks;
@@ -813,7 +918,9 @@ static void openssl_lock(int, openssl_lock_t *, const char *, int);
static unsigned long openssl_id_function();
#endif
char *des_key_file;
+#ifndef EMBEDDED_LIBRARY
struct st_VioSSLFd *ssl_acceptor_fd;
+#endif
#endif /* HAVE_OPENSSL */
/**
@@ -826,26 +933,27 @@ uint connection_count= 0;
pthread_handler_t signal_hand(void *arg);
static int mysql_init_variables(void);
-static int get_options(int *argc,char **argv);
+static int get_options(int *argc_ptr, char ***argv_ptr);
+static bool add_terminator(DYNAMIC_ARRAY *options);
extern "C" my_bool mysqld_get_one_option(int, const struct my_option *, char *);
static void set_server_version(void);
static int init_thread_environment();
static char *get_relative_path(const char *path);
static int fix_paths(void);
-pthread_handler_t handle_connections_sockets(void *arg);
+void handle_connections_sockets();
+#ifdef _WIN32
+pthread_handler_t handle_connections_sockets_thread(void *arg);
+#endif
pthread_handler_t kill_server_thread(void *arg);
-static void bootstrap(FILE *file);
+static void bootstrap(MYSQL_FILE *file);
static bool read_init_file(char *file_name);
-#ifdef __NT__
+#ifdef _WIN32
pthread_handler_t handle_connections_namedpipes(void *arg);
#endif
#ifdef HAVE_SMEM
pthread_handler_t handle_connections_shared_memory(void *arg);
#endif
pthread_handler_t handle_slave(void *arg);
-static ulong find_bit_type(const char *x, TYPELIB *bit_lib);
-static ulong find_bit_type_or_exit(const char *x, TYPELIB *bit_lib,
- const char *option, int *error);
static void clean_up(bool print_message);
static int test_if_case_insensitive(const char *dir_name);
@@ -856,8 +964,9 @@ static void close_server_sock();
static void clean_up_mutexes(void);
static void wait_for_signal_thread_to_end(void);
static void create_pid_file();
-static void end_ssl();
+static void mysqld_exit(int exit_code) __attribute__((noreturn));
#endif
+static void end_ssl();
#ifndef EMBEDDED_LIBRARY
@@ -877,10 +986,10 @@ static void close_connections(void)
flush_thread_cache();
/* kill connection thread */
-#if !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__)
DBUG_PRINT("quit", ("waiting for select thread: 0x%lx",
(ulong) select_thread));
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
while (select_thread_in_use)
{
@@ -896,18 +1005,18 @@ static void close_connections(void)
set_timespec(abstime, 2);
for (uint tmp=0 ; tmp < 10 && select_thread_in_use; tmp++)
{
- error=pthread_cond_timedwait(&COND_thread_count,&LOCK_thread_count,
- &abstime);
+ error= mysql_cond_timedwait(&COND_thread_count, &LOCK_thread_count,
+ &abstime);
if (error != EINTR)
break;
}
#ifdef EXTRA_DEBUG
if (error != 0 && !count++)
- sql_print_error("Got error %d from pthread_cond_timedwait",error);
+ sql_print_error("Got error %d from mysql_cond_timedwait", error);
#endif
close_server_sock();
}
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
#endif /* __WIN__ */
@@ -922,7 +1031,7 @@ static void close_connections(void)
ip_sock= INVALID_SOCKET;
}
}
-#ifdef __NT__
+#ifdef _WIN32
if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
{
HANDLE temp;
@@ -964,7 +1073,7 @@ static void close_connections(void)
*/
THD *tmp;
- (void) pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
I_List_iterator<THD> it(threads);
while ((tmp=it++))
@@ -976,21 +1085,23 @@ static void close_connections(void)
continue;
tmp->killed= THD::KILL_CONNECTION;
- thread_scheduler.post_kill_notification(tmp);
+ MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->mysys_var)
{
tmp->mysys_var->abort=1;
- pthread_mutex_lock(&tmp->mysys_var->mutex);
+ mysql_mutex_lock(&tmp->mysys_var->mutex);
if (tmp->mysys_var->current_cond)
{
- pthread_mutex_lock(tmp->mysys_var->current_mutex);
- pthread_cond_broadcast(tmp->mysys_var->current_cond);
- pthread_mutex_unlock(tmp->mysys_var->current_mutex);
+ mysql_mutex_lock(tmp->mysys_var->current_mutex);
+ mysql_cond_broadcast(tmp->mysys_var->current_cond);
+ mysql_mutex_unlock(tmp->mysys_var->current_mutex);
}
- pthread_mutex_unlock(&tmp->mysys_var->mutex);
+ mysql_mutex_unlock(&tmp->mysys_var->mutex);
}
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
}
- (void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
+ mysql_mutex_unlock(&LOCK_thread_count); // For unlink from list
Events::deinit();
end_slave();
@@ -1007,18 +1118,18 @@ static void close_connections(void)
for (;;)
{
DBUG_PRINT("quit",("Locking LOCK_thread_count"));
- (void) pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
if (!(tmp=threads.get()))
{
DBUG_PRINT("quit",("Unlocking LOCK_thread_count"));
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
break;
}
#ifndef __bsdi__ // Bug in BSDI kernel
if (tmp->vio_ok())
{
if (global_system_variables.log_warnings)
- sql_print_warning(ER(ER_FORCING_CLOSE),my_progname,
+ sql_print_warning(ER_DEFAULT(ER_FORCING_CLOSE),my_progname,
tmp->thread_id,
(tmp->main_security_ctx.user ?
tmp->main_security_ctx.user : ""));
@@ -1026,17 +1137,17 @@ static void close_connections(void)
}
#endif
DBUG_PRINT("quit",("Unlocking LOCK_thread_count"));
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
}
/* All threads has now been aborted */
DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count));
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
while (thread_count)
{
- (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
+ mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
DBUG_PRINT("quit",("One thread died (count=%u)",thread_count));
}
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
close_active_mi();
DBUG_PRINT("quit",("close_connections thread"));
@@ -1054,31 +1165,15 @@ static void close_server_sock()
{
ip_sock=INVALID_SOCKET;
DBUG_PRINT("info",("calling shutdown on TCP/IP socket"));
- VOID(shutdown(tmp_sock, SHUT_RDWR));
-#if defined(__NETWARE__)
- /*
- The following code is disabled for normal systems as it causes MySQL
- to hang on AIX 4.3 during shutdown
- */
- DBUG_PRINT("info",("calling closesocket on TCP/IP socket"));
- VOID(closesocket(tmp_sock));
-#endif
+ (void) shutdown(tmp_sock, SHUT_RDWR);
}
tmp_sock=unix_sock;
if (tmp_sock != INVALID_SOCKET)
{
unix_sock=INVALID_SOCKET;
DBUG_PRINT("info",("calling shutdown on unix socket"));
- VOID(shutdown(tmp_sock, SHUT_RDWR));
-#if defined(__NETWARE__)
- /*
- The following code is disabled for normal systems as it may cause MySQL
- to hang on AIX 4.3 during shutdown
- */
- DBUG_PRINT("info",("calling closesocket on unix/IP socket"));
- VOID(closesocket(tmp_sock));
-#endif
- VOID(unlink(mysqld_unix_port));
+ (void) shutdown(tmp_sock, SHUT_RDWR);
+ (void) unlink(mysqld_unix_port);
}
DBUG_VOID_RETURN;
#endif
@@ -1126,8 +1221,9 @@ void kill_mysql(void)
{
pthread_t tmp;
abort_loop=1;
- if (pthread_create(&tmp,&connection_attrib, kill_server_thread,
- (void*) 0))
+ if (mysql_thread_create(0, /* Not instrumented */
+ &tmp, &connection_attrib, kill_server_thread,
+ (void*) 0))
sql_print_error("Can't create thread to kill server");
}
#endif
@@ -1145,10 +1241,7 @@ void kill_mysql(void)
or stop, we just want to kill the server.
*/
-#if defined(__NETWARE__)
-extern "C" void kill_server(int sig_ptr)
-#define RETURN_FROM_KILL_SERVER return
-#elif !defined(__WIN__)
+#if !defined(__WIN__)
static void *kill_server(void *sig_ptr)
#define RETURN_FROM_KILL_SERVER return 0
#else
@@ -1170,9 +1263,9 @@ static void __cdecl kill_server(int sig_ptr)
if (sig != 0) // 0 is not a valid signal number
my_sigset(sig, SIG_IGN); /* purify inspected */
if (sig == MYSQL_KILL_SIGNAL || sig == 0)
- sql_print_information(ER(ER_NORMAL_SHUTDOWN),my_progname);
+ sql_print_information(ER_DEFAULT(ER_NORMAL_SHUTDOWN),my_progname);
else
- sql_print_error(ER(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */
+ sql_print_error(ER_DEFAULT(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */
#if defined(HAVE_SMEM) && defined(__WIN__)
/*
@@ -1194,11 +1287,6 @@ static void __cdecl kill_server(int sig_ptr)
unireg_end();
/* purecov: begin deadcode */
-#ifdef __NETWARE__
- if (!event_flag)
- pthread_join(select_thread, NULL); // wait for main thread
-#endif /* __NETWARE__ */
-
DBUG_LEAVE; // Must match DBUG_ENTER()
my_thread_end();
pthread_exit(0);
@@ -1215,7 +1303,7 @@ static void __cdecl kill_server(int sig_ptr)
}
-#if defined(USE_ONE_SIGNAL_HAND) || (defined(__NETWARE__) && defined(SIGNALS_DONT_BREAK_READ))
+#if defined(USE_ONE_SIGNAL_HAND)
pthread_handler_t kill_server_thread(void *arg __attribute__((unused)))
{
my_thread_init(); // Initialize new thread
@@ -1236,7 +1324,7 @@ extern "C" sig_handler print_signal_warning(int sig)
#ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY
my_sigset(sig,print_signal_warning); /* int. thread system calls */
#endif
-#if !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__)
if (sig == SIGALRM)
alarm(2); /* reschedule alarm */
#endif
@@ -1244,6 +1332,18 @@ extern "C" sig_handler print_signal_warning(int sig)
#ifndef EMBEDDED_LIBRARY
+static void init_error_log_mutex()
+{
+ mysql_mutex_init(key_LOCK_error_log, &LOCK_error_log, MY_MUTEX_INIT_FAST);
+}
+
+
+static void clean_up_error_log_mutex()
+{
+ mysql_mutex_destroy(&LOCK_error_log);
+}
+
+
/**
cleanup all memory and end program nicely.
@@ -1258,13 +1358,14 @@ void unireg_end(void)
{
clean_up(1);
my_thread_end();
-#if defined(SIGNALS_DONT_BREAK_READ) && !defined(__NETWARE__)
+#if defined(SIGNALS_DONT_BREAK_READ)
exit(0);
#else
pthread_exit(0); // Exit is in main thread
#endif
}
+
extern "C" void unireg_abort(int exit_code)
{
DBUG_ENTER("unireg_abort");
@@ -1275,14 +1376,31 @@ extern "C" void unireg_abort(int exit_code)
sql_print_error("Aborting\n");
clean_up(!opt_help && (exit_code || !opt_bootstrap)); /* purecov: inspected */
DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
+ mysqld_exit(exit_code);
+}
+
+static void mysqld_exit(int exit_code)
+{
+ /*
+ Important note: we wait for the signal thread to end,
+ but if a kill -15 signal was sent, the signal thread did
+ spawn the kill_server_thread thread, which is running concurrently.
+ */
wait_for_signal_thread_to_end();
+ mysql_audit_finalize();
clean_up_mutexes();
+ clean_up_error_log_mutex();
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+ /*
+ Bug#56666 needs to be fixed before calling:
+ shutdown_performance_schema();
+ */
+#endif
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
exit(exit_code); /* purecov: inspected */
}
-#endif /*EMBEDDED_LIBRARY*/
-
+#endif /* !EMBEDDED_LIBRARY */
void clean_up(bool print_message)
{
@@ -1309,20 +1427,17 @@ void clean_up(bool print_message)
bitmap_free(&slave_error_mask);
#endif
my_tz_free();
- my_database_names_free();
+ my_dboptions_cache_free();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
servers_free(1);
acl_free(1);
grant_free();
#endif
query_cache_destroy();
- table_cache_free();
- table_def_free();
hostname_cache_free();
item_user_lock_free();
lex_free(); /* Free some memory */
item_create_cleanup();
- set_var_free();
free_charsets();
if (!opt_noacl)
{
@@ -1330,35 +1445,24 @@ void clean_up(bool print_message)
udf_free();
#endif
}
+ table_def_start_shutdown();
plugin_shutdown();
ha_end();
if (tc_log)
tc_log->close();
+ delegates_destroy();
xid_cache_free();
- delete_elements(&key_caches, (void (*)(const char*, uchar*)) free_key_cache);
+ table_def_free();
+ mdl_destroy();
+ key_caches.delete_elements((void (*)(const char*, uchar*)) free_key_cache);
multi_keycache_free();
free_status_vars();
end_thr_alarm(1); /* Free allocated memory */
my_free_open_file_info();
- my_free((char*) global_system_variables.date_format,
- MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*) global_system_variables.time_format,
- MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*) global_system_variables.datetime_format,
- MYF(MY_ALLOW_ZERO_PTR));
if (defaults_argv)
free_defaults(defaults_argv);
- my_free(sys_init_connect.value, MYF(MY_ALLOW_ZERO_PTR));
- my_free(sys_init_slave.value, MYF(MY_ALLOW_ZERO_PTR));
- my_free(sys_var_general_log_path.value, MYF(MY_ALLOW_ZERO_PTR));
- my_free(sys_var_slow_log_path.value, MYF(MY_ALLOW_ZERO_PTR));
free_tmpdir(&mysql_tmpdir_list);
-#ifdef HAVE_REPLICATION
- my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR));
-#endif
- x_free(opt_bin_logname);
- x_free(opt_relay_logname);
- x_free(opt_secure_file_priv);
+ my_free(opt_bin_logname);
bitmap_free(&temp_pool);
free_max_user_conn();
#ifdef HAVE_REPLICATION
@@ -1366,13 +1470,9 @@ void clean_up(bool print_message)
#endif
delete binlog_filter;
delete rpl_filter;
-#ifndef EMBEDDED_LIBRARY
end_ssl();
-#endif
vio_end();
-#ifdef USE_REGEX
my_regex_end();
-#endif
#if defined(ENABLED_DEBUG_SYNC)
/* End the debug sync facility. See debug_sync.cc. */
debug_sync_end();
@@ -1380,23 +1480,27 @@ void clean_up(bool print_message)
#if !defined(EMBEDDED_LIBRARY)
if (!opt_bootstrap)
- (void) my_delete(pidfile_name,MYF(0)); // This may not always exist
+ mysql_file_delete(key_file_pid, pidfile_name, MYF(0)); // This may not always exist
#endif
- if (print_message && errmesg && server_start_time)
- sql_print_information(ER(ER_SHUTDOWN_COMPLETE),my_progname);
- thread_scheduler.end();
+ if (print_message && my_default_lc_messages && server_start_time)
+ sql_print_information(ER_DEFAULT(ER_SHUTDOWN_COMPLETE),my_progname);
+ cleanup_errmsgs();
+ MYSQL_CALLBACK(thread_scheduler, end, ());
+ mysql_client_plugin_deinit();
finish_client_errs();
- my_free((uchar*) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST),
- MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
+ (void) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST); // finish server errs
DBUG_PRINT("quit", ("Error messages freed"));
/* Tell main we are ready */
logger.cleanup_end();
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ my_atomic_rwlock_destroy(&global_query_id_lock);
+ my_atomic_rwlock_destroy(&thread_running_lock);
+ mysql_mutex_lock(&LOCK_thread_count);
DBUG_PRINT("quit", ("got thread count lock"));
ready_to_exit=1;
/* do the broadcast inside the lock to ensure that my_end() is not called */
- (void) pthread_cond_broadcast(&COND_thread_count);
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
+ sys_var_end();
/*
The following lines may never be executed as the main thread may have
@@ -1414,7 +1518,6 @@ void clean_up(bool print_message)
*/
static void wait_for_signal_thread_to_end()
{
-#ifndef __NETWARE__
uint i;
/*
Wait up to 10 seconds for signal thread to die. We use this mainly to
@@ -1426,59 +1529,46 @@ static void wait_for_signal_thread_to_end()
break;
my_sleep(100); // Give it time to die
}
-#endif
}
static void clean_up_mutexes()
{
- (void) pthread_mutex_destroy(&LOCK_mysql_create_db);
- (void) pthread_mutex_destroy(&LOCK_lock_db);
- (void) pthread_mutex_destroy(&LOCK_Acl);
- (void) rwlock_destroy(&LOCK_grant);
- (void) pthread_mutex_destroy(&LOCK_open);
- (void) pthread_mutex_destroy(&LOCK_thread_count);
- (void) pthread_mutex_destroy(&LOCK_mapped_file);
- (void) pthread_mutex_destroy(&LOCK_status);
- (void) pthread_mutex_destroy(&LOCK_error_log);
- (void) pthread_mutex_destroy(&LOCK_delayed_insert);
- (void) pthread_mutex_destroy(&LOCK_delayed_status);
- (void) pthread_mutex_destroy(&LOCK_delayed_create);
- (void) pthread_mutex_destroy(&LOCK_manager);
- (void) pthread_mutex_destroy(&LOCK_crypt);
- (void) pthread_mutex_destroy(&LOCK_bytes_sent);
- (void) pthread_mutex_destroy(&LOCK_bytes_received);
- (void) pthread_mutex_destroy(&LOCK_user_conn);
- (void) pthread_mutex_destroy(&LOCK_connection_count);
- Events::destroy_mutexes();
+ mysql_rwlock_destroy(&LOCK_grant);
+ mysql_mutex_destroy(&LOCK_thread_count);
+ mysql_mutex_destroy(&LOCK_status);
+ mysql_mutex_destroy(&LOCK_delayed_insert);
+ mysql_mutex_destroy(&LOCK_delayed_status);
+ mysql_mutex_destroy(&LOCK_delayed_create);
+ mysql_mutex_destroy(&LOCK_manager);
+ mysql_mutex_destroy(&LOCK_crypt);
+ mysql_mutex_destroy(&LOCK_user_conn);
+ mysql_mutex_destroy(&LOCK_connection_count);
#ifdef HAVE_OPENSSL
- (void) pthread_mutex_destroy(&LOCK_des_key_file);
+ mysql_mutex_destroy(&LOCK_des_key_file);
#ifndef HAVE_YASSL
for (int i= 0; i < CRYPTO_num_locks(); ++i)
- (void) rwlock_destroy(&openssl_stdlocks[i].lock);
+ mysql_rwlock_destroy(&openssl_stdlocks[i].lock);
OPENSSL_free(openssl_stdlocks);
#endif
#endif
#ifdef HAVE_REPLICATION
- (void) pthread_mutex_destroy(&LOCK_rpl_status);
- (void) pthread_cond_destroy(&COND_rpl_status);
-#endif
- (void) pthread_mutex_destroy(&LOCK_active_mi);
- (void) rwlock_destroy(&LOCK_sys_init_connect);
- (void) rwlock_destroy(&LOCK_sys_init_slave);
- (void) pthread_mutex_destroy(&LOCK_global_system_variables);
- (void) rwlock_destroy(&LOCK_system_variables_hash);
- (void) pthread_mutex_destroy(&LOCK_global_read_lock);
- (void) pthread_mutex_destroy(&LOCK_uuid_generator);
- (void) pthread_mutex_destroy(&LOCK_prepared_stmt_count);
- (void) pthread_cond_destroy(&COND_thread_count);
- (void) pthread_cond_destroy(&COND_refresh);
- (void) pthread_cond_destroy(&COND_global_read_lock);
- (void) pthread_cond_destroy(&COND_thread_cache);
- (void) pthread_cond_destroy(&COND_flush_thread_cache);
- (void) pthread_cond_destroy(&COND_manager);
+ mysql_mutex_destroy(&LOCK_rpl_status);
+ mysql_cond_destroy(&COND_rpl_status);
+#endif
+ mysql_mutex_destroy(&LOCK_active_mi);
+ mysql_rwlock_destroy(&LOCK_sys_init_connect);
+ mysql_rwlock_destroy(&LOCK_sys_init_slave);
+ mysql_mutex_destroy(&LOCK_global_system_variables);
+ mysql_rwlock_destroy(&LOCK_system_variables_hash);
+ mysql_mutex_destroy(&LOCK_uuid_generator);
+ mysql_mutex_destroy(&LOCK_prepared_stmt_count);
+ mysql_mutex_destroy(&LOCK_error_messages);
+ mysql_cond_destroy(&COND_thread_count);
+ mysql_cond_destroy(&COND_thread_cache);
+ mysql_cond_destroy(&COND_flush_thread_cache);
+ mysql_cond_destroy(&COND_manager);
}
-
#endif /*EMBEDDED_LIBRARY*/
@@ -1528,7 +1618,7 @@ static void set_ports()
static struct passwd *check_user(const char *user)
{
-#if !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__)
struct passwd *tmp_user_info;
uid_t user_id= geteuid();
@@ -1593,7 +1683,7 @@ err:
static void set_user(const char *user, struct passwd *user_info_arg)
{
/* purecov: begin tested */
-#if !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__)
DBUG_ASSERT(user_info_arg != 0);
#ifdef HAVE_INITGROUPS
/*
@@ -1623,7 +1713,7 @@ static void set_user(const char *user, struct passwd *user_info_arg)
static void set_effective_user(struct passwd *user_info_arg)
{
-#if !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__)
DBUG_ASSERT(user_info_arg != 0);
if (setregid((gid_t)-1, user_info_arg->pw_gid) == -1)
{
@@ -1642,7 +1732,7 @@ static void set_effective_user(struct passwd *user_info_arg)
/** Change root user if started with @c --chroot . */
static void set_root(const char *path)
{
-#if !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__)
if (chroot(path) == -1)
{
sql_perror("chroot");
@@ -1652,47 +1742,87 @@ static void set_root(const char *path)
#endif
}
+
static void network_init(void)
{
- struct sockaddr_in IPaddr;
#ifdef HAVE_SYS_UN_H
struct sockaddr_un UNIXaddr;
#endif
- int arg=1;
+ int arg;
int ret;
uint waited;
uint this_wait;
uint retry;
+ char port_buf[NI_MAXSERV];
DBUG_ENTER("network_init");
LINT_INIT(ret);
- if (thread_scheduler.init())
+ if (MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0))
unireg_abort(1); /* purecov: inspected */
set_ports();
if (mysqld_port != 0 && !opt_disable_networking && !opt_bootstrap)
{
+ struct addrinfo *ai, *a;
+ struct addrinfo hints;
+ int error;
DBUG_PRINT("general",("IP Socket is %d",mysqld_port));
- ip_sock = socket(AF_INET, SOCK_STREAM, 0);
+
+ bzero(&hints, sizeof (hints));
+ hints.ai_flags= AI_PASSIVE;
+ hints.ai_socktype= SOCK_STREAM;
+ hints.ai_family= AF_UNSPEC;
+
+ my_snprintf(port_buf, NI_MAXSERV, "%d", mysqld_port);
+ error= getaddrinfo(my_bind_addr_str, port_buf, &hints, &ai);
+ if (error != 0)
+ {
+ DBUG_PRINT("error",("Got error: %d from getaddrinfo()", error));
+ sql_perror(ER_DEFAULT(ER_IPSOCK_ERROR)); /* purecov: tested */
+ unireg_abort(1); /* purecov: tested */
+ }
+
+ for (a= ai; a != NULL; a= a->ai_next)
+ {
+ ip_sock= socket(a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (ip_sock != INVALID_SOCKET)
+ break;
+ }
+
if (ip_sock == INVALID_SOCKET)
{
DBUG_PRINT("error",("Got error: %d from socket()",socket_errno));
- sql_perror(ER(ER_IPSOCK_ERROR)); /* purecov: tested */
+ sql_perror(ER_DEFAULT(ER_IPSOCK_ERROR)); /* purecov: tested */
unireg_abort(1); /* purecov: tested */
}
- bzero((char*) &IPaddr, sizeof(IPaddr));
- IPaddr.sin_family = AF_INET;
- IPaddr.sin_addr.s_addr = my_bind_addr;
- IPaddr.sin_port = (unsigned short) htons((unsigned short) mysqld_port);
#ifndef __WIN__
/*
We should not use SO_REUSEADDR on windows as this would enable a
user to open two mysqld servers with the same TCP/IP port.
*/
+ arg= 1;
(void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg));
#endif /* __WIN__ */
+
+#ifdef IPV6_V6ONLY
+ /*
+ For interoperability with older clients, IPv6 socket should
+ listen on both IPv6 and IPv4 wildcard addresses.
+ Turn off IPV6_V6ONLY option.
+
+ NOTE: this will work starting from Windows Vista only.
+ On Windows XP dual stack is not available, so it will not
+ listen on the corresponding IPv4-address.
+ */
+ if (a->ai_family == AF_INET6)
+ {
+ arg= 0;
+ (void) setsockopt(ip_sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
+ sizeof(arg));
+ }
+#endif
/*
Sometimes the port is not released fast enough when stopping and
restarting the server. This happens quite often with the test suite
@@ -1703,8 +1833,7 @@ static void network_init(void)
*/
for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
{
- if (((ret= bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr),
- sizeof(IPaddr))) >= 0) ||
+ if (((ret= bind(ip_sock, a->ai_addr, a->ai_addrlen)) >= 0 ) ||
(socket_errno != SOCKET_EADDRINUSE) ||
(waited >= mysqld_port_timeout))
break;
@@ -1712,6 +1841,7 @@ static void network_init(void)
this_wait= retry * retry / 3 + 1;
sleep(this_wait);
}
+ freeaddrinfo(ai);
if (ret < 0)
{
DBUG_PRINT("error",("Got error: %d from bind",socket_errno));
@@ -1728,12 +1858,11 @@ static void network_init(void)
}
}
-#ifdef __NT__
+#ifdef _WIN32
/* create named pipe */
if (Service.IsNT() && mysqld_unix_port[0] && !opt_bootstrap &&
opt_enable_named_pipe)
{
-
strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\.\\pipe\\",
mysqld_unix_port, NullS);
bzero((char*) &saPipeSecurity, sizeof(saPipeSecurity));
@@ -1799,10 +1928,11 @@ static void network_init(void)
UNIXaddr.sun_family = AF_UNIX;
strmov(UNIXaddr.sun_path, mysqld_unix_port);
(void) unlink(mysqld_unix_port);
+ arg= 1;
(void) setsockopt(unix_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,
sizeof(arg));
umask(0);
- if (bind(unix_sock, my_reinterpret_cast(struct sockaddr *) (&UNIXaddr),
+ if (bind(unix_sock, reinterpret_cast<struct sockaddr *>(&UNIXaddr),
sizeof(UNIXaddr)) < 0)
{
sql_perror("Can't start server : Bind on unix socket"); /* purecov: tested */
@@ -1843,18 +1973,24 @@ void close_connection(THD *thd, uint errcode, bool lock)
DBUG_PRINT("enter",("fd: %s error: '%s'",
thd->net.vio ? vio_description(thd->net.vio) :
"(not connected)",
- errcode ? ER(errcode) : ""));
+ errcode ? ER_DEFAULT(errcode) : ""));
if (lock)
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->killed= THD::KILL_CONNECTION;
if ((vio= thd->net.vio) != 0)
{
if (errcode)
- net_send_error(thd, errcode, ER(errcode)); /* purecov: inspected */
+ net_send_error(thd, errcode,
+ ER_DEFAULT(errcode), NULL); /* purecov: inspected */
vio_close(vio); /* vio is freed in delete thd */
}
if (lock)
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
+ MYSQL_CONNECTION_DONE((int) errcode, thd->thread_id);
+ if (MYSQL_CONNECTION_DONE_ENABLED())
+ {
+ sleep(0); /* Workaround to avoid tailcall optimisation */
+ }
DBUG_VOID_RETURN;
}
#endif /* EMBEDDED_LIBRARY */
@@ -1869,7 +2005,7 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
if (thd && ! thd->bootstrap)
{
statistic_increment(killed_threads, &LOCK_status);
- thread_scheduler.end_thread(thd,0); /* purecov: inspected */
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd,0)); /* purecov: inspected */
}
DBUG_VOID_RETURN; /* purecov: deadcode */
}
@@ -1892,11 +2028,11 @@ void unlink_thd(THD *thd)
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
thd->cleanup();
- pthread_mutex_lock(&LOCK_connection_count);
+ mysql_mutex_lock(&LOCK_connection_count);
--connection_count;
- pthread_mutex_unlock(&LOCK_connection_count);
+ mysql_mutex_unlock(&LOCK_connection_count);
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thread_count--;
delete thd;
DBUG_VOID_RETURN;
@@ -1921,18 +2057,28 @@ void unlink_thd(THD *thd)
static bool cache_thread()
{
- safe_mutex_assert_owner(&LOCK_thread_count);
+ mysql_mutex_assert_owner(&LOCK_thread_count);
if (cached_thread_count < thread_cache_size &&
! abort_loop && !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++;
+
+#ifdef HAVE_PSI_INTERFACE
+ /*
+ Delete the instrumentation for the job that just completed,
+ before parking this pthread in the cache (blocked on COND_thread_cache).
+ */
+ if (likely(PSI_server != NULL))
+ PSI_server->delete_current_thread();
+#endif
+
while (!abort_loop && ! wake_thread && ! kill_cached_threads)
- (void) pthread_cond_wait(&COND_thread_cache, &LOCK_thread_count);
+ mysql_cond_wait(&COND_thread_cache, &LOCK_thread_count);
cached_thread_count--;
if (kill_cached_threads)
- pthread_cond_signal(&COND_flush_thread_cache);
+ mysql_cond_signal(&COND_flush_thread_cache);
if (wake_thread)
{
THD *thd;
@@ -1940,6 +2086,21 @@ static bool cache_thread()
thd= thread_cache.get();
thd->thread_stack= (char*) &thd; // For store_globals
(void) thd->store_globals();
+
+#ifdef HAVE_PSI_INTERFACE
+ /*
+ Create new instrumentation for the new THD job,
+ and attach it to this running pthread.
+ */
+ if (likely(PSI_server != NULL))
+ {
+ PSI_thread *psi= PSI_server->new_thread(key_thread_one_connection,
+ thd, thd->thread_id);
+ if (likely(psi != NULL))
+ PSI_server->set_thread(psi);
+ }
+#endif
+
/*
THD::mysys_var::abort is associated with physical thread rather
than with THD object. So we need to reset this flag before using
@@ -1980,7 +2141,7 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
unlink_thd(thd);
if (put_in_cache)
put_in_cache= cache_thread();
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
if (put_in_cache)
DBUG_RETURN(0); // Thread is reused
@@ -1988,7 +2149,7 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
DBUG_PRINT("signal", ("Broadcasting COND_thread_count"));
DBUG_LEAVE; // Must match DBUG_ENTER()
my_thread_end();
- (void) pthread_cond_broadcast(&COND_thread_count);
+ mysql_cond_broadcast(&COND_thread_count);
pthread_exit(0);
return 0; // Avoid compiler warnings
@@ -1997,15 +2158,15 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
void flush_thread_cache()
{
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
kill_cached_threads++;
while (cached_thread_count)
{
- pthread_cond_broadcast(&COND_thread_cache);
- pthread_cond_wait(&COND_flush_thread_cache,&LOCK_thread_count);
+ mysql_cond_broadcast(&COND_thread_cache);
+ mysql_cond_wait(&COND_flush_thread_cache, &LOCK_thread_count);
}
kill_cached_threads--;
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
}
@@ -2070,29 +2231,7 @@ static BOOL WINAPI console_event_handler( DWORD type )
}
-/*
- In Visual Studio 2005 and later, default SIGABRT handler will overwrite
- any unhandled exception filter set by the application and will try to
- call JIT debugger. This is not what we want, this we calling __debugbreak
- to stop in debugger, if process is being debugged or to generate
- EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
-*/
-#if (_MSC_VER >= 1400)
-static void my_sigabrt_handler(int sig)
-{
- __debugbreak();
-}
-#endif /*_MSC_VER >=1400 */
-
-void win_install_sigabrt_handler(void)
-{
-#if (_MSC_VER >=1400)
- /*abort() should not override our exception filter*/
- _set_abort_behavior(0,_CALL_REPORTFAULT);
- signal(SIGABRT,my_sigabrt_handler);
-#endif /* _MSC_VER >=1400 */
-}
#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER
#define DEBUGGER_ATTACH_TIMEOUT 120
@@ -2171,7 +2310,6 @@ LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers)
static void init_signals(void)
{
- win_install_sigabrt_handler();
if(opt_console)
SetConsoleCtrlHandler(console_event_handler,TRUE);
@@ -2209,243 +2347,7 @@ static void start_signal_handler(void)
static void check_data_home(const char *path)
{}
-
-#elif defined(__NETWARE__)
-
-/// down server event callback.
-void mysql_down_server_cb(void *, void *)
-{
- event_flag= TRUE;
- kill_server(0);
-}
-
-
-/// destroy callback resources.
-void mysql_cb_destroy(void *)
-{
- UnRegisterEventNotification(eh); // cleanup down event notification
- NX_UNWRAP_INTERFACE(ref);
- /* Deregister NSS volume deactivation event */
- NX_UNWRAP_INTERFACE(refneb);
- if (neb_consumer_id)
- UnRegisterConsumer(neb_consumer_id, NULL);
-}
-
-
-/// initialize callbacks.
-void mysql_cb_init()
-{
- // register for down server event
- void *handle = getnlmhandle();
- rtag_t rt= AllocateResourceTag(handle, "MySQL Down Server Callback",
- EventSignature);
- NX_WRAP_INTERFACE((void *)mysql_down_server_cb, 2, (void **)&ref);
- eh= RegisterForEventNotification(rt, EVENT_PRE_DOWN_SERVER,
- EVENT_PRIORITY_APPLICATION,
- NULL, ref, NULL);
-
- /*
- Register for volume deactivation event
- Wrap the callback function, as it is called by non-LibC thread
- */
- (void *) NX_WRAP_INTERFACE(neb_event_callback, 1, &refneb);
- registerwithneb();
-
- NXVmRegisterExitHandler(mysql_cb_destroy, NULL); // clean-up
-}
-
-
-/** To get the name of the NetWare volume having MySQL data folder. */
-static void getvolumename()
-{
- char *p;
- /*
- We assume that data path is already set.
- If not it won't come here. Terminate after volume name
- */
- if ((p= strchr(mysql_real_data_home, ':')))
- strmake(datavolname, mysql_real_data_home,
- (uint) (p - mysql_real_data_home));
-}
-
-
-/**
- Registering with NEB for NSS Volume Deactivation event.
-*/
-
-static void registerwithneb()
-{
-
- ConsumerRegistrationInfo reg_info;
-
- /* Clear NEB registration structure */
- bzero((char*) &reg_info, sizeof(struct ConsumerRegistrationInfo));
-
- /* Fill the NEB consumer information structure */
- reg_info.CRIVersion= 1; // NEB version
- /* NEB Consumer name */
- reg_info.CRIConsumerName= (BYTE *) "MySQL Database Server";
- /* Event of interest */
- reg_info.CRIEventName= (BYTE *) "NSS.ChangeVolState.Enter";
- reg_info.CRIUserParameter= NULL; // Consumer Info
- reg_info.CRIEventFlags= 0; // Event flags
- /* Consumer NLM handle */
- reg_info.CRIOwnerID= (LoadDefinitionStructure *)getnlmhandle();
- reg_info.CRIConsumerESR= NULL; // No consumer ESR required
- reg_info.CRISecurityToken= 0; // No security token for the event
- reg_info.CRIConsumerFlags= 0; // SMP_ENABLED_BIT;
- reg_info.CRIFilterName= 0; // No event filtering
- reg_info.CRIFilterDataLength= 0; // No filtering data
- reg_info.CRIFilterData= 0; // No filtering data
- /* Callback function for the event */
- (void *)reg_info.CRIConsumerCallback= (void *) refneb;
- reg_info.CRIOrder= 0; // Event callback order
- reg_info.CRIConsumerType= CHECK_CONSUMER; // Consumer type
-
- /* Register for the event with NEB */
- if (RegisterConsumer(&reg_info))
- {
- consoleprintf("Failed to register for NSS Volume Deactivation event \n");
- return;
- }
- /* This ID is required for deregistration */
- neb_consumer_id= reg_info.CRIConsumerID;
-
- /* Get MySQL data volume name, stored in global variable datavolname */
- getvolumename();
-
- /*
- Get the NSS volume ID of the MySQL Data volume.
- Volume ID is stored in a global variable
- */
- getvolumeID((BYTE*) datavolname);
-}
-
-
-/**
- Callback for NSS Volume Deactivation event.
-*/
-
-ulong neb_event_callback(struct EventBlock *eblock)
-{
- EventChangeVolStateEnter_s *voldata;
- extern bool nw_panic;
-
- voldata= (EventChangeVolStateEnter_s *)eblock->EBEventData;
-
- /* Deactivation of a volume */
- if ((voldata->oldState == zVOLSTATE_ACTIVE &&
- voldata->newState == zVOLSTATE_DEACTIVE ||
- voldata->newState == zVOLSTATE_MAINTENANCE))
- {
- /*
- Ensure that we bring down MySQL server only for MySQL data
- volume deactivation
- */
- if (!memcmp(&voldata->volID, &datavolid, sizeof(VolumeID_t)))
- {
- consoleprintf("MySQL data volume is deactivated, shutting down MySQL Server \n");
- event_flag= TRUE;
- nw_panic = TRUE;
- event_flag= TRUE;
- kill_server(0);
- }
- }
- return 0;
-}
-
-
-#define ADMIN_VOL_PATH "_ADMIN:/Volumes/"
-
-/**
- Function to get NSS volume ID of the MySQL data.
-*/
-static void getvolumeID(BYTE *volumeName)
-{
- char path[zMAX_FULL_NAME];
- Key_t rootKey= 0, fileKey= 0;
- QUAD getInfoMask;
- zInfo_s info;
- STATUS status;
-
- /* Get the root key */
- if ((status= zRootKey(0, &rootKey)) != zOK)
- {
- consoleprintf("\nGetNSSVolumeProperties - Failed to get root key, status: %d\n.", (int) status);
- goto exit;
- }
-
- /*
- Get the file key. This is the key to the volume object in the
- NSS admin volumes directory.
- */
-
- strxmov(path, (const char *) ADMIN_VOL_PATH, (const char *) volumeName,
- NullS);
- if ((status= zOpen(rootKey, zNSS_TASK, zNSPACE_LONG|zMODE_UTF8,
- (BYTE *) path, zRR_READ_ACCESS, &fileKey)) != zOK)
- {
- consoleprintf("\nGetNSSVolumeProperties - Failed to get file, status: %d\n.", (int) status);
- goto exit;
- }
-
- getInfoMask= zGET_IDS | zGET_VOLUME_INFO ;
- if ((status= zGetInfo(fileKey, getInfoMask, sizeof(info),
- zINFO_VERSION_A, &info)) != zOK)
- {
- consoleprintf("\nGetNSSVolumeProperties - Failed in zGetInfo, status: %d\n.", (int) status);
- goto exit;
- }
-
- /* Copy the data to global variable */
- datavolid.timeLow= info.vol.volumeID.timeLow;
- datavolid.timeMid= info.vol.volumeID.timeMid;
- datavolid.timeHighAndVersion= info.vol.volumeID.timeHighAndVersion;
- datavolid.clockSeqHighAndReserved= info.vol.volumeID.clockSeqHighAndReserved;
- datavolid.clockSeqLow= info.vol.volumeID.clockSeqLow;
- /* This is guranteed to be 6-byte length (but sizeof() would be better) */
- memcpy(datavolid.node, info.vol.volumeID.node, (unsigned int) 6);
-
-exit:
- if (rootKey)
- zClose(rootKey);
- if (fileKey)
- zClose(fileKey);
-}
-
-
-static void init_signals(void)
-{
- int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT};
-
- for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++)
- signal(signals[i], kill_server);
- mysql_cb_init(); // initialize callbacks
-
-}
-
-
-static void start_signal_handler(void)
-{
- // Save vm id of this process
- if (!opt_bootstrap)
- create_pid_file();
- // no signal handler
-}
-
-
-/**
- Warn if the data is on a Traditional volume.
-
- @note
- Already done by mysqld_safe
-*/
-
-static void check_data_home(const char *path)
-{
-}
-
-#endif /*__WIN__ || __NETWARE */
+#endif /* __WIN__ */
#ifdef HAVE_LINUXTHREADS
#define UNSAFE_DEFAULT_LINUX_THREADS 200
@@ -2499,14 +2401,15 @@ and this may fail.\n\n");
(ulong) dflt_key_cache->key_cache_mem_size);
fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size);
fprintf(stderr, "max_used_connections=%lu\n", max_used_connections);
- fprintf(stderr, "max_threads=%u\n", thread_scheduler.max_threads);
- fprintf(stderr, "threads_connected=%u\n", thread_count);
+ fprintf(stderr, "max_threads=%u\n", thread_scheduler->max_threads);
+ fprintf(stderr, "thread_count=%u\n", thread_count);
+ fprintf(stderr, "connection_count=%u\n", connection_count);
fprintf(stderr, "It is possible that mysqld could use up to \n\
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = %lu K\n\
bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size +
(global_system_variables.read_buff_size +
global_system_variables.sortbuff_size) *
- thread_scheduler.max_threads +
+ thread_scheduler->max_threads +
max_connections * sizeof(THD)) / 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
@@ -2616,7 +2519,7 @@ bugs.\n");
#endif
}
-#if !defined(__WIN__) && !defined(__NETWARE__)
+#if !defined(__WIN__)
#ifndef SA_RESETHAND
#define SA_RESETHAND 0
#endif
@@ -2713,8 +2616,6 @@ static void start_signal_handler(void)
#if !defined(HAVE_DEC_3_2_THREADS)
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM);
(void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
- if (!(opt_specialflag & SPECIAL_NO_PRIOR))
- my_pthread_attr_setprio(&thr_attr,INTERRUPT_PRIOR);
#if defined(__ia64__) || defined(__ia64)
/*
Peculiar things with ia64 platforms - it seems we only have half the
@@ -2726,15 +2627,16 @@ static void start_signal_handler(void)
#endif
#endif
- (void) pthread_mutex_lock(&LOCK_thread_count);
- if ((error=pthread_create(&signal_thread,&thr_attr,signal_hand,0)))
+ mysql_mutex_lock(&LOCK_thread_count);
+ if ((error= mysql_thread_create(key_thread_signal_hand,
+ &signal_thread, &thr_attr, signal_hand, 0)))
{
sql_print_error("Can't create interrupt-thread (error %d, errno: %d)",
error,errno);
exit(1);
}
- (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
(void) pthread_attr_destroy(&thr_attr);
DBUG_VOID_RETURN;
@@ -2756,7 +2658,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
This should actually be '+ max_number_of_slaves' instead of +10,
but the +10 should be quite safe.
*/
- init_thr_alarm(thread_scheduler.max_threads +
+ init_thr_alarm(thread_scheduler->max_threads +
global_system_variables.max_insert_delayed_threads + 10);
if (thd_lib_detected != THD_LIB_LT && (test_flags & TEST_SIGINT))
{
@@ -2784,11 +2686,11 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
This works by waiting for start_signal_handler to free mutex,
after which we signal it that we are ready.
At this pointer there is no other threads running, so there
- should not be any other pthread_cond_signal() calls.
+ should not be any other mysql_cond_signal() calls.
*/
- (void) pthread_mutex_lock(&LOCK_thread_count);
- (void) pthread_mutex_unlock(&LOCK_thread_count);
- (void) pthread_cond_broadcast(&COND_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_broadcast(&COND_thread_count);
(void) pthread_sigmask(SIG_BLOCK,&set,NULL);
for (;;)
@@ -2824,12 +2726,16 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
if (!abort_loop)
{
abort_loop=1; // mark abort for threads
+#ifdef HAVE_PSI_INTERFACE
+ /* Delete the instrumentation for the signal thread */
+ if (likely(PSI_server != NULL))
+ PSI_server->delete_current_thread();
+#endif
#ifdef USE_ONE_SIGNAL_HAND
pthread_t tmp;
- if (!(opt_specialflag & SPECIAL_NO_PRIOR))
- my_pthread_attr_setprio(&connection_attrib,INTERRUPT_PRIOR);
- if (pthread_create(&tmp,&connection_attrib, kill_server_thread,
- (void*) &sig))
+ if (mysql_thread_create(0, /* Not instrumented */
+ &tmp, &connection_attrib, kill_server_thread,
+ (void*) &sig))
sql_print_error("Can't create thread to kill server");
#else
kill_server((void*) sig); // MIT THREAD has a alarm thread
@@ -2888,11 +2794,11 @@ static void check_data_home(const char *path)
for the client.
*/
/* ARGSUSED */
-extern "C" int my_message_sql(uint error, const char *str, myf MyFlags);
+extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
-int my_message_sql(uint error, const char *str, myf MyFlags)
+void my_message_sql(uint error, const char *str, myf MyFlags)
{
- THD *thd;
+ THD *thd= current_thd;
DBUG_ENTER("my_message_sql");
DBUG_PRINT("error", ("error: %u message: '%s'", error, str));
@@ -2914,77 +2820,24 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
error= ER_UNKNOWN_ERROR;
}
- if ((thd= current_thd))
- {
- /*
- TODO: There are two exceptions mechanism (THD and sp_rcontext),
- this could be improved by having a common stack of handlers.
- */
- if (thd->handle_error(error, str,
- MYSQL_ERROR::WARN_LEVEL_ERROR))
- DBUG_RETURN(0);
-
- thd->is_slave_error= 1; // needed to catch query errors during replication
-
- /*
- thd->lex->current_select == 0 if lex structure is not inited
- (not query command (COM_QUERY))
- */
- if (thd->lex->current_select &&
- thd->lex->current_select->no_error && !thd->is_fatal_error)
- {
- DBUG_PRINT("error",
- ("Error converted to warning: current_select: no_error %d "
- "fatal_error: %d",
- (thd->lex->current_select ?
- thd->lex->current_select->no_error : 0),
- (int) thd->is_fatal_error));
- }
- else
- {
- if (! thd->main_da.is_error()) // Return only first message
- {
- thd->main_da.set_error_status(thd, error, str);
- }
- query_cache_abort(&thd->net);
- }
- /*
- If a continue handler is found, the error message will be cleared
- by the stored procedures code.
- */
- if (thd->spcont &&
- ! (MyFlags & ME_NO_SP_HANDLER) &&
- thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
- {
- /*
- Do not push any warnings, a handled error must be completely
- silenced.
- */
- DBUG_RETURN(0);
- }
-
- /* When simulating OOM, skip writing to error log to avoid mtr errors */
- DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(0););
+ mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_ERROR, error, str);
- if (!thd->no_warnings_for_error &&
- !(MyFlags & ME_NO_WARNING_FOR_ERROR))
- {
- /*
- Suppress infinite recursion if there a memory allocation error
- inside push_warning.
- */
- thd->no_warnings_for_error= TRUE;
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
- thd->no_warnings_for_error= FALSE;
- }
+ if (thd)
+ {
+ if (MyFlags & ME_FATALERROR)
+ thd->is_fatal_error= 1;
+ (void) thd->raise_condition(error,
+ NULL,
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ str);
}
/* When simulating OOM, skip writing to error log to avoid mtr errors */
- DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(0););
+ DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_VOID_RETURN;);
if (!thd || MyFlags & ME_NOREFRESH)
sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
@@ -3000,7 +2853,7 @@ void *my_str_malloc_mysqld(size_t size)
void my_str_free_mysqld(void *ptr)
{
- my_free((uchar*)ptr, MYF(MY_FAE));
+ my_free(ptr);
}
#endif /* EMBEDDED_LIBRARY */
@@ -3040,10 +2893,6 @@ sizeof(load_default_groups)/sizeof(load_default_groups[0]);
@param format_type What kind of format should be supported
@param var_ptr Pointer to variable that should be updated
- @note
- The default value is taken from either opt_date_time_formats[] or
- the ISO format (ANSI SQL)
-
@retval
0 ok
@retval
@@ -3051,27 +2900,21 @@ sizeof(load_default_groups)/sizeof(load_default_groups[0]);
*/
static bool init_global_datetime_format(timestamp_type format_type,
- DATE_TIME_FORMAT **var_ptr)
+ DATE_TIME_FORMAT *format)
{
- /* Get command line option */
- const char *str= opt_date_time_formats[format_type];
+ /*
+ Get command line option
+ format->format.str is already set by my_getopt
+ */
+ format->format.length= strlen(format->format.str);
- if (!str) // No specified format
- {
- str= get_date_time_format_str(&known_date_time_formats[ISO_FORMAT],
- format_type);
- /*
- Set the "command line" option to point to the generated string so
- that we can set global formats back to default
- */
- opt_date_time_formats[format_type]= str;
- }
- if (!(*var_ptr= date_time_format_make(format_type, str, strlen(str))))
+ if (parse_date_time_format(format_type, format))
{
- fprintf(stderr, "Wrong date/time format specifier: %s\n", str);
- return 1;
+ fprintf(stderr, "Wrong date/time format specifier: %s\n",
+ format->format.str);
+ return true;
}
- return 0;
+ return false;
}
SHOW_VAR com_status_vars[]= {
@@ -3086,7 +2929,6 @@ SHOW_VAR com_status_vars[]= {
{"alter_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_TABLE]), SHOW_LONG_STATUS},
{"alter_tablespace", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_TABLESPACE]), SHOW_LONG_STATUS},
{"analyze", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ANALYZE]), SHOW_LONG_STATUS},
- {"backup_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_BACKUP_TABLE]), SHOW_LONG_STATUS},
{"begin", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_BEGIN]), SHOW_LONG_STATUS},
{"binlog", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_BINLOG_BASE64_EVENT]), SHOW_LONG_STATUS},
{"call_procedure", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CALL]), SHOW_LONG_STATUS},
@@ -3133,8 +2975,6 @@ SHOW_VAR com_status_vars[]= {
{"install_plugin", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_INSTALL_PLUGIN]), SHOW_LONG_STATUS},
{"kill", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_KILL]), SHOW_LONG_STATUS},
{"load", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOAD]), SHOW_LONG_STATUS},
- {"load_master_data", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOAD_MASTER_DATA]), SHOW_LONG_STATUS},
- {"load_master_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOAD_MASTER_TABLE]), SHOW_LONG_STATUS},
{"lock_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOCK_TABLES]), SHOW_LONG_STATUS},
{"optimize", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_OPTIMIZE]), SHOW_LONG_STATUS},
{"preload_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PRELOAD_KEYS]), SHOW_LONG_STATUS},
@@ -3148,7 +2988,7 @@ SHOW_VAR com_status_vars[]= {
{"replace", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPLACE]), SHOW_LONG_STATUS},
{"replace_select", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPLACE_SELECT]), SHOW_LONG_STATUS},
{"reset", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESET]), SHOW_LONG_STATUS},
- {"restore_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESTORE_TABLE]), SHOW_LONG_STATUS},
+ {"resignal", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESIGNAL]), SHOW_LONG_STATUS},
{"revoke", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REVOKE]), SHOW_LONG_STATUS},
{"revoke_all", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REVOKE_ALL]), SHOW_LONG_STATUS},
{"rollback", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ROLLBACK]), SHOW_LONG_STATUS},
@@ -3156,12 +2996,12 @@ SHOW_VAR com_status_vars[]= {
{"savepoint", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SAVEPOINT]), SHOW_LONG_STATUS},
{"select", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SELECT]), SHOW_LONG_STATUS},
{"set_option", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SET_OPTION]), SHOW_LONG_STATUS},
+ {"signal", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SIGNAL]), SHOW_LONG_STATUS},
{"show_authors", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_AUTHORS]), SHOW_LONG_STATUS},
{"show_binlog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOG_EVENTS]), SHOW_LONG_STATUS},
{"show_binlogs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOGS]), SHOW_LONG_STATUS},
{"show_charsets", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CHARSETS]), SHOW_LONG_STATUS},
{"show_collations", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLLATIONS]), SHOW_LONG_STATUS},
- {"show_column_types", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLUMN_TYPES]), SHOW_LONG_STATUS},
{"show_contributors", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CONTRIBUTORS]), SHOW_LONG_STATUS},
{"show_create_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CREATE_DB]), SHOW_LONG_STATUS},
{"show_create_event", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CREATE_EVENT]), SHOW_LONG_STATUS},
@@ -3194,6 +3034,7 @@ SHOW_VAR com_status_vars[]= {
{"show_processlist", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PROCESSLIST]), SHOW_LONG_STATUS},
{"show_profile", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PROFILE]), SHOW_LONG_STATUS},
{"show_profiles", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PROFILES]), SHOW_LONG_STATUS},
+ {"show_relaylog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_RELAYLOG_EVENTS]), SHOW_LONG_STATUS},
{"show_slave_hosts", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_HOSTS]), SHOW_LONG_STATUS},
{"show_slave_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_STAT]), SHOW_LONG_STATUS},
{"show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS},
@@ -3226,10 +3067,21 @@ SHOW_VAR com_status_vars[]= {
{NullS, NullS, SHOW_LONG}
};
-static int init_common_variables(const char *conf_file_name, int argc,
- char **argv, const char **groups)
+/**
+ Create the name of the default general log file
+
+ @param[IN] buff Location for building new string.
+ @param[IN] log_ext The extension for the file (e.g .log)
+ @returns Pointer to a new string containing the name
+*/
+static inline char *make_default_log_name(char *buff,const char* log_ext)
{
- char buff[FN_REFLEN], *s;
+ return make_log_name(buff, default_logfile_name, log_ext);
+}
+
+static int init_common_variables()
+{
+ char buff[FN_REFLEN];
umask(((~my_umask) & 0666));
my_decimal_set_zero(&decimal_zero); // set decimal_zero constant;
tzset(); // Set tzname
@@ -3285,13 +3137,34 @@ static int init_common_variables(const char *conf_file_name, int argc,
strmake(glob_hostname, STRING_WITH_LEN("localhost"));
sql_print_warning("gethostname failed, using '%s' as hostname",
glob_hostname);
- strmake(pidfile_name, STRING_WITH_LEN("mysql"));
+ strmake(default_logfile_name, STRING_WITH_LEN("mysql"));
}
else
- strmake(pidfile_name, glob_hostname, sizeof(pidfile_name)-5);
+ strmake(default_logfile_name, glob_hostname,
+ sizeof(default_logfile_name)-5);
+
+ strmake(pidfile_name, default_logfile_name, sizeof(pidfile_name)-5);
strmov(fn_ext(pidfile_name),".pid"); // Add proper extension
/*
+ The default-storage-engine entry in my_long_options should have a
+ non-null default value. It was earlier intialized as
+ (longlong)"MyISAM" in my_long_options but this triggered a
+ compiler error in the Sun Studio 12 compiler. As a work-around we
+ set the def_value member to 0 in my_long_options and initialize it
+ to the correct value here.
+
+ From MySQL 5.5 onwards, the default storage engine is InnoDB
+ (except in the embedded server, where the default continues to
+ be MyISAM)
+ */
+#ifdef EMBEDDED_LIBRARY
+ default_storage_engine= const_cast<char *>("MyISAM");
+#else
+ default_storage_engine= const_cast<char *>("InnoDB");
+#endif
+
+ /*
Add server status variables to the dynamic list of
status variables that is shown by SHOW STATUS.
Later, in plugin_init, and mysql_install_plugin
@@ -3326,15 +3199,15 @@ static int init_common_variables(const char *conf_file_name, int argc,
SQLCOM_END + 8);
#endif
- orig_argc=argc;
- orig_argv=argv;
- load_defaults(conf_file_name, groups, &argc, &argv);
- defaults_argv=argv;
- defaults_argc=argc;
- if (get_options(&defaults_argc, defaults_argv))
+ if (get_options(&remaining_argc, &remaining_argv))
return 1;
set_server_version();
+#ifndef EMBEDDED_LIBRARY
+ if (opt_help && !opt_verbose)
+ unireg_abort(0);
+#endif /*!EMBEDDED_LIBRARY*/
+
DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname,
server_version, SYSTEM_TYPE,MACHINE_TYPE));
@@ -3342,10 +3215,70 @@ static int init_common_variables(const char *conf_file_name, int argc,
/* Initialize large page size */
if (opt_large_pages && (opt_large_page_size= my_get_large_page_size()))
{
+ DBUG_PRINT("info", ("Large page set, large_page_size = %d",
+ opt_large_page_size));
my_use_large_pages= 1;
my_large_page_size= opt_large_page_size;
}
+ else
+ {
+ opt_large_pages= 0;
+ /*
+ Either not configured to use large pages or Linux haven't
+ been compiled with large page support
+ */
+ }
#endif /* HAVE_LARGE_PAGES */
+#ifdef HAVE_SOLARIS_LARGE_PAGES
+#define LARGE_PAGESIZE (4*1024*1024) /* 4MB */
+#define SUPER_LARGE_PAGESIZE (256*1024*1024) /* 256MB */
+ if (opt_large_pages)
+ {
+ /*
+ tell the kernel that we want to use 4/256MB page for heap storage
+ and also for the stack. We use 4 MByte as default and if the
+ super-large-page is set we increase it to 256 MByte. 256 MByte
+ is for server installations with GBytes of RAM memory where
+ the MySQL Server will have page caches and other memory regions
+ measured in a number of GBytes.
+ We use as big pages as possible which isn't bigger than the above
+ desired page sizes.
+ */
+ int nelem;
+ size_t max_desired_page_size;
+ if (opt_super_large_pages)
+ max_desired_page_size= SUPER_LARGE_PAGESIZE;
+ else
+ max_desired_page_size= LARGE_PAGESIZE;
+ nelem = getpagesizes(NULL, 0);
+ if (nelem > 0)
+ {
+ size_t *pagesize = (size_t *) malloc(sizeof(size_t) * nelem);
+ if (pagesize != NULL && getpagesizes(pagesize, nelem) > 0)
+ {
+ size_t i, max_page_size= 0;
+ for (i= 0; i < nelem; i++)
+ {
+ if (pagesize[i] > max_page_size &&
+ pagesize[i] <= max_desired_page_size)
+ max_page_size= pagesize[i];
+ }
+ free(pagesize);
+ if (max_page_size > 0)
+ {
+ struct memcntl_mha mpss;
+
+ mpss.mha_cmd= MHA_MAPSIZE_BSSBRK;
+ mpss.mha_pagesize= max_page_size;
+ mpss.mha_flags= 0;
+ memcntl(NULL, 0, MC_HAT_ADVISE, (caddr_t)&mpss, 0, 0);
+ mpss.mha_cmd= MHA_MAPSIZE_STACK;
+ memcntl(NULL, 0, MC_HAT_ADVISE, (caddr_t)&mpss, 0, 0);
+ }
+ }
+ }
+ }
+#endif /* HAVE_SOLARIS_LARGE_PAGES */
/* connections and databases needs lots of files */
{
@@ -3399,23 +3332,22 @@ static int init_common_variables(const char *conf_file_name, int argc,
open_files_limit= files;
}
unireg_init(opt_specialflag); /* Set up extern variabels */
+ if (!(my_default_lc_messages=
+ my_locale_by_name(lc_messages)))
+ {
+ sql_print_error("Unknown locale: '%s'", lc_messages);
+ return 1;
+ }
+ global_system_variables.lc_messages= my_default_lc_messages;
if (init_errmessage()) /* Read error messages from file */
return 1;
init_client_errs();
+ mysql_client_plugin_init();
lex_init();
if (item_create_init())
return 1;
item_init();
- if (set_var_init())
- return 1;
-#ifdef HAVE_REPLICATION
- if (init_replication_sys_vars())
- return 1;
-#endif
- mysys_uses_curses=0;
-#ifdef USE_REGEX
my_regex_init(&my_charset_latin1);
-#endif
/*
Process a comma-separated character set list and choose
the first available character set. This is mostly for
@@ -3449,12 +3381,12 @@ static int init_common_variables(const char *conf_file_name, int argc,
default_collation= get_charset_by_name(default_collation_name, MYF(0));
if (!default_collation)
{
- sql_print_error(ER(ER_UNKNOWN_COLLATION), default_collation_name);
+ sql_print_error(ER_DEFAULT(ER_UNKNOWN_COLLATION), default_collation_name);
return 1;
}
if (!my_charset_same(default_charset_info, default_collation))
{
- sql_print_error(ER(ER_COLLATION_CHARSET_MISMATCH),
+ sql_print_error(ER_DEFAULT(ER_COLLATION_CHARSET_MISMATCH),
default_collation_name,
default_charset_info->csname);
return 1;
@@ -3466,8 +3398,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
global_system_variables.collation_database= default_charset_info;
global_system_variables.collation_connection= default_charset_info;
global_system_variables.character_set_results= default_charset_info;
- global_system_variables.character_set_client= default_charset_info;
-
+ global_system_variables.character_set_client= default_charset_info;
if (!(character_set_filesystem=
get_charset_by_csname(character_set_filesystem_name,
MY_CS_PRIMARY, MYF(MY_WME))))
@@ -3481,20 +3412,6 @@ static int init_common_variables(const char *conf_file_name, int argc,
return 1;
}
global_system_variables.lc_time_names= my_default_lc_time_names;
-
- sys_init_connect.value_length= 0;
- if ((sys_init_connect.value= opt_init_connect))
- sys_init_connect.value_length= strlen(opt_init_connect);
- else
- sys_init_connect.value=my_strdup("",MYF(0));
- sys_init_connect.is_os_charset= TRUE;
-
- sys_init_slave.value_length= 0;
- if ((sys_init_slave.value= opt_init_slave))
- sys_init_slave.value_length= strlen(opt_init_slave);
- else
- sys_init_slave.value=my_strdup("",MYF(0));
- sys_init_slave.is_os_charset= TRUE;
/* check log options and issue warnings if needed */
if (opt_log && opt_logname && !(log_output_options & LOG_FILE) &&
@@ -3506,16 +3423,20 @@ static int init_common_variables(const char *conf_file_name, int argc,
if (opt_slow_log && opt_slow_logname && !(log_output_options & LOG_FILE)
&& !(log_output_options & LOG_NONE))
sql_print_warning("Although a path was specified for the "
- "--log_slow_queries option, log tables are used. "
+ "--log-slow-queries option, log tables are used. "
"To enable logging to files use the --log-output=file option.");
- s= opt_logname ? opt_logname : make_default_log_name(buff, ".log");
- sys_var_general_log_path.value= my_strdup(s, MYF(0));
- sys_var_general_log_path.value_length= strlen(s);
+#define FIX_LOG_VAR(VAR, ALT) \
+ if (!VAR || !*VAR) \
+ { \
+ my_free(VAR); /* it could be an allocated empty string "" */ \
+ VAR= my_strdup(ALT, MYF(0)); \
+ }
- s= opt_slow_logname ? opt_slow_logname : make_default_log_name(buff, "-slow.log");
- sys_var_slow_log_path.value= my_strdup(s, MYF(0));
- sys_var_slow_log_path.value_length= strlen(s);
+ FIX_LOG_VAR(opt_logname,
+ make_default_log_name(buff, ".log"));
+ FIX_LOG_VAR(opt_slow_logname,
+ make_default_log_name(buff, "-slow.log"));
#if defined(ENABLED_DEBUG_SYNC)
/* Initialize the debug sync facility. See debug_sync.cc. */
@@ -3530,7 +3451,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
use_temp_pool= 0;
#endif
- if (my_database_names_init())
+ if (my_dboptions_cache_init())
return 1;
/*
@@ -3587,36 +3508,39 @@ You should consider changing lower_case_table_names to 1 or 2",
static int init_thread_environment()
{
- (void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_lock_db,MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_Acl,MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_open, MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_mapped_file,MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_status,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_error_log,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_delayed_insert,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_delayed_status,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_delayed_create,MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_manager,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
- (void) my_rwlock_init(&LOCK_system_variables_hash, NULL);
- (void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_prepared_stmt_count, MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_connection_count, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_thread_count, &LOCK_thread_count, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_status, &LOCK_status, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_delayed_insert,
+ &LOCK_delayed_insert, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_delayed_status,
+ &LOCK_delayed_status, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_delayed_create,
+ &LOCK_delayed_create, MY_MUTEX_INIT_SLOW);
+ mysql_mutex_init(key_LOCK_manager,
+ &LOCK_manager, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_crypt, &LOCK_crypt, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_user_conn, &LOCK_user_conn, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_active_mi, &LOCK_active_mi, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_global_system_variables,
+ &LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
+ mysql_rwlock_init(key_rwlock_LOCK_system_variables_hash,
+ &LOCK_system_variables_hash);
+ mysql_mutex_init(key_LOCK_prepared_stmt_count,
+ &LOCK_prepared_stmt_count, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_error_messages,
+ &LOCK_error_messages, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_uuid_generator,
+ &LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_connection_count,
+ &LOCK_connection_count, MY_MUTEX_INIT_FAST);
#ifdef HAVE_OPENSSL
- (void) pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_des_key_file,
+ &LOCK_des_key_file, MY_MUTEX_INIT_FAST);
#ifndef HAVE_YASSL
openssl_stdlocks= (openssl_lock_t*) OPENSSL_malloc(CRYPTO_num_locks() *
sizeof(openssl_lock_t));
for (int i= 0; i < CRYPTO_num_locks(); ++i)
- (void) my_rwlock_init(&openssl_stdlocks[i].lock, NULL);
+ mysql_rwlock_init(key_rwlock_openssl, &openssl_stdlocks[i].lock);
CRYPTO_set_dynlock_create_callback(openssl_dynlock_create);
CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy);
CRYPTO_set_dynlock_lock_callback(openssl_lock);
@@ -3624,21 +3548,20 @@ static int init_thread_environment()
CRYPTO_set_id_callback(openssl_id_function);
#endif
#endif
- (void) my_rwlock_init(&LOCK_sys_init_connect, NULL);
- (void) my_rwlock_init(&LOCK_sys_init_slave, NULL);
- (void) my_rwlock_init(&LOCK_grant, NULL);
- (void) pthread_cond_init(&COND_thread_count,NULL);
- (void) pthread_cond_init(&COND_refresh,NULL);
- (void) pthread_cond_init(&COND_global_read_lock,NULL);
- (void) pthread_cond_init(&COND_thread_cache,NULL);
- (void) pthread_cond_init(&COND_flush_thread_cache,NULL);
- (void) pthread_cond_init(&COND_manager,NULL);
+ mysql_rwlock_init(key_rwlock_LOCK_sys_init_connect, &LOCK_sys_init_connect);
+ mysql_rwlock_init(key_rwlock_LOCK_sys_init_slave, &LOCK_sys_init_slave);
+ mysql_rwlock_init(key_rwlock_LOCK_grant, &LOCK_grant);
+ mysql_cond_init(key_COND_thread_count, &COND_thread_count, NULL);
+ mysql_cond_init(key_COND_thread_cache, &COND_thread_cache, NULL);
+ mysql_cond_init(key_COND_flush_thread_cache, &COND_flush_thread_cache, NULL);
+ mysql_cond_init(key_COND_manager, &COND_manager, NULL);
#ifdef HAVE_REPLICATION
- (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST);
- (void) pthread_cond_init(&COND_rpl_status, NULL);
+ mysql_mutex_init(key_LOCK_rpl_status, &LOCK_rpl_status, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_rpl_status, &COND_rpl_status, NULL);
#endif
- (void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
- (void) pthread_cond_init(&COND_server_started,NULL);
+ mysql_mutex_init(key_LOCK_server_started,
+ &LOCK_server_started, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_server_started, &COND_server_started, NULL);
sp_cache_init();
#ifdef HAVE_EVENT_SCHEDULER
Events::init_mutexes();
@@ -3648,8 +3571,6 @@ static int init_thread_environment()
(void) pthread_attr_setdetachstate(&connection_attrib,
PTHREAD_CREATE_DETACHED);
pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM);
- if (!(opt_specialflag & SPECIAL_NO_PRIOR))
- my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR);
if (pthread_key_create(&THR_THD,NULL) ||
pthread_key_create(&THR_MALLOC,NULL))
@@ -3671,7 +3592,7 @@ static unsigned long openssl_id_function()
static openssl_lock_t *openssl_dynlock_create(const char *file, int line)
{
openssl_lock_t *lock= new openssl_lock_t;
- my_rwlock_init(&lock->lock, NULL);
+ mysql_rwlock_init(key_rwlock_openssl, &lock->lock);
return lock;
}
@@ -3679,7 +3600,7 @@ static openssl_lock_t *openssl_dynlock_create(const char *file, int line)
static void openssl_dynlock_destroy(openssl_lock_t *lock, const char *file,
int line)
{
- rwlock_destroy(&lock->lock);
+ mysql_rwlock_destroy(&lock->lock);
delete lock;
}
@@ -3705,16 +3626,16 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file,
switch (mode) {
case CRYPTO_LOCK|CRYPTO_READ:
what = "read lock";
- err = rw_rdlock(&lock->lock);
+ err= mysql_rwlock_rdlock(&lock->lock);
break;
case CRYPTO_LOCK|CRYPTO_WRITE:
what = "write lock";
- err = rw_wrlock(&lock->lock);
+ err= mysql_rwlock_wrlock(&lock->lock);
break;
case CRYPTO_UNLOCK|CRYPTO_READ:
case CRYPTO_UNLOCK|CRYPTO_WRITE:
what = "unlock";
- err = rw_unlock(&lock->lock);
+ err= mysql_rwlock_unlock(&lock->lock);
break;
default:
/* Unknown locking mode. */
@@ -3730,11 +3651,10 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file,
#endif /* HAVE_OPENSSL */
-#ifndef EMBEDDED_LIBRARY
-
static void init_ssl()
{
#ifdef HAVE_OPENSSL
+#ifndef EMBEDDED_LIBRARY
if (opt_use_ssl)
{
enum enum_ssl_init_error error= SSL_INITERR_NOERROR;
@@ -3756,6 +3676,9 @@ static void init_ssl()
{
have_ssl= SHOW_OPTION_DISABLED;
}
+#else
+ have_ssl= SHOW_OPTION_DISABLED;
+#endif /* ! EMBEDDED_LIBRARY */
if (des_key_file)
load_des_key_file(des_key_file);
#endif /* HAVE_OPENSSL */
@@ -3765,16 +3688,16 @@ static void init_ssl()
static void end_ssl()
{
#ifdef HAVE_OPENSSL
+#ifndef EMBEDDED_LIBRARY
if (ssl_acceptor_fd)
{
free_vio_ssl_acceptor_fd(ssl_acceptor_fd);
ssl_acceptor_fd= 0;
}
+#endif /* ! EMBEDDED_LIBRARY */
#endif /* HAVE_OPENSSL */
}
-#endif /* EMBEDDED_LIBRARY */
-
static int init_server_components()
{
@@ -3783,10 +3706,10 @@ static int init_server_components()
We need to call each of these following functions to ensure that
all things are initialized so that unireg_abort() doesn't fail
*/
- if (table_cache_init() | table_def_init() | hostname_cache_init())
+ mdl_init();
+ if (table_def_init() | hostname_cache_init())
unireg_abort(1);
- query_cache_result_size_limit(query_cache_limit);
query_cache_set_min_res_unit(query_cache_min_res_unit);
query_cache_init();
query_cache_resize(query_cache_size);
@@ -3812,8 +3735,13 @@ static int init_server_components()
else
fn_format(log_error_file, log_error_file_ptr, mysql_data_home, ".err",
MY_UNPACK_FILENAME | MY_SAFE_PATH);
+ /*
+ _ptr may have been set to my_disabled_option or "" if no argument was
+ passed, but we need to show the real name in SHOW VARIABLES:
+ */
+ log_error_file_ptr= log_error_file;
if (!log_error_file[0])
- opt_error_log= 1; // Too long file name
+ opt_error_log= 0; // Too long file name
else
{
my_bool res;
@@ -3828,94 +3756,42 @@ static int init_server_components()
}
}
+ proc_info_hook= set_thd_proc_info;
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+ /*
+ Parsing the performance schema command line option may have reported
+ warnings/information messages.
+ Now that the logger is finally available, and redirected
+ to the proper file when the --log--error option is used,
+ print the buffered messages to the log.
+ */
+ buffered_logs.print();
+ buffered_logs.cleanup();
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
if (xid_cache_init())
{
sql_print_error("Out of memory");
unireg_abort(1);
}
+ /*
+ initialize delegates for extension observers, errors have already
+ been reported in the function
+ */
+ if (delegates_init())
+ unireg_abort(1);
+
/* need to configure logging before initializing storage engines */
- if (opt_update_log)
- {
- /*
- Update log is removed since 5.0. But we still accept the option.
- The idea is if the user already uses the binlog and the update log,
- we completely ignore any option/variable related to the update log, like
- if the update log did not exist. But if the user uses only the update
- log, then we translate everything into binlog for him (with warnings).
- Implementation of the above :
- - If mysqld is started with --log-update and --log-bin,
- ignore --log-update (print a warning), push a warning when SQL_LOG_UPDATE
- is used, and turn off --sql-bin-update-same.
- This will completely ignore SQL_LOG_UPDATE
- - If mysqld is started with --log-update only,
- change it to --log-bin (with the filename passed to log-update,
- plus '-bin') (print a warning), push a warning when SQL_LOG_UPDATE is
- used, and turn on --sql-bin-update-same.
- This will translate SQL_LOG_UPDATE to SQL_LOG_BIN.
-
- Note that we tell the user that --sql-bin-update-same is deprecated and
- does nothing, and we don't take into account if he used this option or
- not; but internally we give this variable a value to have the behaviour
- we want (i.e. have SQL_LOG_UPDATE influence SQL_LOG_BIN or not).
- As sql-bin-update-same, log-update and log-bin cannot be changed by the
- user after starting the server (they are not variables), the user will
- not later interfere with the settings we do here.
- */
- if (opt_bin_log)
- {
- opt_sql_bin_update= 0;
- sql_print_error("The update log is no longer supported by MySQL in \
-version 5.0 and above. It is replaced by the binary log.");
- }
- else
- {
- opt_sql_bin_update= 1;
- opt_bin_log= 1;
- if (opt_update_logname)
- {
- /* as opt_bin_log==0, no need to free opt_bin_logname */
- if (!(opt_bin_logname= my_strdup(opt_update_logname, MYF(MY_WME))))
- {
- sql_print_error("Out of memory");
- return EXIT_OUT_OF_MEMORY;
- }
- sql_print_error("The update log is no longer supported by MySQL in \
-version 5.0 and above. It is replaced by the binary log. Now starting MySQL \
-with --log-bin='%s' instead.",opt_bin_logname);
- }
- else
- sql_print_error("The update log is no longer supported by MySQL in \
-version 5.0 and above. It is replaced by the binary log. Now starting MySQL \
-with --log-bin instead.");
- }
- }
if (opt_log_slave_updates && !opt_bin_log)
{
- sql_print_error("You need to use --log-bin to make "
+ sql_print_warning("You need to use --log-bin to make "
"--log-slave-updates work.");
- unireg_abort(1);
}
- if (!opt_bin_log)
- {
- if (opt_binlog_format_id != BINLOG_FORMAT_UNSPEC)
- {
- sql_print_error("You need to use --log-bin to make "
+ if (!opt_bin_log && binlog_format_used)
+ sql_print_warning("You need to use --log-bin to make "
"--binlog-format work.");
- unireg_abort(1);
- }
- else
- {
- global_system_variables.binlog_format= BINLOG_FORMAT_STMT;
- }
- }
- else
- if (opt_binlog_format_id == BINLOG_FORMAT_UNSPEC)
- global_system_variables.binlog_format= BINLOG_FORMAT_STMT;
- else
- {
- DBUG_ASSERT(global_system_variables.binlog_format != BINLOG_FORMAT_UNSPEC);
- }
/* Check that we have not let the format to unspecified at this point */
DBUG_ASSERT((uint)global_system_variables.binlog_format <=
@@ -3924,11 +3800,17 @@ with --log-bin instead.");
#ifdef HAVE_REPLICATION
if (opt_log_slave_updates && replicate_same_server_id)
{
- sql_print_error("\
-using --replicate-same-server-id in conjunction with \
+ if (opt_bin_log)
+ {
+ sql_print_error("using --replicate-same-server-id in conjunction with \
--log-slave-updates is impossible, it would lead to infinite loops in this \
server.");
- unireg_abort(1);
+ unireg_abort(1);
+ }
+ else
+ sql_print_warning("using --replicate-same-server-id in conjunction with \
+--log-slave-updates would lead to infinite loops in this server. However this \
+will be ignored as the --log-bin option is not defined.");
}
#endif
@@ -3975,7 +3857,7 @@ a file name for --log-bin-index option", opt_binlog_index_name);
}
if (ln == buf)
{
- my_free(opt_bin_logname, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_bin_logname);
opt_bin_logname=my_strdup(buf, MYF(0));
}
if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln, TRUE))
@@ -3991,25 +3873,26 @@ a file name for --log-bin-index option", opt_binlog_index_name);
if (ha_init_errors())
DBUG_RETURN(1);
- {
- if (plugin_init(&defaults_argc, defaults_argv,
- (opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
- (opt_help ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))
- {
- sql_print_error("Failed to initialize plugins.");
- unireg_abort(1);
- }
- plugins_are_initialized= TRUE; /* Don't separate from init function */
+ if (plugin_init(&remaining_argc, remaining_argv,
+ (opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
+ (opt_help ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))
+ {
+ sql_print_error("Failed to initialize plugins.");
+ unireg_abort(1);
}
+ plugins_are_initialized= TRUE; /* Don't separate from init function */
- if (opt_help)
- unireg_abort(0);
+ have_csv= plugin_status(STRING_WITH_LEN("csv"),
+ MYSQL_STORAGE_ENGINE_PLUGIN);
+ have_ndbcluster= plugin_status(STRING_WITH_LEN("ndbcluster"),
+ MYSQL_STORAGE_ENGINE_PLUGIN);
+ have_partitioning= plugin_status(STRING_WITH_LEN("partition"),
+ MYSQL_STORAGE_ENGINE_PLUGIN);
/* we do want to exit if there are any other unknown options */
- if (defaults_argc > 1)
+ if (remaining_argc > 1)
{
int ho_error;
- char **tmp_argv= defaults_argv;
struct my_option no_opts[]=
{
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
@@ -4017,28 +3900,32 @@ a file name for --log-bin-index option", opt_binlog_index_name);
/*
We need to eat any 'loose' arguments first before we conclude
that there are unprocessed options.
- But we need to preserve defaults_argv pointer intact for
- free_defaults() to work. Thus we use a copy here.
*/
my_getopt_skip_unknown= 0;
- if ((ho_error= handle_options(&defaults_argc, &tmp_argv, no_opts,
+ if ((ho_error= handle_options(&remaining_argc, &remaining_argv, no_opts,
mysqld_get_one_option)))
unireg_abort(ho_error);
+ /* Add back the program name handle_options removes */
+ remaining_argc++;
+ remaining_argv--;
my_getopt_skip_unknown= TRUE;
- if (defaults_argc)
+ if (remaining_argc > 1)
{
fprintf(stderr, "%s: Too many arguments (first extra is '%s').\n"
"Use --verbose --help to get a list of available options\n",
- my_progname, *tmp_argv);
+ my_progname, remaining_argv[1]);
unireg_abort(1);
}
}
+ if (opt_help)
+ unireg_abort(0);
+
/* if the errmsg.sys is not loaded, terminate to maintain behaviour */
- if (!errmesg[0][0])
- unireg_abort(1);
+ if (!DEFAULT_ERRMSGS[0][0])
+ unireg_abort(1);
/* We have to initialize the storage engines before CSV logging */
if (ha_init())
@@ -4087,42 +3974,37 @@ a file name for --log-bin-index option", opt_binlog_index_name);
#endif
/*
- Check that the default storage engine is actually available.
+ Set the default storage engine
*/
- if (default_storage_engine_str)
+ LEX_STRING name= { default_storage_engine, strlen(default_storage_engine) };
+ plugin_ref plugin;
+ handlerton *hton;
+ if ((plugin= ha_resolve_by_name(0, &name)))
+ hton= plugin_data(plugin, handlerton*);
+ else
{
- LEX_STRING name= { default_storage_engine_str,
- strlen(default_storage_engine_str) };
- plugin_ref plugin;
- handlerton *hton;
-
- if ((plugin= ha_resolve_by_name(0, &name)))
- hton= plugin_data(plugin, handlerton*);
- else
+ sql_print_error("Unknown/unsupported storage engine: %s",
+ default_storage_engine);
+ unireg_abort(1);
+ }
+ if (!ha_storage_engine_is_enabled(hton))
+ {
+ if (!opt_bootstrap)
{
- sql_print_error("Unknown/unsupported table type: %s",
- default_storage_engine_str);
+ sql_print_error("Default storage engine (%s) is not available",
+ default_storage_engine);
unireg_abort(1);
}
- if (!ha_storage_engine_is_enabled(hton))
- {
- if (!opt_bootstrap)
- {
- sql_print_error("Default storage engine (%s) is not available",
- default_storage_engine_str);
- unireg_abort(1);
- }
- DBUG_ASSERT(global_system_variables.table_plugin);
- }
- else
- {
- /*
- Need to unlock as global_system_variables.table_plugin
- was acquired during plugin_init()
- */
- plugin_unlock(0, global_system_variables.table_plugin);
- global_system_variables.table_plugin= plugin;
- }
+ DBUG_ASSERT(global_system_variables.table_plugin);
+ }
+ else
+ {
+ /*
+ Need to unlock as global_system_variables.table_plugin
+ was acquired during plugin_init()
+ */
+ plugin_unlock(0, global_system_variables.table_plugin);
+ global_system_variables.table_plugin= plugin;
}
tc_log= (total_ha_2pc > 1 ? (opt_bin_log ?
@@ -4153,10 +4035,6 @@ a file name for --log-bin-index option", opt_binlog_index_name);
mysql_bin_log.purge_logs_before_date(purge_time);
}
#endif
-#ifdef __NETWARE__
- /* Increasing stacksize of threads on NetWare */
- pthread_attr_setstacksize(&connection_attrib, NW_THD_STACKSIZE);
-#endif
if (opt_myisam_log)
(void) mi_log(1);
@@ -4197,7 +4075,8 @@ static void create_shutdown_thread()
#ifdef __WIN__
hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name);
pthread_t hThread;
- if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0))
+ if (mysql_thread_create(key_thread_handle_shutdown,
+ &hThread, &connection_attrib, handle_shutdown, 0))
sql_print_warning("Can't create thread to handle shutdown requests");
// On "Stop Service" we have to do regular shutdown
@@ -4208,12 +4087,11 @@ static void create_shutdown_thread()
#endif /* EMBEDDED_LIBRARY */
-#if (defined(__NT__) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
+#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
static void handle_connections_methods()
{
pthread_t hThread;
DBUG_ENTER("handle_connections_methods");
-#ifdef __NT__
if (hPipe == INVALID_HANDLE_VALUE &&
(!have_tcpip || opt_disable_networking) &&
!opt_enable_shared_memory)
@@ -4221,28 +4099,27 @@ static void handle_connections_methods()
sql_print_error("TCP/IP, --shared-memory, or --named-pipe should be configured on NT OS");
unireg_abort(1); // Will not return
}
-#endif
- pthread_mutex_lock(&LOCK_thread_count);
- (void) pthread_cond_init(&COND_handler_count,NULL);
+ mysql_mutex_lock(&LOCK_thread_count);
+ mysql_cond_init(key_COND_handler_count, &COND_handler_count, NULL);
handler_count=0;
-#ifdef __NT__
if (hPipe != INVALID_HANDLE_VALUE)
{
handler_count++;
- if (pthread_create(&hThread,&connection_attrib,
- handle_connections_namedpipes, 0))
+ if (mysql_thread_create(key_thread_handle_con_namedpipes,
+ &hThread, &connection_attrib,
+ handle_connections_namedpipes, 0))
{
sql_print_warning("Can't create thread to handle named pipes");
handler_count--;
}
}
-#endif /* __NT__ */
if (have_tcpip && !opt_disable_networking)
{
handler_count++;
- if (pthread_create(&hThread,&connection_attrib,
- handle_connections_sockets, 0))
+ if (mysql_thread_create(key_thread_handle_con_sockets,
+ &hThread, &connection_attrib,
+ handle_connections_sockets_thread, 0))
{
sql_print_warning("Can't create thread to handle TCP/IP");
handler_count--;
@@ -4252,8 +4129,9 @@ static void handle_connections_methods()
if (opt_enable_shared_memory)
{
handler_count++;
- if (pthread_create(&hThread,&connection_attrib,
- handle_connections_shared_memory, 0))
+ if (mysql_thread_create(key_thread_handle_con_sharedmem,
+ &hThread, &connection_attrib,
+ handle_connections_shared_memory, 0))
{
sql_print_warning("Can't create thread to handle shared memory");
handler_count--;
@@ -4262,22 +4140,22 @@ static void handle_connections_methods()
#endif
while (handler_count > 0)
- pthread_cond_wait(&COND_handler_count,&LOCK_thread_count);
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_wait(&COND_handler_count, &LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
}
void decrement_handler_count()
{
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
handler_count--;
- pthread_cond_signal(&COND_handler_count);
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_signal(&COND_handler_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
my_thread_end();
}
#else
#define decrement_handler_count()
-#endif /* defined(__NT__) || defined(HAVE_SMEM) */
+#endif /* defined(_WIN32) || defined(HAVE_SMEM) */
#ifndef EMBEDDED_LIBRARY
@@ -4318,15 +4196,124 @@ static void test_lc_time_sz()
}
#endif//DBUG_OFF
-
#ifdef __WIN__
int win_main(int argc, char **argv)
#else
-int main(int argc, char **argv)
+int mysqld_main(int argc, char **argv)
#endif
{
- MY_INIT(argv[0]); // init my_sys library & pthreads
- /* nothing should come before this line ^^^ */
+ /*
+ Perform basic thread library and malloc initialization,
+ to be able to read defaults files and parse options.
+ */
+ my_progname= argv[0];
+ if (my_basic_init())
+ {
+ fprintf(stderr, "my_basic_init() failed.");
+ return 1;
+ }
+
+ orig_argc= argc;
+ orig_argv= argv;
+ if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv))
+ return 1;
+ defaults_argc= argc;
+ defaults_argv= argv;
+ remaining_argc= argc;
+ remaining_argv= argv;
+
+ /* Must be initialized early for comparison of options name */
+ system_charset_info= &my_charset_utf8_general_ci;
+
+ sys_var_init();
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+ /*
+ The performance schema needs to be initialized as early as possible,
+ before to-be-instrumented objects of the server are initialized.
+ */
+ int ho_error;
+ DYNAMIC_ARRAY all_early_options;
+
+ my_getopt_register_get_addr(NULL);
+ /* Skip unknown options so that they may be processed later */
+ my_getopt_skip_unknown= TRUE;
+
+ /* prepare all_early_options array */
+ my_init_dynamic_array(&all_early_options, sizeof(my_option), 100, 25);
+ sys_var_add_options(&all_early_options, sys_var::PARSE_EARLY);
+ add_terminator(&all_early_options);
+
+ /*
+ Logs generated while parsing the command line
+ options are buffered and printed later.
+ */
+ buffered_logs.init();
+ my_getopt_error_reporter= buffered_option_error_reporter;
+
+ ho_error= handle_options(&remaining_argc, &remaining_argv,
+ (my_option*)(all_early_options.buffer), NULL);
+ delete_dynamic(&all_early_options);
+ if (ho_error == 0)
+ {
+ /* Add back the program name handle_options removes */
+ remaining_argc++;
+ remaining_argv--;
+ if (pfs_param.m_enabled)
+ {
+ PSI_hook= initialize_performance_schema(&pfs_param);
+ if (PSI_hook == NULL)
+ {
+ pfs_param.m_enabled= false;
+ buffered_logs.buffer(WARNING_LEVEL,
+ "Performance schema disabled (reason: init failed).");
+ }
+ }
+ }
+#else
+ /*
+ Other provider of the instrumentation interface should
+ initialize PSI_hook here:
+ - HAVE_PSI_INTERFACE is for the instrumentation interface
+ - WITH_PERFSCHEMA_STORAGE_ENGINE is for one implementation
+ of the interface,
+ but there could be alternate implementations, which is why
+ these two defines are kept separate.
+ */
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
+#ifdef HAVE_PSI_INTERFACE
+ /*
+ Obtain the current performance schema instrumentation interface,
+ if available.
+ */
+ if (PSI_hook)
+ PSI_server= (PSI*) PSI_hook->get_interface(PSI_CURRENT_VERSION);
+
+ if (PSI_server)
+ {
+ /*
+ Now that we have parsed the command line arguments, and have initialized
+ the performance schema itself, the next step is to register all the
+ server instruments.
+ */
+ init_server_psi_keys();
+ /* Instrument the main thread */
+ PSI_thread *psi= PSI_server->new_thread(key_thread_main, NULL, 0);
+ if (psi)
+ PSI_server->set_thread(psi);
+
+ /*
+ Now that some instrumentation is in place,
+ recreate objects which were initialised early,
+ so that they are instrumented as well.
+ */
+ my_thread_basic_global_reinit();
+ }
+#endif /* HAVE_PSI_INTERFACE */
+
+ my_init(); // init my_sys library & pthreads
+ init_error_log_mutex();
/* Set signal used to kill MySQL */
#if defined(SIGUSR2)
@@ -4335,12 +4322,37 @@ int main(int argc, char **argv)
thr_kill_signal= SIGINT;
#endif
+ /* Initialize audit interface globals. Audit plugins are inited later. */
+ mysql_audit_initialize();
+
/*
Perform basic logger initialization logger. Should be called after
MY_INIT, as it initializes mutexes. Log tables are inited later.
*/
logger.init_base();
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+ if (ho_error)
+ {
+ /*
+ Parsing command line option failed,
+ Since we don't have a workable remaining_argc/remaining_argv
+ to continue the server initialization, this is as far as this
+ code can go.
+ This is the best effort to log meaningful messages:
+ - messages will be printed to stderr, which is not redirected yet,
+ - messages will be printed in the NT event log, for windows.
+ */
+ buffered_logs.print();
+ buffered_logs.cleanup();
+ /*
+ Not enough initializations for unireg_abort()
+ Using exit() for windows.
+ */
+ exit (ho_error);
+ }
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
#ifdef _CUSTOMSTARTUPCONFIG_
if (_cust_check_startup())
{
@@ -4349,29 +4361,10 @@ int main(int argc, char **argv)
}
#endif
-#ifdef __WIN__
- /*
- Before performing any socket operation (like retrieving hostname
- in init_common_variables we have to call WSAStartup
- */
- {
- WSADATA WsaData;
- if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
- {
- /* errors are not read yet, so we use english text here */
- my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0));
- unireg_abort(1);
- }
- }
-#endif /* __WIN__ */
-
- if (init_common_variables(MYSQL_CONFIG_NAME,
- argc, argv, load_default_groups))
+ if (init_common_variables())
unireg_abort(1); // Will do exit
init_signals();
- if (!(opt_specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),CONNECT_PRIOR);
#if defined(__ia64__) || defined(__ia64)
/*
Peculiar things with ia64 platforms - it seems we only have half the
@@ -4403,10 +4396,6 @@ int main(int argc, char **argv)
}
}
#endif
-#ifdef __NETWARE__
- /* Increasing stacksize of threads on NetWare */
- pthread_attr_setstacksize(&connection_attrib, NW_THD_STACKSIZE);
-#endif
(void) thr_setconcurrency(concurrency); // 10 by default
@@ -4428,10 +4417,6 @@ int main(int argc, char **argv)
check_data_home(mysql_real_data_home);
if (my_setwd(mysql_real_data_home,MYF(MY_WME)) && !opt_help)
unireg_abort(1); /* purecov: inspected */
- mysql_data_home= mysql_data_home_buff;
- mysql_data_home[0]=FN_CURLIB; // all paths are relative from here
- mysql_data_home[1]=0;
- mysql_data_home_len= 2;
if ((user_info= check_user(mysqld_user)))
{
@@ -4445,21 +4430,12 @@ int main(int argc, char **argv)
if (opt_bin_log && !server_id)
{
- server_id= !master_host ? 1 : 2;
+ server_id= 1;
#ifdef EXTRA_DEBUG
- switch (server_id) {
- case 1:
- sql_print_warning("\
-You have enabled the binary log, but you haven't set server-id to \
-a non-zero value: we force server id to 1; updates will be logged to the \
-binary log, but connections from slaves will not be accepted.");
- break;
- case 2:
- sql_print_warning("\
-You should set server-id to a non-0 value if master_host is set; \
-we force server id to 2, but this MySQL server will not act as a slave.");
- break;
- }
+ sql_print_warning("You have enabled the binary log, but you haven't set "
+ "server-id to a non-zero value: we force server id to 1; "
+ "updates will be logged to the binary log, but "
+ "connections from slaves will not be accepted.");
#endif
}
@@ -4497,17 +4473,18 @@ we force server id to 2, but this MySQL server will not act as a slave.");
{
abort_loop=1;
select_thread_in_use=0;
-#ifndef __NETWARE__
+
(void) pthread_kill(signal_thread, MYSQL_KILL_SIGNAL);
-#endif /* __NETWARE__ */
+
if (!opt_bootstrap)
- (void) my_delete(pidfile_name,MYF(MY_WME)); // Not needed anymore
+ mysql_file_delete(key_file_pid, pidfile_name, MYF(MY_WME)); // Not needed anymore
if (unix_sock != INVALID_SOCKET)
unlink(mysqld_unix_port);
exit(1);
}
+
if (!opt_noacl)
(void) grant_init();
@@ -4524,6 +4501,8 @@ we force server id to 2, but this MySQL server will not act as a slave.");
init_status_vars();
if (opt_bootstrap) /* If running with bootstrap, do not start replication. */
opt_skip_slave_start= 1;
+
+ binlog_unsafe_map_init();
/*
init_slave() must be called after the thread keys are created.
Some parts of the code (e.g. SHOW STATUS LIKE 'slave_running' and other
@@ -4535,6 +4514,20 @@ we force server id to 2, but this MySQL server will not act as a slave.");
unireg_abort(1);
}
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+ initialize_performance_schema_acl(opt_bootstrap);
+ /*
+ Do not check the structure of the performance schema tables
+ during bootstrap:
+ - the tables are not supposed to exist yet, bootstrap will create them
+ - a check would print spurious error messages
+ */
+ if (! opt_bootstrap)
+ check_performance_schema();
+#endif
+
+ initialize_information_schema_acl();
+
execute_ddl_log_recovery();
if (Events::init(opt_noacl || opt_bootstrap))
@@ -4543,10 +4536,10 @@ we force server id to 2, but this MySQL server will not act as a slave.");
if (opt_bootstrap)
{
select_thread_in_use= 0; // Allow 'kill' to work
- bootstrap(stdin);
+ bootstrap(mysql_stdin);
unireg_abort(bootstrap_error ? 1 : 0);
}
- if (opt_init_file)
+ if (opt_init_file && *opt_init_file)
{
if (read_init_file(opt_init_file))
unireg_abort(1);
@@ -4555,7 +4548,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
create_shutdown_thread();
start_handle_manager();
- sql_print_information(ER(ER_STARTUP),my_progname,server_version,
+ sql_print_information(ER_DEFAULT(ER_STARTUP),my_progname,server_version,
((unix_sock == INVALID_SOCKET) ? (char*) ""
: mysqld_unix_port),
mysqld_port,
@@ -4566,23 +4559,16 @@ we force server id to 2, but this MySQL server will not act as a slave.");
/* Signal threads waiting for server to be started */
- pthread_mutex_lock(&LOCK_server_started);
+ mysql_mutex_lock(&LOCK_server_started);
mysqld_server_started= 1;
- pthread_cond_signal(&COND_server_started);
- pthread_mutex_unlock(&LOCK_server_started);
+ mysql_cond_signal(&COND_server_started);
+ mysql_mutex_unlock(&LOCK_server_started);
-#if defined(__NT__) || defined(HAVE_SMEM)
+#if defined(_WIN32) || defined(HAVE_SMEM)
handle_connections_methods();
#else
-#ifdef __WIN__
- if (!have_tcpip || opt_disable_networking)
- {
- sql_print_error("TCP/IP unavailable or disabled with --skip-networking; no available interfaces");
- unireg_abort(1);
- }
-#endif
- handle_connections_sockets(0);
-#endif /* __NT__ */
+ handle_connections_sockets();
+#endif /* _WIN32 || HAVE_SMEM */
/* (void) pthread_attr_destroy(&connection_attrib); */
@@ -4592,21 +4578,30 @@ we force server id to 2, but this MySQL server will not act as a slave.");
#ifdef EXTRA_DEBUG2
sql_print_error("Before Lock_thread_count");
#endif
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
DBUG_PRINT("quit", ("Got thread_count mutex"));
select_thread_in_use=0; // For close_connections
- (void) pthread_mutex_unlock(&LOCK_thread_count);
- (void) pthread_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_broadcast(&COND_thread_count);
#ifdef EXTRA_DEBUG2
sql_print_error("After lock_thread_count");
#endif
#endif /* __WIN__ */
+#ifdef HAVE_PSI_INTERFACE
+ /*
+ Disable the main thread instrumentation,
+ to avoid recording events during the shutdown.
+ */
+ if (PSI_server)
+ PSI_server->delete_current_thread();
+#endif
+
/* Wait until cleanup is done */
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
while (!ready_to_exit)
- pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
if (Service.IsNT() && start_mode)
@@ -4619,15 +4614,10 @@ we force server id to 2, but this MySQL server will not act as a slave.");
}
#endif
clean_up(1);
- wait_for_signal_thread_to_end();
- clean_up_mutexes();
- my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
-
- exit(0);
- return(0); /* purecov: deadcode */
+ mysqld_exit(0);
}
-#endif /* EMBEDDED_LIBRARY */
+#endif /* !EMBEDDED_LIBRARY */
/****************************************************************************
@@ -4730,7 +4720,7 @@ default_service_handling(char **argv,
}
-int main(int argc, char **argv)
+int mysqld_main(int argc, char **argv)
{
/*
When several instances are running on the same machine, we
@@ -4838,7 +4828,7 @@ int main(int argc, char **argv)
create MySQL privilege tables without having to start a full MySQL server.
*/
-static void bootstrap(FILE *file)
+static void bootstrap(MYSQL_FILE *file)
{
DBUG_ENTER("bootstrap");
@@ -4853,24 +4843,25 @@ static void bootstrap(FILE *file)
bootstrap_file=file;
#ifndef EMBEDDED_LIBRARY // TODO: Enable this
- if (pthread_create(&thd->real_id,&connection_attrib,handle_bootstrap,
- (void*) thd))
+ if (mysql_thread_create(key_thread_bootstrap,
+ &thd->real_id, &connection_attrib, handle_bootstrap,
+ (void*) thd))
{
sql_print_warning("Can't create thread to handle bootstrap");
bootstrap_error=-1;
DBUG_VOID_RETURN;
}
/* Wait for thread to die */
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
while (in_bootstrap)
{
- (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
+ mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
DBUG_PRINT("quit",("One thread died (count=%u)",thread_count));
}
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
#else
thd->mysql= 0;
- handle_bootstrap((void *)thd);
+ do_handle_bootstrap(thd);
#endif
DBUG_VOID_RETURN;
@@ -4879,13 +4870,14 @@ static void bootstrap(FILE *file)
static bool read_init_file(char *file_name)
{
- FILE *file;
+ MYSQL_FILE *file;
DBUG_ENTER("read_init_file");
DBUG_PRINT("enter",("name: %s",file_name));
- if (!(file=my_fopen(file_name,O_RDONLY,MYF(MY_WME))))
+ if (!(file= mysql_file_fopen(key_file_init, file_name,
+ O_RDONLY, MYF(MY_WME))))
DBUG_RETURN(TRUE);
bootstrap(file);
- (void) my_fclose(file,MYF(MY_WME));
+ mysql_file_fclose(file, MYF(MY_WME));
DBUG_RETURN(FALSE);
}
@@ -4901,15 +4893,15 @@ static bool read_init_file(char *file_name)
When we enter this function, LOCK_thread_count is hold!
*/
-
+
void handle_connection_in_main_thread(THD *thd)
{
- safe_mutex_assert_owner(&LOCK_thread_count);
+ mysql_mutex_assert_owner(&LOCK_thread_count);
thread_cache_size=0; // Safety
threads.append(thd);
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
thd->start_utime= my_micro_time();
- handle_one_connection(thd);
+ do_handle_one_connection(thd);
}
@@ -4924,7 +4916,7 @@ void create_thread_to_handle_connection(THD *thd)
/* Get thread from cache */
thread_cache.append(thd);
wake_thread++;
- pthread_cond_signal(&COND_thread_cache);
+ mysql_cond_signal(&COND_thread_cache);
}
else
{
@@ -4935,9 +4927,10 @@ void create_thread_to_handle_connection(THD *thd)
threads.append(thd);
DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id));
thd->prior_thr_create_utime= thd->start_utime= my_micro_time();
- if ((error=pthread_create(&thd->real_id,&connection_attrib,
- handle_one_connection,
- (void*) thd)))
+ if ((error= mysql_thread_create(key_thread_one_connection,
+ &thd->real_id, &connection_attrib,
+ handle_one_connection,
+ (void*) thd)))
{
/* purecov: begin inspected */
DBUG_PRINT("error",
@@ -4945,26 +4938,26 @@ void create_thread_to_handle_connection(THD *thd)
error));
thread_count--;
thd->killed= THD::KILL_CONNECTION; // Safety
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
- pthread_mutex_lock(&LOCK_connection_count);
+ mysql_mutex_lock(&LOCK_connection_count);
--connection_count;
- pthread_mutex_unlock(&LOCK_connection_count);
+ mysql_mutex_unlock(&LOCK_connection_count);
statistic_increment(aborted_connects,&LOCK_status);
/* Can't use my_error() since store_globals has not been called. */
my_snprintf(error_message_buff, sizeof(error_message_buff),
- ER(ER_CANT_CREATE_THREAD), error);
- net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff);
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ ER_THD(thd, ER_CANT_CREATE_THREAD), error);
+ net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff, NULL);
+ mysql_mutex_lock(&LOCK_thread_count);
close_connection(thd,0,0);
delete thd;
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
return;
/* purecov: end */
}
}
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
DBUG_PRINT("info",("Thread created"));
}
@@ -4984,22 +4977,18 @@ void create_thread_to_handle_connection(THD *thd)
static void create_new_thread(THD *thd)
{
- NET *net=&thd->net;
DBUG_ENTER("create_new_thread");
- if (protocol_version > 9)
- net->return_errno=1;
-
/*
Don't allow too many connections. We roughly check here that we allow
only (max_connections + 1) connections.
*/
- pthread_mutex_lock(&LOCK_connection_count);
+ mysql_mutex_lock(&LOCK_connection_count);
if (connection_count >= max_connections + 1 || abort_loop)
{
- pthread_mutex_unlock(&LOCK_connection_count);
+ mysql_mutex_unlock(&LOCK_connection_count);
DBUG_PRINT("error",("Too many connections"));
close_connection(thd, ER_CON_COUNT_ERROR, 1);
@@ -5012,11 +5001,11 @@ static void create_new_thread(THD *thd)
if (connection_count > max_used_connections)
max_used_connections= connection_count;
- pthread_mutex_unlock(&LOCK_connection_count);
+ mysql_mutex_unlock(&LOCK_connection_count);
/* Start a new thread to handle connection. */
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
/*
The initialization of thread_id is done in create_embedded_thd() for
@@ -5027,7 +5016,7 @@ static void create_new_thread(THD *thd)
thread_count++;
- thread_scheduler.add_connection(thd);
+ MYSQL_CALLBACK(thread_scheduler, add_connection, (thd));
DBUG_VOID_RETURN;
}
@@ -5038,15 +5027,12 @@ static void create_new_thread(THD *thd)
inline void kill_broken_server()
{
/* hack to get around signals ignored in syscalls for problem OS's */
- if (
-#if !defined(__NETWARE__)
- unix_sock == INVALID_SOCKET ||
-#endif
+ if (unix_sock == INVALID_SOCKET ||
(!opt_disable_networking && ip_sock == INVALID_SOCKET))
{
select_thread_in_use = 0;
/* The following call will never return */
- kill_server(IF_NETWARE(MYSQL_KILL_SIGNAL, (void*) MYSQL_KILL_SIGNAL));
+ kill_server((void*) MYSQL_KILL_SIGNAL);
}
}
#define MAYBE_BROKEN_SYSCALL kill_broken_server();
@@ -5057,32 +5043,50 @@ inline void kill_broken_server()
/* Handle new connections and spawn new process to handle them */
#ifndef EMBEDDED_LIBRARY
-pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
+
+void handle_connections_sockets()
{
- my_socket sock,new_sock;
+ my_socket UNINIT_VAR(sock), UNINIT_VAR(new_sock);
uint error_count=0;
- uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1);
- fd_set readFDs,clientFDs;
THD *thd;
- struct sockaddr_in cAddr;
- int ip_flags=0,socket_flags=0,flags;
+ struct sockaddr_storage cAddr;
+ int ip_flags=0,socket_flags=0,flags=0,retval;
st_vio *vio_tmp;
- DBUG_ENTER("handle_connections_sockets");
-
- LINT_INIT(new_sock);
+#ifdef HAVE_POLL
+ int socket_count= 0;
+ struct pollfd fds[2]; // for ip_sock and unix_sock
+#else
+ fd_set readFDs,clientFDs;
+ uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1);
+#endif
- (void) my_pthread_getprio(pthread_self()); // For debugging
+ DBUG_ENTER("handle_connections_sockets");
+#ifndef HAVE_POLL
FD_ZERO(&clientFDs);
+#endif
+
if (ip_sock != INVALID_SOCKET)
{
+#ifdef HAVE_POLL
+ fds[socket_count].fd= ip_sock;
+ fds[socket_count].events= POLLIN;
+ socket_count++;
+#else
FD_SET(ip_sock,&clientFDs);
+#endif
#ifdef HAVE_FCNTL
ip_flags = fcntl(ip_sock, F_GETFL, 0);
#endif
}
#ifdef HAVE_SYS_UN_H
+#ifdef HAVE_POLL
+ fds[socket_count].fd= unix_sock;
+ fds[socket_count].events= POLLIN;
+ socket_count++;
+#else
FD_SET(unix_sock,&clientFDs);
+#endif
#ifdef HAVE_FCNTL
socket_flags=fcntl(unix_sock, F_GETFL, 0);
#endif
@@ -5092,12 +5096,15 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
MAYBE_BROKEN_SYSCALL;
while (!abort_loop)
{
- readFDs=clientFDs;
-#ifdef HPUX10
- if (select(max_used_connection,(int*) &readFDs,0,0,0) < 0)
- continue;
+#ifdef HAVE_POLL
+ retval= poll(fds, socket_count, -1);
#else
- if (select((int) max_used_connection,&readFDs,0,0,0) < 0)
+ readFDs=clientFDs;
+
+ retval= select((int) max_used_connection,&readFDs,0,0,0);
+#endif
+
+ if (retval < 0)
{
if (socket_errno != SOCKET_EINTR)
{
@@ -5107,7 +5114,7 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
MAYBE_BROKEN_SYSCALL
continue;
}
-#endif /* HPUX10 */
+
if (abort_loop)
{
MAYBE_BROKEN_SYSCALL;
@@ -5115,6 +5122,21 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
}
/* Is this a new connection request ? */
+#ifdef HAVE_POLL
+ for (int i= 0; i < socket_count; ++i)
+ {
+ if (fds[i].revents & POLLIN)
+ {
+ sock= fds[i].fd;
+#ifdef HAVE_FCNTL
+ flags= fcntl(sock, F_GETFL, 0);
+#else
+ flags= 0;
+#endif // HAVE_FCNTL
+ break;
+ }
+ }
+#else // HAVE_POLL
#ifdef HAVE_SYS_UN_H
if (FD_ISSET(unix_sock,&readFDs))
{
@@ -5122,11 +5144,12 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
flags= socket_flags;
}
else
-#endif
+#endif // HAVE_SYS_UN_H
{
sock = ip_sock;
flags= ip_flags;
}
+#endif // HAVE_POLL
#if !defined(NO_FCNTL_NONBLOCK)
if (!(test_flags & TEST_BLOCKING))
@@ -5140,16 +5163,9 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
#endif /* NO_FCNTL_NONBLOCK */
for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++)
{
- size_socket length=sizeof(struct sockaddr_in);
- new_sock = accept(sock, my_reinterpret_cast(struct sockaddr *) (&cAddr),
- &length);
-#ifdef __NETWARE__
- // TODO: temporary fix, waiting for TCP/IP fix - DEFECT000303149
- if ((new_sock == INVALID_SOCKET) && (socket_errno == EINVAL))
- {
- kill_server(SIGTERM);
- }
-#endif
+ size_socket length= sizeof(struct sockaddr_storage);
+ new_sock= accept(sock, (struct sockaddr *)(&cAddr),
+ &length);
if (new_sock != INVALID_SOCKET ||
(socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN))
break;
@@ -5213,9 +5229,10 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
{
size_socket dummyLen;
- struct sockaddr dummy;
- dummyLen = sizeof(struct sockaddr);
- if (getsockname(new_sock,&dummy, &dummyLen) < 0)
+ struct sockaddr_storage dummy;
+ dummyLen = sizeof(dummy);
+ if ( getsockname(new_sock,(struct sockaddr *)&dummy,
+ (SOCKET_SIZE_TYPE *)&dummyLen) < 0 )
{
sql_perror("Error on new connection socket");
(void) shutdown(new_sock, SHUT_RDWR);
@@ -5231,7 +5248,7 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
if (!(thd= new THD))
{
(void) shutdown(new_sock, SHUT_RDWR);
- VOID(closesocket(new_sock));
+ (void) closesocket(new_sock);
continue;
}
if (!(vio_tmp=vio_new(new_sock,
@@ -5260,13 +5277,19 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
create_new_thread(thd);
}
- DBUG_LEAVE;
+ DBUG_VOID_RETURN;
+}
+
+
+#ifdef _WIN32
+pthread_handler_t handle_connections_sockets_thread(void *arg)
+{
+ my_thread_init();
+ handle_connections_sockets();
decrement_handler_count();
return 0;
}
-
-#ifdef __NT__
pthread_handler_t handle_connections_namedpipes(void *arg)
{
HANDLE hConnectedPipe;
@@ -5362,7 +5385,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg)
decrement_handler_count();
return 0;
}
-#endif /* __NT__ */
+#endif /* _WIN32 */
#ifdef HAVE_SMEM
@@ -5562,7 +5585,7 @@ errorconn:
NullS);
sql_perror(buff);
}
- if (handle_client_file_map)
+ if (handle_client_file_map)
CloseHandle(handle_client_file_map);
if (handle_client_map)
UnmapViewOfFile(handle_client_map);
@@ -5582,7 +5605,7 @@ errorconn:
/* End shared memory handling */
error:
if (tmp)
- my_free(tmp, MYF(0));
+ my_free(tmp);
if (errmsg)
{
@@ -5608,198 +5631,26 @@ error:
Handle start options
******************************************************************************/
-enum options_mysqld
-{
- OPT_ISAM_LOG=256, OPT_SKIP_NEW,
- OPT_SKIP_GRANT, OPT_SKIP_LOCK,
- OPT_ENABLE_LOCK, OPT_USE_LOCKING,
- OPT_SOCKET, OPT_UPDATE_LOG,
- OPT_BIN_LOG, OPT_SKIP_RESOLVE,
- OPT_SKIP_NETWORKING, OPT_BIN_LOG_INDEX,
- OPT_BIND_ADDRESS, OPT_PID_FILE,
- OPT_SKIP_PRIOR, OPT_BIG_TABLES,
- OPT_STANDALONE, OPT_ONE_THREAD,
- OPT_CONSOLE, OPT_LOW_PRIORITY_UPDATES,
- OPT_SKIP_HOST_CACHE, OPT_SHORT_LOG_FORMAT,
- OPT_FLUSH, OPT_SAFE,
- OPT_BOOTSTRAP, OPT_SKIP_SHOW_DB,
- OPT_STORAGE_ENGINE, OPT_INIT_FILE,
- OPT_DELAY_KEY_WRITE_ALL, OPT_SLOW_QUERY_LOG,
- OPT_DELAY_KEY_WRITE, OPT_CHARSETS_DIR,
- OPT_MASTER_HOST, OPT_MASTER_USER,
- OPT_MASTER_PASSWORD, OPT_MASTER_PORT,
- OPT_MASTER_INFO_FILE, OPT_MASTER_CONNECT_RETRY,
- OPT_MASTER_RETRY_COUNT, OPT_LOG_TC, OPT_LOG_TC_SIZE,
- OPT_MASTER_SSL, OPT_MASTER_SSL_KEY,
- OPT_MASTER_SSL_CERT, OPT_MASTER_SSL_CAPATH,
- OPT_MASTER_SSL_CIPHER, OPT_MASTER_SSL_CA,
- OPT_SQL_BIN_UPDATE_SAME, OPT_REPLICATE_DO_DB,
- OPT_REPLICATE_IGNORE_DB, OPT_LOG_SLAVE_UPDATES,
- OPT_BINLOG_DO_DB, OPT_BINLOG_IGNORE_DB,
- OPT_BINLOG_FORMAT,
-#ifndef DBUG_OFF
- OPT_BINLOG_SHOW_XID,
-#endif
- OPT_BINLOG_ROWS_EVENT_MAX_SIZE,
- OPT_WANT_CORE, OPT_CONCURRENT_INSERT,
- OPT_MEMLOCK, OPT_MYISAM_RECOVER,
- OPT_REPLICATE_REWRITE_DB, OPT_SERVER_ID,
- OPT_SKIP_SLAVE_START, OPT_SAFE_SHOW_DB,
- OPT_SAFEMALLOC_MEM_LIMIT, OPT_REPLICATE_DO_TABLE,
- OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE,
- OPT_REPLICATE_WILD_IGNORE_TABLE, OPT_REPLICATE_SAME_SERVER_ID,
- OPT_DISCONNECT_SLAVE_EVENT_COUNT, OPT_TC_HEURISTIC_RECOVER,
- OPT_ABORT_SLAVE_EVENT_COUNT,
- OPT_LOG_BIN_TRUST_FUNCTION_CREATORS,
- OPT_LOG_BIN_TRUST_FUNCTION_CREATORS_OLD,
- OPT_ENGINE_CONDITION_PUSHDOWN, OPT_NDB_CONNECTSTRING,
- OPT_NDB_USE_EXACT_COUNT, OPT_NDB_USE_TRANSACTIONS,
- OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
- OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_CACHE_CHECK_TIME,
- OPT_NDB_MGMD, OPT_NDB_NODEID,
- OPT_NDB_DISTRIBUTION,
- OPT_NDB_INDEX_STAT_ENABLE,
- OPT_NDB_EXTRA_LOGGING,
- OPT_NDB_REPORT_THRESH_BINLOG_EPOCH_SLIP,
- OPT_NDB_REPORT_THRESH_BINLOG_MEM_USAGE,
- OPT_NDB_USE_COPYING_ALTER_TABLE,
- OPT_SKIP_SAFEMALLOC,
- OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE,
- OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
- OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
- OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
- OPT_HAVE_NAMED_PIPE,
- OPT_DO_PSTACK, OPT_EVENT_SCHEDULER, OPT_REPORT_HOST,
- OPT_REPORT_USER, OPT_REPORT_PASSWORD, OPT_REPORT_PORT,
- OPT_SHOW_SLAVE_AUTH_INFO,
- OPT_SLAVE_LOAD_TMPDIR, OPT_NO_MIX_TYPE,
- OPT_RPL_RECOVERY_RANK,OPT_INIT_RPL_ROLE,
- OPT_RELAY_LOG, OPT_RELAY_LOG_INDEX, OPT_RELAY_LOG_INFO_FILE,
- OPT_SLAVE_SKIP_ERRORS, OPT_DES_KEY_FILE, OPT_LOCAL_INFILE,
- OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA,
- OPT_SSL_CAPATH, OPT_SSL_CIPHER,
- OPT_BACK_LOG, OPT_BINLOG_CACHE_SIZE,
- OPT_CONNECT_TIMEOUT, OPT_DELAYED_INSERT_TIMEOUT,
- OPT_DELAYED_INSERT_LIMIT, OPT_DELAYED_QUEUE_SIZE,
- OPT_FLUSH_TIME, OPT_FT_MIN_WORD_LEN, OPT_FT_BOOLEAN_SYNTAX,
- OPT_FT_MAX_WORD_LEN, OPT_FT_QUERY_EXPANSION_LIMIT, OPT_FT_STOPWORD_FILE,
- OPT_INTERACTIVE_TIMEOUT, OPT_JOIN_BUFF_SIZE,
- OPT_KEY_BUFFER_SIZE, OPT_KEY_CACHE_BLOCK_SIZE,
- OPT_KEY_CACHE_DIVISION_LIMIT, OPT_KEY_CACHE_AGE_THRESHOLD,
- OPT_LONG_QUERY_TIME,
- OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET,
- OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE,
- OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS,
- OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE,
- OPT_MAX_JOIN_SIZE, OPT_MAX_PREPARED_STMT_COUNT,
- OPT_MAX_RELAY_LOG_SIZE, OPT_MAX_SORT_LENGTH,
- OPT_MAX_SEEKS_FOR_KEY, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS,
- OPT_MAX_LENGTH_FOR_SORT_DATA,
- OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
- OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE,
- OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
- OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
- OPT_MYISAM_USE_MMAP, OPT_MYISAM_REPAIR_THREADS,
- OPT_MYISAM_MMAP_SIZE,
- OPT_MYISAM_STATS_METHOD,
- OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT,
- OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT,
- OPT_OPEN_FILES_LIMIT,
- OPT_PRELOAD_BUFFER_SIZE,
- OPT_QUERY_CACHE_LIMIT, OPT_QUERY_CACHE_MIN_RES_UNIT, OPT_QUERY_CACHE_SIZE,
- OPT_QUERY_CACHE_TYPE, OPT_QUERY_CACHE_WLOCK_INVALIDATE, OPT_RECORD_BUFFER,
- OPT_RECORD_RND_BUFFER, OPT_DIV_PRECINCREMENT, OPT_RELAY_LOG_SPACE_LIMIT,
- OPT_RELAY_LOG_PURGE,
- OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME,
- OPT_SLAVE_TRANS_RETRIES, OPT_READONLY, OPT_DEBUGGING,
- OPT_SORT_BUFFER, OPT_TABLE_OPEN_CACHE, OPT_TABLE_DEF_CACHE,
- OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE,
- OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK,
- OPT_WAIT_TIMEOUT,
- OPT_ERROR_LOG_FILE,
- OPT_DEFAULT_WEEK_FORMAT,
- OPT_RANGE_ALLOC_BLOCK_SIZE, OPT_ALLOW_SUSPICIOUS_UDFS,
- OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE,
- OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE,
- OPT_SYNC_FRM, OPT_SYNC_BINLOG,
- OPT_SYNC_REPLICATION,
- OPT_SYNC_REPLICATION_SLAVE_ID,
- OPT_SYNC_REPLICATION_TIMEOUT,
- OPT_ENABLE_SHARED_MEMORY,
- OPT_SHARED_MEMORY_BASE_NAME,
- OPT_OLD_PASSWORDS,
- OPT_OLD_ALTER_TABLE,
- OPT_EXPIRE_LOGS_DAYS,
- OPT_GROUP_CONCAT_MAX_LEN,
- OPT_DEFAULT_COLLATION,
- OPT_DEFAULT_COLLATION_OLD,
- OPT_CHARACTER_SET_CLIENT_HANDSHAKE,
- OPT_CHARACTER_SET_FILESYSTEM,
- OPT_LC_TIME_NAMES,
- OPT_INIT_CONNECT,
- OPT_INIT_SLAVE,
- OPT_SECURE_AUTH,
- OPT_DATE_FORMAT,
- OPT_TIME_FORMAT,
- OPT_DATETIME_FORMAT,
- OPT_LOG_QUERIES_NOT_USING_INDEXES,
- OPT_DEFAULT_TIME_ZONE,
- OPT_SYSDATE_IS_NOW,
- OPT_OPTIMIZER_SEARCH_DEPTH,
- OPT_OPTIMIZER_PRUNE_LEVEL,
- OPT_OPTIMIZER_SWITCH,
- OPT_UPDATABLE_VIEWS_WITH_LIMIT,
- OPT_SP_AUTOMATIC_PRIVILEGES,
- OPT_MAX_SP_RECURSION_DEPTH,
- OPT_AUTO_INCREMENT, OPT_AUTO_INCREMENT_OFFSET,
- OPT_ENABLE_LARGE_PAGES,
- OPT_TIMED_MUTEXES,
- OPT_OLD_STYLE_USER_LIMITS,
- OPT_LOG_SLOW_ADMIN_STATEMENTS,
- OPT_TABLE_LOCK_WAIT_TIMEOUT,
- OPT_PLUGIN_LOAD,
- OPT_PLUGIN_DIR,
- OPT_SYMBOLIC_LINKS,
- OPT_WARNINGS,
- OPT_RECORD_BUFFER_OLD,
- OPT_LOG_OUTPUT,
- OPT_PORT_OPEN_TIMEOUT,
- OPT_PROFILING,
- OPT_KEEP_FILES_ON_CREATE,
- OPT_GENERAL_LOG,
- OPT_SLOW_LOG,
- OPT_THREAD_HANDLING,
- OPT_INNODB_ROLLBACK_ON_TIMEOUT,
- OPT_SECURE_FILE_PRIV,
- OPT_MIN_EXAMINED_ROW_LIMIT,
- OPT_LOG_SLOW_SLAVE_STATEMENTS,
-#if defined(ENABLED_DEBUG_SYNC)
- OPT_DEBUG_SYNC_TIMEOUT,
-#endif /* defined(ENABLED_DEBUG_SYNC) */
- OPT_OLD_MODE,
- OPT_SLAVE_EXEC_MODE,
- OPT_GENERAL_LOG_FILE,
- OPT_SLOW_QUERY_LOG_FILE,
- OPT_IGNORE_BUILTIN_INNODB,
- OPT_BINLOG_DIRECT_NON_TRANS_UPDATE,
- OPT_DEFAULT_CHARACTER_SET_OLD
-};
-
+DYNAMIC_ARRAY all_options;
-#define LONG_TIMEOUT ((ulong) 3600L*24L*365L)
+/**
+ System variables are automatically command-line options (few
+ exceptions are documented in sys_var.h), so don't need
+ to be listed here.
+*/
-struct my_option my_long_options[] =
+struct my_option my_long_options[]=
{
{"help", '?', "Display this help and exit.",
&opt_help, &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
#ifdef HAVE_REPLICATION
- {"abort-slave-event-count", OPT_ABORT_SLAVE_EVENT_COUNT,
+ {"abort-slave-event-count", 0,
"Option used by mysql-test for debugging and testing of replication.",
&abort_slave_event_count, &abort_slave_event_count,
0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_REPLICATION */
- {"allow-suspicious-udfs", OPT_ALLOW_SUSPICIOUS_UDFS,
+ {"allow-suspicious-udfs", 0,
"Allows use of UDFs consisting of only one symbol xxx() "
"without corresponding xxx_init() or xxx_deinit(). That also means "
"that one can load any function from any library, for example exit() "
@@ -5809,43 +5660,15 @@ struct my_option my_long_options[] =
{"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax. This mode "
"will also set transaction isolation level 'serializable'.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"auto-increment-increment", OPT_AUTO_INCREMENT,
- "Auto-increment columns are incremented by this.",
- &global_system_variables.auto_increment_increment,
- &max_system_variables.auto_increment_increment, 0, GET_ULONG,
- OPT_ARG, 1, 1, 65535, 0, 1, 0 },
- {"auto-increment-offset", OPT_AUTO_INCREMENT_OFFSET,
- "Offset added to Auto-increment columns. Used when auto-increment-increment != 1.",
- &global_system_variables.auto_increment_offset,
- &max_system_variables.auto_increment_offset, 0, GET_ULONG, OPT_ARG,
- 1, 1, 65535, 0, 1, 0 },
- {"automatic-sp-privileges", OPT_SP_AUTOMATIC_PRIVILEGES,
- "Creating and dropping stored procedures alters ACLs. Disable with --skip-automatic-sp-privileges.",
- &sp_automatic_privileges, &sp_automatic_privileges,
- 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
- {"basedir", 'b',
- "Path to installation directory. All paths are usually resolved relative to this.",
- &mysql_home_ptr, &mysql_home_ptr, 0, GET_STR, REQUIRED_ARG,
- 0, 0, 0, 0, 0, 0},
- {"big-tables", OPT_BIG_TABLES,
- "Allow big result sets by saving all temporary sets on file (solves most 'table full' errors).",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ /*
+ Because Sys_var_bit does not support command-line options, we need to
+ explicitely add one for --autocommit
+ */
+ {"autocommit", OPT_AUTOCOMMIT, "Set default value for autocommit (0 or 1)",
+ NULL, NULL, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, NULL},
{"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.",
&my_bind_addr_str, &my_bind_addr_str, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"binlog_format", OPT_BINLOG_FORMAT,
- "Does not have any effect without '--log-bin'. "
- "Tell the master the form of binary logging to use: either 'row' for "
- "row-based binary logging, 'statement' for statement-based binary "
- "logging, or 'mixed'. 'mixed' is statement-based binary logging except "
- "for statements where only row-based is correct: Statements that involve "
- "user-defined functions (i.e., UDFs) or the UUID() function."
-#ifdef HAVE_NDB_BINLOG
- "If ndbcluster is enabled and binlog_format is `mixed', the format switches"
- " to 'row' and back implicitly per each query accessing a NDB table."
-#endif
- , &opt_binlog_format, &opt_binlog_format,
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"binlog-do-db", OPT_BINLOG_DO_DB,
"Tells the master it should log updates for the specified database, "
"and exclude all others not explicitly mentioned.",
@@ -5853,7 +5676,7 @@ struct my_option my_long_options[] =
{"binlog-ignore-db", OPT_BINLOG_IGNORE_DB,
"Tells the master that updates to the given database should not be logged to the binary log.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"binlog-row-event-max-size", OPT_BINLOG_ROWS_EVENT_MAX_SIZE,
+ {"binlog-row-event-max-size", 0,
"The maximum size of a row-based binary log event in bytes. Rows will be "
"grouped into events smaller than this size if possible. "
"The value has to be a multiple of 256.",
@@ -5867,12 +5690,12 @@ struct my_option my_long_options[] =
{"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
- {"character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE,
+ {"character-set-client-handshake", 0,
"Don't ignore client side character set value sent during handshake.",
&opt_character_set_client_handshake,
&opt_character_set_client_handshake,
0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
- {"character-set-filesystem", OPT_CHARACTER_SET_FILESYSTEM,
+ {"character-set-filesystem", 0,
"Set the filesystem character set.",
&character_set_filesystem_name,
&character_set_filesystem_name,
@@ -5880,511 +5703,149 @@ struct my_option my_long_options[] =
{"character-set-server", 'C', "Set the default character set.",
&default_character_set_name, &default_character_set_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"character-sets-dir", OPT_CHARSETS_DIR,
- "Directory where character sets are.", &charsets_dir,
- &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"chroot", 'r', "Chroot mysqld daemon during startup.",
&mysqld_chroot, &mysqld_chroot, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
- {"collation-server", OPT_DEFAULT_COLLATION, "Set the default collation.",
+ {"collation-server", 0, "Set the default collation.",
&default_collation_name, &default_collation_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"completion-type", OPT_COMPLETION_TYPE, "Default completion type.",
- &global_system_variables.completion_type,
- &max_system_variables.completion_type, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, 2, 0, 1, 0},
- {"concurrent-insert", OPT_CONCURRENT_INSERT,
- "Use concurrent insert with MyISAM. Disable with --concurrent-insert=0.",
- &myisam_concurrent_insert, &myisam_concurrent_insert,
- 0, GET_ULONG, OPT_ARG, 1, 0, 2, 0, 0, 0},
{"console", OPT_CONSOLE, "Write error output on screen; don't remove the console window on windows.",
&opt_console, &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
{"core-file", OPT_WANT_CORE, "Write core on errors.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
- {"datadir", 'h', "Path to the database root.", &mysql_data_home,
- &mysql_data_home, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#ifndef DBUG_OFF
- {"debug", '#', "Debug log.", &default_dbug_option,
- &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
-#endif
- {"default-character-set", OPT_DEFAULT_CHARACTER_SET_OLD,
- "Set the default character set (deprecated option, use --character-set-server instead).",
- &default_character_set_name, &default_character_set_name,
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"default-collation", OPT_DEFAULT_COLLATION_OLD, "Set the default collation "
- "(deprecated option, use --collation-server instead).",
- &default_collation_name, &default_collation_name,
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"default-storage-engine", OPT_STORAGE_ENGINE,
- "Set the default storage engine (table type) for tables.",
- &default_storage_engine_str, &default_storage_engine_str,
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"default-table-type", OPT_STORAGE_ENGINE,
- "(deprecated) Use --default-storage-engine.",
- &default_storage_engine_str, &default_storage_engine_str,
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"default-time-zone", OPT_DEFAULT_TIME_ZONE, "Set the default time zone.",
+ /* default-storage-engine should have "MyISAM" as def_value. Instead
+ of initializing it here it is done in init_common_variables() due
+ to a compiler bug in Sun Studio compiler. */
+ {"default-storage-engine", 0, "The default storage engine for new tables",
+ &default_storage_engine, 0, 0, GET_STR, REQUIRED_ARG,
+ 0, 0, 0, 0, 0, 0 },
+ {"default-time-zone", 0, "Set the default time zone.",
&default_tz_name, &default_tz_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"delay-key-write", OPT_DELAY_KEY_WRITE, "Type of DELAY_KEY_WRITE.",
- 0,0,0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"delay-key-write-for-all-tables", OPT_DELAY_KEY_WRITE_ALL,
- "Don't flush key buffers between writes for any MyISAM table. "
- "(Deprecated option, use --delay-key-write=all instead.)",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_OPENSSL
- {"des-key-file", OPT_DES_KEY_FILE,
+ {"des-key-file", 0,
"Load keys for des_encrypt() and des_encrypt from given file.",
&des_key_file, &des_key_file, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
#endif /* HAVE_OPENSSL */
#ifdef HAVE_REPLICATION
- {"disconnect-slave-event-count", OPT_DISCONNECT_SLAVE_EVENT_COUNT,
+ {"disconnect-slave-event-count", 0,
"Option used by mysql-test for debugging and testing of replication.",
&disconnect_slave_event_count, &disconnect_slave_event_count,
0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_REPLICATION */
- {"enable-locking", OPT_ENABLE_LOCK,
- "Deprecated option, use --external-locking instead.",
- &opt_external_locking, &opt_external_locking,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
-#ifdef __NT__
- {"enable-named-pipe", OPT_HAVE_NAMED_PIPE, "Enable the named pipe (NT).",
- &opt_enable_named_pipe, &opt_enable_named_pipe, 0, GET_BOOL,
- NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif
-#ifdef HAVE_STACK_TRACE_ON_SEGV
- {"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure. "
- "This option is deprecated and has no effect; a symbolic stack trace will "
- "be printed after a crash whenever possible.", &opt_do_pstack, &opt_do_pstack,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif /* HAVE_STACK_TRACE_ON_SEGV */
- {"engine-condition-pushdown",
- OPT_ENGINE_CONDITION_PUSHDOWN,
- "Push supported query conditions to the storage engine.",
- &global_system_variables.engine_condition_pushdown,
- &global_system_variables.engine_condition_pushdown,
- 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
- /* See how it's handled in get_one_option() */
- {"event-scheduler", OPT_EVENT_SCHEDULER, "Enable/disable the event scheduler.",
- NULL, NULL, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"exit-info", 'T', "Used for debugging. Use at your own risk.", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"external-locking", OPT_USE_LOCKING, "Use system (external) locking "
- "(disabled by default). With this option enabled you can run myisamchk "
- "to test (not repair) tables while the MySQL server is running. "
- "Disable with --skip-external-locking.",
- &opt_external_locking, &opt_external_locking,
+
+ {"external-locking", 0, "Use system (external) locking (disabled by "
+ "default). With this option enabled you can run myisamchk to test "
+ "(not repair) tables while the MySQL server is running. Disable with "
+ "--skip-external-locking.", &opt_external_locking, &opt_external_locking,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"flush", OPT_FLUSH, "Flush tables to disk between SQL commands.", 0, 0, 0,
- GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
/* We must always support the next option to make scripts like mysqltest
easier to do */
- {"gdb", OPT_DEBUGGING,
+ {"gdb", 0,
"Set up signals usable for debugging.",
&opt_debugging, &opt_debugging,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"general_log", OPT_GENERAL_LOG,
- "Enable/disable general log.", &opt_log,
- &opt_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
-#ifdef HAVE_LARGE_PAGES
- {"large-pages", OPT_ENABLE_LARGE_PAGES, "Enable support for large pages. "
- "Disable with --skip-large-pages.", &opt_large_pages, &opt_large_pages,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef HAVE_LARGE_PAGE_OPTION
+ {"super-large-pages", 0, "Enable support for super large pages.",
+ &opt_super_large_pages, &opt_super_large_pages, 0,
+ GET_BOOL, OPT_ARG, 0, 0, 1, 0, 1, 0},
#endif
- {"ignore-builtin-innodb", OPT_IGNORE_BUILTIN_INNODB ,
- "Disable initialization of builtin InnoDB plugin.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"init-connect", OPT_INIT_CONNECT,
- "Command(s) that are executed for each new connection.",
- &opt_init_connect, &opt_init_connect, 0, GET_STR_ALLOC,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#ifndef DISABLE_GRANT_OPTIONS
- {"init-file", OPT_INIT_FILE, "Read SQL commands from this file at startup.",
- &opt_init_file, &opt_init_file, 0, GET_STR, REQUIRED_ARG,
- 0, 0, 0, 0, 0, 0},
-#endif
- {"init-rpl-role", OPT_INIT_RPL_ROLE, "Set the replication role.", 0, 0, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"init-slave", OPT_INIT_SLAVE, "Command(s) that are executed by a slave server \
-each time the SQL thread starts.",
- &opt_init_slave, &opt_init_slave, 0, GET_STR_ALLOC,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"language", 'L',
- "Client error messages in given language. May be given as a full path.",
- &language_ptr, &language_ptr, 0, GET_STR, REQUIRED_ARG,
- 0, 0, 0, 0, 0, 0},
- {"lc-time-names", OPT_LC_TIME_NAMES,
+ "Client error messages in given language. May be given as a full path. "
+ "Deprecated. Use --lc-messages-dir instead.",
+ &lc_messages_dir_ptr, &lc_messages_dir_ptr, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"lc-messages", 0,
+ "Set the language used for the error messages.",
+ &lc_messages, &lc_messages, 0, GET_STR, REQUIRED_ARG,
+ 0, 0, 0, 0, 0, 0 },
+ {"lc-time-names", 0,
"Set the language used for the month names and the days of the week.",
&lc_time_names_name, &lc_time_names_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"local-infile", OPT_LOCAL_INFILE,
- "Enable/disable LOAD DATA LOCAL INFILE (takes values 1 or 0).",
- &opt_local_infile, &opt_local_infile, 0, GET_BOOL, OPT_ARG,
- 1, 0, 0, 0, 0, 0},
{"log", 'l', "Log connections and queries to file (deprecated option, use "
- "--general_log/--general_log_file instead).", &opt_logname,
- &opt_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"general_log_file", OPT_GENERAL_LOG_FILE,
- "Log connections and queries to given file.", &opt_logname,
- &opt_logname, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ "--general-log/--general-log-file instead).", &opt_logname, &opt_logname,
+ 0, GET_STR_ALLOC, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-bin", OPT_BIN_LOG,
"Log update queries in binary format. Optional (but strongly recommended "
"to avoid replication problems if server's hostname changes) argument "
"should be the chosen location for the binary log files.",
&opt_bin_logname, &opt_bin_logname, 0, GET_STR_ALLOC,
OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"log-bin-index", OPT_BIN_LOG_INDEX,
+ {"log-bin-index", 0,
"File that holds the names for last binary log files.",
&opt_binlog_index_name, &opt_binlog_index_name, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#ifndef TO_BE_REMOVED_IN_5_1_OR_6_0
- /*
- In 5.0.6 we introduced the below option, then in 5.0.16 we renamed it to
- log-bin-trust-function-creators but kept also the old name for
- compatibility; the behaviour was also changed to apply only to functions
- (and triggers). In a future release this old name could be removed.
- */
- {"log-bin-trust-routine-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS_OLD,
- "(deprecated) Use log-bin-trust-function-creators.",
- &trust_function_creators, &trust_function_creators, 0,
- GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif
- /*
- This option starts with "log-bin" to emphasize that it is specific of
- binary logging.
- */
- {"log-bin-trust-function-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS,
- "If equal to 0 (the default), then when --log-bin is used, creation of "
- "a stored function (or trigger) is allowed only to users having the SUPER "
- "privilege, and only if this stored function (trigger) may not break "
- "binary logging."
- "Note that if ALL connections to this server ALWAYS use row-based binary "
- "logging, the security issues do not exist and the binary logging cannot "
- "break, so you can safely set this to 1."
- ,&trust_function_creators, &trust_function_creators, 0,
- GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"log-error", OPT_ERROR_LOG_FILE, "Error log file.",
- &log_error_file_ptr, &log_error_file_ptr, 0, GET_STR,
- OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-isam", OPT_ISAM_LOG, "Log all MyISAM changes to file.",
&myisam_log_filename, &myisam_log_filename, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"log-long-format", '0',
- "Log some extra information to update log. Please note that this option "
- "is deprecated; see --log-short-format option.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
-#ifdef WITH_CSV_STORAGE_ENGINE
- {"log-output", OPT_LOG_OUTPUT,
- "Syntax: log-output[=value[,value...]], where \"value\" could be TABLE, "
- "FILE or NONE.",
- &log_output_str, &log_output_str, 0,
- GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
-#endif
- {"log-queries-not-using-indexes", OPT_LOG_QUERIES_NOT_USING_INDEXES,
- "Log queries that are executed without benefit of any index to the slow log if it is open.",
- &opt_log_queries_not_using_indexes, &opt_log_queries_not_using_indexes,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"log-short-format", OPT_SHORT_LOG_FORMAT,
+ {"log-short-format", 0,
"Don't log extra information to update and slow-query logs.",
&opt_short_log_format, &opt_short_log_format,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"log-slave-updates", OPT_LOG_SLAVE_UPDATES,
- "Tells the slave to log the updates from the slave thread to the binary log. "
- "You will need to turn it on if you plan to daisy-chain the slaves.",
- &opt_log_slave_updates, &opt_log_slave_updates, 0, GET_BOOL,
- NO_ARG, 0, 0, 0, 0, 0, 0},
- {"log-slow-admin-statements", OPT_LOG_SLOW_ADMIN_STATEMENTS,
- "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements "
- "to the slow log if it is open.", &opt_log_slow_admin_statements,
+ {"log-slow-admin-statements", 0,
+ "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to "
+ "the slow log if it is open.", &opt_log_slow_admin_statements,
&opt_log_slow_admin_statements, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"log-slow-slave-statements", OPT_LOG_SLOW_SLAVE_STATEMENTS,
+ {"log-slow-slave-statements", 0,
"Log slow statements executed by slave thread to the slow log if it is open.",
- &opt_log_slow_slave_statements,
- &opt_log_slow_slave_statements,
+ &opt_log_slow_slave_statements, &opt_log_slow_slave_statements,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"log_slow_queries", OPT_SLOW_QUERY_LOG,
- "Log slow queries to a table or log file. Defaults logging to table "
- "mysql.slow_log or hostname-slow.log if --log-output=file is used. "
- "Must be enabled to activate other slow log options. "
- "(deprecated option, use --slow_query_log/--slow_query_log_file instead)",
- &opt_slow_logname, &opt_slow_logname, 0, GET_STR, OPT_ARG,
+ {"log-slow-queries", OPT_SLOW_QUERY_LOG,
+ "Log slow queries to a table or log file. Defaults logging to table "
+ "mysql.slow_log or hostname-slow.log if --log-output=file is used. "
+ "Must be enabled to activate other slow log options. "
+ "Deprecated option, use --slow-query-log/--slow-query-log-file instead.",
+ &opt_slow_logname, &opt_slow_logname, 0, GET_STR_ALLOC, OPT_ARG,
0, 0, 0, 0, 0, 0},
- {"slow_query_log_file", OPT_SLOW_QUERY_LOG_FILE,
- "Log slow queries to given log file. Defaults logging to hostname-slow.log. "
- "Must be enabled to activate other slow log options.",
- &opt_slow_logname, &opt_slow_logname, 0, GET_STR,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"log-tc", OPT_LOG_TC,
+ {"log-tc", 0,
"Path to transaction coordinator log (used for transactions that affect "
"more than one storage engine, when binary log is disabled).",
&opt_tc_log_file, &opt_tc_log_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_MMAP
- {"log-tc-size", OPT_LOG_TC_SIZE, "Size of transaction coordinator log.",
+ {"log-tc-size", 0, "Size of transaction coordinator log.",
&opt_tc_log_size, &opt_tc_log_size, 0, GET_ULONG,
REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, ULONG_MAX, 0,
TC_LOG_PAGE_SIZE, 0},
#endif
- {"log-update", OPT_UPDATE_LOG,
- "The update log is deprecated since version 5.0, is replaced by the binary "
- "log and this option just turns on --log-bin instead.",
- &opt_update_logname, &opt_update_logname, 0, GET_STR,
- OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"log-warnings", 'W', "Log some not critical warnings to the log file.",
- &global_system_variables.log_warnings,
- &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, 0,
- 0, 0, 0},
- {"low-priority-updates", OPT_LOW_PRIORITY_UPDATES,
- "INSERT/DELETE/UPDATE has lower priority than selects.",
- &global_system_variables.low_priority_updates,
- &max_system_variables.low_priority_updates,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"master-connect-retry", OPT_MASTER_CONNECT_RETRY,
- "The number of seconds the slave thread will sleep before retrying to "
- "connect to the master, in case the master goes down or the connection "
- "is lost.",
- &master_connect_retry, &master_connect_retry, 0, GET_UINT,
- REQUIRED_ARG, 60, 0, 0, 0, 0, 0},
- {"master-host", OPT_MASTER_HOST,
- "Master hostname or IP address for replication. If not set, the slave "
- "thread will not be started. Note that the setting of master-host will "
- "be ignored if there exists a valid master.info file.",
- &master_host, &master_host, 0, GET_STR, REQUIRED_ARG, 0, 0,
- 0, 0, 0, 0},
- {"master-info-file", OPT_MASTER_INFO_FILE,
+ {"master-info-file", 0,
"The location and name of the file that remembers the master and where "
"the I/O replication thread is in the master's binlogs.",
&master_info_file, &master_info_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"master-password", OPT_MASTER_PASSWORD,
- "The password the slave thread will authenticate with when connecting to "
- "the master. If not set, an empty password is assumed. The value in "
- "master.info will take precedence if it can be read.",
- &master_password, &master_password, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"master-port", OPT_MASTER_PORT,
- "The port the master is listening on. If not set, the compiled setting of "
- "MYSQL_PORT is assumed. If you have not tinkered with configure options, "
- "this should be 3306. The value in master.info will take precedence if it "
- "can be read.", &master_port, &master_port, 0, GET_UINT, REQUIRED_ARG,
- MYSQL_PORT, 0, 0, 0, 0, 0},
- {"master-retry-count", OPT_MASTER_RETRY_COUNT,
+ {"master-retry-count", 0,
"The number of tries the slave will make to connect to the master before giving up.",
&master_retry_count, &master_retry_count, 0, GET_ULONG,
REQUIRED_ARG, 3600*24, 0, 0, 0, 0, 0},
- {"master-ssl", OPT_MASTER_SSL,
- "Enable the slave to connect to the master using SSL.",
- &master_ssl, &master_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
- 0, 0},
- {"master-ssl-ca", OPT_MASTER_SSL_CA,
- "Master SSL CA file. Only applies if you have enabled master-ssl.",
- &master_ssl_ca, &master_ssl_ca, 0, GET_STR, OPT_ARG,
- 0, 0, 0, 0, 0, 0},
- {"master-ssl-capath", OPT_MASTER_SSL_CAPATH,
- "Master SSL CA path. Only applies if you have enabled master-ssl.",
- &master_ssl_capath, &master_ssl_capath, 0, GET_STR, OPT_ARG,
- 0, 0, 0, 0, 0, 0},
- {"master-ssl-cert", OPT_MASTER_SSL_CERT,
- "Master SSL certificate file name. Only applies if you have enabled "
- "master-ssl.",
- &master_ssl_cert, &master_ssl_cert, 0, GET_STR, OPT_ARG,
- 0, 0, 0, 0, 0, 0},
- {"master-ssl-cipher", OPT_MASTER_SSL_CIPHER,
- "Master SSL cipher. Only applies if you have enabled master-ssl.",
- &master_ssl_cipher, &master_ssl_capath, 0, GET_STR, OPT_ARG,
- 0, 0, 0, 0, 0, 0},
- {"master-ssl-key", OPT_MASTER_SSL_KEY,
- "Master SSL keyfile name. Only applies if you have enabled master-ssl.",
- &master_ssl_key, &master_ssl_key, 0, GET_STR, OPT_ARG,
- 0, 0, 0, 0, 0, 0},
- {"master-user", OPT_MASTER_USER,
- "The username the slave thread will use for authentication when "
- "connecting to the master. The user must have FILE privilege. "
- "If the master user is not set, user test is assumed. The value "
- "in master.info will take precedence if it can be read.",
- &master_user, &master_user, 0, GET_STR, REQUIRED_ARG, 0, 0,
- 0, 0, 0, 0},
#ifdef HAVE_REPLICATION
- {"max-binlog-dump-events", OPT_MAX_BINLOG_DUMP_EVENTS,
+ {"init-rpl-role", 0, "Set the replication role.",
+ &rpl_status, &rpl_status, &rpl_role_typelib,
+ GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"max-binlog-dump-events", 0,
"Option used by mysql-test for debugging and testing of replication.",
&max_binlog_dump_events, &max_binlog_dump_events, 0,
GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_REPLICATION */
- {"memlock", OPT_MEMLOCK, "Lock mysqld in memory.", &locked_in_memory,
+ {"memlock", 0, "Lock mysqld in memory.", &locked_in_memory,
&locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"myisam-recover", OPT_MYISAM_RECOVER,
- "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.",
- &myisam_recover_options_str, &myisam_recover_options_str, 0,
- GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
-#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
- {"ndb-connectstring", OPT_NDB_CONNECTSTRING,
- "Connect string for ndbcluster.",
- &opt_ndb_connectstring, &opt_ndb_connectstring,
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"ndb-mgmd-host", OPT_NDB_MGMD,
- "Set host and port for ndb_mgmd. Syntax: hostname[:port]",
- &opt_ndb_mgmd, &opt_ndb_mgmd,
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"ndb-nodeid", OPT_NDB_NODEID,
- "Nodeid for this mysqlserver in the cluster.",
- &opt_ndb_nodeid,
- &opt_ndb_nodeid,
- 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"ndb-autoincrement-prefetch-sz", OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
- "Specify number of autoincrement values that are prefetched.",
- &global_system_variables.ndb_autoincrement_prefetch_sz,
- &max_system_variables.ndb_autoincrement_prefetch_sz,
- 0, GET_ULONG, REQUIRED_ARG, 1, 1, 256, 0, 0, 0},
- {"ndb-force-send", OPT_NDB_FORCE_SEND,
- "Force send of buffers to ndb immediately without waiting for "
- "other threads.",
- &global_system_variables.ndb_force_send,
- &global_system_variables.ndb_force_send,
- 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
- {"ndb_force_send", OPT_NDB_FORCE_SEND,
- "same as --ndb-force-send.",
- &global_system_variables.ndb_force_send,
- &global_system_variables.ndb_force_send,
- 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
- {"ndb-extra-logging", OPT_NDB_EXTRA_LOGGING,
- "Turn on more logging in the error log.",
- &ndb_extra_logging,
- &ndb_extra_logging,
- 0, GET_INT, OPT_ARG, 0, 0, 0, 0, 0, 0},
-#ifdef HAVE_NDB_BINLOG
- {"ndb-report-thresh-binlog-epoch-slip", OPT_NDB_REPORT_THRESH_BINLOG_EPOCH_SLIP,
- "Threshold on number of epochs to be behind before reporting binlog status. "
- "E.g., 3 means that if the difference between what epoch has been received "
- "from the storage nodes and what has been applied to the binlog is 3 or more, "
- "a status message will be sent to the cluster log.",
- &ndb_report_thresh_binlog_epoch_slip,
- &ndb_report_thresh_binlog_epoch_slip,
- 0, GET_ULONG, REQUIRED_ARG, 3, 0, 256, 0, 0, 0},
- {"ndb-report-thresh-binlog-mem-usage", OPT_NDB_REPORT_THRESH_BINLOG_MEM_USAGE,
- "Threshold on percentage of free memory before reporting binlog status. E.g., "
- "10 means that if amount of available memory for receiving binlog data from "
- "the storage nodes goes below 10%, "
- "a status message will be sent to the cluster log.",
- &ndb_report_thresh_binlog_mem_usage,
- &ndb_report_thresh_binlog_mem_usage,
- 0, GET_ULONG, REQUIRED_ARG, 10, 0, 100, 0, 0, 0},
-#endif
- {"ndb-use-exact-count", OPT_NDB_USE_EXACT_COUNT,
- "Use exact records count during query planning and for fast "
- "select count(*), disable for faster queries.",
- &global_system_variables.ndb_use_exact_count,
- &global_system_variables.ndb_use_exact_count,
- 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
- {"ndb_use_exact_count", OPT_NDB_USE_EXACT_COUNT,
- "Same as --ndb-use-exact-count.",
- &global_system_variables.ndb_use_exact_count,
- &global_system_variables.ndb_use_exact_count,
- 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
- {"ndb-use-transactions", OPT_NDB_USE_TRANSACTIONS,
- "Use transactions for large inserts, if enabled then large "
- "inserts will be split into several smaller transactions",
- &global_system_variables.ndb_use_transactions,
- &global_system_variables.ndb_use_transactions,
- 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
- {"ndb_use_transactions", OPT_NDB_USE_TRANSACTIONS,
- "Same as --ndb-use-transactions.",
- &global_system_variables.ndb_use_transactions,
- &global_system_variables.ndb_use_transactions,
- 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
- {"ndb-shm", OPT_NDB_SHM,
- "Use shared memory connections when available.",
- &opt_ndb_shm, &opt_ndb_shm,
- 0, GET_BOOL, OPT_ARG, OPT_NDB_SHM_DEFAULT, 0, 0, 0, 0, 0},
- {"ndb-optimized-node-selection", OPT_NDB_OPTIMIZED_NODE_SELECTION,
- "Select nodes for transactions in a more optimal way.",
- &opt_ndb_optimized_node_selection,
- &opt_ndb_optimized_node_selection,
- 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
- { "ndb-cache-check-time", OPT_NDB_CACHE_CHECK_TIME,
- "A dedicated thread is created to, at the given milliseconds interval, "
- "invalidate the query cache if another MySQL server in the cluster has "
- "changed the data in the database.",
- &opt_ndb_cache_check_time, &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG,
- 0, 0, LONG_TIMEOUT, 0, 1, 0},
- {"ndb-index-stat-enable", OPT_NDB_INDEX_STAT_ENABLE,
- "Use ndb index statistics in query optimization.",
- &global_system_variables.ndb_index_stat_enable,
- &max_system_variables.ndb_index_stat_enable,
- 0, GET_BOOL, OPT_ARG, 0, 0, 1, 0, 0, 0},
-#endif
- {"ndb-use-copying-alter-table",
- OPT_NDB_USE_COPYING_ALTER_TABLE,
- "Force ndbcluster to always copy tables at alter table "
- "(should only be used if on-line alter table fails).",
- &global_system_variables.ndb_use_copying_alter_table,
- &global_system_variables.ndb_use_copying_alter_table,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"new", 'n', "Use very new, possibly 'unsafe', functions.",
- &global_system_variables.new_mode,
- &max_system_variables.new_mode,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
-#ifdef NOT_YET
- {"no-mix-table-types", OPT_NO_MIX_TYPE,
- "Don't allow commands that use two different table types.",
- &opt_no_mix_types, &opt_no_mix_types, 0, GET_BOOL, NO_ARG,
- 0, 0, 0, 0, 0, 0},
-#endif
- {"old-alter-table", OPT_OLD_ALTER_TABLE,
- "Use old, non-optimized alter table.",
- &global_system_variables.old_alter_table,
- &max_system_variables.old_alter_table, 0, GET_BOOL, NO_ARG,
- 0, 0, 0, 0, 0, 0},
- {"old-passwords", OPT_OLD_PASSWORDS, "Use old password "
- "encryption method (needed for 4.0 and older clients).",
- &global_system_variables.old_passwords,
- &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG,
- 0, 0, 0, 0, 0, 0},
{"one-thread", OPT_ONE_THREAD,
"(Deprecated): Only use one thread (for debugging under Linux). Use "
"thread-handling=no-threads instead.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"old-style-user-limits", OPT_OLD_STYLE_USER_LIMITS,
+ {"old-style-user-limits", 0,
"Enable old-style user limits (before 5.0.3, user resources were counted "
"per each user+host vs. per account).",
&opt_old_style_user_limits, &opt_old_style_user_limits,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"pid-file", OPT_PID_FILE, "Pid file used by safe_mysqld.",
- &pidfile_name_ptr, &pidfile_name_ptr, 0, GET_STR,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"port", 'P', "Port number to use for connection or 0 for default to, in "
- "order of preference, my.cnf, $MYSQL_TCP_PORT, "
-#if MYSQL_PORT_DEFAULT == 0
- "/etc/services, "
-#endif
- "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
- &mysqld_port,
- &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"port-open-timeout", OPT_PORT_OPEN_TIMEOUT,
+ {"port-open-timeout", 0,
"Maximum time in seconds to wait for the port to become free. "
- "(Default: No wait).", &mysqld_port_timeout,
- &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
- {"profiling_history_size", OPT_PROFILING, "Limit of query profiling memory.",
- &global_system_variables.profiling_history_size,
- &max_system_variables.profiling_history_size,
- 0, GET_ULONG, REQUIRED_ARG, 15, 0, 100, 0, 0, 0},
-#endif
- {"relay-log", OPT_RELAY_LOG,
- "The location and name to use for relay logs.",
- &opt_relay_logname, &opt_relay_logname, 0,
- GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"relay-log-index", OPT_RELAY_LOG_INDEX,
- "The location and name to use for the file that keeps a list of the last \
-relay logs.",
- &opt_relaylog_index_name, &opt_relaylog_index_name, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"relay-log-info-file", OPT_RELAY_LOG_INFO_FILE,
- "The location and name of the file that remembers where the SQL replication \
-thread is in the relay logs.",
- &relay_log_info_file, &relay_log_info_file, 0, GET_STR,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ "(Default: No wait).", &mysqld_port_timeout, &mysqld_port_timeout, 0,
+ GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"replicate-do-db", OPT_REPLICATE_DO_DB,
"Tells the slave thread to restrict replication to the specified database. "
"To specify more than one database, use the directive multiple times, "
@@ -6416,7 +5877,7 @@ thread is in the relay logs.",
"replicate-rewrite-db=master_db_name->slave_db_name.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_REPLICATION
- {"replicate-same-server-id", OPT_REPLICATE_SAME_SERVER_ID,
+ {"replicate-same-server-id", 0,
"In replication, if set to 1, do not skip events having our server id. "
"Default value is 0 (to break infinite loops in circular replication). "
"Can't be set to 1 if --log-slave-updates is used.",
@@ -6439,160 +5900,51 @@ thread is in the relay logs.",
"will not do updates to tables in databases that start with foo and whose "
"table names start with bar.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- // In replication, we may need to tell the other servers how to connect
- {"report-host", OPT_REPORT_HOST,
- "Hostname or IP of the slave to be reported to the master during slave "
- "registration. Will appear in the output of SHOW SLAVE HOSTS. Leave unset "
- "if you do not want the slave to register itself with the master. Note that "
- "it is not sufficient for the master to simply read the IP of the slave "
- "from the socket once the slave connects. Due to NAT and other routing "
- "issues, that IP may not be valid for connecting to the slave from the "
- "master or other hosts.",
- &report_host, &report_host, 0, GET_STR, REQUIRED_ARG, 0, 0,
- 0, 0, 0, 0},
- {"report-password", OPT_REPORT_PASSWORD, "Undocumented.",
- &report_password, &report_password, 0, GET_STR,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"report-port", OPT_REPORT_PORT,
- "Port for connecting to slave reported to the master during slave "
- "registration. Set it only if the slave is listening on a non-default "
- "port or if you have a special tunnel from the master or other clients "
- "to the slave. If not sure, leave this option unset.",
- &report_port, &report_port, 0, GET_UINT, REQUIRED_ARG,
- MYSQL_PORT, 0, 0, 0, 0, 0},
- {"report-user", OPT_REPORT_USER, "Undocumented.", &report_user,
- &report_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"rpl-recovery-rank", OPT_RPL_RECOVERY_RANK, "Undocumented.",
- &rpl_recovery_rank, &rpl_recovery_rank, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
-#ifndef TO_BE_DELETED
- {"safe-show-database", OPT_SAFE_SHOW_DB,
- "Deprecated option; use GRANT SHOW DATABASES instead.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif
- {"safe-user-create", OPT_SAFE_USER_CREATE,
+ {"safe-user-create", 0,
"Don't allow new user creation by the user who has no write privileges to the mysql.user table.",
&opt_safe_user_create, &opt_safe_user_create, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
- {"safemalloc-mem-limit", OPT_SAFEMALLOC_MEM_LIMIT,
- "Simulate memory shortage when compiled with the --with-debug=full option.",
- 0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"secure-auth", OPT_SECURE_AUTH, "Disallow authentication for accounts that have old (pre-4.1) passwords.",
- &opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG,
- my_bool(0), 0, 0, 0, 0, 0},
- {"secure-file-priv", OPT_SECURE_FILE_PRIV,
- "Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files within specified directory.",
- &opt_secure_file_priv, &opt_secure_file_priv, 0,
- GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"server-id", OPT_SERVER_ID,
- "Uniquely identifies the server instance in the community of replication partners.",
- &server_id, &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, UINT_MAX32,
- 0, 0, 0},
- {"set-variable", 'O',
- "Change the value of a variable. Please note that this option is deprecated; "
- "you can set variables directly with --variable-name=value.",
- 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#ifdef HAVE_SMEM
- {"shared-memory", OPT_ENABLE_SHARED_MEMORY,
- "Enable the shared memory.",&opt_enable_shared_memory, &opt_enable_shared_memory,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif
-#ifdef HAVE_SMEM
- {"shared-memory-base-name",OPT_SHARED_MEMORY_BASE_NAME,
- "Base name of shared memory.", &shared_memory_base_name, &shared_memory_base_name,
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#endif
- {"show-slave-auth-info", OPT_SHOW_SLAVE_AUTH_INFO,
+ {"show-slave-auth-info", 0,
"Show user and password in SHOW SLAVE HOSTS on this master.",
&opt_show_slave_auth_info, &opt_show_slave_auth_info, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifndef DISABLE_GRANT_OPTIONS
- {"skip-grant-tables", OPT_SKIP_GRANT,
+ {"skip-grant-tables", 0,
"Start without grant tables. This gives all users FULL ACCESS to all tables.",
&opt_noacl, &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
0},
#endif
{"skip-host-cache", OPT_SKIP_HOST_CACHE, "Don't cache host names.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"skip-locking", OPT_SKIP_LOCK,
- "Deprecated option, use --skip-external-locking instead.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"skip-name-resolve", OPT_SKIP_RESOLVE,
- "Don't resolve hostnames. All hostnames are IP's or 'localhost'.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"skip-networking", OPT_SKIP_NETWORKING,
- "Don't allow connection with TCP/IP.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0,
- 0, 0, 0},
{"skip-new", OPT_SKIP_NEW, "Don't use new, possibly wrong routines.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
-#ifndef DBUG_OFF
-#ifdef SAFEMALLOC
- {"skip-safemalloc", OPT_SKIP_SAFEMALLOC,
- "Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG,
- 0, 0, 0, 0, 0, 0},
-#endif
-#endif
- {"skip-show-database", OPT_SKIP_SHOW_DB,
- "Don't allow 'SHOW DATABASE' commands.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
- 0, 0, 0, 0},
- {"skip-slave-start", OPT_SKIP_SLAVE_START,
+ {"skip-slave-start", 0,
"If set, slave is not autostarted.", &opt_skip_slave_start,
&opt_skip_slave_start, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"skip-stack-trace", OPT_SKIP_STACK_TRACE,
"Don't print a stack trace on failure.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
0, 0, 0, 0},
- {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. "
- "Deprecated option. Use --skip-symbolic-links instead.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"skip-thread-priority", OPT_SKIP_PRIOR,
- "Don't give threads different priorities. Deprecated option.", 0, 0, 0, GET_NO_ARG, NO_ARG,
- DEFAULT_SKIP_THREAD_PRIORITY, 0, 0, 0, 0, 0},
-#ifdef HAVE_REPLICATION
- {"slave-load-tmpdir", OPT_SLAVE_LOAD_TMPDIR,
- "The location where the slave should put its temporary files when "
- "replicating a LOAD DATA INFILE command.",
- &slave_load_tmpdir, &slave_load_tmpdir, 0, GET_STR_ALLOC,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"slave-skip-errors", OPT_SLAVE_SKIP_ERRORS,
- "Tells the slave thread to continue replication when a query event returns an error from the provided list.",
- 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"slave-exec-mode", OPT_SLAVE_EXEC_MODE,
- "Modes for how replication events should be executed. Legal values are "
- "STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode, replication will "
- "not stop for operations that are idempotent. In STRICT mode, replication "
- "will stop on any unexpected difference between the master and the slave.",
- &slave_exec_mode_str, &slave_exec_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#endif
- {"slow-query-log", OPT_SLOW_LOG,
- "Enable/disable slow query log.", &opt_slow_log,
- &opt_slow_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"socket", OPT_SOCKET, "Socket file to use for connection.",
- &mysqld_unix_port, &mysqld_unix_port, 0, GET_STR,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ "Don't give threads different priorities. This option is deprecated "
+ "because it has no effect; the implied behavior is already the default.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_REPLICATION
- {"sporadic-binlog-dump-fail", OPT_SPORADIC_BINLOG_DUMP_FAIL,
+ {"sporadic-binlog-dump-fail", 0,
"Option used by mysql-test for debugging and testing of replication.",
&opt_sporadic_binlog_dump_fail,
&opt_sporadic_binlog_dump_fail, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
0},
#endif /* HAVE_REPLICATION */
- {"sql-bin-update-same", OPT_SQL_BIN_UPDATE_SAME,
- "The update log is deprecated since version 5.0, is replaced by the "
- "binary log and this option does nothing anymore.",
- 0, 0, 0, GET_DISABLED, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"sql-mode", OPT_SQL_MODE,
- "Syntax: sql-mode=option[,option[,option...]] where option can be one "
- "of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, "
- "ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.",
- &sql_mode_str, &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0,
- 0, 0, 0, 0, 0},
#ifdef HAVE_OPENSSL
-#include "sslopt-longopts.h"
+ {"ssl", 0,
+ "Enable SSL for connection (automatically enabled with other flags).",
+ &opt_use_ssl, &opt_use_ssl, 0, GET_BOOL, OPT_ARG, 0, 0, 0,
+ 0, 0, 0},
#endif
#ifdef __WIN__
- {"standalone", OPT_STANDALONE,
+ {"standalone", 0,
"Dummy option to start as a standalone program (NT).", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
@@ -6604,16 +5956,16 @@ thread is in the relay logs.",
option if compiled with valgrind support.
*/
IF_PURIFY(0,1), 0, 0, 0, 0, 0},
- {"sysdate-is-now", OPT_SYSDATE_IS_NOW,
+ {"sysdate-is-now", 0,
"Non-default option to alias SYSDATE() to NOW() to make it safe-replicable. "
"Since 5.0, SYSDATE() returns a `dynamic' value different for different "
"invocations, even within the same statement.",
&global_system_variables.sysdate_is_now,
0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
- {"tc-heuristic-recover", OPT_TC_HEURISTIC_RECOVER,
+ {"tc-heuristic-recover", 0,
"Decision to use in heuristic recover process. Possible values are COMMIT "
- "or ROLLBACK.", &opt_tc_heuristic_recover, &opt_tc_heuristic_recover,
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ "or ROLLBACK.", &tc_heuristic_recover, &tc_heuristic_recover,
+ &tc_heuristic_recover_typelib, GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#if defined(ENABLED_DEBUG_SYNC)
{"debug-sync-timeout", OPT_DEBUG_SYNC_TIMEOUT,
"Enable the debug sync facility "
@@ -6622,7 +5974,7 @@ thread is in the relay logs.",
&opt_debug_sync_timeout, 0,
0, GET_UINT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0},
#endif /* defined(ENABLED_DEBUG_SYNC) */
- {"temp-pool", OPT_TEMP_POOL,
+ {"temp-pool", 0,
#if (ENABLE_TEMP_POOL)
"Using this option will cause most temporary files created to use a small "
"set of names, rather than a unique name for each new file.",
@@ -6631,614 +5983,26 @@ thread is in the relay logs.",
#endif
&use_temp_pool, &use_temp_pool, 0, GET_BOOL, NO_ARG, 1,
0, 0, 0, 0, 0},
- {"timed_mutexes", OPT_TIMED_MUTEXES,
- "Specify whether to time mutexes (only InnoDB mutexes are currently supported).",
- &timed_mutexes, &timed_mutexes, 0, GET_BOOL, NO_ARG, 0,
- 0, 0, 0, 0, 0},
- {"tmpdir", 't',
- "Path for temporary files. Several paths may be specified, separated by a "
-#if defined(__WIN__) || defined(__NETWARE__)
- "semicolon (;)"
-#else
- "colon (:)"
-#endif
- ", in this case they are used in a round-robin fashion.",
- &opt_mysql_tmpdir, &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG,
- 0, 0, 0, 0, 0, 0},
- {"transaction-isolation", OPT_TX_ISOLATION,
- "Default transaction isolation level.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0,
- 0, 0, 0, 0, 0},
- {"use-symbolic-links", OPT_SYMBOLIC_LINKS, "Enable symbolic link support. "
- "Deprecated option; use --symbolic-links instead.",
- &my_use_symdir, &my_use_symdir, 0, GET_BOOL, NO_ARG,
- IF_PURIFY(0,1), 0, 0, 0, 0, 0},
+ {"transaction-isolation", 0,
+ "Default transaction isolation level.",
+ &global_system_variables.tx_isolation,
+ &global_system_variables.tx_isolation, &tx_isolation_typelib,
+ GET_ENUM, REQUIRED_ARG, ISO_REPEATABLE_READ, 0, 0, 0, 0, 0},
{"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
{"verbose", 'v', "Used with --help option for detailed help.",
&opt_verbose, &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
- {"warnings", OPT_WARNINGS, "Deprecated; use --log-warnings instead.",
- &global_system_variables.log_warnings,
- &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG,
- 1, 0, ULONG_MAX, 0, 0, 0},
- {"back_log", OPT_BACK_LOG,
- "The number of outstanding connection requests MySQL can have. This "
- "comes into play when the main MySQL thread gets very many connection "
- "requests in a very short time.", &back_log, &back_log, 0, GET_ULONG,
- REQUIRED_ARG, 50, 1, 65535, 0, 1, 0 },
- {"binlog_cache_size", OPT_BINLOG_CACHE_SIZE,
- "The size of the cache to hold the SQL statements for the binary log "
- "during a transaction. If you often use big, multi-statement "
- "transactions you can increase this to get more performance.",
- &binlog_cache_size, &binlog_cache_size, 0, GET_ULONG,
- REQUIRED_ARG, 32*1024L, IO_SIZE, ULONG_MAX, 0, IO_SIZE, 0},
- {"bulk_insert_buffer_size", OPT_BULK_INSERT_BUFFER_SIZE,
- "Size of tree cache used in bulk insert optimization. Note that this "
- "is a limit per thread.", &global_system_variables.bulk_insert_buff_size,
- &max_system_variables.bulk_insert_buff_size,
- 0, GET_ULONG, REQUIRED_ARG, 8192*1024, 0, ULONG_MAX, 0, 1, 0},
- {"connect_timeout", OPT_CONNECT_TIMEOUT,
- "The number of seconds the mysqld server is waiting for a connect packet "
- "before responding with 'Bad handshake'.", &connect_timeout, &connect_timeout,
- 0, GET_ULONG, REQUIRED_ARG, CONNECT_TIMEOUT, 2, LONG_TIMEOUT, 0, 1, 0 },
- { "date_format", OPT_DATE_FORMAT,
- "The DATE format (for future).",
- &opt_date_time_formats[MYSQL_TIMESTAMP_DATE],
- &opt_date_time_formats[MYSQL_TIMESTAMP_DATE],
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- { "datetime_format", OPT_DATETIME_FORMAT,
- "The DATETIME/TIMESTAMP format (for future).",
- &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME],
- &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME],
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- { "default_week_format", OPT_DEFAULT_WEEK_FORMAT,
- "The default week format used by WEEK() functions.",
- &global_system_variables.default_week_format,
- &max_system_variables.default_week_format,
- 0, GET_ULONG, REQUIRED_ARG, 0, 0, 7L, 0, 1, 0},
- {"delayed_insert_limit", OPT_DELAYED_INSERT_LIMIT,
- "After inserting delayed_insert_limit rows, the INSERT DELAYED handler "
- "will check if there are any SELECT statements pending. If so, it allows "
- "these to execute before continuing.",
- &delayed_insert_limit, &delayed_insert_limit, 0, GET_ULONG,
- REQUIRED_ARG, DELAYED_LIMIT, 1, ULONG_MAX, 0, 1, 0},
- {"delayed_insert_timeout", OPT_DELAYED_INSERT_TIMEOUT,
- "How long a INSERT DELAYED thread should wait for INSERT statements before terminating.",
- &delayed_insert_timeout, &delayed_insert_timeout, 0,
- GET_ULONG, REQUIRED_ARG, DELAYED_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
- { "delayed_queue_size", OPT_DELAYED_QUEUE_SIZE,
- "What size queue (in rows) should be allocated for handling INSERT DELAYED. "
- "If the queue becomes full, any client that does INSERT DELAYED will wait "
- "until there is room in the queue again.",
- &delayed_queue_size, &delayed_queue_size, 0, GET_ULONG,
- REQUIRED_ARG, DELAYED_QUEUE_SIZE, 1, ULONG_MAX, 0, 1, 0},
- {"div_precision_increment", OPT_DIV_PRECINCREMENT,
- "Precision of the result of '/' operator will be increased on that value.",
- &global_system_variables.div_precincrement,
- &max_system_variables.div_precincrement, 0, GET_ULONG,
- REQUIRED_ARG, 4, 0, DECIMAL_MAX_SCALE, 0, 0, 0},
- {"expire_logs_days", OPT_EXPIRE_LOGS_DAYS,
- "If non-zero, binary logs will be purged after expire_logs_days "
- "days; possible purges happen at startup and at binary log rotation.",
- &expire_logs_days, &expire_logs_days, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, 99, 0, 1, 0},
- { "flush_time", OPT_FLUSH_TIME,
- "A dedicated thread is created to flush all tables at the given interval.",
- &flush_time, &flush_time, 0, GET_ULONG, REQUIRED_ARG,
- FLUSH_TIME, 0, LONG_TIMEOUT, 0, 1, 0},
- { "ft_boolean_syntax", OPT_FT_BOOLEAN_SYNTAX,
- "List of operators for MATCH ... AGAINST ( ... IN BOOLEAN MODE).",
- 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- { "ft_max_word_len", OPT_FT_MAX_WORD_LEN,
- "The maximum length of the word to be included in a FULLTEXT index. "
- "Note: FULLTEXT indexes must be rebuilt after changing this variable.",
- &ft_max_word_len, &ft_max_word_len, 0, GET_ULONG,
- REQUIRED_ARG, HA_FT_MAXCHARLEN, 10, HA_FT_MAXCHARLEN, 0, 1, 0},
- { "ft_min_word_len", OPT_FT_MIN_WORD_LEN,
- "The minimum length of the word to be included in a FULLTEXT index. "
- "Note: FULLTEXT indexes must be rebuilt after changing this variable.",
- &ft_min_word_len, &ft_min_word_len, 0, GET_ULONG,
- REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN, 0, 1, 0},
- { "ft_query_expansion_limit", OPT_FT_QUERY_EXPANSION_LIMIT,
- "Number of best matches to use for query expansion.",
- &ft_query_expansion_limit, &ft_query_expansion_limit, 0, GET_ULONG,
- REQUIRED_ARG, 20, 0, 1000, 0, 1, 0},
- { "ft_stopword_file", OPT_FT_STOPWORD_FILE,
- "Use stopwords from this file instead of built-in list.",
- &ft_stopword_file, &ft_stopword_file, 0, GET_STR,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- { "group_concat_max_len", OPT_GROUP_CONCAT_MAX_LEN,
- "The maximum length of the result of function group_concat.",
- &global_system_variables.group_concat_max_len,
- &max_system_variables.group_concat_max_len, 0, GET_ULONG,
- REQUIRED_ARG, 1024, 4, ULONG_MAX, 0, 1, 0},
- {"interactive_timeout", OPT_INTERACTIVE_TIMEOUT,
- "The number of seconds the server waits for activity on an interactive "
- "connection before closing it.",
- &global_system_variables.net_interactive_timeout,
- &max_system_variables.net_interactive_timeout, 0,
- GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
- {"join_buffer_size", OPT_JOIN_BUFF_SIZE,
- "The size of the buffer that is used for full joins.",
- &global_system_variables.join_buff_size,
- &max_system_variables.join_buff_size, 0, GET_ULONG,
- REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ULONG_MAX,
- MALLOC_OVERHEAD, IO_SIZE, 0},
- {"keep_files_on_create", OPT_KEEP_FILES_ON_CREATE,
- "Don't overwrite stale .MYD and .MYI even if no directory is specified.",
- &global_system_variables.keep_files_on_create,
- &max_system_variables.keep_files_on_create,
- 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"key_buffer_size", OPT_KEY_BUFFER_SIZE,
- "The size of the buffer used for index blocks for MyISAM tables. Increase "
- "this to get better index handling (for all reads and multiple writes) to "
- "as much as you can afford; 1GB on a 4GB machine that mainly runs MySQL is "
- "quite common.",
- &dflt_key_cache_var.param_buff_size, NULL, NULL, (GET_ULL | GET_ASK_ADDR),
- REQUIRED_ARG, KEY_CACHE_SIZE, 0, SIZE_T_MAX, MALLOC_OVERHEAD,
- IO_SIZE, 0},
- {"key_cache_age_threshold", OPT_KEY_CACHE_AGE_THRESHOLD,
- "This characterizes the number of hits a hot block has to be untouched "
- "until it is considered aged enough to be downgraded to a warm block. "
- "This specifies the percentage ratio of that number of hits to the total "
- "number of blocks in key cache.",
- &dflt_key_cache_var.param_age_threshold, NULL, NULL,
- (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, 300, 100, ULONG_MAX, 0, 100, 0},
- {"key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE,
- "The default size of key cache blocks.",
- &dflt_key_cache_var.param_block_size, NULL, NULL, (GET_ULONG | GET_ASK_ADDR),
- REQUIRED_ARG, KEY_CACHE_BLOCK_SIZE, 512, 1024 * 16, 0, 512, 0},
- {"key_cache_division_limit", OPT_KEY_CACHE_DIVISION_LIMIT,
- "The minimum percentage of warm blocks in key cache.",
- &dflt_key_cache_var.param_division_limit, NULL, NULL,
- (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100, 1, 100, 0, 1, 0},
- {"long_query_time", OPT_LONG_QUERY_TIME,
- "Log all queries that have taken more than long_query_time seconds to "
- "execute. The argument will be treated as a decimal value with "
- "microsecond precision.",
- &long_query_time, &long_query_time, 0, GET_DOUBLE,
- REQUIRED_ARG, 10, 0, LONG_TIMEOUT, 0, 0, 0},
- {"lower_case_table_names", OPT_LOWER_CASE_TABLE_NAMES,
- "If set to 1, table names are stored in lowercase on disk and table names "
- "will be case-insensitive. Should be set to 2 if you are using a case-"
- "insensitive file system.",
- &lower_case_table_names, &lower_case_table_names, 0, GET_UINT, OPT_ARG,
-#ifdef FN_NO_CASE_SENCE
- 1
-#else
- 0
-#endif
- , 0, 2, 0, 1, 0},
- {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET,
- "The maximum packet length to send to or receive from server.",
- &global_system_variables.max_allowed_packet,
- &max_system_variables.max_allowed_packet, 0, GET_ULONG,
- REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
- {"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE,
- "Can be used to restrict the total size used to cache a multi-transaction query.",
- &max_binlog_cache_size, &max_binlog_cache_size, 0,
- GET_ULL, REQUIRED_ARG, ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0},
- {"max_binlog_size", OPT_MAX_BINLOG_SIZE,
- "Binary log will be rotated automatically when the size exceeds this "
- "value. Will also apply to relay logs if max_relay_log_size is 0. "
- "The minimum value for this variable is 4096.",
- &max_binlog_size, &max_binlog_size, 0, GET_ULONG,
- REQUIRED_ARG, 1024*1024L*1024L, IO_SIZE, 1024*1024L*1024L, 0, IO_SIZE, 0},
- {"max_connect_errors", OPT_MAX_CONNECT_ERRORS,
- "If there is more than this number of interrupted connections from a host "
- "this host will be blocked from further connections.",
- &max_connect_errors, &max_connect_errors, 0, GET_ULONG,
- REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, ULONG_MAX, 0, 1, 0},
- // Default max_connections of 151 is larger than Apache's default max
- // children, to avoid "too many connections" error in a common setup
- {"max_connections", OPT_MAX_CONNECTIONS,
- "The number of simultaneous clients allowed.", &max_connections,
- &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 100000, 0, 1, 0},
- {"max_delayed_threads", OPT_MAX_DELAYED_THREADS,
- "Don't start more than this number of threads to handle INSERT DELAYED "
- "statements. If set to zero, which means INSERT DELAYED is not used.",
- &global_system_variables.max_insert_delayed_threads,
- &max_system_variables.max_insert_delayed_threads,
- 0, GET_ULONG, REQUIRED_ARG, 20, 0, 16384, 0, 1, 0},
- {"max_error_count", OPT_MAX_ERROR_COUNT,
- "Max number of errors/warnings to store for a statement.",
- &global_system_variables.max_error_count,
- &max_system_variables.max_error_count,
- 0, GET_ULONG, REQUIRED_ARG, DEFAULT_ERROR_COUNT, 0, 65535, 0, 1, 0},
- {"max_heap_table_size", OPT_MAX_HEP_TABLE_SIZE,
- "Don't allow creation of heap tables bigger than this.",
- &global_system_variables.max_heap_table_size,
- &max_system_variables.max_heap_table_size, 0, GET_ULL,
- REQUIRED_ARG, 16*1024*1024L, 16384, MAX_MEM_TABLE_SIZE,
- MALLOC_OVERHEAD, 1024, 0},
- {"max_join_size", OPT_MAX_JOIN_SIZE,
- "Joins that are probably going to read more than max_join_size records return an error.",
- &global_system_variables.max_join_size,
- &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG,
- HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0},
- {"max_length_for_sort_data", OPT_MAX_LENGTH_FOR_SORT_DATA,
- "Max number of bytes in sorted records.",
- &global_system_variables.max_length_for_sort_data,
- &max_system_variables.max_length_for_sort_data, 0, GET_ULONG,
- REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0},
- {"max_prepared_stmt_count", OPT_MAX_PREPARED_STMT_COUNT,
- "Maximum number of prepared statements in the server.",
- &max_prepared_stmt_count, &max_prepared_stmt_count,
- 0, GET_ULONG, REQUIRED_ARG, 16382, 0, 1*1024*1024, 0, 1, 0},
- {"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE,
- "If non-zero: relay log will be rotated automatically when the size "
- "exceeds this value; if zero (the default): when the size exceeds "
- "max_binlog_size. 0 excepted, the minimum value for this variable is 4096.",
- &max_relay_log_size, &max_relay_log_size, 0, GET_ULONG,
- REQUIRED_ARG, 0L, 0L, 1024*1024L*1024L, 0, IO_SIZE, 0},
- { "max_seeks_for_key", OPT_MAX_SEEKS_FOR_KEY,
- "Limit assumed max number of seeks when looking up rows based on a key.",
- &global_system_variables.max_seeks_for_key,
- &max_system_variables.max_seeks_for_key, 0, GET_ULONG,
- REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0 },
- {"max_sort_length", OPT_MAX_SORT_LENGTH,
- "The number of bytes to use when sorting BLOB or TEXT values (only the "
- "first max_sort_length bytes of each value are used; the rest are ignored).",
- &global_system_variables.max_sort_length,
- &max_system_variables.max_sort_length, 0, GET_ULONG,
- REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0},
- {"max_sp_recursion_depth", OPT_MAX_SP_RECURSION_DEPTH,
- "Maximum stored procedure recursion depth. (discussed with docs).",
- &global_system_variables.max_sp_recursion_depth,
- &max_system_variables.max_sp_recursion_depth, 0, GET_ULONG,
- OPT_ARG, 0, 0, 255, 0, 1, 0 },
- {"max_tmp_tables", OPT_MAX_TMP_TABLES,
- "Maximum number of temporary tables a client can keep open at a time.",
- &global_system_variables.max_tmp_tables,
- &max_system_variables.max_tmp_tables, 0, GET_ULONG,
- REQUIRED_ARG, 32, 1, ULONG_MAX, 0, 1, 0},
- {"max_user_connections", OPT_MAX_USER_CONNECTIONS,
- "The maximum number of active connections for a single user (0 = no limit).",
- &max_user_connections, &max_user_connections, 0, GET_UINT,
- REQUIRED_ARG, 0, 0, UINT_MAX, 0, 1, 0},
- {"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT,
- "After this many write locks, allow some read locks to run in between.",
- &max_write_lock_count, &max_write_lock_count, 0, GET_ULONG,
- REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0},
- {"min_examined_row_limit", OPT_MIN_EXAMINED_ROW_LIMIT,
- "Don't log queries which examine less than min_examined_row_limit rows to file.",
- &global_system_variables.min_examined_row_limit,
- &max_system_variables.min_examined_row_limit, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, ULONG_MAX, 0, 1L, 0},
- {"multi_range_count", OPT_MULTI_RANGE_COUNT,
- "Number of key ranges to request at once.",
- &global_system_variables.multi_range_count,
- &max_system_variables.multi_range_count, 0,
- GET_ULONG, REQUIRED_ARG, 256, 1, ULONG_MAX, 0, 1, 0},
- {"myisam_block_size", OPT_MYISAM_BLOCK_SIZE,
- "Block size to be used for MyISAM index pages.",
- &opt_myisam_block_size, &opt_myisam_block_size, 0, GET_ULONG, REQUIRED_ARG,
- MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH, MI_MAX_KEY_BLOCK_LENGTH,
- 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
- {"myisam_data_pointer_size", OPT_MYISAM_DATA_POINTER_SIZE,
- "Default pointer size to be used for MyISAM tables.",
- &myisam_data_pointer_size,
- &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG,
- 6, 2, 7, 0, 1, 0},
- {"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
- "This is a deprecated option that does nothing anymore. "
- "It will be removed in MySQL " VER_CELOSIA,
- &global_system_variables.myisam_max_extra_sort_file_size,
- &max_system_variables.myisam_max_extra_sort_file_size,
- 0, GET_ULL, REQUIRED_ARG, (ulonglong) INT_MAX32,
- 0, (ulonglong) MAX_FILE_SIZE, 0, 1, 0},
- {"myisam_max_sort_file_size", OPT_MYISAM_MAX_SORT_FILE_SIZE,
- "Don't use the fast sort index method to created index if the temporary "
- "file would get bigger than this.",
- &global_system_variables.myisam_max_sort_file_size,
- &max_system_variables.myisam_max_sort_file_size, 0,
- GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, (ulonglong) MAX_FILE_SIZE,
- 0, 1024*1024, 0},
- {"myisam_mmap_size", OPT_MYISAM_MMAP_SIZE,
- "Can be used to restrict the total memory used for memory mmaping of myisam files",
- &myisam_mmap_size, &myisam_mmap_size, 0,
- GET_ULL, REQUIRED_ARG, SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, 0, 1, 0},
- {"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS,
- "Specifies whether several threads should be used when repairing MyISAM "
- "tables. For values > 1, one thread is used per index. The value of 1 "
- "disables parallel repair.",
- &global_system_variables.myisam_repair_threads,
- &max_system_variables.myisam_repair_threads, 0,
- GET_ULONG, REQUIRED_ARG, 1, 1, ULONG_MAX, 0, 1, 0},
- {"myisam_sort_buffer_size", OPT_MYISAM_SORT_BUFFER_SIZE,
- "The buffer that is allocated when sorting the index when doing a REPAIR "
- "or when creating indexes with CREATE INDEX or ALTER TABLE.",
- &global_system_variables.myisam_sort_buff_size,
- &max_system_variables.myisam_sort_buff_size, 0,
- GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, ~0L, 0, 1, 0},
- {"myisam_use_mmap", OPT_MYISAM_USE_MMAP,
- "Use memory mapping for reading and writing MyISAM tables.",
- &opt_myisam_use_mmap, &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG,
- 0, 0, 0, 0, 0, 0},
- {"myisam_stats_method", OPT_MYISAM_STATS_METHOD,
- "Specifies how MyISAM index statistics collection code should threat NULLs. "
- "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
- "\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
- &myisam_stats_method_str, &myisam_stats_method_str, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"net_buffer_length", OPT_NET_BUFFER_LENGTH,
- "Buffer length for TCP/IP and socket communication.",
- &global_system_variables.net_buffer_length,
- &max_system_variables.net_buffer_length, 0, GET_ULONG,
- REQUIRED_ARG, 16384, 1024, 1024*1024L, 0, 1024, 0},
- {"net_read_timeout", OPT_NET_READ_TIMEOUT,
- "Number of seconds to wait for more data from a connection before aborting the read.",
- &global_system_variables.net_read_timeout,
- &max_system_variables.net_read_timeout, 0, GET_ULONG,
- REQUIRED_ARG, NET_READ_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
- {"net_retry_count", OPT_NET_RETRY_COUNT,
- "If a read on a communication port is interrupted, retry this many times before giving up.",
- &global_system_variables.net_retry_count,
- &max_system_variables.net_retry_count,0,
- GET_ULONG, REQUIRED_ARG, MYSQLD_NET_RETRY_COUNT, 1, ULONG_MAX, 0, 1, 0},
- {"net_write_timeout", OPT_NET_WRITE_TIMEOUT,
- "Number of seconds to wait for a block to be written to a connection before "
- "aborting the write.",
- &global_system_variables.net_write_timeout,
- &max_system_variables.net_write_timeout, 0, GET_ULONG,
- REQUIRED_ARG, NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
- { "old", OPT_OLD_MODE, "Use compatible behavior.",
- &global_system_variables.old_mode,
- &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG,
- 0, 0, 0, 0, 0, 0},
- {"open_files_limit", OPT_OPEN_FILES_LIMIT,
- "If this is not 0, then mysqld will use this value to reserve file "
- "descriptors to use with setrlimit(). If this value is 0 then mysqld "
- "will reserve max_connections*5 or max_connections + table_cache*2 "
- "(whichever is larger) number of files.",
- &open_files_limit, &open_files_limit, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, OS_FILE_LIMIT, 0, 1, 0},
- {"optimizer_prune_level", OPT_OPTIMIZER_PRUNE_LEVEL,
- "Controls the heuristic(s) applied during query optimization to prune "
- "less-promising partial plans from the optimizer search space. Meaning: "
- "0 - do not apply any heuristic, thus perform exhaustive search; 1 - "
- "prune plans based on number of retrieved rows.",
- &global_system_variables.optimizer_prune_level,
- &max_system_variables.optimizer_prune_level,
- 0, GET_ULONG, OPT_ARG, 1, 0, 1, 0, 1, 0},
- {"optimizer_search_depth", OPT_OPTIMIZER_SEARCH_DEPTH,
- "Maximum depth of search performed by the query optimizer. Values larger "
- "than the number of relations in a query result in better query plans, "
- "but take longer to compile a query. Smaller values than the number of "
- "tables in a relation result in faster optimization, but may produce "
- "very bad query plans. If set to 0, the system will automatically pick "
- "a reasonable value; if set to MAX_TABLES+2, the optimizer will switch "
- "to the original find_best (used for testing/comparison).",
- &global_system_variables.optimizer_search_depth,
- &max_system_variables.optimizer_search_depth,
- 0, GET_ULONG, OPT_ARG, MAX_TABLES+1, 0, MAX_TABLES+2, 0, 1, 0},
- {"optimizer_switch", OPT_OPTIMIZER_SWITCH,
- "optimizer_switch=option=val[,option=val...], where option={index_merge, "
- "index_merge_union, index_merge_sort_union, index_merge_intersection} and "
- "val={on, off, default}.",
- &optimizer_switch_str, &optimizer_switch_str, 0, GET_STR, REQUIRED_ARG,
- /*OPTIMIZER_SWITCH_DEFAULT*/0, 0, 0, 0, 0, 0},
- {"plugin_dir", OPT_PLUGIN_DIR,
- "Directory for plugins.",
- &opt_plugin_dir_ptr, &opt_plugin_dir_ptr, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"plugin-load", OPT_PLUGIN_LOAD,
+ {"plugin-load", 0,
"Optional semicolon-separated list of plugins to load, where each plugin is "
"identified as name=library, where name is the plugin name and library "
"is the plugin library in plugin_dir.",
&opt_plugin_load, &opt_plugin_load, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE,
- "The size of the buffer that is allocated when preloading indexes.",
- &global_system_variables.preload_buff_size,
- &max_system_variables.preload_buff_size, 0, GET_ULONG,
- REQUIRED_ARG, 32*1024L, 1024, 1024*1024*1024L, 0, 1, 0},
- {"query_alloc_block_size", OPT_QUERY_ALLOC_BLOCK_SIZE,
- "Allocation block size for query parsing and execution.",
- &global_system_variables.query_alloc_block_size,
- &max_system_variables.query_alloc_block_size, 0, GET_ULONG,
- REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ULONG_MAX, 0, 1024, 0},
-#ifdef HAVE_QUERY_CACHE
- {"query_cache_limit", OPT_QUERY_CACHE_LIMIT,
- "Don't cache results that are bigger than this.",
- &query_cache_limit, &query_cache_limit, 0, GET_ULONG,
- REQUIRED_ARG, 1024*1024L, 0, ULONG_MAX, 0, 1, 0},
- {"query_cache_min_res_unit", OPT_QUERY_CACHE_MIN_RES_UNIT,
- "Minimal size of unit in which space for results is allocated (last unit "
- "will be trimmed after writing all result data).",
- &query_cache_min_res_unit, &query_cache_min_res_unit,
- 0, GET_ULONG, REQUIRED_ARG, QUERY_CACHE_MIN_RESULT_DATA_SIZE,
- 0, ULONG_MAX, 0, 1, 0},
-#endif /*HAVE_QUERY_CACHE*/
- {"query_cache_size", OPT_QUERY_CACHE_SIZE,
- "The memory allocated to store results from old queries.",
- &query_cache_size, &query_cache_size, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1024, 0},
-#ifdef HAVE_QUERY_CACHE
- {"query_cache_type", OPT_QUERY_CACHE_TYPE,
- "0 = OFF = Don't cache or retrieve results. 1 = ON = Cache all results "
- "except SELECT SQL_NO_CACHE ... queries. 2 = DEMAND = Cache only SELECT "
- "SQL_CACHE ... queries.", &global_system_variables.query_cache_type,
- &max_system_variables.query_cache_type,
- 0, GET_ULONG, REQUIRED_ARG, 1, 0, 2, 0, 1, 0},
- {"query_cache_wlock_invalidate", OPT_QUERY_CACHE_WLOCK_INVALIDATE,
- "Invalidate queries in query cache on LOCK for write.",
- &global_system_variables.query_cache_wlock_invalidate,
- &max_system_variables.query_cache_wlock_invalidate,
- 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
-#endif /*HAVE_QUERY_CACHE*/
- {"query_prealloc_size", OPT_QUERY_PREALLOC_SIZE,
- "Persistent buffer for query parsing and execution.",
- &global_system_variables.query_prealloc_size,
- &max_system_variables.query_prealloc_size, 0, GET_ULONG,
- REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, QUERY_ALLOC_PREALLOC_SIZE,
- ULONG_MAX, 0, 1024, 0},
- {"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE,
- "Allocation block size for storing ranges during optimization.",
- &global_system_variables.range_alloc_block_size,
- &max_system_variables.range_alloc_block_size, 0, GET_ULONG,
- REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, RANGE_ALLOC_BLOCK_SIZE, ULONG_MAX,
- 0, 1024, 0},
- {"read_buffer_size", OPT_RECORD_BUFFER,
- "Each thread that does a sequential scan allocates a buffer of this size "
- "for each table it scans. If you do many sequential scans, you may want "
- "to increase this value.", &global_system_variables.read_buff_size,
- &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
- 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE,
- 0},
- {"read_only", OPT_READONLY,
- "Make all non-temporary tables read-only, with the exception of replication "
- "(slave) threads and users with the SUPER privilege.",
- &opt_readonly,
- &opt_readonly,
- 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
- {"read_rnd_buffer_size", OPT_RECORD_RND_BUFFER,
- "When reading rows in sorted order after a sort, the rows are read through "
- "this buffer to avoid disk seeks. If not set, then it's set to the value of "
- "record_buffer.",
- &global_system_variables.read_rnd_buff_size,
- &max_system_variables.read_rnd_buff_size, 0,
- GET_ULONG, REQUIRED_ARG, 256*1024L, IO_SIZE*2+MALLOC_OVERHEAD,
- INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0},
- {"record_buffer", OPT_RECORD_BUFFER_OLD,
- "Alias for read_buffer_size. This variable is deprecated and will be removed in a future release.",
- &global_system_variables.read_buff_size,
- &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
- 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0},
-#ifdef HAVE_REPLICATION
- {"relay_log_purge", OPT_RELAY_LOG_PURGE,
- "0 = do not purge relay logs. 1 = purge them as soon as they are no more needed.",
- &relay_log_purge,
- &relay_log_purge, 0, GET_BOOL, NO_ARG,
- 1, 0, 1, 0, 1, 0},
- {"relay_log_space_limit", OPT_RELAY_LOG_SPACE_LIMIT,
- "Maximum space to use for all relay logs.",
- &relay_log_space_limit,
- &relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L,
- (longlong) ULONG_MAX, 0, 1, 0},
- {"slave_compressed_protocol", OPT_SLAVE_COMPRESSED_PROTOCOL,
- "Use compression on master/slave protocol.",
- &opt_slave_compressed_protocol,
- &opt_slave_compressed_protocol,
- 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
- {"slave_net_timeout", OPT_SLAVE_NET_TIMEOUT,
- "Number of seconds to wait for more data from a master/slave connection before aborting the read.",
- &slave_net_timeout, &slave_net_timeout, 0,
- GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
- {"slave_transaction_retries", OPT_SLAVE_TRANS_RETRIES,
- "Number of times the slave SQL thread will retry a transaction in case "
- "it failed with a deadlock or elapsed lock wait timeout, "
- "before giving up and stopping.",
- &slave_trans_retries, &slave_trans_retries, 0,
- GET_ULONG, REQUIRED_ARG, 10L, 0L, (longlong) ULONG_MAX, 0, 1, 0},
-#endif /* HAVE_REPLICATION */
- {"slow_launch_time", OPT_SLOW_LAUNCH_TIME,
- "If creating the thread takes longer than this value (in seconds), "
- "the Slow_launch_threads counter will be incremented.",
- &slow_launch_time, &slow_launch_time, 0, GET_ULONG,
- REQUIRED_ARG, 2L, 0L, LONG_TIMEOUT, 0, 1, 0},
- {"sort_buffer_size", OPT_SORT_BUFFER,
- "Each thread that needs to do a sort allocates a buffer of this size.",
- &global_system_variables.sortbuff_size,
- &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG,
- MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD,
- 1, 0},
- {"sync-binlog", OPT_SYNC_BINLOG,
- "Synchronously flush binary log to disk after every #th event. "
- "Use 0 (default) to disable synchronous flushing.",
- &sync_binlog_period, &sync_binlog_period, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, ULONG_MAX, 0, 1, 0},
- {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.",
- &opt_sync_frm, &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0,
- 0, 0, 0, 0},
- {"table_cache", OPT_TABLE_OPEN_CACHE,
- "Deprecated; use --table_open_cache instead.",
- &table_cache_size, &table_cache_size, 0, GET_ULONG,
- REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0},
- {"table_definition_cache", OPT_TABLE_DEF_CACHE,
- "The number of cached table definitions.",
- &table_def_size, &table_def_size,
- 0, GET_ULONG, REQUIRED_ARG, TABLE_DEF_CACHE_DEFAULT, TABLE_DEF_CACHE_MIN,
- 512*1024L, 0, 1, 0},
- {"table_open_cache", OPT_TABLE_OPEN_CACHE,
- "The number of cached open tables.",
+ {"table_cache", 0, "Deprecated; use --table-open-cache instead.",
&table_cache_size, &table_cache_size, 0, GET_ULONG,
REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0},
- {"table_lock_wait_timeout", OPT_TABLE_LOCK_WAIT_TIMEOUT,
- "Timeout in seconds to wait for a table level lock before returning an "
- "error. Used only if the connection has active cursors.",
- &table_lock_wait_timeout, &table_lock_wait_timeout,
- 0, GET_ULONG, REQUIRED_ARG, 50, 1, 1024 * 1024 * 1024, 0, 1, 0},
- {"thread_cache_size", OPT_THREAD_CACHE_SIZE,
- "How many threads we should keep in a cache for reuse.",
- &thread_cache_size, &thread_cache_size, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, 16384, 0, 1, 0},
- {"thread_concurrency", OPT_THREAD_CONCURRENCY,
- "Permits the application to give the threads system a hint for the "
- "desired number of threads that should be run at the same time.",
- &concurrency, &concurrency, 0, GET_ULONG, REQUIRED_ARG,
- DEFAULT_CONCURRENCY, 1, 512, 0, 1, 0},
-#if HAVE_POOL_OF_THREADS == 1
- {"thread_pool_size", OPT_THREAD_CACHE_SIZE,
- "How many threads we should create to handle query requests in case of "
- "'thread_handling=pool-of-threads'.",
- &thread_pool_size, &thread_pool_size, 0, GET_ULONG,
- REQUIRED_ARG, 20, 1, 16384, 0, 1, 0},
-#endif
- {"thread_stack", OPT_THREAD_STACK,
- "The stack size for each thread.", &my_thread_stack_size,
- &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
- 1024L*128L, ULONG_MAX, 0, 1024, 0},
- { "time_format", OPT_TIME_FORMAT,
- "The TIME format (for future).",
- &opt_date_time_formats[MYSQL_TIMESTAMP_TIME],
- &opt_date_time_formats[MYSQL_TIMESTAMP_TIME],
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"tmp_table_size", OPT_TMP_TABLE_SIZE,
- "If an internal in-memory temporary table exceeds this size, MySQL will"
- " automatically convert it to an on-disk MyISAM table.",
- &global_system_variables.tmp_table_size,
- &max_system_variables.tmp_table_size, 0, GET_ULL,
- REQUIRED_ARG, 16*1024*1024L, 1024, MAX_MEM_TABLE_SIZE, 0, 1, 0},
- {"transaction_alloc_block_size", OPT_TRANS_ALLOC_BLOCK_SIZE,
- "Allocation block size for transactions to be stored in binary log.",
- &global_system_variables.trans_alloc_block_size,
- &max_system_variables.trans_alloc_block_size, 0, GET_ULONG,
- REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ULONG_MAX, 0, 1024, 0},
- {"transaction_prealloc_size", OPT_TRANS_PREALLOC_SIZE,
- "Persistent buffer for transactions to be stored in binary log.",
- &global_system_variables.trans_prealloc_size,
- &max_system_variables.trans_prealloc_size, 0, GET_ULONG,
- REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ULONG_MAX, 0, 1024, 0},
- {"thread_handling", OPT_THREAD_HANDLING,
- "Define threads usage for handling queries: "
- "one-thread-per-connection or no-threads.", 0, 0,
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"updatable_views_with_limit", OPT_UPDATABLE_VIEWS_WITH_LIMIT,
- "1 = YES = Don't issue an error message (warning only) if a VIEW without "
- "presence of a key of the underlying table is used in queries with a "
- "LIMIT clause for updating. 0 = NO = Prohibit update of a VIEW, which "
- "does not contain a key of the underlying table and the query uses a "
- "LIMIT clause (usually get from GUI tools).",
- &global_system_variables.updatable_views_with_limit,
- &max_system_variables.updatable_views_with_limit,
- 0, GET_ULONG, REQUIRED_ARG, 1, 0, 1, 0, 1, 0},
- {"wait_timeout", OPT_WAIT_TIMEOUT,
- "The number of seconds the server waits for activity on a connection before closing it.",
- &global_system_variables.net_wait_timeout,
- &max_system_variables.net_wait_timeout, 0, GET_ULONG,
- REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT),
- 0, 1, 0},
- {"binlog-direct-non-transactional-updates", OPT_BINLOG_DIRECT_NON_TRANS_UPDATE,
- "Causes updates to non-transactional engines using statement format to be "
- "written directly to binary log. Before using this option, make sure that "
- "there are no dependencies between transactional and non-transactional "
- "tables such as in the statement INSERT INTO t_myisam SELECT * FROM "
- "t_innodb; otherwise, slaves may diverge from the master.",
- &global_system_variables.binlog_direct_non_trans_update,
- &max_system_variables.binlog_direct_non_trans_update,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -7266,7 +6030,7 @@ static int show_starttime(THD *thd, SHOW_VAR *var, char *buff)
return 0;
}
-#ifdef COMMUNITY_SERVER
+#ifdef ENABLED_PROFILING
static int show_flushstatustime(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONG;
@@ -7287,12 +6051,12 @@ static int show_rpl_status(THD *thd, SHOW_VAR *var, char *buff)
static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_MY_BOOL;
- pthread_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_active_mi);
var->value= buff;
*((my_bool *)buff)= (my_bool) (active_mi &&
active_mi->slave_running == MYSQL_SLAVE_RUN_CONNECT &&
active_mi->rli.slave_running);
- pthread_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_unlock(&LOCK_active_mi);
return 0;
}
@@ -7302,20 +6066,54 @@ static int show_slave_retried_trans(THD *thd, SHOW_VAR *var, char *buff)
TODO: with multimaster, have one such counter per line in
SHOW SLAVE STATUS, and have the sum over all lines here.
*/
- pthread_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_active_mi);
if (active_mi)
{
var->type= SHOW_LONG;
var->value= buff;
- pthread_mutex_lock(&active_mi->rli.data_lock);
+ mysql_mutex_lock(&active_mi->rli.data_lock);
*((long *)buff)= (long)active_mi->rli.retried_trans;
- pthread_mutex_unlock(&active_mi->rli.data_lock);
+ mysql_mutex_unlock(&active_mi->rli.data_lock);
+ }
+ else
+ var->type= SHOW_UNDEF;
+ mysql_mutex_unlock(&LOCK_active_mi);
+ return 0;
+}
+
+static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff)
+{
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (active_mi)
+ {
+ var->type= SHOW_LONGLONG;
+ var->value= buff;
+ mysql_mutex_lock(&active_mi->rli.data_lock);
+ *((longlong *)buff)= active_mi->received_heartbeats;
+ mysql_mutex_unlock(&active_mi->rli.data_lock);
}
else
var->type= SHOW_UNDEF;
- pthread_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_unlock(&LOCK_active_mi);
return 0;
}
+
+static int show_heartbeat_period(THD *thd, SHOW_VAR *var, char *buff)
+{
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (active_mi)
+ {
+ var->type= SHOW_CHAR;
+ var->value= buff;
+ sprintf(buff, "%.3f", active_mi->heartbeat_period);
+ }
+ else
+ var->type= SHOW_UNDEF;
+ mysql_mutex_unlock(&LOCK_active_mi);
+ return 0;
+}
+
+
#endif /* HAVE_REPLICATION */
static int show_open_tables(THD *thd, SHOW_VAR *var, char *buff)
@@ -7330,9 +6128,9 @@ static int show_prepared_stmt_count(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONG;
var->value= buff;
- pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ mysql_mutex_lock(&LOCK_prepared_stmt_count);
*((long *)buff)= (long)prepared_stmt_count;
- pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+ mysql_mutex_unlock(&LOCK_prepared_stmt_count);
return 0;
}
@@ -7344,7 +6142,7 @@ static int show_table_definitions(THD *thd, SHOW_VAR *var, char *buff)
return 0;
}
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
/* Functions relying on CTX */
static int show_ssl_ctx_sess_accept(THD *thd, SHOW_VAR *var, char *buff)
{
@@ -7600,7 +6398,7 @@ static int show_ssl_get_cipher_list(THD *thd, SHOW_VAR *var, char *buff)
return 0;
}
-#endif /* HAVE_OPENSSL */
+#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
/*
@@ -7612,6 +6410,8 @@ SHOW_VAR status_vars[]= {
{"Aborted_connects", (char*) &aborted_connects, SHOW_LONG},
{"Binlog_cache_disk_use", (char*) &binlog_cache_disk_use, SHOW_LONG},
{"Binlog_cache_use", (char*) &binlog_cache_use, SHOW_LONG},
+ {"Binlog_stmt_cache_disk_use",(char*) &binlog_stmt_cache_disk_use, SHOW_LONG},
+ {"Binlog_stmt_cache_use", (char*) &binlog_stmt_cache_use, SHOW_LONG},
{"Bytes_received", (char*) offsetof(STATUS_VAR, bytes_received), SHOW_LONGLONG_STATUS},
{"Bytes_sent", (char*) offsetof(STATUS_VAR, bytes_sent), SHOW_LONGLONG_STATUS},
{"Com", (char*) com_status_vars, SHOW_ARRAY},
@@ -7630,6 +6430,7 @@ SHOW_VAR status_vars[]= {
{"Handler_prepare", (char*) offsetof(STATUS_VAR, ha_prepare_count), SHOW_LONG_STATUS},
{"Handler_read_first", (char*) offsetof(STATUS_VAR, ha_read_first_count), SHOW_LONG_STATUS},
{"Handler_read_key", (char*) offsetof(STATUS_VAR, ha_read_key_count), SHOW_LONG_STATUS},
+ {"Handler_read_last", (char*) offsetof(STATUS_VAR, ha_read_last_count), SHOW_LONG_STATUS},
{"Handler_read_next", (char*) offsetof(STATUS_VAR, ha_read_next_count), SHOW_LONG_STATUS},
{"Handler_read_prev", (char*) offsetof(STATUS_VAR, ha_read_prev_count), SHOW_LONG_STATUS},
{"Handler_read_rnd", (char*) offsetof(STATUS_VAR, ha_read_rnd_count), SHOW_LONG_STATUS},
@@ -7680,6 +6481,8 @@ SHOW_VAR status_vars[]= {
{"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_LONG},
#ifdef HAVE_REPLICATION
{"Slave_retried_transactions",(char*) &show_slave_retried_trans, SHOW_FUNC},
+ {"Slave_heartbeat_period", (char*) &show_heartbeat_period, SHOW_FUNC},
+ {"Slave_received_heartbeats",(char*) &show_slave_received_heartbeats, SHOW_FUNC},
{"Slave_running", (char*) &show_slave_running, SHOW_FUNC},
#endif
{"Slow_launch_threads", (char*) &slow_launch_threads, SHOW_LONG},
@@ -7689,6 +6492,7 @@ SHOW_VAR status_vars[]= {
{"Sort_rows", (char*) offsetof(STATUS_VAR, filesort_rows), SHOW_LONG_STATUS},
{"Sort_scan", (char*) offsetof(STATUS_VAR, filesort_scan_count), SHOW_LONG_STATUS},
#ifdef HAVE_OPENSSL
+#ifndef EMBEDDED_LIBRARY
{"Ssl_accept_renegotiates", (char*) &show_ssl_ctx_sess_accept_renegotiate, SHOW_FUNC},
{"Ssl_accepts", (char*) &show_ssl_ctx_sess_accept, SHOW_FUNC},
{"Ssl_callback_cache_hits", (char*) &show_ssl_ctx_sess_cb_hits, SHOW_FUNC},
@@ -7712,6 +6516,7 @@ SHOW_VAR status_vars[]= {
{"Ssl_verify_depth", (char*) &show_ssl_get_verify_depth, SHOW_FUNC},
{"Ssl_verify_mode", (char*) &show_ssl_get_verify_mode, SHOW_FUNC},
{"Ssl_version", (char*) &show_ssl_get_version, SHOW_FUNC},
+#endif
#endif /* HAVE_OPENSSL */
{"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG},
{"Table_locks_waited", (char*) &locks_waited, SHOW_LONG},
@@ -7721,30 +6526,78 @@ SHOW_VAR status_vars[]= {
{"Tc_log_page_waits", (char*) &tc_log_page_waits, SHOW_LONG},
#endif
{"Threads_cached", (char*) &cached_thread_count, SHOW_LONG_NOFLUSH},
- {"Threads_connected", (char*) &thread_count, SHOW_INT},
+ {"Threads_connected", (char*) &connection_count, SHOW_INT},
{"Threads_created", (char*) &thread_created, SHOW_LONG_NOFLUSH},
{"Threads_running", (char*) &thread_running, SHOW_INT},
{"Uptime", (char*) &show_starttime, SHOW_FUNC},
-#ifdef COMMUNITY_SERVER
+#ifdef ENABLED_PROFILING
{"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_FUNC},
#endif
{NullS, NullS, SHOW_LONG}
};
+bool add_terminator(DYNAMIC_ARRAY *options)
+{
+ my_option empty_element= {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0};
+ return insert_dynamic(options, (uchar *)&empty_element);
+}
+
#ifndef EMBEDDED_LIBRARY
static void print_version(void)
{
set_server_version();
- /*
- Note: the instance manager keys off the string 'Ver' so it can find the
- version from the output of 'mysqld --version', so don't change it!
- */
+
printf("%s Ver %s for %s on %s (%s)\n",my_progname,
server_version,SYSTEM_TYPE,MACHINE_TYPE, MYSQL_COMPILATION_COMMENT);
}
+/** Compares two options' names, treats - and _ the same */
+static int option_cmp(my_option *a, my_option *b)
+{
+ const char *sa= a->name;
+ const char *sb= b->name;
+ for (; *sa || *sb; sa++, sb++)
+ {
+ if (*sa < *sb)
+ {
+ if (*sa == '-' && *sb == '_')
+ continue;
+ else
+ return -1;
+ }
+ if (*sa > *sb)
+ {
+ if (*sa == '_' && *sb == '-')
+ continue;
+ else
+ return 1;
+ }
+ }
+ DBUG_ASSERT(a->name == b->name);
+ return 0;
+}
+
+static void print_help()
+{
+ MEM_ROOT mem_root;
+ init_alloc_root(&mem_root, 4096, 4096);
+
+ pop_dynamic(&all_options);
+ sys_var_add_options(&all_options, sys_var::PARSE_EARLY);
+ add_plugin_options(&all_options, &mem_root);
+ sort_dynamic(&all_options, (qsort_cmp) option_cmp);
+ add_terminator(&all_options);
+
+ my_print_help((my_option*) all_options.buffer);
+ my_print_variables((my_option*) all_options.buffer);
+
+ free_root(&mem_root, MYF(0));
+ delete_dynamic(&all_options);
+}
+
static void usage(void)
{
+ DBUG_ENTER("usage");
if (!(default_charset_info= get_charset_by_csname(default_character_set_name,
MY_CS_PRIMARY,
MYF(MY_WME))))
@@ -7752,13 +6605,8 @@ static void usage(void)
if (!default_collation_name)
default_collation_name= (char*) default_charset_info->name;
print_version();
- puts("\
-Copyright (C) 2000-2008 MySQL AB, by Monty and others.\n\
-Copyright (C) 2008 Sun Microsystems, Inc.\n\
-This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
-and you are welcome to modify and redistribute it under the GPL license\n\n\
-Starts the MySQL database server.\n");
-
+ puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000, 2010"));
+ puts("Starts the MySQL database server.\n");
printf("Usage: %s [OPTIONS]\n", my_progname);
if (!opt_verbose)
puts("\nFor more help options (several pages), use mysqld --verbose --help.");
@@ -7782,7 +6630,7 @@ Starts the MySQL database server.\n");
set_ports();
/* Print out all the options including plugin supplied options */
- my_print_help_inc_plugins(my_long_options, sizeof(my_long_options)/sizeof(my_option));
+ print_help();
if (! plugins_are_initialized)
{
@@ -7795,15 +6643,12 @@ because execution stopped before plugins were initialized.");
To see what values a running MySQL server is using, type\n\
'mysqladmin variables' instead of 'mysqld --verbose --help'.");
}
+ DBUG_VOID_RETURN;
}
#endif /*!EMBEDDED_LIBRARY*/
-
/**
- Initialize all MySQL global variables to default values.
-
- We don't need to set numeric variables refered to in my_long_options
- as these are initialized by my_getopt.
+ Initialize MySQL global variables to default values.
@note
The reason to set a lot of global variables to zero is to allow one to
@@ -7811,20 +6656,17 @@ To see what values a running MySQL server is using, type\n\
It's also needed on some exotic platforms where global variables are
not set to 0 when a program starts.
- We don't need to set numeric variables refered to in my_long_options
+ We don't need to set variables refered to in my_long_options
as these are initialized by my_getopt.
*/
static int mysql_init_variables(void)
{
- int error;
/* Things reset to zero */
opt_skip_slave_start= opt_reckless_slave = 0;
mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0;
myisam_test_invalid_symlink= test_if_data_home_dir;
opt_log= opt_slow_log= 0;
- opt_update_log= 0;
- log_output_options= find_bit_type(log_output_str, &log_output_typelib);
opt_bin_log= 0;
opt_disable_networking= opt_skip_show_db=0;
opt_skip_name_resolve= 0;
@@ -7832,13 +6674,10 @@ static int mysql_init_variables(void)
opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0;
opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name !
opt_secure_auth= 0;
- opt_secure_file_priv= 0;
opt_bootstrap= opt_myisam_log= 0;
mqh_used= 0;
segfaulted= kill_in_progress= 0;
cleanup_done= 0;
- defaults_argc= 0;
- defaults_argv= 0;
server_id_supplied= 0;
test_flags= select_errors= dropping_tables= ha_open_options=0;
thread_count= thread_running= kill_cached_threads= wake_thread=0;
@@ -7856,11 +6695,11 @@ static int mysql_init_variables(void)
max_used_connections= slow_launch_threads = 0;
mysqld_user= mysqld_chroot= opt_init_file= opt_bin_logname = 0;
prepared_stmt_count= 0;
- errmesg= 0;
mysqld_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS;
bzero((uchar*) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list));
bzero((char *) &global_status_var, sizeof(global_status_var));
opt_large_pages= 0;
+ opt_super_large_pages= 0;
#if defined(ENABLED_DEBUG_SYNC)
opt_debug_sync_timeout= 0;
#endif /* defined(ENABLED_DEBUG_SYNC) */
@@ -7873,34 +6712,19 @@ static int mysql_init_variables(void)
table_alias_charset= &my_charset_bin;
character_set_filesystem= &my_charset_bin;
- opt_date_time_formats[0]= opt_date_time_formats[1]= opt_date_time_formats[2]= 0;
-
- /* Things with default values that are not zero */
- delay_key_write_options= (uint) DELAY_KEY_WRITE_ON;
- slave_exec_mode_options= find_bit_type_or_exit(slave_exec_mode_str,
- &slave_exec_mode_typelib,
- NULL, &error);
- /* Default mode string must not yield a error. */
- DBUG_ASSERT(!error);
- if (error)
- return 1;
opt_specialflag= SPECIAL_ENGLISH;
unix_sock= ip_sock= INVALID_SOCKET;
mysql_home_ptr= mysql_home;
pidfile_name_ptr= pidfile_name;
log_error_file_ptr= log_error_file;
- language_ptr= language;
- mysql_data_home= mysql_real_data_home;
- thd_startup_options= (OPTION_AUTO_IS_NULL | OPTION_BIN_LOG |
- OPTION_QUOTE_SHOW_CREATE | OPTION_SQL_NOTES);
+ lc_messages_dir_ptr= lc_messages_dir;
protocol_version= PROTOCOL_VERSION;
what_to_log= ~ (1L << (uint) COM_TIME);
refresh_version= 1L; /* Increments on each reload */
global_query_id= thread_id= 1L;
+ my_atomic_rwlock_init(&global_query_id_lock);
+ my_atomic_rwlock_init(&thread_running_lock);
strmov(server_version, MYSQL_SERVER_VERSION);
- myisam_recover_options_str= sql_mode_str= "OFF";
- myisam_stats_method_str= "nulls_unequal";
- my_bind_addr = htonl(INADDR_ANY);
threads.empty();
thread_cache.empty();
key_caches.empty();
@@ -7914,20 +6738,12 @@ static int mysql_init_variables(void)
multi_keycache_init();
/* Set directory paths */
- strmake(language, LANGUAGE, sizeof(language)-1);
- strmake(mysql_real_data_home, get_relative_path(MYSQL_DATADIR),
- sizeof(mysql_real_data_home)-1);
- mysql_data_home_buff[0]=FN_CURLIB; // all paths are relative from here
- mysql_data_home_buff[1]=0;
- mysql_data_home_len= 2;
-
+ mysql_real_data_home_len=
+ strmake(mysql_real_data_home, get_relative_path(MYSQL_DATADIR),
+ sizeof(mysql_real_data_home)-1) - mysql_real_data_home;
/* Replication parameters */
- master_user= (char*) "test";
- master_password= master_host= 0;
master_info_file= (char*) "master.info",
relay_log_info_file= (char*) "relay-log.info";
- master_ssl_key= master_ssl_cert= master_ssl_ca=
- master_ssl_capath= master_ssl_cipher= 0;
report_user= report_password = report_host= 0; /* TO BE DELETED */
opt_relay_logname= opt_relaylog_index_name= 0;
@@ -7935,44 +6751,22 @@ static int mysql_init_variables(void)
charsets_dir= 0;
default_character_set_name= (char*) MYSQL_DEFAULT_CHARSET_NAME;
default_collation_name= compiled_default_collation_name;
- sys_charset_system.value= (char*) system_charset_info->csname;
character_set_filesystem_name= (char*) "binary";
+ lc_messages= (char*) "en_US";
lc_time_names_name= (char*) "en_US";
- /* Set default values for some option variables */
- default_storage_engine_str= (char*) "MyISAM";
- global_system_variables.table_plugin= NULL;
- global_system_variables.tx_isolation= ISO_REPEATABLE_READ;
- global_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
- max_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
- global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
- max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
- global_system_variables.old_passwords= 0;
- global_system_variables.old_alter_table= 0;
- global_system_variables.binlog_format= BINLOG_FORMAT_UNSPEC;
- /*
- Default behavior for 4.1 and 5.0 is to treat NULL values as unequal
- when collecting index statistics for MyISAM tables.
- */
- global_system_variables.myisam_stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
- global_system_variables.optimizer_switch= OPTIMIZER_SWITCH_DEFAULT;
/* Variables that depends on compile options */
#ifndef DBUG_OFF
default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace",
"d:t:i:o,/tmp/mysqld.trace");
#endif
opt_error_log= IF_WIN(1,0);
-#ifdef COMMUNITY_SERVER
- have_community_features = SHOW_OPTION_YES;
+#ifdef ENABLED_PROFILING
+ have_profiling = SHOW_OPTION_YES;
#else
- have_community_features = SHOW_OPTION_NO;
-#endif
- global_system_variables.ndb_index_stat_enable=FALSE;
- max_system_variables.ndb_index_stat_enable=TRUE;
- global_system_variables.ndb_index_stat_cache_entries=32;
- max_system_variables.ndb_index_stat_cache_entries=~0L;
- global_system_variables.ndb_index_stat_update_freq=20;
- max_system_variables.ndb_index_stat_update_freq=~0L;
+ have_profiling = SHOW_OPTION_NO;
+#endif
+
#ifdef HAVE_OPENSSL
have_ssl=SHOW_OPTION_YES;
#else
@@ -8018,32 +6812,29 @@ static int mysql_init_variables(void)
#endif
#ifdef HAVE_OPENSSL
des_key_file = 0;
+#ifndef EMBEDDED_LIBRARY
ssl_acceptor_fd= 0;
-#endif
+#endif /* ! EMBEDDED_LIBRARY */
+#endif /* HAVE_OPENSSL */
#ifdef HAVE_SMEM
shared_memory_base_name= default_shared_memory_base_name;
#endif
-#if !defined(my_pthread_setprio) && !defined(HAVE_PTHREAD_SETSCHEDPARAM)
- opt_specialflag |= SPECIAL_NO_PRIOR;
-#endif
-#if defined(__WIN__) || defined(__NETWARE__)
- /* Allow Win32 and NetWare users to move MySQL anywhere */
+#if defined(__WIN__)
+ /* Allow Win32 users to move MySQL anywhere */
{
char prg_dev[LIBLEN];
-#if defined __WIN__
- char executing_path_name[LIBLEN];
- if (!test_if_hard_path(my_progname))
- {
- // we don't want to use GetModuleFileName inside of my_path since
- // my_path is a generic path dereferencing function and here we care
- // only about the executing binary.
- GetModuleFileName(NULL, executing_path_name, sizeof(executing_path_name));
- my_path(prg_dev, executing_path_name, NULL);
- }
- else
-#endif
- my_path(prg_dev,my_progname,"mysql/bin");
+ char executing_path_name[LIBLEN];
+ if (!test_if_hard_path(my_progname))
+ {
+ // we don't want to use GetModuleFileName inside of my_path since
+ // my_path is a generic path dereferencing function and here we care
+ // only about the executing binary.
+ GetModuleFileName(NULL, executing_path_name, sizeof(executing_path_name));
+ my_path(prg_dev, executing_path_name, NULL);
+ }
+ else
+ my_path(prg_dev, my_progname, "mysql/bin");
strcat(prg_dev,"/../"); // Remove 'bin' to get base dir
cleanup_dirname(mysql_home,prg_dev);
}
@@ -8056,14 +6847,11 @@ static int mysql_init_variables(void)
return 0;
}
-
my_bool
mysqld_get_one_option(int optid,
const struct my_option *opt __attribute__((unused)),
char *argument)
{
- int error;
-
switch(optid) {
case '#':
#ifndef DBUG_OFF
@@ -8071,34 +6859,25 @@ mysqld_get_one_option(int optid,
#endif
opt_endinfo=1; /* unireg: memory allocation */
break;
- case '0':
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--log-long-format", "--log-short-format");
- break;
case 'a':
- global_system_variables.sql_mode= fix_sql_mode(MODE_ANSI);
+ global_system_variables.sql_mode= MODE_ANSI;
global_system_variables.tx_isolation= ISO_SERIALIZABLE;
break;
case 'b':
strmake(mysql_home,argument,sizeof(mysql_home)-1);
break;
- case OPT_DEFAULT_CHARACTER_SET_OLD: // --default-character-set
- WARN_DEPRECATED(NULL, VER_CELOSIA,
- "--default-character-set",
- "--character-set-server");
- /* Fall through */
case 'C':
if (default_collation_name == compiled_default_collation_name)
default_collation_name= 0;
break;
case 'l':
- WARN_DEPRECATED(NULL, "7.0", "--log", "'--general_log'/'--general_log_file'");
+ WARN_DEPRECATED(NULL, 7, 0, "--log", "'--general-log'/'--general-log-file'");
opt_log=1;
break;
case 'h':
strmake(mysql_real_data_home,argument, sizeof(mysql_real_data_home)-1);
/* Correct pointer set by my_getopt (for embedded library) */
- mysql_data_home= mysql_real_data_home;
- mysql_data_home_len= strlen(mysql_data_home);
+ mysql_real_data_home_ptr= mysql_real_data_home;
break;
case 'u':
if (!mysqld_user || !strcmp(mysqld_user, argument))
@@ -8107,27 +6886,11 @@ mysqld_get_one_option(int optid,
sql_print_warning("Ignoring user change to '%s' because the user was set to '%s' earlier on the command line\n", argument, mysqld_user);
break;
case 'L':
- strmake(language, argument, sizeof(language)-1);
+ strmake(lc_messages_dir, argument, sizeof(lc_messages_dir)-1);
+ lc_messages_dir_ptr= lc_messages_dir;
break;
- case 'O':
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--set-variable", "--variable-name=value");
- break;
-#ifdef HAVE_REPLICATION
- case OPT_SLAVE_SKIP_ERRORS:
- init_slave_skip_errors(argument);
- break;
- case OPT_SLAVE_EXEC_MODE:
- slave_exec_mode_options= find_bit_type_or_exit(argument,
- &slave_exec_mode_typelib,
- "", &error);
- if (error)
- return 1;
- break;
-#endif
- case OPT_SAFEMALLOC_MEM_LIMIT:
-#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
- sf_malloc_mem_limit = atoi(argument);
-#endif
+ case OPT_BINLOG_FORMAT:
+ binlog_format_used= true;
break;
#include <sslopt-case.h>
#ifndef EMBEDDED_LIBRARY
@@ -8135,9 +6898,6 @@ mysqld_get_one_option(int optid,
print_version();
exit(0);
#endif /*EMBEDDED_LIBRARY*/
- case OPT_WARNINGS:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--warnings", "--log-warnings");
- /* Note: fall-through to 'W' */
case 'W':
if (!argument)
global_system_variables.log_warnings++;
@@ -8150,45 +6910,13 @@ mysqld_get_one_option(int optid,
test_flags= argument ? (uint) atoi(argument) : 0;
opt_endinfo=1;
break;
- case (int) OPT_DEFAULT_COLLATION_OLD:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--default-collation", "--collation-server");
- break;
- case (int) OPT_SAFE_SHOW_DB:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--safe-show-database", "GRANT SHOW DATABASES");
- break;
- case (int) OPT_LOG_BIN_TRUST_FUNCTION_CREATORS_OLD:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--log-bin-trust-routine-creators", "--log-bin-trust-function-creators");
- break;
- case (int) OPT_ENABLE_LOCK:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--enable-locking", "--external-locking");
- break;
- case (int) OPT_BIG_TABLES:
- thd_startup_options|=OPTION_BIG_TABLES;
- break;
- case (int) OPT_IGNORE_BUILTIN_INNODB:
- opt_ignore_builtin_innodb= 1;
- break;
case (int) OPT_ISAM_LOG:
opt_myisam_log=1;
break;
- case (int) OPT_UPDATE_LOG:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--log-update", "--log-bin");
- opt_update_log=1;
- break;
case (int) OPT_BIN_LOG:
opt_bin_log= test(argument != disabled_my_option);
break;
- case (int) OPT_ERROR_LOG_FILE:
- opt_error_log= 1;
- break;
#ifdef HAVE_REPLICATION
- case (int) OPT_INIT_RPL_ROLE:
- {
- int role;
- role= find_type_or_exit(argument, &rpl_role_typelib, opt->name);
- rpl_status = (role == 1) ? RPL_AUTH_MASTER : RPL_IDLE_SLAVE;
- break;
- }
case (int)OPT_REPLICATE_IGNORE_DB:
{
rpl_filter->add_ignore_db(argument);
@@ -8235,13 +6963,6 @@ mysqld_get_one_option(int optid,
binlog_filter->add_ignore_db(argument);
break;
}
- case OPT_BINLOG_FORMAT:
- {
- int id;
- id= find_type_or_exit(argument, &binlog_format_typelib, opt->name);
- global_system_variables.binlog_format= opt_binlog_format_id= id - 1;
- break;
- }
case (int)OPT_BINLOG_DO_DB:
{
binlog_filter->add_do_db(argument);
@@ -8285,41 +7006,14 @@ mysqld_get_one_option(int optid,
}
#endif /* HAVE_REPLICATION */
case (int) OPT_SLOW_QUERY_LOG:
- WARN_DEPRECATED(NULL, "7.0", "--log_slow_queries", "'--slow_query_log'/'--slow_query_log_file'");
+ WARN_DEPRECATED(NULL, 7, 0, "--log-slow-queries", "'--slow-query-log'/'--slow-query-log-file'");
opt_slow_log= 1;
break;
-#ifdef WITH_CSV_STORAGE_ENGINE
- case OPT_LOG_OUTPUT:
- {
- if (!argument || !argument[0])
- {
- log_output_options= LOG_FILE;
- log_output_str= log_output_typelib.type_names[1];
- }
- else
- {
- log_output_str= argument;
- log_output_options=
- find_bit_type_or_exit(argument, &log_output_typelib, opt->name, &error);
- if (error)
- return 1;
- }
- break;
- }
-#endif
- case OPT_EVENT_SCHEDULER:
-#ifndef HAVE_EVENT_SCHEDULER
- sql_perror("Event scheduler is not supported in embedded build.");
-#else
- if (Events::set_opt_event_scheduler(argument))
- return 1;
-#endif
- break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
- delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE;
+ delay_key_write_options= DELAY_KEY_WRITE_NONE;
myisam_concurrent_insert=0;
- myisam_recover_options= HA_RECOVER_NONE;
+ myisam_recover_options= HA_RECOVER_OFF;
sp_automatic_privileges=0;
my_use_symdir=0;
ha_open_options&= ~(HA_OPEN_ABORT_IF_CRASHED | HA_OPEN_DELAY_KEY_WRITE);
@@ -8329,28 +7023,15 @@ mysqld_get_one_option(int optid,
break;
case (int) OPT_SAFE:
opt_specialflag|= SPECIAL_SAFE_MODE;
- delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE;
+ delay_key_write_options= DELAY_KEY_WRITE_NONE;
myisam_recover_options= HA_RECOVER_DEFAULT;
ha_open_options&= ~(HA_OPEN_DELAY_KEY_WRITE);
break;
case (int) OPT_SKIP_PRIOR:
opt_specialflag|= SPECIAL_NO_PRIOR;
sql_print_warning("The --skip-thread-priority startup option is deprecated "
- "and will be removed in MySQL 7.0. MySQL 6.0 and up do not "
- "give threads different priorities.");
- break;
- case (int) OPT_SKIP_LOCK:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--skip-locking", "--skip-external-locking");
- opt_external_locking=0;
- break;
- case (int) OPT_SQL_BIN_UPDATE_SAME:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--sql-bin-update-same", "the binary log");
- break;
- case (int) OPT_RECORD_BUFFER_OLD:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "record_buffer", "read_buffer_size");
- break;
- case (int) OPT_SYMBOLIC_LINKS:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--use-symbolic-links", "--symbolic-links");
+ "and will be removed in MySQL 7.0. This option has no effect "
+ "as the implied behavior is already the default.");
break;
case (int) OPT_SKIP_HOST_CACHE:
opt_specialflag|= SPECIAL_NO_HOST_CACHE;
@@ -8359,301 +7040,50 @@ mysqld_get_one_option(int optid,
opt_skip_name_resolve= 1;
opt_specialflag|=SPECIAL_NO_RESOLVE;
break;
- case (int) OPT_SKIP_NETWORKING:
-#if defined(__NETWARE__)
- sql_perror("Can't start server: skip-networking option is currently not supported on NetWare");
- return 1;
-#endif
- opt_disable_networking=1;
- mysqld_port=0;
- break;
- case (int) OPT_SKIP_SHOW_DB:
- opt_skip_show_db=1;
- opt_specialflag|=SPECIAL_SKIP_SHOW_DB;
- break;
case (int) OPT_WANT_CORE:
test_flags |= TEST_CORE_ON_SIGNAL;
break;
case (int) OPT_SKIP_STACK_TRACE:
test_flags|=TEST_NO_STACKTRACE;
break;
- case (int) OPT_SKIP_SYMLINKS:
- WARN_DEPRECATED(NULL, VER_CELOSIA, "--skip-symlink", "--skip-symbolic-links");
- my_use_symdir=0;
- break;
case (int) OPT_BIND_ADDRESS:
- if ((my_bind_addr= (ulong) inet_addr(argument)) == INADDR_NONE)
{
- struct hostent *ent;
- if (argument[0])
- ent=gethostbyname(argument);
- else
+ struct addrinfo *res_lst, hints;
+
+ bzero(&hints, sizeof(struct addrinfo));
+ hints.ai_socktype= SOCK_STREAM;
+ hints.ai_protocol= IPPROTO_TCP;
+
+ if (getaddrinfo(argument, NULL, &hints, &res_lst) != 0)
{
- char myhostname[255];
- if (gethostname(myhostname,sizeof(myhostname)) < 0)
- {
- sql_perror("Can't start server: cannot get my own hostname!");
- return 1;
- }
- ent=gethostbyname(myhostname);
+ sql_print_error("Can't start server: cannot resolve hostname!");
+ return 1;
}
- if (!ent)
+
+ if (res_lst->ai_next)
{
- sql_perror("Can't start server: cannot resolve hostname!");
+ sql_print_error("Can't start server: bind-address refers to multiple interfaces!");
return 1;
}
- my_bind_addr = (ulong) ((in_addr*)ent->h_addr_list[0])->s_addr;
- }
- break;
- case (int) OPT_PID_FILE:
- strmake(pidfile_name, argument, sizeof(pidfile_name)-1);
- break;
-#ifdef __WIN__
- case (int) OPT_STANDALONE: /* Dummy option for NT */
- break;
-#endif
- /*
- The following change issues a deprecation warning if the slave
- configuration is specified either in the my.cnf file or on
- the command-line. See BUG#21490.
- */
- case OPT_MASTER_HOST:
- case OPT_MASTER_USER:
- case OPT_MASTER_PASSWORD:
- case OPT_MASTER_PORT:
- case OPT_MASTER_CONNECT_RETRY:
- case OPT_MASTER_SSL:
- case OPT_MASTER_SSL_KEY:
- case OPT_MASTER_SSL_CERT:
- case OPT_MASTER_SSL_CAPATH:
- case OPT_MASTER_SSL_CIPHER:
- case OPT_MASTER_SSL_CA:
- if (!slave_warning_issued) //only show the warning once
- {
- slave_warning_issued = true;
- WARN_DEPRECATED(NULL, "6.0", "for replication startup options",
- "'CHANGE MASTER'");
+ freeaddrinfo(res_lst);
}
break;
case OPT_CONSOLE:
if (opt_console)
opt_error_log= 0; // Force logs to stdout
break;
- case (int) OPT_FLUSH:
- myisam_flush=1;
- flush_time=0; // No auto flush
- break;
- case OPT_LOW_PRIORITY_UPDATES:
- thr_upgraded_concurrent_insert_lock= TL_WRITE_LOW_PRIORITY;
- global_system_variables.low_priority_updates=1;
- break;
case OPT_BOOTSTRAP:
opt_noacl=opt_bootstrap=1;
break;
case OPT_SERVER_ID:
server_id_supplied = 1;
break;
- case OPT_DELAY_KEY_WRITE_ALL:
- WARN_DEPRECATED(NULL, VER_CELOSIA,
- "--delay-key-write-for-all-tables",
- "--delay-key-write=ALL");
- if (argument != disabled_my_option)
- argument= (char*) "ALL";
- /* Fall through */
- case OPT_DELAY_KEY_WRITE:
- if (argument == disabled_my_option)
- delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE;
- else if (! argument)
- delay_key_write_options= (uint) DELAY_KEY_WRITE_ON;
- else
- {
- int type;
- type= find_type_or_exit(argument, &delay_key_write_typelib, opt->name);
- delay_key_write_options= (uint) type-1;
- }
- break;
- case OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE:
- sql_print_warning("--myisam_max_extra_sort_file_size is deprecated and "
- "does nothing in this version. It will be removed in "
- "a future release.");
- break;
- case OPT_CHARSETS_DIR:
- strmake(mysql_charsets_dir, argument, sizeof(mysql_charsets_dir)-1);
- charsets_dir = mysql_charsets_dir;
- break;
- case OPT_TX_ISOLATION:
- {
- int type;
- type= find_type_or_exit(argument, &tx_isolation_typelib, opt->name);
- global_system_variables.tx_isolation= (type-1);
- break;
- }
-#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
- case OPT_NDB_MGMD:
- case OPT_NDB_NODEID:
- {
- int len= my_snprintf(opt_ndb_constrbuf+opt_ndb_constrbuf_len,
- sizeof(opt_ndb_constrbuf)-opt_ndb_constrbuf_len,
- "%s%s%s",opt_ndb_constrbuf_len > 0 ? ",":"",
- optid == OPT_NDB_NODEID ? "nodeid=" : "",
- argument);
- opt_ndb_constrbuf_len+= len;
- }
- /* fall through to add the connectstring to the end
- * and set opt_ndbcluster_connectstring
- */
- case OPT_NDB_CONNECTSTRING:
- if (opt_ndb_connectstring && opt_ndb_connectstring[0])
- my_snprintf(opt_ndb_constrbuf+opt_ndb_constrbuf_len,
- sizeof(opt_ndb_constrbuf)-opt_ndb_constrbuf_len,
- "%s%s", opt_ndb_constrbuf_len > 0 ? ",":"",
- opt_ndb_connectstring);
- else
- opt_ndb_constrbuf[opt_ndb_constrbuf_len]= 0;
- opt_ndbcluster_connectstring= opt_ndb_constrbuf;
- break;
- case OPT_NDB_DISTRIBUTION:
- int id;
- id= find_type_or_exit(argument, &ndb_distribution_typelib, opt->name);
- opt_ndb_distribution_id= (enum ndb_distribution)(id-1);
- break;
- case OPT_NDB_EXTRA_LOGGING:
- if (!argument)
- ndb_extra_logging++;
- else if (argument == disabled_my_option)
- ndb_extra_logging= 0L;
- else
- ndb_extra_logging= atoi(argument);
- break;
-#endif
- case OPT_MYISAM_RECOVER:
- {
- if (!argument)
- {
- myisam_recover_options= HA_RECOVER_DEFAULT;
- myisam_recover_options_str= myisam_recover_typelib.type_names[0];
- }
- else if (!argument[0])
- {
- myisam_recover_options= HA_RECOVER_NONE;
- myisam_recover_options_str= "OFF";
- }
- else
- {
- myisam_recover_options_str=argument;
- myisam_recover_options=
- find_bit_type_or_exit(argument, &myisam_recover_typelib, opt->name,
- &error);
- if (error)
- return 1;
- }
- ha_open_options|=HA_OPEN_ABORT_IF_CRASHED;
- break;
- }
- case OPT_CONCURRENT_INSERT:
- /* The following code is mainly here to emulate old behavior */
- if (!argument) /* --concurrent-insert */
- myisam_concurrent_insert= 1;
- else if (argument == disabled_my_option)
- myisam_concurrent_insert= 0; /* --skip-concurrent-insert */
- break;
- case OPT_TC_HEURISTIC_RECOVER:
- tc_heuristic_recover= find_type_or_exit(argument,
- &tc_heuristic_recover_typelib,
- opt->name);
- break;
- case OPT_MYISAM_STATS_METHOD:
- {
- ulong method_conv;
- int method;
- LINT_INIT(method_conv);
-
- myisam_stats_method_str= argument;
- method= find_type_or_exit(argument, &myisam_stats_method_typelib,
- opt->name);
- switch (method-1) {
- case 2:
- method_conv= MI_STATS_METHOD_IGNORE_NULLS;
- break;
- case 1:
- method_conv= MI_STATS_METHOD_NULLS_EQUAL;
- break;
- case 0:
- default:
- method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
- break;
- }
- global_system_variables.myisam_stats_method= method_conv;
- break;
- }
- case OPT_SQL_MODE:
- {
- sql_mode_str= argument;
- global_system_variables.sql_mode=
- find_bit_type_or_exit(argument, &sql_mode_typelib, opt->name, &error);
- if (error)
- return 1;
- global_system_variables.sql_mode= fix_sql_mode(global_system_variables.
- sql_mode);
- break;
- }
- case OPT_OPTIMIZER_SWITCH:
- {
- bool not_used;
- char *error= 0;
- uint error_len= 0;
- optimizer_switch_str= argument;
- global_system_variables.optimizer_switch=
- (ulong)find_set_from_flags(&optimizer_switch_typelib,
- optimizer_switch_typelib.count,
- global_system_variables.optimizer_switch,
- global_system_variables.optimizer_switch,
- argument, strlen(argument), NULL,
- &error, &error_len, &not_used);
- if (error)
- {
- char buf[512];
- char *cbuf= buf;
- cbuf += my_snprintf(buf, 512, "Error in parsing optimizer_switch setting near %*s\n", error_len, error);
- sql_perror(buf);
- return 1;
- }
- break;
- }
case OPT_ONE_THREAD:
- global_system_variables.thread_handling=
- SCHEDULER_ONE_THREAD_PER_CONNECTION;
- break;
- case OPT_THREAD_HANDLING:
- {
- global_system_variables.thread_handling=
- find_type_or_exit(argument, &thread_handling_typelib, opt->name)-1;
- break;
- }
- case OPT_FT_BOOLEAN_SYNTAX:
- if (ft_boolean_check_syntax_string((uchar*) argument))
- {
- sql_print_error("Invalid ft-boolean-syntax string: %s\n", argument);
- return 1;
- }
- strmake(ft_boolean_syntax, argument, sizeof(ft_boolean_syntax)-1);
- break;
- case OPT_SKIP_SAFEMALLOC:
-#ifdef SAFEMALLOC
- sf_malloc_quick=1;
-#endif
+ thread_handling= SCHEDULER_ONE_THREAD_PER_CONNECTION;
break;
case OPT_LOWER_CASE_TABLE_NAMES:
- lower_case_table_names= argument ? atoi(argument) : 1;
lower_case_table_names_used= 1;
break;
-#ifdef HAVE_STACK_TRACE_ON_SEGV
- case OPT_DO_PSTACK:
- sql_print_warning("'--enable-pstack' is deprecated and will be removed "
- "in a future release. A symbolic stack trace will be "
- "printed after a crash whenever possible.");
- break;
-#endif
#if defined(ENABLED_DEBUG_SYNC)
case OPT_DEBUG_SYNC_TIMEOUT:
/*
@@ -8670,16 +7100,41 @@ mysqld_get_one_option(int optid,
}
break;
#endif /* defined(ENABLED_DEBUG_SYNC) */
+ case OPT_ENGINE_CONDITION_PUSHDOWN:
+ /*
+ The last of --engine-condition-pushdown and --optimizer_switch on
+ command line wins (see get_options().
+ */
+ if (global_system_variables.engine_condition_pushdown)
+ global_system_variables.optimizer_switch|=
+ OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN;
+ else
+ global_system_variables.optimizer_switch&=
+ ~OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN;
+ break;
+ case OPT_LOG_ERROR:
+ /*
+ "No --log-error" == "write errors to stderr",
+ "--log-error without argument" == "write errors to a file".
+ */
+ if (argument == NULL) /* no argument */
+ log_error_file_ptr= const_cast<char*>("");
+ break;
+ case OPT_AUTOCOMMIT:
+ const ulonglong turn_bit_on= (argument && (atoi(argument) == 0)) ?
+ OPTION_NOT_AUTOCOMMIT : OPTION_AUTOCOMMIT;
+ global_system_variables.option_bits=
+ (global_system_variables.option_bits &
+ ~(OPTION_NOT_AUTOCOMMIT | OPTION_AUTOCOMMIT)) | turn_bit_on;
+ break;
}
return 0;
}
/** Handle arguments for multiple key caches. */
+
C_MODE_START
-static void* mysql_getopt_value(const char *, uint,
- const struct my_option *, int *);
-C_MODE_END
static void*
mysql_getopt_value(const char *keyname, uint key_length,
@@ -8715,10 +7170,7 @@ mysql_getopt_value(const char *keyname, uint key_length,
return option->value;
}
-
-extern "C" void option_error_reporter(enum loglevel level, const char *format, ...);
-
-void option_error_reporter(enum loglevel level, const char *format, ...)
+static void option_error_reporter(enum loglevel level, const char *format, ...)
{
va_list args;
va_start(args, format);
@@ -8732,34 +7184,106 @@ void option_error_reporter(enum loglevel level, const char *format, ...)
va_end(args);
}
+C_MODE_END
/**
+ Get server options from the command line,
+ and perform related server initializations.
+ @param [in, out] argc_ptr command line options (count)
+ @param [in, out] argv_ptr command line options (values)
+ @return 0 on success
+
@todo
- FIXME add EXIT_TOO_MANY_ARGUMENTS to "mysys_err.h" and return that code?
*/
-static int get_options(int *argc,char **argv)
+static int get_options(int *argc_ptr, char ***argv_ptr)
{
int ho_error;
my_getopt_register_get_addr(mysql_getopt_value);
- strmake(def_ft_boolean_syntax, ft_boolean_syntax,
- sizeof(ft_boolean_syntax)-1);
my_getopt_error_reporter= option_error_reporter;
+ /* prepare all_options array */
+ my_init_dynamic_array(&all_options, sizeof(my_option),
+ array_elements(my_long_options),
+ array_elements(my_long_options)/4);
+ for (my_option *opt= my_long_options;
+ opt < my_long_options + array_elements(my_long_options) - 1;
+ opt++)
+ insert_dynamic(&all_options, (uchar*) opt);
+ sys_var_add_options(&all_options, sys_var::PARSE_NORMAL);
+ add_terminator(&all_options);
+
/* Skip unknown options so that they may be processed later by plugins */
my_getopt_skip_unknown= TRUE;
- if ((ho_error= handle_options(argc, &argv, my_long_options,
+ if ((ho_error= handle_options(argc_ptr, argv_ptr, (my_option*)(all_options.buffer),
mysqld_get_one_option)))
return ho_error;
- (*argc)++; /* add back one for the progname handle_options removes */
- /* no need to do this for argv as we are discarding it. */
+
+ if (!opt_help)
+ delete_dynamic(&all_options);
+
+ /* Add back the program name handle_options removes */
+ (*argc_ptr)++;
+ (*argv_ptr)--;
+
+ /*
+ Options have been parsed. Now some of them need additional special
+ handling, like custom value checking, checking of incompatibilites
+ between options, setting of multiple variables, etc.
+ Do them here.
+ */
if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes ||
opt_log_slow_slave_statements) &&
!opt_slow_log)
sql_print_warning("options --log-slow-admin-statements, --log-queries-not-using-indexes and --log-slow-slave-statements have no effect if --log_slow_queries is not set");
+ if (log_error_file_ptr != disabled_my_option)
+ opt_error_log= 1;
+ else
+ log_error_file_ptr= const_cast<char*>("");
+
+ opt_init_connect.length=strlen(opt_init_connect.str);
+ opt_init_slave.length=strlen(opt_init_slave.str);
+
+ if (global_system_variables.low_priority_updates)
+ thr_upgraded_concurrent_insert_lock= TL_WRITE_LOW_PRIORITY;
+
+ if (ft_boolean_check_syntax_string((uchar*) ft_boolean_syntax))
+ {
+ sql_print_error("Invalid ft-boolean-syntax string: %s\n",
+ ft_boolean_syntax);
+ return 1;
+ }
+
+ if (opt_disable_networking)
+ mysqld_port= 0;
+
+ if (opt_skip_show_db)
+ opt_specialflag|= SPECIAL_SKIP_SHOW_DB;
+
+ if (myisam_flush)
+ flush_time= 0;
+
+#ifdef HAVE_REPLICATION
+ if (opt_slave_skip_errors)
+ init_slave_skip_errors(opt_slave_skip_errors);
+#endif
+
+ if (global_system_variables.max_join_size == HA_POS_ERROR)
+ global_system_variables.option_bits|= OPTION_BIG_SELECTS;
+ else
+ global_system_variables.option_bits&= ~OPTION_BIG_SELECTS;
+
+ if (global_system_variables.option_bits & OPTION_AUTOCOMMIT)
+ global_system_variables.option_bits&= ~OPTION_NOT_AUTOCOMMIT;
+ else
+ global_system_variables.option_bits|= OPTION_NOT_AUTOCOMMIT;
+
+ global_system_variables.sql_mode=
+ expand_sql_mode(global_system_variables.sql_mode);
#if defined(HAVE_BROKEN_REALPATH)
my_use_symdir=0;
my_disable_symlinks=1;
@@ -8778,15 +7302,13 @@ static int get_options(int *argc,char **argv)
test_flags&= ~TEST_CORE_ON_SIGNAL;
}
/* Set global MyISAM variables from delay_key_write_options */
- fix_delay_key_write((THD*) 0, OPT_GLOBAL);
- /* Set global slave_exec_mode from its option */
- fix_slave_exec_mode();
+ fix_delay_key_write(0, 0, OPT_GLOBAL);
#ifndef EMBEDDED_LIBRARY
if (mysqld_chroot)
set_root(mysqld_chroot);
#else
- global_system_variables.thread_handling = SCHEDULER_NO_THREADS;
+ thread_handling = SCHEDULER_NO_THREADS;
max_allowed_packet= global_system_variables.max_allowed_packet;
net_buffer_length= global_system_variables.net_buffer_length;
#endif
@@ -8799,38 +7321,34 @@ static int get_options(int *argc,char **argv)
*/
my_disable_locking= myisam_single_user= test(opt_external_locking == 0);
my_default_record_cache_size=global_system_variables.read_buff_size;
- myisam_max_temp_length=
- (my_off_t) global_system_variables.myisam_max_sort_file_size;
- /* Set global variables based on startup options */
- myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
-
- /* long_query_time is in microseconds */
- global_system_variables.long_query_time= max_system_variables.long_query_time=
- (longlong) (long_query_time * 1000000.0);
+ global_system_variables.long_query_time= (ulonglong)
+ (global_system_variables.long_query_time_double * 1e6);
if (opt_short_log_format)
opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT;
if (init_global_datetime_format(MYSQL_TIMESTAMP_DATE,
- &global_system_variables.date_format) ||
+ &global_date_format) ||
init_global_datetime_format(MYSQL_TIMESTAMP_TIME,
- &global_system_variables.time_format) ||
+ &global_time_format) ||
init_global_datetime_format(MYSQL_TIMESTAMP_DATETIME,
- &global_system_variables.datetime_format))
+ &global_datetime_format))
return 1;
#ifdef EMBEDDED_LIBRARY
- one_thread_scheduler(&thread_scheduler);
+ one_thread_scheduler();
#else
- if (global_system_variables.thread_handling <=
- SCHEDULER_ONE_THREAD_PER_CONNECTION)
- one_thread_per_connection_scheduler(&thread_scheduler);
- else if (global_system_variables.thread_handling == SCHEDULER_NO_THREADS)
- one_thread_scheduler(&thread_scheduler);
- else
- pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */
+ if (thread_handling <= SCHEDULER_ONE_THREAD_PER_CONNECTION)
+ one_thread_per_connection_scheduler();
+ else /* thread_handling == SCHEDULER_NO_THREADS) */
+ one_thread_scheduler();
#endif
+
+ global_system_variables.engine_condition_pushdown=
+ test(global_system_variables.optimizer_switch &
+ OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN);
+
return 0;
}
@@ -8853,7 +7371,7 @@ static void set_server_version(void)
if (!strstr(MYSQL_SERVER_SUFFIX_STR, "-debug"))
end= strmov(end, "-debug");
#endif
- if (opt_log || opt_update_log || opt_slow_log || opt_bin_log)
+ if (opt_log || opt_slow_log || opt_bin_log)
strmov(end, "-log"); // This may slow down system
}
@@ -8865,7 +7383,7 @@ static char *get_relative_path(const char *path)
strcmp(DEFAULT_MYSQL_HOME,FN_ROOTDIR))
{
path+=(uint) strlen(DEFAULT_MYSQL_HOME);
- while (*path == FN_LIBCHAR)
+ while (*path == FN_LIBCHAR || *path == FN_LIBCHAR2)
path++;
}
return (char*) path;
@@ -8950,11 +7468,11 @@ static int fix_paths(void)
pos[0]= FN_LIBCHAR;
pos[1]= 0;
}
- convert_dirname(language,language,NullS);
+ convert_dirname(lc_messages_dir, lc_messages_dir, NullS);
convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS);
(void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir
(void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home);
- (void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home);
+ (void) my_load_path(pidfile_name, pidfile_name_ptr, mysql_real_data_home);
(void) my_load_path(opt_plugin_dir, opt_plugin_dir_ptr ? opt_plugin_dir_ptr :
get_relative_path(PLUGINDIR), mysql_home);
opt_plugin_dir_ptr= opt_plugin_dir;
@@ -8971,26 +7489,25 @@ static int fix_paths(void)
else
strxnmov(buff,sizeof(buff)-1,mysql_home,sharedir,NullS);
convert_dirname(buff,buff,NullS);
- (void) my_load_path(language,language,buff);
+ (void) my_load_path(lc_messages_dir, lc_messages_dir, buff);
/* If --character-sets-dir isn't given, use shared library dir */
- if (charsets_dir != mysql_charsets_dir)
- {
+ if (charsets_dir)
+ strmake(mysql_charsets_dir, charsets_dir, sizeof(mysql_charsets_dir)-1);
+ else
strxnmov(mysql_charsets_dir, sizeof(mysql_charsets_dir)-1, buff,
CHARSET_DIR, NullS);
- }
(void) my_load_path(mysql_charsets_dir, mysql_charsets_dir, buff);
convert_dirname(mysql_charsets_dir, mysql_charsets_dir, NullS);
charsets_dir=mysql_charsets_dir;
if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir))
return 1;
+ if (!opt_mysql_tmpdir)
+ opt_mysql_tmpdir= mysql_tmpdir;
#ifdef HAVE_REPLICATION
if (!slave_load_tmpdir)
- {
- if (!(slave_load_tmpdir = (char*) my_strdup(mysql_tmpdir, MYF(MY_FAE))))
- return 1;
- }
+ slave_load_tmpdir= mysql_tmpdir;
#endif /* HAVE_REPLICATION */
/*
Convert the secure-file-priv option to system format, allowing
@@ -9013,7 +7530,7 @@ static int fix_paths(void)
}
char *secure_file_real_path= (char *)my_malloc(FN_REFLEN, MYF(MY_FAE));
convert_dirname(secure_file_real_path, buff, NullS);
- my_free(opt_secure_file_priv, MYF(0));
+ my_free(opt_secure_file_priv);
opt_secure_file_priv= secure_file_real_path;
}
}
@@ -9021,100 +7538,6 @@ static int fix_paths(void)
return 0;
}
-
-static ulong find_bit_type_or_exit(const char *x, TYPELIB *bit_lib,
- const char *option, int *error)
-{
- ulong result;
- const char **ptr;
-
- *error= 0;
- if ((result= find_bit_type(x, bit_lib)) == ~(ulong) 0)
- {
- char *buff= (char *) my_alloca(2048);
- char *cbuf;
- ptr= bit_lib->type_names;
- cbuf= buff + ((!*x) ?
- my_snprintf(buff, 2048, "No option given to %s\n", option) :
- my_snprintf(buff, 2048, "Wrong option to %s. Option(s) given: %s\n",
- option, x));
- cbuf+= my_snprintf(cbuf, 2048 - (cbuf-buff), "Alternatives are: '%s'", *ptr);
- while (*++ptr)
- cbuf+= my_snprintf(cbuf, 2048 - (cbuf-buff), ",'%s'", *ptr);
- my_snprintf(cbuf, 2048 - (cbuf-buff), "\n");
- sql_perror(buff);
- *error= 1;
- my_afree(buff);
- return 0;
- }
-
- return result;
-}
-
-
-/**
- @return
- a bitfield from a string of substrings separated by ','
- or
- ~(ulong) 0 on error.
-*/
-
-static ulong find_bit_type(const char *x, TYPELIB *bit_lib)
-{
- bool found_end;
- int found_count;
- const char *end,*i,*j;
- const char **array, *pos;
- ulong found,found_int,bit;
- DBUG_ENTER("find_bit_type");
- DBUG_PRINT("enter",("x: '%s'",x));
-
- found=0;
- found_end= 0;
- pos=(char *) x;
- while (*pos == ' ') pos++;
- found_end= *pos == 0;
- while (!found_end)
- {
- if (!*(end=strcend(pos,','))) /* Let end point at fieldend */
- {
- while (end > pos && end[-1] == ' ')
- end--; /* Skip end-space */
- found_end=1;
- }
- found_int=0; found_count=0;
- for (array=bit_lib->type_names, bit=1 ; (i= *array++) ; bit<<=1)
- {
- j=pos;
- while (j != end)
- {
- if (my_toupper(mysqld_charset,*i++) !=
- my_toupper(mysqld_charset,*j++))
- goto skip;
- }
- found_int=bit;
- if (! *i)
- {
- found_count=1;
- break;
- }
- else if (j != pos) // Half field found
- {
- found_count++; // Could be one of two values
- }
-skip: ;
- }
- if (found_count != 1)
- DBUG_RETURN(~(ulong) 0); // No unique value
- found|=found_int;
- pos=end+1;
- }
-
- DBUG_PRINT("exit",("bit-field: %ld",(ulong) found));
- DBUG_RETURN(found);
-} /* find_bit_type */
-
-
/**
Check if file system used for databases is case insensitive.
@@ -9140,16 +7563,17 @@ static int test_if_case_insensitive(const char *dir_name)
MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR);
fn_format(buff2, glob_hostname, dir_name, ".LOWER-TEST",
MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR);
- (void) my_delete(buff2, MYF(0));
- if ((file= my_create(buff, 0666, O_RDWR, MYF(0))) < 0)
+ mysql_file_delete(key_file_casetest, buff2, MYF(0));
+ if ((file= mysql_file_create(key_file_casetest,
+ buff, 0666, O_RDWR, MYF(0))) < 0)
{
sql_print_warning("Can't create test file %s", buff);
DBUG_RETURN(-1);
}
- my_close(file, MYF(0));
- if (my_stat(buff2, &stat_info, MYF(0)))
+ mysql_file_close(file, MYF(0));
+ if (mysql_file_stat(key_file_casetest, buff2, &stat_info, MYF(0)))
result= 1; // Can access file
- (void) my_delete(buff, MYF(MY_WME));
+ mysql_file_delete(key_file_casetest, buff, MYF(MY_WME));
DBUG_PRINT("exit", ("result: %d", result));
DBUG_RETURN(result);
}
@@ -9163,18 +7587,19 @@ static int test_if_case_insensitive(const char *dir_name)
static void create_pid_file()
{
File file;
- if ((file = my_create(pidfile_name,0664,
- O_WRONLY | O_TRUNC, MYF(MY_WME))) >= 0)
+ if ((file= mysql_file_create(key_file_pid, pidfile_name, 0664,
+ O_WRONLY | O_TRUNC, MYF(MY_WME))) >= 0)
{
char buff[21], *end;
end= int10_to_str((long) getpid(), buff, 10);
*end++= '\n';
- if (!my_write(file, (uchar*) buff, (uint) (end-buff), MYF(MY_WME | MY_NABP)))
+ if (!mysql_file_write(file, (uchar*) buff, (uint) (end-buff),
+ MYF(MY_WME | MY_NABP)))
{
- (void) my_close(file, MYF(0));
+ mysql_file_close(file, MYF(0));
return;
}
- (void) my_close(file, MYF(0));
+ mysql_file_close(file, MYF(0));
}
sql_perror("Can't start server: can't create PID file");
exit(1);
@@ -9184,7 +7609,7 @@ static void create_pid_file()
/** Clear most status variables. */
void refresh_status(THD *thd)
{
- pthread_mutex_lock(&LOCK_status);
+ mysql_mutex_lock(&LOCK_status);
/* Add thread's status variabes to global status */
add_to_status(&global_status_var, &thd->status_var);
@@ -9197,10 +7622,8 @@ void refresh_status(THD *thd)
/* Reset the counters of all key caches (default and named). */
process_key_caches(reset_key_cache_counters);
-#ifdef COMMUNITY_SERVER
flush_status_time= time((time_t*) 0);
-#endif
- pthread_mutex_unlock(&LOCK_status);
+ mysql_mutex_unlock(&LOCK_status);
/*
Set max_used_connections to the number of currently open
@@ -9208,9 +7631,9 @@ void refresh_status(THD *thd)
deadlocks. Status reset becomes not atomic, but status data is
not exact anyway.
*/
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
max_used_connections= thread_count-delayed_insert_threads;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
}
@@ -9219,11 +7642,6 @@ void refresh_status(THD *thd)
This section should go away soon
*****************************************************************************/
-#ifndef WITH_NDBCLUSTER_STORAGE_ENGINE
-ulong ndb_cache_check_time;
-ulong ndb_extra_logging;
-#endif
-
/*****************************************************************************
Instantiate templates
*****************************************************************************/
@@ -9234,7 +7652,255 @@ template class I_List<THD>;
template class I_List_iterator<THD>;
template class I_List<i_string>;
template class I_List<i_string_pair>;
-template class I_List<NAMED_LIST>;
template class I_List<Statement>;
template class I_List_iterator<Statement>;
#endif
+
+#ifdef HAVE_PSI_INTERFACE
+#ifdef HAVE_MMAP
+PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool;
+#endif /* HAVE_MMAP */
+
+#ifdef HAVE_OPENSSL
+PSI_mutex_key key_LOCK_des_key_file;
+#endif /* HAVE_OPENSSL */
+
+PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids,
+ 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_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
+ key_LOCK_gdl, key_LOCK_global_system_variables,
+ key_LOCK_manager,
+ key_LOCK_prepared_stmt_count,
+ key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status,
+ key_LOCK_system_variables_hash, key_LOCK_table_share, key_LOCK_thd_data,
+ key_LOCK_user_conn, key_LOCK_uuid_generator, key_LOG_LOCK_log,
+ key_master_info_data_lock, key_master_info_run_lock,
+ key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock,
+ key_relay_log_info_log_space_lock, key_relay_log_info_run_lock,
+ key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data,
+ key_LOCK_error_messages, key_LOG_INFO_lock, key_LOCK_thread_count,
+ key_PARTITION_LOCK_auto_inc;
+
+static PSI_mutex_info all_server_mutexes[]=
+{
+#ifdef HAVE_MMAP
+ { &key_PAGE_lock, "PAGE::lock", 0},
+ { &key_LOCK_sync, "TC_LOG_MMAP::LOCK_sync", 0},
+ { &key_LOCK_active, "TC_LOG_MMAP::LOCK_active", 0},
+ { &key_LOCK_pool, "TC_LOG_MMAP::LOCK_pool", 0},
+#endif /* HAVE_MMAP */
+
+#ifdef HAVE_OPENSSL
+ { &key_LOCK_des_key_file, "LOCK_des_key_file", PSI_FLAG_GLOBAL},
+#endif /* HAVE_OPENSSL */
+
+ { &key_BINLOG_LOCK_index, "MYSQL_BIN_LOG::LOCK_index", 0},
+ { &key_BINLOG_LOCK_prep_xids, "MYSQL_BIN_LOG::LOCK_prep_xids", 0},
+ { &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_crypt, "LOCK_crypt", PSI_FLAG_GLOBAL},
+ { &key_LOCK_delayed_create, "LOCK_delayed_create", PSI_FLAG_GLOBAL},
+ { &key_LOCK_delayed_insert, "LOCK_delayed_insert", PSI_FLAG_GLOBAL},
+ { &key_LOCK_delayed_status, "LOCK_delayed_status", PSI_FLAG_GLOBAL},
+ { &key_LOCK_error_log, "LOCK_error_log", PSI_FLAG_GLOBAL},
+ { &key_LOCK_gdl, "LOCK_gdl", PSI_FLAG_GLOBAL},
+ { &key_LOCK_global_system_variables, "LOCK_global_system_variables", PSI_FLAG_GLOBAL},
+ { &key_LOCK_manager, "LOCK_manager", PSI_FLAG_GLOBAL},
+ { &key_LOCK_prepared_stmt_count, "LOCK_prepared_stmt_count", PSI_FLAG_GLOBAL},
+ { &key_LOCK_rpl_status, "LOCK_rpl_status", PSI_FLAG_GLOBAL},
+ { &key_LOCK_server_started, "LOCK_server_started", PSI_FLAG_GLOBAL},
+ { &key_LOCK_status, "LOCK_status", PSI_FLAG_GLOBAL},
+ { &key_LOCK_system_variables_hash, "LOCK_system_variables_hash", PSI_FLAG_GLOBAL},
+ { &key_LOCK_table_share, "LOCK_table_share", PSI_FLAG_GLOBAL},
+ { &key_LOCK_thd_data, "THD::LOCK_thd_data", 0},
+ { &key_LOCK_user_conn, "LOCK_user_conn", PSI_FLAG_GLOBAL},
+ { &key_LOCK_uuid_generator, "LOCK_uuid_generator", PSI_FLAG_GLOBAL},
+ { &key_LOG_LOCK_log, "LOG::LOCK_log", 0},
+ { &key_master_info_data_lock, "Master_info::data_lock", 0},
+ { &key_master_info_run_lock, "Master_info::run_lock", 0},
+ { &key_mutex_slave_reporting_capability_err_lock, "Slave_reporting_capability::err_lock", 0},
+ { &key_relay_log_info_data_lock, "Relay_log_info::data_lock", 0},
+ { &key_relay_log_info_log_space_lock, "Relay_log_info::log_space_lock", 0},
+ { &key_relay_log_info_run_lock, "Relay_log_info::run_lock", 0},
+ { &key_structure_guard_mutex, "Query_cache::structure_guard_mutex", 0},
+ { &key_TABLE_SHARE_LOCK_ha_data, "TABLE_SHARE::LOCK_ha_data", 0},
+ { &key_LOCK_error_messages, "LOCK_error_messages", PSI_FLAG_GLOBAL},
+ { &key_LOG_INFO_lock, "LOG_INFO::lock", 0},
+ { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL},
+ { &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0}
+};
+
+PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger,
+ key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave,
+ key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock;
+
+static PSI_rwlock_info all_server_rwlocks[]=
+{
+#if defined (HAVE_OPENSSL) && !defined(HAVE_YASSL)
+ { &key_rwlock_openssl, "CRYPTO_dynlock_value::lock", 0},
+#endif
+ { &key_rwlock_LOCK_grant, "LOCK_grant", PSI_FLAG_GLOBAL},
+ { &key_rwlock_LOCK_logger, "LOGGER::LOCK_logger", 0},
+ { &key_rwlock_LOCK_sys_init_connect, "LOCK_sys_init_connect", PSI_FLAG_GLOBAL},
+ { &key_rwlock_LOCK_sys_init_slave, "LOCK_sys_init_slave", PSI_FLAG_GLOBAL},
+ { &key_rwlock_LOCK_system_variables_hash, "LOCK_system_variables_hash", PSI_FLAG_GLOBAL},
+ { &key_rwlock_query_cache_query_lock, "Query_cache_query::lock", 0}
+};
+
+#ifdef HAVE_MMAP
+PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool;
+#endif /* HAVE_MMAP */
+
+PSI_cond_key key_BINLOG_COND_prep_xids, key_BINLOG_update_cond,
+ key_COND_cache_status_changed, key_COND_manager,
+ key_COND_rpl_status, key_COND_server_started,
+ key_delayed_insert_cond, key_delayed_insert_cond_client,
+ key_item_func_sleep_cond, key_master_info_data_cond,
+ key_master_info_start_cond, key_master_info_stop_cond,
+ key_relay_log_info_data_cond, key_relay_log_info_log_space_cond,
+ key_relay_log_info_start_cond, key_relay_log_info_stop_cond,
+ key_TABLE_SHARE_cond, key_user_level_lock_cond,
+ key_COND_thread_count, key_COND_thread_cache, key_COND_flush_thread_cache;
+
+static PSI_cond_info all_server_conds[]=
+{
+#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
+ { &key_COND_handler_count, "COND_handler_count", PSI_FLAG_GLOBAL},
+#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
+#ifdef HAVE_MMAP
+ { &key_PAGE_cond, "PAGE::cond", 0},
+ { &key_COND_active, "TC_LOG_MMAP::COND_active", 0},
+ { &key_COND_pool, "TC_LOG_MMAP::COND_pool", 0},
+#endif /* HAVE_MMAP */
+ { &key_BINLOG_COND_prep_xids, "MYSQL_BIN_LOG::COND_prep_xids", 0},
+ { &key_BINLOG_update_cond, "MYSQL_BIN_LOG::update_cond", 0},
+ { &key_COND_cache_status_changed, "Query_cache::COND_cache_status_changed", 0},
+ { &key_COND_manager, "COND_manager", PSI_FLAG_GLOBAL},
+ { &key_COND_rpl_status, "COND_rpl_status", PSI_FLAG_GLOBAL},
+ { &key_COND_server_started, "COND_server_started", PSI_FLAG_GLOBAL},
+ { &key_delayed_insert_cond, "Delayed_insert::cond", 0},
+ { &key_delayed_insert_cond_client, "Delayed_insert::cond_client", 0},
+ { &key_item_func_sleep_cond, "Item_func_sleep::cond", 0},
+ { &key_master_info_data_cond, "Master_info::data_cond", 0},
+ { &key_master_info_start_cond, "Master_info::start_cond", 0},
+ { &key_master_info_stop_cond, "Master_info::stop_cond", 0},
+ { &key_relay_log_info_data_cond, "Relay_log_info::data_cond", 0},
+ { &key_relay_log_info_log_space_cond, "Relay_log_info::log_space_cond", 0},
+ { &key_relay_log_info_start_cond, "Relay_log_info::start_cond", 0},
+ { &key_relay_log_info_stop_cond, "Relay_log_info::stop_cond", 0},
+ { &key_TABLE_SHARE_cond, "TABLE_SHARE::cond", 0},
+ { &key_user_level_lock_cond, "User_level_lock::cond", 0},
+ { &key_COND_thread_count, "COND_thread_count", PSI_FLAG_GLOBAL},
+ { &key_COND_thread_cache, "COND_thread_cache", PSI_FLAG_GLOBAL},
+ { &key_COND_flush_thread_cache, "COND_flush_thread_cache", PSI_FLAG_GLOBAL}
+};
+
+PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert,
+ key_thread_handle_manager, key_thread_main,
+ key_thread_one_connection, key_thread_signal_hand;
+
+static PSI_thread_info all_server_threads[]=
+{
+#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
+ { &key_thread_handle_con_namedpipes, "con_named_pipes", PSI_FLAG_GLOBAL},
+#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
+
+#if defined(HAVE_SMEM) && !defined(EMBEDDED_LIBRARY)
+ { &key_thread_handle_con_sharedmem, "con_shared_mem", PSI_FLAG_GLOBAL},
+#endif /* HAVE_SMEM && !EMBEDDED_LIBRARY */
+
+#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
+ { &key_thread_handle_con_sockets, "con_sockets", PSI_FLAG_GLOBAL},
+#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
+
+#ifdef __WIN__
+ { &key_thread_handle_shutdown, "shutdown", PSI_FLAG_GLOBAL},
+#endif /* __WIN__ */
+
+ { &key_thread_bootstrap, "bootstrap", PSI_FLAG_GLOBAL},
+ { &key_thread_delayed_insert, "delayed_insert", 0},
+ { &key_thread_handle_manager, "manager", PSI_FLAG_GLOBAL},
+ { &key_thread_main, "main", PSI_FLAG_GLOBAL},
+ { &key_thread_one_connection, "one_connection", 0},
+ { &key_thread_signal_hand, "signal_handler", PSI_FLAG_GLOBAL}
+};
+
+#ifdef HAVE_MMAP
+PSI_file_key key_file_map;
+#endif /* HAVE_MMAP */
+
+PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest,
+ key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file,
+ key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load,
+ key_file_loadfile, key_file_log_event_data, key_file_log_event_info,
+ key_file_master_info, key_file_misc, key_file_partition,
+ key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog,
+ key_file_trg, key_file_trn, key_file_init;
+PSI_file_key key_file_query_log, key_file_slow_log;
+
+static PSI_file_info all_server_files[]=
+{
+#ifdef HAVE_MMAP
+ { &key_file_map, "map", 0},
+#endif /* HAVE_MMAP */
+ { &key_file_binlog, "binlog", 0},
+ { &key_file_binlog_index, "binlog_index", 0},
+ { &key_file_casetest, "casetest", 0},
+ { &key_file_dbopt, "dbopt", 0},
+ { &key_file_des_key_file, "des_key_file", 0},
+ { &key_file_ERRMSG, "ERRMSG", 0},
+ { &key_select_to_file, "select_to_file", 0},
+ { &key_file_fileparser, "file_parser", 0},
+ { &key_file_frm, "FRM", 0},
+ { &key_file_global_ddl_log, "global_ddl_log", 0},
+ { &key_file_load, "load", 0},
+ { &key_file_loadfile, "LOAD_FILE", 0},
+ { &key_file_log_event_data, "log_event_data", 0},
+ { &key_file_log_event_info, "log_event_info", 0},
+ { &key_file_master_info, "master_info", 0},
+ { &key_file_misc, "misc", 0},
+ { &key_file_partition, "partition", 0},
+ { &key_file_pid, "pid", 0},
+ { &key_file_query_log, "query_log", 0},
+ { &key_file_relay_log_info, "relay_log_info", 0},
+ { &key_file_send_file, "send_file", 0},
+ { &key_file_slow_log, "slow_log", 0},
+ { &key_file_tclog, "tclog", 0},
+ { &key_file_trg, "trigger_name", 0},
+ { &key_file_trn, "trigger", 0},
+ { &key_file_init, "init", 0}
+};
+
+/**
+ Initialise all the performance schema instrumentation points
+ used by the server.
+*/
+void init_server_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_server_mutexes);
+ PSI_server->register_mutex(category, all_server_mutexes, count);
+
+ count= array_elements(all_server_rwlocks);
+ PSI_server->register_rwlock(category, all_server_rwlocks, count);
+
+ count= array_elements(all_server_conds);
+ PSI_server->register_cond(category, all_server_conds, count);
+
+ count= array_elements(all_server_threads);
+ PSI_server->register_thread(category, all_server_threads, count);
+
+ count= array_elements(all_server_files);
+ PSI_server->register_file(category, all_server_files, count);
+}
+
+#endif /* HAVE_PSI_INTERFACE */
+
diff --git a/sql/mysqld.h b/sql/mysqld.h
new file mode 100644
index 00000000000..712b26382d1
--- /dev/null
+++ b/sql/mysqld.h
@@ -0,0 +1,508 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 MYSQLD_INCLUDED
+#define MYSQLD_INCLUDED
+
+#include "my_global.h" /* MYSQL_PLUGIN_IMPORT, FN_REFLEN, FN_EXTLEN */
+#include "sql_bitmap.h" /* Bitmap */
+#include "my_decimal.h" /* my_decimal */
+#include "mysql_com.h" /* SERVER_VERSION_LENGTH */
+#include "my_atomic.h" /* my_atomic_rwlock_t */
+#include "mysql/psi/mysql_file.h" /* MYSQL_FILE */
+#include "sql_list.h" /* I_List */
+
+class THD;
+struct handlerton;
+class Time_zone;
+
+struct scheduler_functions;
+
+typedef struct st_mysql_const_lex_string LEX_CSTRING;
+typedef struct st_mysql_show_var SHOW_VAR;
+
+/*
+ This forward declaration is used from C files where the real
+ definition is included before. Since C does not allow repeated
+ typedef declarations, even when identical, the definition may not be
+ repeated.
+*/
+#ifndef CHARSET_INFO_DEFINED
+typedef struct charset_info_st CHARSET_INFO;
+#endif /* CHARSET_INFO_DEFINED */
+
+#if MAX_INDEXES <= 64
+typedef Bitmap<64> key_map; /* Used for finding keys */
+#else
+typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
+#endif
+
+ /* Bits from testflag */
+#define TEST_PRINT_CACHED_TABLES 1
+#define TEST_NO_KEY_GROUP 2
+#define TEST_MIT_THREAD 4
+#define TEST_BLOCKING 8
+#define TEST_KEEP_TMP_TABLES 16
+#define TEST_READCHECK 64 /**< Force use of readcheck */
+#define TEST_NO_EXTRA 128
+#define TEST_CORE_ON_SIGNAL 256 /**< Give core if signal */
+#define TEST_NO_STACKTRACE 512
+#define TEST_SIGINT 1024 /**< Allow sigint on threads */
+#define TEST_SYNCHRONIZATION 2048 /**< get server to do sleep in
+ some places */
+/* Function prototypes */
+void kill_mysql(void);
+void close_connection(THD *thd, uint errcode, bool lock);
+void handle_connection_in_main_thread(THD *thd);
+void create_thread_to_handle_connection(THD *thd);
+void unlink_thd(THD *thd);
+bool one_thread_per_connection_end(THD *thd, bool put_in_cache);
+void flush_thread_cache();
+void refresh_status(THD *thd);
+bool is_secure_file_path(char *path);
+
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *national_charset_info;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *table_alias_charset;
+
+/**
+ Character set of the buildin error messages loaded from errmsg.sys.
+*/
+extern CHARSET_INFO *error_message_charset_info;
+
+extern CHARSET_INFO *character_set_filesystem;
+
+extern MY_BITMAP temp_pool;
+extern bool opt_large_files, server_id_supplied;
+extern bool opt_update_log, opt_bin_log, opt_error_log;
+extern my_bool opt_log, opt_slow_log;
+extern my_bool opt_backup_history_log;
+extern my_bool opt_backup_progress_log;
+extern ulonglong log_output_options;
+extern ulong log_backup_output_options;
+extern my_bool opt_log_queries_not_using_indexes;
+extern bool opt_disable_networking, opt_skip_show_db;
+extern bool opt_skip_name_resolve;
+extern bool opt_ignore_builtin_innodb;
+extern my_bool opt_character_set_client_handshake;
+extern bool volatile abort_loop;
+extern bool in_bootstrap;
+extern uint volatile thread_count;
+extern 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;
+extern ulong slave_exec_mode_options;
+extern ulonglong slave_type_conversions_options;
+extern my_bool opt_readonly, lower_case_file_system;
+extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
+extern my_bool opt_secure_auth;
+extern char* opt_secure_file_priv;
+extern char* opt_secure_backup_file_priv;
+extern size_t opt_secure_backup_file_priv_len;
+extern my_bool opt_log_slow_admin_statements, opt_log_slow_slave_statements;
+extern my_bool sp_automatic_privileges, opt_noacl;
+extern my_bool opt_old_style_user_limits, trust_function_creators;
+extern uint opt_crash_binlog_innodb;
+extern char *shared_memory_base_name, *mysqld_unix_port;
+extern my_bool opt_enable_shared_memory;
+extern char *default_tz_name;
+extern Time_zone *default_tz;
+extern char *default_storage_engine;
+extern bool opt_endinfo, using_udf_functions;
+extern my_bool locked_in_memory;
+extern bool opt_using_transactions;
+extern ulong current_pid;
+extern ulong expire_logs_days;
+extern my_bool relay_log_recovery;
+extern uint sync_binlog_period, sync_relaylog_period,
+ sync_relayloginfo_period, sync_masterinfo_period;
+extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size;
+extern ulong tc_log_page_waits;
+extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb;
+extern my_bool relay_log_recovery;
+extern uint test_flags,select_errors,ha_open_options;
+extern uint protocol_version, mysqld_port, dropping_tables;
+extern ulong delay_key_write_options;
+extern char *opt_logname, *opt_slow_logname;
+extern char *opt_backup_history_logname, *opt_backup_progress_logname,
+ *opt_backup_settings_name;
+extern const char *log_output_str;
+extern const char *log_backup_output_str;
+extern char *mysql_home_ptr, *pidfile_name_ptr;
+extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
+extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
+extern char default_logfile_name[FN_REFLEN];
+extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
+extern const double log_10[309];
+extern ulonglong keybuff_size;
+extern ulonglong thd_startup_options;
+extern ulong thread_id;
+extern ulong binlog_cache_use, binlog_cache_disk_use;
+extern ulong binlog_stmt_cache_use, binlog_stmt_cache_disk_use;
+extern ulong aborted_threads,aborted_connects;
+extern ulong delayed_insert_timeout;
+extern ulong delayed_insert_limit, delayed_queue_size;
+extern ulong delayed_insert_threads, delayed_insert_writes;
+extern ulong delayed_rows_in_use,delayed_insert_errors;
+extern ulong slave_open_temp_tables;
+extern ulong query_cache_size, query_cache_min_res_unit;
+extern ulong slow_launch_threads, slow_launch_time;
+extern ulong table_cache_size, table_def_size;
+extern MYSQL_PLUGIN_IMPORT ulong max_connections;
+extern ulong max_connect_errors, connect_timeout;
+extern my_bool slave_allow_batching;
+extern my_bool allow_slave_start;
+extern LEX_CSTRING reason_slave_blocked;
+extern ulong slave_trans_retries;
+extern uint slave_net_timeout;
+extern uint max_user_connections;
+extern ulong what_to_log,flush_time;
+extern ulong max_prepared_stmt_count, prepared_stmt_count;
+extern ulong open_files_limit;
+extern ulong binlog_cache_size, binlog_stmt_cache_size;
+extern ulonglong max_binlog_cache_size, max_binlog_stmt_cache_size;
+extern ulong max_binlog_size, max_relay_log_size;
+extern ulong opt_binlog_rows_event_max_size;
+extern ulong rpl_recovery_rank, thread_cache_size;
+extern ulong back_log;
+extern char language[FN_REFLEN];
+extern ulong server_id, concurrency;
+extern time_t server_start_time, flush_status_time;
+extern char *opt_mysql_tmpdir, mysql_charsets_dir[];
+extern int mysql_unpacked_real_data_home_len;
+extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list;
+extern const char *first_keyword, *delayed_user, *binary_keyword;
+extern MYSQL_PLUGIN_IMPORT const char *my_localhost;
+extern MYSQL_PLUGIN_IMPORT const char **errmesg; /* Error messages */
+extern const char *myisam_recover_options_str;
+extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond;
+extern SHOW_VAR status_vars[];
+extern struct system_variables max_system_variables;
+extern struct system_status_var global_status_var;
+extern struct rand_struct sql_rand;
+extern const char *opt_date_time_formats[];
+extern handlerton *partition_hton;
+extern handlerton *myisam_hton;
+extern handlerton *heap_hton;
+extern const char *load_default_groups[];
+extern struct my_option my_long_options[];
+extern int mysqld_server_started;
+extern int orig_argc;
+extern char **orig_argv;
+extern pthread_attr_t connection_attrib;
+extern MYSQL_FILE *bootstrap_file;
+extern my_bool old_mode;
+extern LEX_STRING opt_init_connect, opt_init_slave;
+extern int bootstrap_error;
+extern I_List<THD> threads;
+extern char err_shared_dir[];
+extern TYPELIB thread_handling_typelib;
+extern my_decimal decimal_zero;
+
+extern pthread_key(MEM_ROOT**,THR_MALLOC);
+
+#ifdef HAVE_PSI_INTERFACE
+#ifdef HAVE_MMAP
+extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active,
+ key_LOCK_pool;
+#endif /* HAVE_MMAP */
+
+#ifdef HAVE_OPENSSL
+extern PSI_mutex_key key_LOCK_des_key_file;
+#endif
+
+extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids,
+ 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_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
+ key_LOCK_gdl, key_LOCK_global_system_variables,
+ key_LOCK_logger, key_LOCK_manager,
+ key_LOCK_prepared_stmt_count,
+ key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status,
+ key_LOCK_table_share, key_LOCK_thd_data,
+ key_LOCK_user_conn, key_LOCK_uuid_generator, key_LOG_LOCK_log,
+ key_master_info_data_lock, key_master_info_run_lock,
+ key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock,
+ key_relay_log_info_log_space_lock, key_relay_log_info_run_lock,
+ key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data,
+ key_LOCK_error_messages, key_LOCK_thread_count, key_PARTITION_LOCK_auto_inc;
+
+extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger,
+ key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave,
+ key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock;
+
+#ifdef HAVE_MMAP
+extern PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool;
+#endif /* HAVE_MMAP */
+
+extern PSI_cond_key key_BINLOG_COND_prep_xids, key_BINLOG_update_cond,
+ key_COND_cache_status_changed, key_COND_manager,
+ key_COND_rpl_status, key_COND_server_started,
+ key_delayed_insert_cond, key_delayed_insert_cond_client,
+ key_item_func_sleep_cond, key_master_info_data_cond,
+ key_master_info_start_cond, key_master_info_stop_cond,
+ key_relay_log_info_data_cond, key_relay_log_info_log_space_cond,
+ key_relay_log_info_start_cond, key_relay_log_info_stop_cond,
+ key_TABLE_SHARE_cond, key_user_level_lock_cond,
+ key_COND_thread_count, key_COND_thread_cache, key_COND_flush_thread_cache;
+
+extern PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert,
+ key_thread_handle_manager, key_thread_kill_server, key_thread_main,
+ key_thread_one_connection, key_thread_signal_hand;
+
+#ifdef HAVE_MMAP
+extern PSI_file_key key_file_map;
+#endif /* HAVE_MMAP */
+
+extern PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest,
+ key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file,
+ key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load,
+ key_file_loadfile, key_file_log_event_data, key_file_log_event_info,
+ key_file_master_info, key_file_misc, key_file_partition,
+ key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog,
+ key_file_trg, key_file_trn, key_file_init;
+extern PSI_file_key key_file_query_log, key_file_slow_log;
+
+void init_server_psi_keys();
+#endif /* HAVE_PSI_INTERFACE */
+
+#ifndef __WIN__
+extern pthread_t signal_thread;
+#endif
+
+#ifdef HAVE_OPENSSL
+extern struct st_VioSSLFd * ssl_acceptor_fd;
+#endif /* HAVE_OPENSSL */
+
+/*
+ The following variables were under INNODB_COMPABILITY_HOOKS
+ */
+extern my_bool opt_large_pages;
+extern uint opt_large_page_size;
+extern char lc_messages_dir[FN_REFLEN];
+extern char *lc_messages_dir_ptr, *log_error_file_ptr;
+extern MYSQL_PLUGIN_IMPORT char reg_ext[FN_EXTLEN];
+extern MYSQL_PLUGIN_IMPORT uint reg_ext_length;
+extern MYSQL_PLUGIN_IMPORT uint lower_case_table_names;
+extern MYSQL_PLUGIN_IMPORT bool mysqld_embedded;
+extern ulong specialflag;
+extern uint mysql_data_home_len;
+extern uint mysql_real_data_home_len;
+extern const char *mysql_real_data_home_ptr;
+extern ulong thread_handling;
+extern MYSQL_PLUGIN_IMPORT char *mysql_data_home;
+extern char server_version[SERVER_VERSION_LENGTH];
+extern MYSQL_PLUGIN_IMPORT char mysql_real_data_home[];
+extern char mysql_unpacked_real_data_home[];
+extern MYSQL_PLUGIN_IMPORT struct system_variables global_system_variables;
+extern char default_logfile_name[FN_REFLEN];
+
+#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list))
+
+extern MYSQL_PLUGIN_IMPORT const key_map key_map_empty;
+extern MYSQL_PLUGIN_IMPORT key_map key_map_full; /* Should be threaded as const */
+
+/*
+ Server mutex locks and condition variables.
+ */
+extern mysql_mutex_t
+ LOCK_user_locks, LOCK_status,
+ LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
+ LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
+ LOCK_slave_list, LOCK_active_mi, LOCK_manager,
+ LOCK_global_system_variables, LOCK_user_conn,
+ LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count;
+extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_thread_count;
+#ifdef HAVE_OPENSSL
+extern mysql_mutex_t LOCK_des_key_file;
+#endif
+extern mysql_mutex_t LOCK_server_started;
+extern mysql_cond_t COND_server_started;
+extern mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
+extern mysql_rwlock_t LOCK_system_variables_hash;
+extern mysql_cond_t COND_thread_count;
+extern mysql_cond_t COND_manager;
+extern int32 thread_running;
+extern my_atomic_rwlock_t thread_running_lock;
+
+extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher,
+ *opt_ssl_key;
+
+extern MYSQL_PLUGIN_IMPORT pthread_key(THD*, THR_THD);
+
+/**
+ only options that need special treatment in get_one_option() deserve
+ to be listed below
+*/
+enum options_mysqld
+{
+ OPT_to_set_the_start_number=256,
+ OPT_BIND_ADDRESS,
+ OPT_BINLOG_DO_DB,
+ OPT_BINLOG_FORMAT,
+ OPT_BINLOG_IGNORE_DB,
+ OPT_BIN_LOG,
+ OPT_BOOTSTRAP,
+ OPT_CONSOLE,
+ OPT_DEBUG_SYNC_TIMEOUT,
+ OPT_DELAY_KEY_WRITE_ALL,
+ OPT_ISAM_LOG,
+ OPT_KEY_BUFFER_SIZE,
+ OPT_KEY_CACHE_AGE_THRESHOLD,
+ OPT_KEY_CACHE_BLOCK_SIZE,
+ OPT_KEY_CACHE_DIVISION_LIMIT,
+ OPT_LOWER_CASE_TABLE_NAMES,
+ OPT_ONE_THREAD,
+ OPT_POOL_OF_THREADS,
+ OPT_REPLICATE_DO_DB,
+ OPT_REPLICATE_DO_TABLE,
+ OPT_REPLICATE_IGNORE_DB,
+ OPT_REPLICATE_IGNORE_TABLE,
+ OPT_REPLICATE_REWRITE_DB,
+ OPT_REPLICATE_WILD_DO_TABLE,
+ OPT_REPLICATE_WILD_IGNORE_TABLE,
+ OPT_SAFE,
+ OPT_SERVER_ID,
+ OPT_SKIP_HOST_CACHE,
+ OPT_SKIP_LOCK,
+ OPT_SKIP_NEW,
+ OPT_SKIP_PRIOR,
+ OPT_SKIP_RESOLVE,
+ OPT_SKIP_STACK_TRACE,
+ OPT_SKIP_SYMLINKS,
+ OPT_SLOW_QUERY_LOG,
+ OPT_SSL_CA,
+ OPT_SSL_CAPATH,
+ OPT_SSL_CERT,
+ OPT_SSL_CIPHER,
+ OPT_SSL_KEY,
+ OPT_UPDATE_LOG,
+ OPT_WANT_CORE,
+ OPT_ENGINE_CONDITION_PUSHDOWN,
+ OPT_LOG_ERROR,
+ OPT_AUTOCOMMIT
+};
+
+
+/**
+ Query type constants.
+
+ QT_ORDINARY -- ordinary SQL query.
+ QT_IS -- SQL query to be shown in INFORMATION_SCHEMA (in utf8 and without
+ character set introducers).
+*/
+enum enum_query_type
+{
+ QT_ORDINARY,
+ QT_IS
+};
+
+/* query_id */
+typedef int64 query_id_t;
+extern query_id_t global_query_id;
+extern my_atomic_rwlock_t global_query_id_lock;
+
+void unireg_end(void) __attribute__((noreturn));
+
+/* increment query_id and return it. */
+inline query_id_t next_query_id()
+{
+ query_id_t id;
+ my_atomic_rwlock_wrlock(&global_query_id_lock);
+ id= my_atomic_add64(&global_query_id, 1);
+ my_atomic_rwlock_wrunlock(&global_query_id_lock);
+ return (id+1);
+}
+
+inline query_id_t get_query_id()
+{
+ query_id_t id;
+ my_atomic_rwlock_wrlock(&global_query_id_lock);
+ id= my_atomic_load64(&global_query_id);
+ my_atomic_rwlock_wrunlock(&global_query_id_lock);
+ return id;
+}
+
+
+/*
+ TODO: Replace this with an inline function.
+ */
+#ifndef EMBEDDED_LIBRARY
+extern "C" void unireg_abort(int exit_code) __attribute__((noreturn));
+#else
+extern "C" void unireg_clear(int exit_code);
+#define unireg_abort(exit_code) do { unireg_clear(exit_code); DBUG_RETURN(exit_code); } while(0)
+#endif
+
+inline void table_case_convert(char * name, uint length)
+{
+ if (lower_case_table_names)
+ files_charset_info->cset->casedn(files_charset_info,
+ name, length, name, length);
+}
+
+inline ulong sql_rnd_with_mutex()
+{
+ mysql_mutex_lock(&LOCK_thread_count);
+ ulong tmp=(ulong) (my_rnd(&sql_rand) * 0xffffffff); /* make all bits random */
+ mysql_mutex_unlock(&LOCK_thread_count);
+ return tmp;
+}
+
+inline int32
+inc_thread_running()
+{
+ int32 num_thread_running;
+ my_atomic_rwlock_wrlock(&thread_running_lock);
+ num_thread_running= my_atomic_add32(&thread_running, 1);
+ my_atomic_rwlock_wrunlock(&thread_running_lock);
+ return (num_thread_running+1);
+}
+
+inline int32
+dec_thread_running()
+{
+ int32 num_thread_running;
+ my_atomic_rwlock_wrlock(&thread_running_lock);
+ num_thread_running= my_atomic_add32(&thread_running, -1);
+ my_atomic_rwlock_wrunlock(&thread_running_lock);
+ return (num_thread_running-1);
+}
+
+inline int32
+get_thread_running()
+{
+ int32 num_thread_running;
+ my_atomic_rwlock_wrlock(&thread_running_lock);
+ num_thread_running= my_atomic_load32(&thread_running);
+ my_atomic_rwlock_wrunlock(&thread_running_lock);
+ return num_thread_running;
+}
+
+#if defined(MYSQL_DYNAMIC_PLUGIN) && defined(_WIN32)
+extern "C" THD *_current_thd_noinline();
+#define _current_thd() _current_thd_noinline()
+#else
+extern pthread_key(THD*, THR_THD);
+inline THD *_current_thd(void)
+{
+ return my_pthread_getspecific_ptr(THD*,THR_THD);
+}
+#endif
+#define current_thd _current_thd()
+
+#endif /* MYSQLD_INCLUDED */
diff --git a/sql/mysqld_suffix.h b/sql/mysqld_suffix.h
index 654d7cf88c1..c7ab212f2a2 100644
--- a/sql/mysqld_suffix.h
+++ b/sql/mysqld_suffix.h
@@ -1,3 +1,6 @@
+#ifndef MYSQLD_SUFFIX_INCLUDED
+#define MYSQLD_SUFFIX_INCLUDED
+
/* Copyright (C) 2000-2004 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -27,3 +30,4 @@
#else
#define MYSQL_SERVER_SUFFIX_STR MYSQL_SERVER_SUFFIX_DEF
#endif
+#endif /* MYSQLD_SUFFIX_INCLUDED */
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index f3f6f1bd9a0..488e27296b6 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -35,7 +35,6 @@
*/
#include <my_global.h>
#include <mysql.h>
-#include <mysql_embed.h>
#include <mysql_com.h>
#include <mysqld_error.h>
#include <my_sys.h>
@@ -44,9 +43,7 @@
#include <violite.h>
#include <signal.h>
#include <errno.h>
-#ifdef __NETWARE__
-#include <sys/select.h>
-#endif
+#include "probes_mysql.h"
#ifdef EMBEDDED_LIBRARY
#undef MYSQL_SERVER
@@ -59,15 +56,17 @@
The following handles the differences when this is linked between the
client and the server.
- This gives an error if a too big packet is found
- The server can change this with the -O switch, but because the client
- can't normally do this the client should have a bigger max_allowed_packet.
+ This gives an error if a too big packet is found.
+ The server can change this, but because the client can't normally do this
+ the client should have a bigger max_allowed_packet.
*/
#if defined(__WIN__) || !defined(MYSQL_SERVER)
/* The following is because alarms doesn't work on windows. */
+#ifndef NO_ALARM
#define NO_ALARM
#endif
+#endif
#ifndef NO_ALARM
#include "my_pthread.h"
@@ -81,17 +80,16 @@ void sql_print_error(const char *format,...);
#ifdef MYSQL_SERVER
/*
The following variables/functions should really not be declared
- extern, but as it's hard to include mysql_priv.h here, we have to
+ extern, but as it's hard to include sql_priv.h here, we have to
live with this for a while.
*/
extern uint test_flags;
extern ulong bytes_sent, bytes_received, net_big_packet_count;
-extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#ifndef MYSQL_INSTANCE_MANAGER
#ifdef HAVE_QUERY_CACHE
#define USE_QUERY_CACHE
-extern void query_cache_init_query(NET *net);
-extern void query_cache_insert(NET *net, const char *packet, ulong length);
+extern void query_cache_insert(const char *packet, ulong length,
+ unsigned pkt_nr);
#endif // HAVE_QUERY_CACHE
#define update_statistics(A) A
#endif /* MYSQL_INSTANCE_MANGER */
@@ -120,18 +118,14 @@ my_bool my_net_init(NET *net, Vio* vio)
MYF(MY_WME))))
DBUG_RETURN(1);
net->buff_end=net->buff+net->max_packet;
- net->error=0; net->return_errno=0; net->return_status=0;
+ net->error=0; net->return_status=0;
net->pkt_nr=net->compress_pkt_nr=0;
net->write_pos=net->read_pos = net->buff;
net->last_error[0]=0;
net->compress=0; net->reading_or_writing=0;
net->where_b = net->remain_in_buf=0;
net->last_errno=0;
-#ifdef USE_QUERY_CACHE
- query_cache_init_query(net);
-#else
- net->query_cache_query= 0;
-#endif
+ net->unused= 0;
#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
net->skip_big_packet= FALSE;
#endif
@@ -155,7 +149,7 @@ my_bool my_net_init(NET *net, Vio* vio)
void net_end(NET *net)
{
DBUG_ENTER("net_end");
- my_free(net->buff,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(net->buff);
net->buff=0;
DBUG_VOID_RETURN;
}
@@ -379,8 +373,13 @@ my_bool
my_net_write(NET *net,const uchar *packet,size_t len)
{
uchar buff[NET_HEADER_SIZE];
+ int rc;
+
if (unlikely(!net->vio)) /* nowhere to write */
return 0;
+
+ MYSQL_NET_WRITE_START(len);
+
/*
Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH
length. The last packet is always a packet that is < MAX_PACKET_LENGTH.
@@ -393,7 +392,10 @@ my_net_write(NET *net,const uchar *packet,size_t len)
buff[3]= (uchar) net->pkt_nr++;
if (net_write_buff(net, buff, NET_HEADER_SIZE) ||
net_write_buff(net, packet, z_size))
+ {
+ MYSQL_NET_WRITE_DONE(1);
return 1;
+ }
packet += z_size;
len-= z_size;
}
@@ -401,11 +403,16 @@ my_net_write(NET *net,const uchar *packet,size_t len)
int3store(buff,len);
buff[3]= (uchar) net->pkt_nr++;
if (net_write_buff(net, buff, NET_HEADER_SIZE))
+ {
+ MYSQL_NET_WRITE_DONE(1);
return 1;
+ }
#ifndef DEBUG_DATA_PACKETS
DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE);
#endif
- return test(net_write_buff(net,packet,len));
+ rc= test(net_write_buff(net,packet,len));
+ MYSQL_NET_WRITE_DONE(rc);
+ return rc;
}
/**
@@ -443,9 +450,12 @@ net_write_command(NET *net,uchar command,
size_t length=len+1+head_len; /* 1 extra byte for command */
uchar buff[NET_HEADER_SIZE+1];
uint header_size=NET_HEADER_SIZE+1;
+ int rc;
DBUG_ENTER("net_write_command");
DBUG_PRINT("enter",("length: %lu", (ulong) len));
+ MYSQL_NET_WRITE_START(length);
+
buff[4]=command; /* For first packet */
if (length >= MAX_PACKET_LENGTH)
@@ -459,7 +469,10 @@ net_write_command(NET *net,uchar command,
if (net_write_buff(net, buff, header_size) ||
net_write_buff(net, header, head_len) ||
net_write_buff(net, packet, len))
+ {
+ MYSQL_NET_WRITE_DONE(1);
DBUG_RETURN(1);
+ }
packet+= len;
length-= MAX_PACKET_LENGTH;
len= MAX_PACKET_LENGTH;
@@ -470,9 +483,11 @@ net_write_command(NET *net,uchar command,
}
int3store(buff,length);
buff[3]= (uchar) net->pkt_nr++;
- DBUG_RETURN(test(net_write_buff(net, buff, header_size) ||
- (head_len && net_write_buff(net, header, head_len)) ||
- net_write_buff(net, packet, len) || net_flush(net)));
+ rc= test(net_write_buff(net, buff, header_size) ||
+ (head_len && net_write_buff(net, header, head_len)) ||
+ net_write_buff(net, packet, len) || net_flush(net));
+ MYSQL_NET_WRITE_DONE(rc);
+ DBUG_RETURN(rc);
}
/**
@@ -573,7 +588,7 @@ net_real_write(NET *net,const uchar *packet, size_t len)
DBUG_ENTER("net_real_write");
#if defined(MYSQL_SERVER) && defined(USE_QUERY_CACHE)
- query_cache_insert(net, (char*) packet, len);
+ query_cache_insert((char*) packet, len, net->pkt_nr);
#endif
if (net->error == 2)
@@ -688,7 +703,7 @@ net_real_write(NET *net,const uchar *packet, size_t len)
#endif
#ifdef HAVE_COMPRESS
if (net->compress)
- my_free((char*) packet,MYF(0));
+ my_free((void*) packet);
#endif
if (thr_alarm_in_use(&alarmed))
{
@@ -1014,6 +1029,8 @@ my_net_read(NET *net)
{
size_t len, complen;
+ MYSQL_NET_READ_START();
+
#ifdef HAVE_COMPRESS
if (!net->compress)
{
@@ -1037,6 +1054,7 @@ my_net_read(NET *net)
net->read_pos = net->buff + net->where_b;
if (len != packet_error)
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
+ MYSQL_NET_READ_DONE(0, len);
return len;
#ifdef HAVE_COMPRESS
}
@@ -1120,7 +1138,10 @@ my_net_read(NET *net)
net->where_b=buf_length;
if ((packet_len = my_real_read(net,&complen)) == packet_error)
+ {
+ MYSQL_NET_READ_DONE(1, 0);
return packet_error;
+ }
if (my_uncompress(net->buff + net->where_b, packet_len,
&complen))
{
@@ -1129,6 +1150,7 @@ my_net_read(NET *net)
#ifdef MYSQL_SERVER
my_error(ER_NET_UNCOMPRESS_ERROR, MYF(0));
#endif
+ MYSQL_NET_READ_DONE(1, 0);
return packet_error;
}
buf_length+= complen;
@@ -1143,6 +1165,7 @@ my_net_read(NET *net)
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
}
#endif /* HAVE_COMPRESS */
+ MYSQL_NET_READ_DONE(0, len);
return len;
}
diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc
index f41fa08f828..1f1b7f0c20f 100644
--- a/sql/nt_servc.cc
+++ b/sql/nt_servc.cc
@@ -10,6 +10,7 @@
#include <windows.h>
#include <process.h>
#include <stdio.h>
+#include <stdlib.h>
#include "nt_servc.h"
@@ -374,29 +375,6 @@ void NTService::ServiceCtrlHandler(DWORD ctrlCode)
dwState=pService->dwState; // get current state
switch(ctrlCode) {
-
-#ifdef NOT_USED /* do we need this ? */
- case SERVICE_CONTROL_PAUSE:
- if (pService->bRunning && ! pService->bPause)
- {
- dwState = SERVICE_PAUSED;
- pService->SetStatus(SERVICE_PAUSE_PENDING,NO_ERROR, 0, 1,
- pService->nPauseTimeOut);
- pService->PauseService();
- }
- break;
-
- case SERVICE_CONTROL_CONTINUE:
- if (pService->bRunning && pService->bPause)
- {
- dwState = SERVICE_RUNNING;
- pService->SetStatus(SERVICE_CONTINUE_PENDING,NO_ERROR, 0, 1,
- pService->nResumeTimeOut);
- pService->ResumeService();
- }
- break;
-#endif
-
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
dwState = SERVICE_STOP_PENDING;
diff --git a/sql/nt_servc.h b/sql/nt_servc.h
index 2f0d07df543..5bee42dedf0 100644
--- a/sql/nt_servc.h
+++ b/sql/nt_servc.h
@@ -1,3 +1,6 @@
+#ifndef NT_SERVC_INCLUDED
+#define NT_SERVC_INCLUDED
+
/**
@file
@@ -98,3 +101,5 @@ class NTService
};
/* ------------------------- the end -------------------------------------- */
+
+#endif /* NT_SERVC_INCLUDED */
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index d4a2bc3b138..2ac860d25e3 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -65,7 +65,13 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "key.h" // is_key_used, key_copy, key_cmp, key_restore
+#include "sql_parse.h" // check_stack_overrun
+#include "sql_partition.h" // get_part_id_func, PARTITION_ITERATOR,
+ // struct partition_info
+#include "sql_base.h" // free_io_cache
+#include "records.h" // init_read_record, end_read_record
#include <m_ctype.h>
#include "sql_select.h"
@@ -438,8 +444,19 @@ public:
return 0;
}
- /* returns a number of keypart values appended to the key buffer */
- int store_min_key(KEY_PART *key, uchar **range_key, uint *range_key_flag)
+ /*
+ Returns a number of keypart values appended to the key buffer
+ for min key and max key. This function is used by both Range
+ Analysis and Partition pruning. For partition pruning we have
+ to ensure that we don't store also subpartition fields. Thus
+ we have to stop at the last partition part and not step into
+ the subpartition fields. For Range Analysis we set last_part
+ to MAX_KEY which we should never reach.
+ */
+ int store_min_key(KEY_PART *key,
+ uchar **range_key,
+ uint *range_key_flag,
+ uint last_part)
{
SEL_ARG *key_tree= first();
uint res= key_tree->store_min(key[key_tree->part].store_length,
@@ -447,15 +464,21 @@ public:
*range_key_flag|= key_tree->min_flag;
if (key_tree->next_key_part &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE &&
+ key_tree->part != last_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
!(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)))
- res+= key_tree->next_key_part->store_min_key(key, range_key,
- range_key_flag);
+ res+= key_tree->next_key_part->store_min_key(key,
+ range_key,
+ range_key_flag,
+ last_part);
return res;
}
/* returns a number of keypart values appended to the key buffer */
- int store_max_key(KEY_PART *key, uchar **range_key, uint *range_key_flag)
+ int store_max_key(KEY_PART *key,
+ uchar **range_key,
+ uint *range_key_flag,
+ uint last_part)
{
SEL_ARG *key_tree= last();
uint res=key_tree->store_max(key[key_tree->part].store_length,
@@ -463,10 +486,13 @@ public:
(*range_key_flag)|= key_tree->max_flag;
if (key_tree->next_key_part &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE &&
+ key_tree->part != last_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
!(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)))
- res+= key_tree->next_key_part->store_max_key(key, range_key,
- range_key_flag);
+ res+= key_tree->next_key_part->store_max_key(key,
+ range_key,
+ range_key_flag,
+ last_part);
return res;
}
@@ -634,6 +660,14 @@ public:
using_real_indexes==TRUE
*/
uint real_keynr[MAX_KEY];
+
+ /*
+ Used to store 'current key tuples', in both range analysis and
+ partitioning (list) analysis
+ */
+ uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH],
+ max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
+
/* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */
uint alloced_sel_args;
};
@@ -645,8 +679,6 @@ public:
longlong baseflag;
uint max_key_part, range_count;
- uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH],
- max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
bool quick; // Don't calulate possible keys
uint fields_bitmap_size;
@@ -708,7 +740,8 @@ static
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
double read_time);
static
-TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree);
+TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree,
+ double read_time);
static double get_index_only_read_time(const PARAM* param, ha_rows records,
int keynr);
@@ -1058,7 +1091,7 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
select->file= *head->sort.io_cache;
select->records=(ha_rows) (select->file.end_of_file/
head->file->ref_length);
- my_free(head->sort.io_cache, MYF(0));
+ my_free(head->sort.io_cache);
head->sort.io_cache=0;
}
DBUG_RETURN(select);
@@ -1183,11 +1216,11 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
}
delete_dynamic(&ranges); /* ranges are allocated in alloc */
free_root(&alloc,MYF(0));
- my_free((char*) column_bitmap.bitmap, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(column_bitmap.bitmap);
}
head->column_bitmaps_set(save_read_set, save_write_set);
- x_free(multi_range);
- x_free(multi_range_buff);
+ my_free(multi_range);
+ my_free(multi_range_buff);
DBUG_VOID_RETURN;
}
@@ -1507,6 +1540,29 @@ QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param,
/*
+ Comparison function to be used QUICK_ROR_UNION_SELECT::queue priority
+ queue.
+
+ SYNPOSIS
+ QUICK_ROR_UNION_SELECT_queue_cmp()
+ arg Pointer to QUICK_ROR_UNION_SELECT
+ val1 First merged select
+ val2 Second merged select
+*/
+
+C_MODE_START
+
+static int QUICK_ROR_UNION_SELECT_queue_cmp(void *arg, uchar *val1, uchar *val2)
+{
+ QUICK_ROR_UNION_SELECT *self= (QUICK_ROR_UNION_SELECT*)arg;
+ return self->head->file->cmp_ref(((QUICK_SELECT_I*)val1)->last_rowid,
+ ((QUICK_SELECT_I*)val2)->last_rowid);
+}
+
+C_MODE_END
+
+
+/*
Do post-constructor initialization.
SYNOPSIS
QUICK_ROR_UNION_SELECT::init()
@@ -1520,7 +1576,7 @@ int QUICK_ROR_UNION_SELECT::init()
{
DBUG_ENTER("QUICK_ROR_UNION_SELECT::init");
if (init_queue(&queue, quick_selects.elements, 0,
- FALSE , QUICK_ROR_UNION_SELECT::queue_cmp,
+ FALSE , QUICK_ROR_UNION_SELECT_queue_cmp,
(void*) this))
{
bzero(&queue, sizeof(QUEUE));
@@ -1535,25 +1591,6 @@ int QUICK_ROR_UNION_SELECT::init()
/*
- Comparison function to be used QUICK_ROR_UNION_SELECT::queue priority
- queue.
-
- SYNPOSIS
- QUICK_ROR_UNION_SELECT::queue_cmp()
- arg Pointer to QUICK_ROR_UNION_SELECT
- val1 First merged select
- val2 Second merged select
-*/
-
-int QUICK_ROR_UNION_SELECT::queue_cmp(void *arg, uchar *val1, uchar *val2)
-{
- QUICK_ROR_UNION_SELECT *self= (QUICK_ROR_UNION_SELECT*)arg;
- return self->head->file->cmp_ref(((QUICK_SELECT_I*)val1)->last_rowid,
- ((QUICK_SELECT_I*)val2)->last_rowid);
-}
-
-
-/*
Initialize quick select for row retrieval.
SYNOPSIS
reset()
@@ -1806,96 +1843,6 @@ SEL_ARG *SEL_ARG::clone_tree(RANGE_OPT_PARAM *param)
/*
- Find the best index to retrieve first N records in given order
-
- SYNOPSIS
- get_index_for_order()
- table Table to be accessed
- order Required ordering
- limit Number of records that will be retrieved
-
- DESCRIPTION
- Find the best index that allows to retrieve first #limit records in the
- given order cheaper then one would retrieve them using full table scan.
-
- IMPLEMENTATION
- Run through all table indexes and find the shortest index that allows
- records to be retrieved in given order. We look for the shortest index
- as we will have fewer index pages to read with it.
-
- This function is used only by UPDATE/DELETE, so we take into account how
- the UPDATE/DELETE code will work:
- * index can only be scanned in forward direction
- * HA_EXTRA_KEYREAD will not be used
- Perhaps these assumptions could be relaxed.
-
- RETURN
- Number of the index that produces the required ordering in the cheapest way
- MAX_KEY if no such index was found.
-*/
-
-uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit)
-{
- uint idx;
- uint match_key= MAX_KEY, match_key_len= MAX_KEY_LENGTH + 1;
- ORDER *ord;
-
- for (ord= order; ord; ord= ord->next)
- if (!ord->asc)
- return MAX_KEY;
-
- for (idx= 0; idx < table->s->keys; idx++)
- {
- if (!(table->keys_in_use_for_query.is_set(idx)))
- continue;
- KEY_PART_INFO *keyinfo= table->key_info[idx].key_part;
- uint n_parts= table->key_info[idx].key_parts;
- uint partno= 0;
-
- /*
- The below check is sufficient considering we now have either BTREE
- indexes (records are returned in order for any index prefix) or HASH
- indexes (records are not returned in order for any index prefix).
- */
- if (!(table->file->index_flags(idx, 0, 1) & HA_READ_ORDER))
- continue;
- for (ord= order; ord && partno < n_parts; ord= ord->next, partno++)
- {
- Item *item= order->item[0];
- if (!(item->type() == Item::FIELD_ITEM &&
- ((Item_field*)item)->field->eq(keyinfo[partno].field)))
- break;
- }
-
- if (!ord && table->key_info[idx].key_length < match_key_len)
- {
- /*
- Ok, the ordering is compatible and this key is shorter then
- previous match (we want shorter keys as we'll have to read fewer
- index pages for the same number of records)
- */
- match_key= idx;
- match_key_len= table->key_info[idx].key_length;
- }
- }
-
- if (match_key != MAX_KEY)
- {
- /*
- Found an index that allows records to be retrieved in the requested
- order. Now we'll check if using the index is cheaper then doing a table
- scan.
- */
- double full_scan_time= table->file->scan_time();
- double index_scan_time= table->file->read_time(match_key, 1, limit);
- if (index_scan_time > full_scan_time)
- match_key= MAX_KEY;
- }
- return match_key;
-}
-
-
-/*
Table rows retrieval plan. Range optimizer creates QUICK_SELECT_I-derived
objects from table read plans.
*/
@@ -2044,7 +1991,7 @@ public:
class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN
{
private:
- bool have_min, have_max;
+ bool have_min, have_max, have_agg_distinct;
KEY_PART_INFO *min_max_arg_part;
uint group_prefix_len;
uint used_key_parts;
@@ -2056,11 +2003,13 @@ private:
SEL_TREE *range_tree; /* Represents all range predicates in the query. */
SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */
uint param_idx; /* Index of used key in param->key. */
- /* Number of records selected by the ranges in index_tree. */
+ bool is_index_scan; /* Use index_next() instead of random read */
public:
+ /* Number of records selected by the ranges in index_tree. */
ha_rows quick_prefix_records;
public:
- TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg,
+ TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg,
+ bool have_agg_distinct_arg,
KEY_PART_INFO *min_max_arg_part_arg,
uint group_prefix_len_arg, uint used_key_parts_arg,
uint group_key_parts_arg, KEY *index_info_arg,
@@ -2069,11 +2018,12 @@ public:
SEL_TREE *tree_arg, SEL_ARG *index_tree_arg,
uint param_idx_arg, ha_rows quick_prefix_records_arg)
: have_min(have_min_arg), have_max(have_max_arg),
+ have_agg_distinct(have_agg_distinct_arg),
min_max_arg_part(min_max_arg_part_arg),
group_prefix_len(group_prefix_len_arg), used_key_parts(used_key_parts_arg),
group_key_parts(group_key_parts_arg), index_info(index_info_arg),
index(index_arg), key_infix_len(key_infix_len_arg), range_tree(tree_arg),
- index_tree(index_tree_arg), param_idx(param_idx_arg),
+ index_tree(index_tree_arg), param_idx(param_idx_arg), is_index_scan(FALSE),
quick_prefix_records(quick_prefix_records_arg)
{
if (key_infix_len)
@@ -2083,6 +2033,7 @@ public:
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
MEM_ROOT *parent_alloc);
+ void use_index_scan() { is_index_scan= TRUE; }
};
@@ -2229,9 +2180,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
keys_to_use.intersect(head->keys_in_use_for_query);
if (!keys_to_use.is_clear_all())
{
-#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
uchar buff[STACK_BUFF_ALLOC];
-#endif
MEM_ROOT alloc;
SEL_TREE *tree= NULL;
KEY_PART *key_parts;
@@ -2344,7 +2293,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
Try to construct a QUICK_GROUP_MIN_MAX_SELECT.
Notice that it can be constructed no matter if there is a range tree.
*/
- group_trp= get_best_group_min_max(&param, tree);
+ group_trp= get_best_group_min_max(&param, tree, best_read_time);
if (group_trp)
{
param.table->quick_condition_rows= min(group_trp->records,
@@ -2594,6 +2543,8 @@ typedef struct st_part_prune_param
/* Same as above for subpartitioning */
my_bool *is_subpart_keypart;
+ my_bool ignore_part_fields; /* Ignore rest of partioning fields */
+
/***************************************************************
Following fields form find_used_partitions() recursion context:
**************************************************************/
@@ -2607,8 +2558,13 @@ typedef struct st_part_prune_param
/* Iterator to be used to obtain the "current" set of used partitions */
PARTITION_ITERATOR part_iter;
- /* Initialized bitmap of no_subparts size */
+ /* Initialized bitmap of num_subparts size */
MY_BITMAP subparts_bitmap;
+
+ uchar *cur_min_key;
+ uchar *cur_max_key;
+
+ uint cur_min_flag, cur_max_flag;
} PART_PRUNE_PARAM;
static bool create_partition_index_description(PART_PRUNE_PARAM *prune_par);
@@ -2726,6 +2682,11 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
prune_param.arg_stack_end= prune_param.arg_stack;
prune_param.cur_part_fields= 0;
prune_param.cur_subpart_fields= 0;
+
+ prune_param.cur_min_key= prune_param.range_param.min_key;
+ prune_param.cur_max_key= prune_param.range_param.max_key;
+ prune_param.cur_min_flag= prune_param.cur_max_flag= 0;
+
init_all_partitions_iterator(part_info, &prune_param.part_iter);
if (!tree->keys[0] || (-1 == (res= find_used_partitions(&prune_param,
tree->keys[0]))))
@@ -2863,8 +2824,8 @@ static void mark_full_partition_used_no_parts(partition_info* part_info,
static void mark_full_partition_used_with_parts(partition_info *part_info,
uint32 part_id)
{
- uint32 start= part_id * part_info->no_subparts;
- uint32 end= start + part_info->no_subparts;
+ uint32 start= part_id * part_info->num_subparts;
+ uint32 end= start + part_info->num_subparts;
DBUG_ENTER("mark_full_partition_used_with_parts");
for (; start != end; start++)
@@ -2962,6 +2923,11 @@ int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar, SEL_IMERGE *imerge)
ppar->arg_stack_end= ppar->arg_stack;
ppar->cur_part_fields= 0;
ppar->cur_subpart_fields= 0;
+
+ ppar->cur_min_key= ppar->range_param.min_key;
+ ppar->cur_max_key= ppar->range_param.max_key;
+ ppar->cur_min_flag= ppar->cur_max_flag= 0;
+
init_all_partitions_iterator(ppar->part_info, &ppar->part_iter);
SEL_ARG *key_tree= (*ptree)->keys[0];
if (!key_tree || (-1 == (res |= find_used_partitions(ppar, key_tree))))
@@ -3085,9 +3051,14 @@ static
int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
{
int res, left_res=0, right_res=0;
- int partno= (int)key_tree->part;
- bool pushed= FALSE;
+ int key_tree_part= (int)key_tree->part;
bool set_full_part_if_bad_ret= FALSE;
+ bool ignore_part_fields= ppar->ignore_part_fields;
+ bool did_set_ignore_part_fields= FALSE;
+ RANGE_OPT_PARAM *range_par= &(ppar->range_param);
+
+ if (check_stack_overrun(range_par->thd, 3*STACK_MIN_SIZE, NULL))
+ return -1;
if (key_tree->left != &null_element)
{
@@ -3095,56 +3066,177 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
return -1;
}
+ /* Push SEL_ARG's to stack to enable looking backwards as well */
+ ppar->cur_part_fields+= ppar->is_part_keypart[key_tree_part];
+ ppar->cur_subpart_fields+= ppar->is_subpart_keypart[key_tree_part];
+ *(ppar->arg_stack_end++)= key_tree;
+
if (key_tree->type == SEL_ARG::KEY_RANGE)
{
- if (partno == 0 && (NULL != ppar->part_info->get_part_iter_for_interval))
+ if (ppar->part_info->get_part_iter_for_interval &&
+ key_tree->part <= ppar->last_part_partno)
{
- /*
- Partitioning is done by RANGE|INTERVAL(monotonic_expr(fieldX)), and
- we got "const1 CMP fieldX CMP const2" interval <-- psergey-todo: change
+ if (ignore_part_fields)
+ {
+ /*
+ We come here when a condition on the first partitioning
+ fields led to evaluating the partitioning condition
+ (due to finding a condition of the type a < const or
+ b > const). Thus we must ignore the rest of the
+ partitioning fields but we still want to analyse the
+ subpartitioning fields.
+ */
+ if (key_tree->next_key_part)
+ res= find_used_partitions(ppar, key_tree->next_key_part);
+ else
+ res= -1;
+ goto pop_and_go_right;
+ }
+ /* Collect left and right bound, their lengths and flags */
+ uchar *min_key= ppar->cur_min_key;
+ uchar *max_key= ppar->cur_max_key;
+ uchar *tmp_min_key= min_key;
+ uchar *tmp_max_key= max_key;
+ key_tree->store_min(ppar->key[key_tree->part].store_length,
+ &tmp_min_key, ppar->cur_min_flag);
+ key_tree->store_max(ppar->key[key_tree->part].store_length,
+ &tmp_max_key, ppar->cur_max_flag);
+ uint flag;
+ if (key_tree->next_key_part &&
+ key_tree->next_key_part->part == key_tree->part+1 &&
+ key_tree->next_key_part->part <= ppar->last_part_partno &&
+ key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
+ {
+ /*
+ There are more key parts for partition pruning to handle
+ This mainly happens when the condition is an equality
+ condition.
+ */
+ if ((tmp_min_key - min_key) == (tmp_max_key - max_key) &&
+ (memcmp(min_key, max_key, (uint)(tmp_max_key - max_key)) == 0) &&
+ !key_tree->min_flag && !key_tree->max_flag)
+ {
+ /* Set 'parameters' */
+ ppar->cur_min_key= tmp_min_key;
+ ppar->cur_max_key= tmp_max_key;
+ uint save_min_flag= ppar->cur_min_flag;
+ uint save_max_flag= ppar->cur_max_flag;
+
+ ppar->cur_min_flag|= key_tree->min_flag;
+ ppar->cur_max_flag|= key_tree->max_flag;
+
+ res= find_used_partitions(ppar, key_tree->next_key_part);
+
+ /* Restore 'parameters' back */
+ ppar->cur_min_key= min_key;
+ ppar->cur_max_key= max_key;
+
+ ppar->cur_min_flag= save_min_flag;
+ ppar->cur_max_flag= save_max_flag;
+ goto pop_and_go_right;
+ }
+ /* We have arrived at the last field in the partition pruning */
+ uint tmp_min_flag= key_tree->min_flag,
+ tmp_max_flag= key_tree->max_flag;
+ if (!tmp_min_flag)
+ key_tree->next_key_part->store_min_key(ppar->key,
+ &tmp_min_key,
+ &tmp_min_flag,
+ ppar->last_part_partno);
+ if (!tmp_max_flag)
+ key_tree->next_key_part->store_max_key(ppar->key,
+ &tmp_max_key,
+ &tmp_max_flag,
+ ppar->last_part_partno);
+ flag= tmp_min_flag | tmp_max_flag;
+ }
+ else
+ flag= key_tree->min_flag | key_tree->max_flag;
+
+ if (tmp_min_key != range_par->min_key)
+ flag&= ~NO_MIN_RANGE;
+ else
+ flag|= NO_MIN_RANGE;
+ if (tmp_max_key != range_par->max_key)
+ flag&= ~NO_MAX_RANGE;
+ else
+ flag|= NO_MAX_RANGE;
+
+ /*
+ We need to call the interval mapper if we have a condition which
+ makes sense to prune on. In the example of COLUMNS on a and
+ b it makes sense if we have a condition on a, or conditions on
+ both a and b. If we only have conditions on b it might make sense
+ but this is a harder case we will solve later. For the harder case
+ this clause then turns into use of all partitions and thus we
+ simply set res= -1 as if the mapper had returned that.
+ TODO: What to do here is defined in WL#4065.
*/
- DBUG_EXECUTE("info", dbug_print_segment_range(key_tree,
- ppar->range_param.
- key_parts););
- res= ppar->part_info->
- get_part_iter_for_interval(ppar->part_info,
- FALSE,
- key_tree->min_value,
- key_tree->max_value,
- key_tree->min_flag | key_tree->max_flag,
- &ppar->part_iter);
- if (!res)
- goto go_right; /* res==0 --> no satisfying partitions */
+ if (ppar->arg_stack[0]->part == 0)
+ {
+ uint32 i;
+ uint32 store_length_array[MAX_KEY];
+ uint32 num_keys= ppar->part_fields;
+
+ for (i= 0; i < num_keys; i++)
+ store_length_array[i]= ppar->key[i].store_length;
+ res= ppar->part_info->
+ get_part_iter_for_interval(ppar->part_info,
+ FALSE,
+ store_length_array,
+ range_par->min_key,
+ range_par->max_key,
+ tmp_min_key - range_par->min_key,
+ tmp_max_key - range_par->max_key,
+ flag,
+ &ppar->part_iter);
+ if (!res)
+ goto pop_and_go_right; /* res==0 --> no satisfying partitions */
+ }
+ else
+ res= -1;
+
if (res == -1)
{
- //get a full range iterator
+ /* get a full range iterator */
init_all_partitions_iterator(ppar->part_info, &ppar->part_iter);
}
/*
Save our intent to mark full partition as used if we will not be able
to obtain further limits on subpartitions
*/
+ if (key_tree_part < ppar->last_part_partno)
+ {
+ /*
+ We need to ignore the rest of the partitioning fields in all
+ evaluations after this
+ */
+ did_set_ignore_part_fields= TRUE;
+ ppar->ignore_part_fields= TRUE;
+ }
set_full_part_if_bad_ret= TRUE;
goto process_next_key_part;
}
- if (partno == ppar->last_subpart_partno &&
+ if (key_tree_part == ppar->last_subpart_partno &&
(NULL != ppar->part_info->get_subpart_iter_for_interval))
{
PARTITION_ITERATOR subpart_iter;
DBUG_EXECUTE("info", dbug_print_segment_range(key_tree,
- ppar->range_param.
- key_parts););
+ range_par->key_parts););
res= ppar->part_info->
get_subpart_iter_for_interval(ppar->part_info,
TRUE,
+ NULL, /* Currently not used here */
key_tree->min_value,
key_tree->max_value,
- key_tree->min_flag | key_tree->max_flag,
+ 0, 0, /* Those are ignored here */
+ key_tree->min_flag |
+ key_tree->max_flag,
&subpart_iter);
DBUG_ASSERT(res); /* We can't get "no satisfying subpartitions" */
if (res == -1)
- return -1; /* all subpartitions satisfy */
+ goto pop_and_go_right; /* all subpartitions satisfy */
uint32 subpart_id;
bitmap_clear_all(&ppar->subparts_bitmap);
@@ -3157,23 +3249,19 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) !=
NOT_A_PARTITION_ID)
{
- for (uint i= 0; i < ppar->part_info->no_subparts; i++)
+ for (uint i= 0; i < ppar->part_info->num_subparts; i++)
if (bitmap_is_set(&ppar->subparts_bitmap, i))
bitmap_set_bit(&ppar->part_info->used_partitions,
- part_id * ppar->part_info->no_subparts + i);
+ part_id * ppar->part_info->num_subparts + i);
}
- goto go_right;
+ goto pop_and_go_right;
}
if (key_tree->is_singlepoint())
{
- pushed= TRUE;
- ppar->cur_part_fields+= ppar->is_part_keypart[partno];
- ppar->cur_subpart_fields+= ppar->is_subpart_keypart[partno];
- *(ppar->arg_stack_end++) = key_tree;
-
- if (partno == ppar->last_part_partno &&
- ppar->cur_part_fields == ppar->part_fields)
+ if (key_tree_part == ppar->last_part_partno &&
+ ppar->cur_part_fields == ppar->part_fields &&
+ ppar->part_info->get_part_iter_for_interval == NULL)
{
/*
Ok, we've got "fieldN<=>constN"-type SEL_ARGs for all partitioning
@@ -3202,7 +3290,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
goto process_next_key_part;
}
- if (partno == ppar->last_subpart_partno &&
+ if (key_tree_part == ppar->last_subpart_partno &&
ppar->cur_subpart_fields == ppar->subpart_fields)
{
/*
@@ -3226,7 +3314,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
NOT_A_PARTITION_ID)
{
bitmap_set_bit(&part_info->used_partitions,
- part_id * part_info->no_subparts + subpart_id);
+ part_id * part_info->num_subparts + subpart_id);
}
res= 1; /* Some partitions were marked as used */
goto pop_and_go_right;
@@ -3239,8 +3327,11 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
we're processing subpartititoning's key parts, this means we'll not be
able to infer any suitable condition, so bail out.
*/
- if (partno >= ppar->last_part_partno)
- return -1;
+ if (key_tree_part >= ppar->last_part_partno)
+ {
+ res= -1;
+ goto pop_and_go_right;
+ }
}
}
@@ -3249,7 +3340,17 @@ process_next_key_part:
res= find_used_partitions(ppar, key_tree->next_key_part);
else
res= -1;
-
+
+ if (did_set_ignore_part_fields)
+ {
+ /*
+ We have returned from processing all key trees linked to our next
+ key part. We are ready to be moving down (using right pointers) and
+ this tree is a new evaluation requiring its own decision on whether
+ to ignore partitioning fields.
+ */
+ ppar->ignore_part_fields= FALSE;
+ }
if (set_full_part_if_bad_ret)
{
if (res == -1)
@@ -3272,18 +3373,14 @@ process_next_key_part:
init_all_partitions_iterator(ppar->part_info, &ppar->part_iter);
}
- if (pushed)
- {
pop_and_go_right:
- /* Pop this key part info off the "stack" */
- ppar->arg_stack_end--;
- ppar->cur_part_fields-= ppar->is_part_keypart[partno];
- ppar->cur_subpart_fields-= ppar->is_subpart_keypart[partno];
- }
+ /* Pop this key part info off the "stack" */
+ ppar->arg_stack_end--;
+ ppar->cur_part_fields-= ppar->is_part_keypart[key_tree_part];
+ ppar->cur_subpart_fields-= ppar->is_subpart_keypart[key_tree_part];
if (res == -1)
return -1;
-go_right:
if (key_tree->right != &null_element)
{
if (-1 == (right_res= find_used_partitions(ppar,key_tree->right)))
@@ -3365,13 +3462,14 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
uint used_part_fields, used_subpart_fields;
used_part_fields= fields_ok_for_partition_index(part_info->part_field_array) ?
- part_info->no_part_fields : 0;
+ part_info->num_part_fields : 0;
used_subpart_fields=
fields_ok_for_partition_index(part_info->subpart_field_array)?
- part_info->no_subpart_fields : 0;
+ part_info->num_subpart_fields : 0;
uint total_parts= used_part_fields + used_subpart_fields;
+ ppar->ignore_part_fields= FALSE;
ppar->part_fields= used_part_fields;
ppar->last_part_partno= (int)used_part_fields - 1;
@@ -3406,10 +3504,10 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
if (ppar->subpart_fields)
{
my_bitmap_map *buf;
- uint32 bufsize= bitmap_buffer_size(ppar->part_info->no_subparts);
+ uint32 bufsize= bitmap_buffer_size(ppar->part_info->num_subparts);
if (!(buf= (my_bitmap_map*) alloc_root(alloc, bufsize)))
return TRUE;
- bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->no_subparts,
+ bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->num_subparts,
FALSE);
}
range_par->key_parts= key_part;
@@ -3420,12 +3518,8 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
{
key_part->key= 0;
key_part->part= part;
- key_part->store_length= key_part->length= (uint16) (*field)->key_length();
- if ((*field)->real_maybe_null())
- key_part->store_length+= HA_KEY_NULL_LENGTH;
- if ((*field)->type() == MYSQL_TYPE_BLOB ||
- (*field)->real_type() == MYSQL_TYPE_VARCHAR)
- key_part->store_length+= HA_KEY_BLOB_LENGTH;
+ key_part->length= (uint16)(*field)->key_length();
+ key_part->store_length= (uint16)get_partition_field_store_length(*field);
DBUG_PRINT("info", ("part %u length %u store_length %u", part,
key_part->length, key_part->store_length));
@@ -5656,7 +5750,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
SEL_ARG *tree= 0;
MEM_ROOT *alloc= param->mem_root;
uchar *str;
- ulong orig_sql_mode;
+ ulonglong orig_sql_mode;
int err;
DBUG_ENTER("get_mm_leaf");
@@ -5702,10 +5796,12 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
*/
if (field->result_type() == STRING_RESULT &&
+ ((Field_str*) field)->match_collation_to_optimize_range() &&
value->result_type() == STRING_RESULT &&
key_part->image_type == Field::itRAW &&
((Field_str*)field)->charset() != conf_func->compare_collation() &&
- !(conf_func->compare_collation()->state & MY_CS_BINSORT))
+ !(conf_func->compare_collation()->state & MY_CS_BINSORT &&
+ (type == Item_func::EQUAL_FUNC || type == Item_func::EQ_FUNC)))
goto end;
if (key_part->image_type == Field::itMBR)
@@ -7395,7 +7491,6 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
#endif
-
/*
Calculate estimate of number records that will be retrieved by a range
scan on given index using given SEL_ARG intervals tree.
@@ -7606,12 +7701,16 @@ check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree,
tmp_max_flag=key_tree->max_flag;
if (!tmp_min_flag)
tmp_min_keypart+=
- key_tree->next_key_part->store_min_key(param->key[idx], &tmp_min_key,
- &tmp_min_flag);
+ key_tree->next_key_part->store_min_key(param->key[idx],
+ &tmp_min_key,
+ &tmp_min_flag,
+ MAX_KEY);
if (!tmp_max_flag)
tmp_max_keypart+=
- key_tree->next_key_part->store_max_key(param->key[idx], &tmp_max_key,
- &tmp_max_flag);
+ key_tree->next_key_part->store_max_key(param->key[idx],
+ &tmp_max_key,
+ &tmp_max_flag,
+ MAX_KEY);
min_key_length= (uint) (tmp_min_key - param->min_key);
max_key_length= (uint) (tmp_max_key - param->max_key);
}
@@ -7628,8 +7727,8 @@ check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree,
param->range_count++;
if (!tmp_min_flag && ! tmp_max_flag &&
(uint) key_tree->part+1 == param->table->key_info[keynr].key_parts &&
- (param->table->key_info[keynr].flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
- HA_NOSAME && min_key_length == max_key_length &&
+ param->table->key_info[keynr].flags & HA_NOSAME &&
+ min_key_length == max_key_length &&
!memcmp(param->min_key, param->max_key, min_key_length) &&
!param->first_null_comp)
{
@@ -7881,11 +7980,15 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
{
uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag;
if (!tmp_min_flag)
- min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key,
- &tmp_min_flag);
+ min_part+= key_tree->next_key_part->store_min_key(key,
+ &tmp_min_key,
+ &tmp_min_flag,
+ MAX_KEY);
if (!tmp_max_flag)
- max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key,
- &tmp_max_flag);
+ max_part+= key_tree->next_key_part->store_max_key(key,
+ &tmp_max_key,
+ &tmp_max_flag,
+ MAX_KEY);
flag=tmp_min_flag | tmp_max_flag;
}
}
@@ -7918,8 +8021,7 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
{
KEY *table_key=quick->head->key_info+quick->index;
flag=EQ_RANGE;
- if ((table_key->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME &&
- key->part == table_key->key_parts-1)
+ if ((table_key->flags & HA_NOSAME) && key->part == table_key->key_parts-1)
{
if (!(table_key->flags & HA_NULL_PART_KEY) ||
!null_part_in_key(key,
@@ -7968,8 +8070,7 @@ bool QUICK_RANGE_SELECT::unique_key_range()
if ((tmp->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE)
{
KEY *key=head->key_info+index;
- return ((key->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME &&
- key->key_length == tmp->min_length);
+ return (key->flags & HA_NOSAME) && key->key_length == tmp->min_length;
}
}
return 0;
@@ -8087,8 +8188,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
range->min_length= range->max_length= ref->key_length;
range->min_keypart_map= range->max_keypart_map=
make_prev_keypart_map(ref->key_parts);
- range->flag= ((ref->key_length == key_info->key_length &&
- (key_info->flags & HA_END_SPACE_KEY) == 0) ? EQ_RANGE : 0);
+ range->flag= (ref->key_length == key_info->key_length ? EQ_RANGE : 0);
if (!(quick->key_parts=key_part=(KEY_PART *)
alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts)))
@@ -8502,7 +8602,7 @@ int QUICK_RANGE_SELECT::reset()
}
if (! multi_range_buff)
{
- my_free((char*) multi_range, MYF(0));
+ my_free(multi_range);
multi_range= NULL;
multi_range_length= 0;
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
@@ -8800,7 +8900,6 @@ QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q,
}
rev_it.rewind();
q->dont_free=1; // Don't free shared mem
- delete q;
}
@@ -8890,6 +8989,27 @@ int QUICK_SELECT_DESC::get_next()
}
+/**
+ Create a compatible quick select with the result ordered in an opposite way
+
+ @param used_key_parts_arg Number of used key parts
+
+ @retval NULL in case of errors (OOM etc)
+ @retval pointer to a newly created QUICK_SELECT_DESC if success
+*/
+
+QUICK_SELECT_I *QUICK_RANGE_SELECT::make_reverse(uint used_key_parts_arg)
+{
+ QUICK_SELECT_DESC *new_quick= new QUICK_SELECT_DESC(this, used_key_parts_arg);
+ if (new_quick == NULL || new_quick->error != 0)
+ {
+ delete new_quick;
+ return NULL;
+ }
+ return new_quick;
+}
+
+
/*
Compare if found key is over max-value
Returns 0 if key <= range->max_key
@@ -9157,15 +9277,10 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
double *read_cost, ha_rows *records);
-/*
+/**
Test if this access method is applicable to a GROUP query with MIN/MAX
functions, and if so, construct a new TRP object.
- SYNOPSIS
- get_best_group_min_max()
- param Parameter from test_quick_select
- sel_tree Range tree generated by get_mm_tree
-
DESCRIPTION
Test whether a query can be computed via a QUICK_GROUP_MIN_MAX_SELECT.
Queries computable via a QUICK_GROUP_MIN_MAX_SELECT must satisfy the
@@ -9276,17 +9391,16 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
- Lift the limitation in condition (B3), that is, make this access method
applicable to ROLLUP queries.
- RETURN
- If mem_root != NULL
- - valid TRP_GROUP_MIN_MAX object if this QUICK class can be used for
- the query
- - NULL o/w.
- If mem_root == NULL
- - NULL
+ @param param Parameter from test_quick_select
+ @param sel_tree Range tree generated by get_mm_tree
+ @param read_time Best read time so far (=table/index scan time)
+ @return table read plan
+ @retval NULL Loose index scan not applicable or mem_root == NULL
+ @retval !NULL Loose index scan table read plan
*/
static TRP_GROUP_MIN_MAX *
-get_best_group_min_max(PARAM *param, SEL_TREE *tree)
+get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
{
THD *thd= param->thd;
JOIN *join= thd->lex->current_select->join;
@@ -9307,25 +9421,33 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
ORDER *tmp_group;
Item *item;
Item_field *item_field;
+ bool is_agg_distinct;
+ List<Item_field> agg_distinct_flds;
+
DBUG_ENTER("get_best_group_min_max");
/* Perform few 'cheap' tests whether this access method is applicable. */
if (!join)
DBUG_RETURN(NULL); /* This is not a select statement. */
if ((join->tables != 1) || /* The query must reference one table. */
- ((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
- (!join->select_distinct)) ||
(join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */
DBUG_RETURN(NULL);
if (table->s->keys == 0) /* There are no indexes to use. */
DBUG_RETURN(NULL);
- /* Analyze the query in more detail. */
- List_iterator<Item> select_items_it(join->fields_list);
-
/* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/
if (join->make_sum_func_list(join->all_fields, join->fields_list, 1))
DBUG_RETURN(NULL);
+
+ List_iterator<Item> select_items_it(join->fields_list);
+ is_agg_distinct = is_indexed_agg_distinct(join, &agg_distinct_flds);
+
+ if ((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
+ (!join->select_distinct) &&
+ !is_agg_distinct)
+ DBUG_RETURN(NULL);
+ /* Analyze the query in more detail. */
+
if (join->sum_funcs[0])
{
Item_sum *min_max_item;
@@ -9336,6 +9458,10 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
have_min= TRUE;
else if (min_max_item->sum_func() == Item_sum::MAX_FUNC)
have_max= TRUE;
+ else if (min_max_item->sum_func() == Item_sum::COUNT_DISTINCT_FUNC ||
+ min_max_item->sum_func() == Item_sum::SUM_DISTINCT_FUNC ||
+ min_max_item->sum_func() == Item_sum::AVG_DISTINCT_FUNC)
+ continue;
else
DBUG_RETURN(NULL);
@@ -9352,13 +9478,12 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
DBUG_RETURN(NULL);
}
}
-
/* Check (SA5). */
if (join->select_distinct)
{
while ((item= select_items_it++))
{
- if (item->type() != Item::FIELD_ITEM)
+ if (item->real_item()->type() != Item::FIELD_ITEM)
DBUG_RETURN(NULL);
}
}
@@ -9366,7 +9491,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
/* Check (GA4) - that there are no expressions among the group attributes. */
for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next)
{
- if ((*tmp_group->item)->type() != Item::FIELD_ITEM)
+ if ((*tmp_group->item)->real_item()->type() != Item::FIELD_ITEM)
DBUG_RETURN(NULL);
}
@@ -9385,6 +9510,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
uint best_param_idx= 0;
const uint pk= param->table->s->primary_key;
+ uint max_key_part;
SEL_ARG *cur_index_tree= NULL;
ha_rows cur_quick_prefix_records= 0;
uint cur_param_idx=MAX_KEY;
@@ -9438,6 +9564,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
}
}
+ max_key_part= 0;
+ used_key_parts_map.clear_all();
/*
Check (GA1) for GROUP BY queries.
*/
@@ -9455,12 +9583,14 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
first Item? If so, then why? What is the array for?
*/
/* Above we already checked that all group items are fields. */
- DBUG_ASSERT((*tmp_group->item)->type() == Item::FIELD_ITEM);
- Item_field *group_field= (Item_field *) (*tmp_group->item);
+ DBUG_ASSERT((*tmp_group->item)->real_item()->type() == Item::FIELD_ITEM);
+ Item_field *group_field= (Item_field *) (*tmp_group->item)->real_item();
if (group_field->field->eq(cur_part->field))
{
cur_group_prefix_len+= cur_part->store_length;
++cur_group_key_parts;
+ max_key_part= cur_part - cur_index_info->key_part + 1;
+ used_key_parts_map.set_bit(max_key_part);
}
else
goto next_index;
@@ -9474,14 +9604,26 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
Later group_fields_array of ORDER objects is used to convert the query
to a GROUP query.
*/
- else if (join->select_distinct)
+ if ((!join->group_list && join->select_distinct) ||
+ is_agg_distinct)
{
- select_items_it.rewind();
- used_key_parts_map.clear_all();
- uint max_key_part= 0;
- while ((item= select_items_it++))
+ if (!is_agg_distinct)
{
- item_field= (Item_field*) item; /* (SA5) already checked above. */
+ select_items_it.rewind();
+ }
+
+ List_iterator<Item_field> agg_distinct_flds_it (agg_distinct_flds);
+ while (NULL != (item = (is_agg_distinct ?
+ (Item *) agg_distinct_flds_it++ : select_items_it++)))
+ {
+ /* (SA5) already checked above. */
+ item_field= (Item_field*) item->real_item();
+ DBUG_ASSERT(item->real_item()->type() == Item::FIELD_ITEM);
+
+ /* not doing loose index scan for derived tables */
+ if (!item_field->field)
+ goto next_index;
+
/* Find the order of the key part in the index. */
key_part_nr= get_field_keypart(cur_index_info, item_field->field);
/*
@@ -9490,7 +9632,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
*/
if (used_key_parts_map.is_set(key_part_nr))
continue;
- if (key_part_nr < 1 || key_part_nr > join->fields_list.elements)
+ if (key_part_nr < 1 ||
+ (!is_agg_distinct && key_part_nr > join->fields_list.elements))
goto next_index;
cur_part= cur_index_info->key_part + key_part_nr - 1;
cur_group_prefix_len+= cur_part->store_length;
@@ -9510,10 +9653,6 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
if (all_parts != cur_parts)
goto next_index;
}
- else
- {
- DBUG_ASSERT(FALSE);
- }
/* Check (SA2). */
if (min_max_arg_item)
@@ -9667,7 +9806,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
/* The query passes all tests, so construct a new TRP object. */
read_plan= new (param->mem_root)
- TRP_GROUP_MIN_MAX(have_min, have_max, min_max_arg_part,
+ TRP_GROUP_MIN_MAX(have_min, have_max, is_agg_distinct,
+ min_max_arg_part,
group_prefix_len, used_key_parts,
group_key_parts, index_info, index,
key_infix_len,
@@ -9681,6 +9821,11 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
read_plan->read_cost= best_read_cost;
read_plan->records= best_records;
+ if (read_time < best_read_cost && is_agg_distinct)
+ {
+ read_plan->read_cost= 0;
+ read_plan->use_index_scan();
+ }
DBUG_PRINT("info",
("Returning group min/max plan: cost: %g, records: %lu",
@@ -10190,11 +10335,12 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table,
param->thd->lex->current_select->join,
- have_min, have_max, min_max_arg_part,
+ have_min, have_max,
+ have_agg_distinct, min_max_arg_part,
group_prefix_len, group_key_parts,
used_key_parts, index_info, index,
read_cost, records, key_infix_len,
- key_infix, parent_alloc);
+ key_infix, parent_alloc, is_index_scan);
if (!quick)
DBUG_RETURN(NULL);
@@ -10274,6 +10420,9 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
key_infix_len Length of the key infix appended to the group prefix
key_infix Infix of constants from equality predicates
parent_alloc Memory pool for this and quick_prefix_select data
+ is_index_scan get the next different key not by jumping on it via
+ index read, but by scanning until the end of the
+ rows with equal key value.
RETURN
None
@@ -10281,20 +10430,22 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
QUICK_GROUP_MIN_MAX_SELECT::
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
- bool have_max_arg,
+ bool have_max_arg, bool have_agg_distinct_arg,
KEY_PART_INFO *min_max_arg_part_arg,
uint group_prefix_len_arg, uint group_key_parts_arg,
uint used_key_parts_arg, KEY *index_info_arg,
uint use_index, double read_cost_arg,
ha_rows records_arg, uint key_infix_len_arg,
- uchar *key_infix_arg, MEM_ROOT *parent_alloc)
+ uchar *key_infix_arg, MEM_ROOT *parent_alloc,
+ bool is_index_scan_arg)
:file(table->file), join(join_arg), index_info(index_info_arg),
group_prefix_len(group_prefix_len_arg),
group_key_parts(group_key_parts_arg), have_min(have_min_arg),
- have_max(have_max_arg), seen_first_key(FALSE),
- min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg),
- key_infix_len(key_infix_len_arg), min_functions_it(NULL),
- max_functions_it(NULL)
+ have_max(have_max_arg), have_agg_distinct(have_agg_distinct_arg),
+ seen_first_key(FALSE), min_max_arg_part(min_max_arg_part_arg),
+ key_infix(key_infix_arg), key_infix_len(key_infix_len_arg),
+ min_functions_it(NULL), max_functions_it(NULL),
+ is_index_scan(is_index_scan_arg)
{
head= table;
index= use_index;
@@ -10719,17 +10870,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
} while ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) &&
is_last_prefix != 0);
- if (result == 0)
- {
- /*
- Partially mimic the behavior of end_select_send. Copy the
- field data from Item_field::field into Item_field::result_field
- of each non-aggregated field (the group fields, and optionally
- other fields in non-ANSI SQL mode).
- */
- copy_fields(&join->tmp_table_param);
- }
- else if (result == HA_ERR_KEY_NOT_FOUND)
+ if (result == HA_ERR_KEY_NOT_FOUND)
result= HA_ERR_END_OF_FILE;
DBUG_RETURN(result);
@@ -10856,6 +10997,56 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max()
}
+/**
+ Find the next different key value by skiping all the rows with the same key
+ value.
+
+ Implements a specialized loose index access method for queries
+ containing aggregate functions with distinct of the form:
+ SELECT [SUM|COUNT|AVG](DISTINCT a,...) FROM t
+ This method comes to replace the index scan + Unique class
+ (distinct selection) for loose index scan that visits all the rows of a
+ covering index instead of jumping in the begining of each group.
+ TODO: Placeholder function. To be replaced by a handler API call
+
+ @param is_index_scan hint to use index scan instead of random index read
+ to find the next different value.
+ @param file table handler
+ @param key_part group key to compare
+ @param record row data
+ @param group_prefix current key prefix data
+ @param group_prefix_len length of the current key prefix data
+ @param group_key_parts number of the current key prefix columns
+ @return status
+ @retval 0 success
+ @retval !0 failure
+*/
+
+static int index_next_different (bool is_index_scan, handler *file,
+ KEY_PART_INFO *key_part, uchar * record,
+ const uchar * group_prefix,
+ uint group_prefix_len,
+ uint group_key_parts)
+{
+ if (is_index_scan)
+ {
+ int result= 0;
+
+ while (!key_cmp (key_part, group_prefix, group_prefix_len))
+ {
+ result= file->index_next(record);
+ if (result)
+ return(result);
+ }
+ return result;
+ }
+ else
+ return file->index_read_map(record, group_prefix,
+ make_prev_keypart_map(group_key_parts),
+ HA_READ_AFTER_KEY);
+}
+
+
/*
Determine the prefix of the next group.
@@ -10903,9 +11094,9 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
else
{
/* Load the first key in this group into record. */
- result= file->index_read_map(record, group_prefix,
- make_prev_keypart_map(group_key_parts),
- HA_READ_AFTER_KEY);
+ result= index_next_different (is_index_scan, file, index_info->key_part,
+ record, group_prefix, group_prefix_len,
+ group_key_parts);
if (result)
DBUG_RETURN(result);
}
@@ -11424,6 +11615,7 @@ void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
/* purecov: end */
}
+
void QUICK_INDEX_MERGE_SELECT::dbug_dump(int indent, bool verbose)
{
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
@@ -11512,7 +11704,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose)
}
-#endif /* NOT_USED */
+#endif /* !DBUG_OFF */
/*****************************************************************************
** Instantiate templates
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 5f7a4fd3a2a..6da4d1c2776 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -23,6 +23,20 @@
#pragma interface /* gcc class implementation */
#endif
+#include "thr_malloc.h" /* sql_memdup */
+#include "records.h" /* READ_RECORD */
+#include "queues.h" /* QUEUE */
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" // set_var.h: THD
+#include "set_var.h" /* Item */
+
+class JOIN;
+class Item_sum;
+
typedef struct st_key_part {
uint16 key,part;
/* See KEY_PART_INFO for meaning of the next two: */
@@ -339,6 +353,11 @@ public:
*/
virtual void dbug_dump(int indent, bool verbose)= 0;
#endif
+
+ /*
+ Returns a QUICK_SELECT with reverse order of to the index.
+ */
+ virtual QUICK_SELECT_I *make_reverse(uint used_key_parts_arg) { return NULL; }
};
@@ -424,6 +443,7 @@ public:
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
+ QUICK_SELECT_I *make_reverse(uint used_key_parts_arg);
private:
/* Default copy ctor used by QUICK_SELECT_DESC */
};
@@ -647,7 +667,6 @@ public:
bool have_prev_rowid; /* true if prev_rowid has valid data */
uint rowid_length; /* table rowid length */
private:
- static int queue_cmp(void *arg, uchar *val1, uchar *val2);
bool scans_inited;
};
@@ -699,6 +718,7 @@ private:
uchar *last_prefix; /* Prefix of the last group for detecting EOF. */
bool have_min; /* Specify whether we are computing */
bool have_max; /* a MIN, a MAX, or both. */
+ bool have_agg_distinct;/* aggregate_function(DISTINCT ...). */
bool seen_first_key; /* Denotes whether the first key was retrieved.*/
KEY_PART_INFO *min_max_arg_part; /* The keypart of the only argument field */
/* of all MIN/MAX functions. */
@@ -712,6 +732,11 @@ private:
List<Item_sum> *max_functions;
List_iterator<Item_sum> *min_functions_it;
List_iterator<Item_sum> *max_functions_it;
+ /*
+ Use index scan to get the next different key instead of jumping into it
+ through index read
+ */
+ bool is_index_scan;
public:
/*
The following two members are public to allow easy access from
@@ -729,12 +754,13 @@ private:
void update_max_result();
public:
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min,
- bool have_max, KEY_PART_INFO *min_max_arg_part,
+ bool have_max, bool have_agg_distinct,
+ KEY_PART_INFO *min_max_arg_part,
uint group_prefix_len, uint group_key_parts,
uint used_key_parts, KEY *index_info, uint
use_index, double read_cost, ha_rows records, uint
key_infix_len, uchar *key_infix, MEM_ROOT
- *parent_alloc);
+ *parent_alloc, bool is_index_scan);
~QUICK_GROUP_MIN_MAX_SELECT();
bool add_range(SEL_ARG *sel_range);
void update_key_stat();
@@ -750,6 +776,12 @@ public:
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
+ bool is_agg_distinct() { return have_agg_distinct; }
+ virtual void append_loose_scan_type(String *str)
+ {
+ if (is_index_scan)
+ str->append(STRING_WITH_LEN(" (scanning)"));
+ }
};
@@ -760,6 +792,10 @@ public:
int get_next();
bool reverse_sorted() { return 1; }
int get_type() { return QS_TYPE_RANGE_DESC; }
+ QUICK_SELECT_I *make_reverse(uint used_key_parts_arg)
+ {
+ return this; // is already reverse sorted
+ }
private:
bool range_reads_after_key(QUICK_RANGE *range);
int reset(void) { rev_it.rewind(); return QUICK_RANGE_SELECT::reset(); }
@@ -785,6 +821,7 @@ class SQL_SELECT :public Sql_alloc {
SQL_SELECT();
~SQL_SELECT();
void cleanup();
+ void set_quick(QUICK_SELECT_I *new_quick) { delete quick; quick= new_quick; }
bool check_quick(THD *thd, bool force_quick_range, ha_rows limit)
{
key_map tmp;
@@ -804,7 +841,7 @@ class SQL_SELECT :public Sql_alloc {
class FT_SELECT: public QUICK_RANGE_SELECT {
public:
FT_SELECT(THD *thd, TABLE *table, uint key) :
- QUICK_RANGE_SELECT (thd, table, key, 1) { VOID(init()); }
+ QUICK_RANGE_SELECT (thd, table, key, 1) { (void) init(); }
~FT_SELECT() { file->ft_end(); }
int init() { return error=file->ft_init(); }
int reset() { return 0; }
@@ -815,11 +852,15 @@ public:
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
struct st_table_ref *ref,
ha_rows records);
-uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit);
+SQL_SELECT *make_select(TABLE *head, table_map const_tables,
+ table_map read_tables, COND *conds,
+ bool allow_null_cond, int *error);
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond);
void store_key_image_to_rec(Field *field, uchar *ptr, uint len);
#endif
+extern String null_string;
+
#endif
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index b20a0c4fcbe..e020c94a3bd 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -47,7 +47,8 @@
(assuming a index for column d of table t2 is defined)
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "key.h" // key_cmp_if_same
#include "sql_select.h"
static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, Field* field,
@@ -295,8 +296,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
error= tl->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
if(error)
{
- tl->table->file->print_error(error, MYF(0));
- tl->table->in_use->fatal_error();
+ tl->table->file->print_error(error, MYF(ME_FATALERROR));
return error;
}
count*= tl->table->file->stats.records;
@@ -411,13 +411,18 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
const_result= 0;
break;
}
+ item_sum->set_aggregator(item_sum->has_with_distinct() ?
+ Aggregator::DISTINCT_AGGREGATOR :
+ Aggregator::SIMPLE_AGGREGATOR);
/*
If count == 0 (so is_exact_count == TRUE) and
there're no outer joins, set to NULL,
otherwise set to the constant value.
*/
if (!count && !outer_tables)
- item_sum->clear();
+ {
+ item_sum->aggregator_clear();
+ }
else
item_sum->reset();
item_sum->make_const();
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index 3d65fa1de31..cce0bb262e7 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004 MySQL AB
+/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -20,7 +20,10 @@
Text .frm files management routines
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "parse_file.h"
+#include "unireg.h" // CREATE_MODE
+#include "sql_table.h" // build_table_filename
#include <errno.h>
#include <m_ctype.h>
#include <my_sys.h>
@@ -237,8 +240,9 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
// temporary file name
path[path_end]='~';
path[path_end+1]= '\0';
- if ((handler= my_create(path, CREATE_MODE, O_RDWR | O_TRUNC,
- MYF(MY_WME))) <= 0)
+ if ((handler= mysql_file_create(key_file_fileparser,
+ path, CREATE_MODE, O_RDWR | O_TRUNC,
+ MYF(MY_WME))) <= 0)
{
DBUG_RETURN(TRUE);
}
@@ -267,11 +271,11 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
goto err_w_file;
if (opt_sync_frm) {
- if (my_sync(handler, MYF(MY_WME)))
+ if (mysql_file_sync(handler, MYF(MY_WME)))
goto err_w_file;
}
- if (my_close(handler, MYF(MY_WME)))
+ if (mysql_file_close(handler, MYF(MY_WME)))
{
DBUG_RETURN(TRUE);
}
@@ -283,7 +287,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
char path_to[FN_REFLEN];
memcpy(path_to, path, path_end+1);
path[path_end]='~';
- if (my_rename(path, path_to, MYF(MY_WME)))
+ if (mysql_file_rename(key_file_fileparser, path, path_to, MYF(MY_WME)))
{
DBUG_RETURN(TRUE);
}
@@ -292,7 +296,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
err_w_cache:
end_io_cache(&file);
err_w_file:
- my_close(handler, MYF(MY_WME));
+ mysql_file_close(handler, MYF(MY_WME));
DBUG_RETURN(TRUE);
}
@@ -321,7 +325,7 @@ my_bool rename_in_schema_file(THD *thd,
build_table_filename(new_path, sizeof(new_path) - 1,
new_db, new_name, reg_ext, 0);
- if (my_rename(old_path, new_path, MYF(MY_WME)))
+ if (mysql_file_rename(key_file_frm, old_path, new_path, MYF(MY_WME)))
return 1;
/* check if arc_dir exists: disabled unused feature (see bug #17823). */
@@ -365,7 +369,8 @@ sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
File file;
DBUG_ENTER("sql_parse_prepare");
- if (!my_stat(file_name->str, &stat_info, MYF(MY_WME)))
+ if (!mysql_file_stat(key_file_fileparser,
+ file_name->str, &stat_info, MYF(MY_WME)))
{
DBUG_RETURN(0);
}
@@ -386,20 +391,21 @@ sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
DBUG_RETURN(0);
}
- if ((file= my_open(file_name->str, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
+ if ((file= mysql_file_open(key_file_fileparser, file_name->str,
+ O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
{
DBUG_RETURN(0);
}
- if ((len= my_read(file, (uchar *)parser->buff,
- stat_info.st_size, MYF(MY_WME))) ==
+ if ((len= mysql_file_read(file, (uchar *)parser->buff,
+ stat_info.st_size, MYF(MY_WME))) ==
MY_FILE_ERROR)
{
- my_close(file, MYF(MY_WME));
+ mysql_file_close(file, MYF(MY_WME));
DBUG_RETURN(0);
}
- if (my_close(file, MYF(MY_WME)))
+ if (mysql_file_close(file, MYF(MY_WME)))
{
DBUG_RETURN(0);
}
diff --git a/sql/parse_file.h b/sql/parse_file.h
index 84647e45927..1833e90cadd 100644
--- a/sql/parse_file.h
+++ b/sql/parse_file.h
@@ -17,6 +17,14 @@
#ifndef _PARSE_FILE_H_
#define _PARSE_FILE_H_
+#include "my_global.h" // uchar
+#include "sql_string.h" // LEX_STRING
+#include "sql_list.h" // Sql_alloc
+
+class THD;
+
+typedef struct st_mem_root MEM_ROOT;
+
#define PARSE_FILE_TIMESTAMPLENGTH 19
enum file_opt_type {
diff --git a/sql/partition_element.h b/sql/partition_element.h
index 905bc38165b..cefc32ecac4 100644
--- a/sql/partition_element.h
+++ b/sql/partition_element.h
@@ -1,4 +1,7 @@
-/* Copyright (C) 2006 MySQL AB
+#ifndef PARTITION_ELEMENT_INCLUDED
+#define PARTITION_ELEMENT_INCLUDED
+
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -13,6 +16,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+#include "my_base.h" /* ha_rows */
+#include "handler.h" /* UNDEF_NODEGROUP */
+
/**
* An enum and a struct to handle partitioning and subpartitioning.
*/
@@ -32,10 +38,40 @@ enum partition_state {
PART_REORGED_DROPPED= 5,
PART_CHANGED= 6,
PART_IS_CHANGED= 7,
- PART_IS_ADDED= 8
+ PART_IS_ADDED= 8,
+ PART_ADMIN= 9
};
/*
+ This struct is used to keep track of column expressions as part
+ of the COLUMNS concept in conjunction with RANGE and LIST partitioning.
+ The value can be either of MINVALUE, MAXVALUE and an expression that
+ must be constant and evaluate to the same type as the column it
+ represents.
+
+ The data in this fixed in two steps. The parser will only fill in whether
+ it is a max_value or provide an expression. Filling in
+ column_value, part_info, partition_id, null_value is done by the
+ function fix_column_value_function. However the item tree needs
+ fixed also before writing it into the frm file (in add_column_list_values).
+ To distinguish between those two variants, fixed= 1 after the
+ fixing in add_column_list_values and fixed= 2 otherwise. This is
+ since the fixing in add_column_list_values isn't a complete fixing.
+*/
+
+typedef struct p_column_list_val
+{
+ void* column_value;
+ Item* item_expression;
+ partition_info *part_info;
+ uint partition_id;
+ bool max_value;
+ bool null_value;
+ char fixed;
+} part_column_list_val;
+
+
+/*
This struct is used to contain the value of an element
in the VALUES IN struct. It needs to keep knowledge of
whether it is a signed/unsigned value and whether it is
@@ -45,8 +81,10 @@ enum partition_state {
typedef struct p_elem_val
{
longlong value;
+ uint added_items;
bool null_value;
bool unsigned_flag;
+ part_column_list_val *col_val_array;
} part_elem_value;
struct st_ddl_log_memory_entry;
@@ -68,8 +106,9 @@ public:
enum partition_state part_state;
uint16 nodegroup_id;
bool has_null_value;
- bool signed_flag;/* Indicate whether this partition uses signed constants */
- bool max_value; /* Indicate whether this partition uses MAXVALUE */
+ /* signed_flag and max_value only relevant for subpartitions */
+ bool signed_flag;
+ bool max_value;
partition_element()
: part_max_rows(0), part_min_rows(0), range_value(0),
@@ -97,3 +136,5 @@ public:
}
~partition_element() {}
};
+
+#endif /* PARTITION_ELEMENT_INCLUDED */
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index f37151ea51d..b54339db354 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (c) 2006, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,13 @@
#pragma implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+// Required to get server definitions for mysql/plugin.h right
+#include "sql_plugin.h"
+#include "sql_partition.h" /* partition_info.h: LIST_PART_ENTRY */
+#include "partition_info.h"
+#include "sql_parse.h" // test_if_data_home_dir
+#include "sql_acl.h" // *_ACL
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
@@ -75,7 +81,7 @@ partition_info *partition_info::get_clone()
SYNOPSIS
create_default_partition_names()
part_no Partition number for subparts
- no_parts Number of partitions
+ num_parts Number of partitions
start_no Starting partition number
subpart Is it subpartitions
@@ -91,10 +97,10 @@ partition_info *partition_info::get_clone()
#define MAX_PART_NAME_SIZE 8
char *partition_info::create_default_partition_names(uint part_no,
- uint no_parts_arg,
+ uint num_parts_arg,
uint start_no)
{
- char *ptr= (char*) sql_calloc(no_parts_arg*MAX_PART_NAME_SIZE);
+ char *ptr= (char*) sql_calloc(num_parts_arg*MAX_PART_NAME_SIZE);
char *move_ptr= ptr;
uint i= 0;
DBUG_ENTER("create_default_partition_names");
@@ -105,17 +111,53 @@ char *partition_info::create_default_partition_names(uint part_no,
{
sprintf(move_ptr, "p%u", (start_no + i));
move_ptr+= MAX_PART_NAME_SIZE;
- } while (++i < no_parts_arg);
+ } while (++i < num_parts_arg);
}
else
{
- mem_alloc_error(no_parts_arg*MAX_PART_NAME_SIZE);
+ mem_alloc_error(num_parts_arg*MAX_PART_NAME_SIZE);
}
DBUG_RETURN(ptr);
}
/*
+ Generate a version string for partition expression
+ This function must be updated every time there is a possibility for
+ a new function of a higher version number than 5.5.0.
+
+ SYNOPSIS
+ set_show_version_string()
+ RETURN VALUES
+ None
+*/
+void partition_info::set_show_version_string(String *packet)
+{
+ int version= 0;
+ if (column_list)
+ packet->append(STRING_WITH_LEN("\n/*!50500"));
+ else
+ {
+ if (part_expr)
+ part_expr->walk(&Item::intro_version, 0, (uchar*)&version);
+ if (subpart_expr)
+ subpart_expr->walk(&Item::intro_version, 0, (uchar*)&version);
+ if (version == 0)
+ {
+ /* No new functions in partition function */
+ packet->append(STRING_WITH_LEN("\n/*!50100"));
+ }
+ else
+ {
+ char buf[65];
+ char *buf_ptr= longlong10_to_str((longlong)version, buf, 10);
+ packet->append(STRING_WITH_LEN("\n/*!"));
+ packet->append(buf, (size_t)(buf_ptr - buf));
+ }
+ }
+}
+
+/*
Create a unique name for the subpartition as part_name'sp''subpart_no'
SYNOPSIS
create_subpartition_name()
@@ -189,19 +231,19 @@ bool partition_info::set_up_default_partitions(handler *file,
goto end;
}
- if ((no_parts == 0) &&
- ((no_parts= file->get_default_no_partitions(info)) == 0))
+ if ((num_parts == 0) &&
+ ((num_parts= file->get_default_no_partitions(info)) == 0))
{
my_error(ER_PARTITION_NOT_DEFINED_ERROR, MYF(0), "partitions");
goto end;
}
- if (unlikely(no_parts > MAX_PARTITIONS))
+ if (unlikely(num_parts > MAX_PARTITIONS))
{
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
goto end;
}
- if (unlikely((!(default_name= create_default_partition_names(0, no_parts,
+ if (unlikely((!(default_name= create_default_partition_names(0, num_parts,
start_no)))))
goto end;
i= 0;
@@ -220,7 +262,7 @@ bool partition_info::set_up_default_partitions(handler *file,
mem_alloc_error(sizeof(partition_element));
goto end;
}
- } while (++i < no_parts);
+ } while (++i < num_parts);
result= FALSE;
end:
DBUG_RETURN(result);
@@ -259,9 +301,9 @@ bool partition_info::set_up_default_subpartitions(handler *file,
List_iterator<partition_element> part_it(partitions);
DBUG_ENTER("partition_info::set_up_default_subpartitions");
- if (no_subparts == 0)
- no_subparts= file->get_default_no_partitions(info);
- if (unlikely((no_parts * no_subparts) > MAX_PARTITIONS))
+ if (num_subparts == 0)
+ num_subparts= file->get_default_no_partitions(info);
+ if (unlikely((num_parts * num_subparts) > MAX_PARTITIONS))
{
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
goto end;
@@ -288,8 +330,8 @@ bool partition_info::set_up_default_subpartitions(handler *file,
mem_alloc_error(sizeof(partition_element));
goto end;
}
- } while (++j < no_subparts);
- } while (++i < no_parts);
+ } while (++j < num_subparts);
+ } while (++i < num_parts);
result= FALSE;
end:
DBUG_RETURN(result);
@@ -334,6 +376,49 @@ bool partition_info::set_up_defaults_for_partitioning(handler *file,
/*
+ Support routine for check_partition_info
+
+ SYNOPSIS
+ has_unique_fields
+ no parameters
+
+ RETURN VALUE
+ Erroneus field name Error, there are two fields with same name
+ NULL Ok, no field defined twice
+
+ DESCRIPTION
+ Check that the user haven't defined the same field twice in
+ key or column list partitioning.
+*/
+char* partition_info::has_unique_fields()
+{
+ char *field_name_outer, *field_name_inner;
+ List_iterator<char> it_outer(part_field_list);
+ uint num_fields= part_field_list.elements;
+ uint i,j;
+ DBUG_ENTER("partition_info::has_unique_fields");
+
+ for (i= 0; i < num_fields; i++)
+ {
+ field_name_outer= it_outer++;
+ List_iterator<char> it_inner(part_field_list);
+ for (j= 0; j < num_fields; j++)
+ {
+ field_name_inner= it_inner++;
+ if (i >= j)
+ continue;
+ if (!(my_strcasecmp(system_charset_info,
+ field_name_outer,
+ field_name_inner)))
+ {
+ DBUG_RETURN(field_name_outer);
+ }
+ }
+ }
+ DBUG_RETURN(NULL);
+}
+
+/*
A support function to check if a partition element's name is unique
SYNOPSIS
@@ -518,12 +603,12 @@ bool partition_info::check_engine_mix(handlerton *engine_type,
{
handlerton *old_engine_type= engine_type;
bool first= TRUE;
- uint no_parts= partitions.elements;
+ uint n_parts= partitions.elements;
DBUG_ENTER("partition_info::check_engine_mix");
DBUG_PRINT("info", ("in: engine_type = %s, table_engine_set = %u",
ha_resolve_storage_engine_name(engine_type),
table_engine_set));
- if (no_parts)
+ if (n_parts)
{
List_iterator<partition_element> part_it(partitions);
uint i= 0;
@@ -536,7 +621,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type,
if (is_sub_partitioned() &&
part_elem->subpartitions.elements)
{
- uint no_subparts= part_elem->subpartitions.elements;
+ uint n_subparts= part_elem->subpartitions.elements;
uint j= 0;
List_iterator<partition_element> sub_it(part_elem->subpartitions);
do
@@ -548,7 +633,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type,
if (check_engine_condition(sub_elem, table_engine_set,
&engine_type, &first))
goto error;
- } while (++j < no_subparts);
+ } while (++j < n_subparts);
/* ensure that the partition also has correct engine */
if (check_engine_condition(part_elem, table_engine_set,
&engine_type, &first))
@@ -557,7 +642,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type,
else if (check_engine_condition(part_elem, table_engine_set,
&engine_type, &first))
goto error;
- } while (++i < no_parts);
+ } while (++i < n_parts);
}
DBUG_PRINT("info", ("engine_type = %s",
ha_resolve_storage_engine_name(engine_type)));
@@ -589,6 +674,7 @@ error:
SYNOPSIS
check_range_constants()
+ thd Thread object
RETURN VALUE
TRUE An error occurred during creation of range constants
@@ -601,76 +687,108 @@ error:
called for RANGE PARTITIONed tables.
*/
-bool partition_info::check_range_constants()
+bool partition_info::check_range_constants(THD *thd)
{
partition_element* part_def;
- longlong current_largest;
- longlong part_range_value;
bool first= TRUE;
uint i;
List_iterator<partition_element> it(partitions);
- bool result= TRUE;
- bool signed_flag= !part_expr->unsigned_flag;
+ int result= TRUE;
DBUG_ENTER("partition_info::check_range_constants");
- DBUG_PRINT("enter", ("INT_RESULT with %d parts", no_parts));
+ DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u", num_parts,
+ column_list));
- LINT_INIT(current_largest);
-
- part_result_type= INT_RESULT;
- range_int_array= (longlong*)sql_alloc(no_parts * sizeof(longlong));
- if (unlikely(range_int_array == NULL))
+ if (column_list)
{
- mem_alloc_error(no_parts * sizeof(longlong));
- goto end;
- }
- i= 0;
- do
- {
- part_def= it++;
- if ((i != (no_parts - 1)) || !defined_max_value)
+ part_column_list_val *loc_range_col_array;
+ part_column_list_val *UNINIT_VAR(current_largest_col_val);
+ uint num_column_values= part_field_list.elements;
+ uint size_entries= sizeof(part_column_list_val) * num_column_values;
+ range_col_array= (part_column_list_val*)sql_calloc(num_parts *
+ size_entries);
+ if (unlikely(range_col_array == NULL))
{
- part_range_value= part_def->range_value;
- if (!signed_flag)
- part_range_value-= 0x8000000000000000ULL;
+ mem_alloc_error(num_parts * size_entries);
+ goto end;
}
- else
- part_range_value= LONGLONG_MAX;
- if (first)
+ loc_range_col_array= range_col_array;
+ i= 0;
+ do
{
- current_largest= part_range_value;
- range_int_array[0]= part_range_value;
+ part_def= it++;
+ {
+ List_iterator<part_elem_value> list_val_it(part_def->list_val_list);
+ part_elem_value *range_val= list_val_it++;
+ part_column_list_val *col_val= range_val->col_val_array;
+
+ if (fix_column_value_functions(thd, range_val, i))
+ goto end;
+ memcpy(loc_range_col_array, (const void*)col_val, size_entries);
+ loc_range_col_array+= num_column_values;
+ if (!first)
+ {
+ if (compare_column_values((const void*)current_largest_col_val,
+ (const void*)col_val) >= 0)
+ goto range_not_increasing_error;
+ }
+ current_largest_col_val= col_val;
+ }
first= FALSE;
+ } while (++i < num_parts);
+ }
+ else
+ {
+ longlong UNINIT_VAR(current_largest);
+ longlong part_range_value;
+ bool signed_flag= !part_expr->unsigned_flag;
+
+ range_int_array= (longlong*)sql_alloc(num_parts * sizeof(longlong));
+ if (unlikely(range_int_array == NULL))
+ {
+ mem_alloc_error(num_parts * sizeof(longlong));
+ goto end;
}
- else
+ i= 0;
+ do
{
- if (likely(current_largest < part_range_value))
+ part_def= it++;
+ if ((i != (num_parts - 1)) || !defined_max_value)
{
- current_largest= part_range_value;
- range_int_array[i]= part_range_value;
- }
- else if (defined_max_value &&
- current_largest == part_range_value &&
- part_range_value == LONGLONG_MAX &&
- i == (no_parts - 1))
- {
- range_int_array[i]= part_range_value;
+ part_range_value= part_def->range_value;
+ if (!signed_flag)
+ part_range_value-= 0x8000000000000000ULL;
}
else
+ part_range_value= LONGLONG_MAX;
+
+ if (!first)
{
- my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0));
- goto end;
+ if (unlikely(current_largest > part_range_value) ||
+ (unlikely(current_largest == part_range_value) &&
+ (part_range_value < LONGLONG_MAX ||
+ i != (num_parts - 1) ||
+ !defined_max_value)))
+ goto range_not_increasing_error;
}
- }
- } while (++i < no_parts);
+ range_int_array[i]= part_range_value;
+ current_largest= part_range_value;
+ first= FALSE;
+ } while (++i < num_parts);
+ }
result= FALSE;
end:
DBUG_RETURN(result);
+
+range_not_increasing_error:
+ my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0));
+ goto end;
}
/*
Support routines for check_list_constants used by qsort to sort the
- constant list expressions. One routine for unsigned and one for signed.
+ constant list expressions. One routine for integers and one for
+ column lists.
SYNOPSIS
list_part_cmp()
@@ -683,7 +801,8 @@ end:
-1 a < b
*/
-int partition_info::list_part_cmp(const void* a, const void* b)
+extern "C"
+int partition_info_list_part_cmp(const void* a, const void* b)
{
longlong a1= ((LIST_PART_ENTRY*)a)->list_value;
longlong b1= ((LIST_PART_ENTRY*)b)->list_value;
@@ -696,6 +815,70 @@ int partition_info::list_part_cmp(const void* a, const void* b)
}
+int partition_info::list_part_cmp(const void* a, const void* b)
+{
+ return partition_info_list_part_cmp(a, b);
+}
+
+
+/*
+ Compare two lists of column values in RANGE/LIST partitioning
+ SYNOPSIS
+ compare_column_values()
+ first First column list argument
+ second Second column list argument
+ RETURN VALUES
+ 0 Equal
+ -1 First argument is smaller
+ +1 First argument is larger
+*/
+
+extern "C"
+int partition_info_compare_column_values(const void *first_arg,
+ const void *second_arg)
+{
+ const part_column_list_val *first= (part_column_list_val*)first_arg;
+ const part_column_list_val *second= (part_column_list_val*)second_arg;
+ partition_info *part_info= first->part_info;
+ Field **field;
+
+ for (field= part_info->part_field_array; *field;
+ field++, first++, second++)
+ {
+ if (first->max_value || second->max_value)
+ {
+ if (first->max_value && second->max_value)
+ return 0;
+ if (second->max_value)
+ return -1;
+ else
+ return +1;
+ }
+ if (first->null_value || second->null_value)
+ {
+ if (first->null_value && second->null_value)
+ continue;
+ if (second->null_value)
+ return +1;
+ else
+ return -1;
+ }
+ int res= (*field)->cmp((const uchar*)first->column_value,
+ (const uchar*)second->column_value);
+ if (res)
+ return res;
+ }
+ return 0;
+}
+
+
+int partition_info::compare_column_values(const void *first_arg,
+ const void *second_arg)
+{
+ return partition_info_compare_column_values(first_arg, second_arg);
+}
+
+
/*
This routine allocates an array for all list constants to achieve a fast
check what partition a certain value belongs to. At the same time it does
@@ -704,6 +887,7 @@ int partition_info::list_part_cmp(const void* a, const void* b)
SYNOPSIS
check_list_constants()
+ thd Thread object
RETURN VALUE
TRUE An error occurred during creation of list constants
@@ -716,20 +900,23 @@ int partition_info::list_part_cmp(const void* a, const void* b)
called for LIST PARTITIONed tables.
*/
-bool partition_info::check_list_constants()
+bool partition_info::check_list_constants(THD *thd)
{
- uint i;
+ uint i, size_entries, num_column_values;
uint list_index= 0;
part_elem_value *list_value;
bool result= TRUE;
- longlong curr_value, prev_value, type_add, calc_value;
+ longlong type_add, calc_value;
+ void *curr_value;
+ void *UNINIT_VAR(prev_value);
partition_element* part_def;
bool found_null= FALSE;
+ qsort_cmp compare_func;
+ void *ptr;
List_iterator<partition_element> list_func_it(partitions);
DBUG_ENTER("partition_info::check_list_constants");
- part_result_type= INT_RESULT;
- no_list_values= 0;
+ num_list_values= 0;
/*
We begin by calculating the number of list values that have been
defined in the first step.
@@ -762,51 +949,85 @@ bool partition_info::check_list_constants()
}
List_iterator<part_elem_value> list_val_it1(part_def->list_val_list);
while (list_val_it1++)
- no_list_values++;
- } while (++i < no_parts);
+ num_list_values++;
+ } while (++i < num_parts);
list_func_it.rewind();
- list_array= (LIST_PART_ENTRY*)sql_alloc((no_list_values+1) *
- sizeof(LIST_PART_ENTRY));
- if (unlikely(list_array == NULL))
+ num_column_values= part_field_list.elements;
+ size_entries= column_list ?
+ (num_column_values * sizeof(part_column_list_val)) :
+ sizeof(LIST_PART_ENTRY);
+ ptr= sql_calloc((num_list_values+1) * size_entries);
+ if (unlikely(ptr == NULL))
{
- mem_alloc_error(no_list_values * sizeof(LIST_PART_ENTRY));
+ mem_alloc_error(num_list_values * size_entries);
goto end;
}
-
- i= 0;
- /*
- Fix to be able to reuse signed sort functions also for unsigned
- partition functions.
- */
- type_add= (longlong)(part_expr->unsigned_flag ?
+ if (column_list)
+ {
+ part_column_list_val *loc_list_col_array;
+ loc_list_col_array= (part_column_list_val*)ptr;
+ list_col_array= (part_column_list_val*)ptr;
+ compare_func= partition_info_compare_column_values;
+ i= 0;
+ do
+ {
+ part_def= list_func_it++;
+ List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
+ while ((list_value= list_val_it2++))
+ {
+ part_column_list_val *col_val= list_value->col_val_array;
+ if (unlikely(fix_column_value_functions(thd, list_value, i)))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ memcpy(loc_list_col_array, (const void*)col_val, size_entries);
+ loc_list_col_array+= num_column_values;
+ }
+ } while (++i < num_parts);
+ }
+ else
+ {
+ compare_func= partition_info_list_part_cmp;
+ list_array= (LIST_PART_ENTRY*)ptr;
+ i= 0;
+ /*
+ Fix to be able to reuse signed sort functions also for unsigned
+ partition functions.
+ */
+ type_add= (longlong)(part_expr->unsigned_flag ?
0x8000000000000000ULL :
0ULL);
- do
- {
- part_def= list_func_it++;
- List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
- while ((list_value= list_val_it2++))
+ do
{
- calc_value= list_value->value - type_add;
- list_array[list_index].list_value= calc_value;
- list_array[list_index++].partition_id= i;
- }
- } while (++i < no_parts);
-
- if (fixed && no_list_values)
+ part_def= list_func_it++;
+ List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
+ while ((list_value= list_val_it2++))
+ {
+ calc_value= list_value->value - type_add;
+ list_array[list_index].list_value= calc_value;
+ list_array[list_index++].partition_id= i;
+ }
+ } while (++i < num_parts);
+ }
+ DBUG_ASSERT(fixed);
+ if (num_list_values)
{
bool first= TRUE;
- my_qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY),
- &list_part_cmp);
-
+ /*
+ list_array and list_col_array are unions, so this works for both
+ variants of LIST partitioning.
+ */
+ my_qsort((void*)list_array, num_list_values, size_entries,
+ compare_func);
+
i= 0;
- LINT_INIT(prev_value);
do
{
- DBUG_ASSERT(i < no_list_values);
- curr_value= list_array[i].list_value;
- if (likely(first || prev_value != curr_value))
+ DBUG_ASSERT(i < num_list_values);
+ curr_value= column_list ? (void*)&list_col_array[num_column_values * i] :
+ (void*)&list_array[i];
+ if (likely(first || compare_func(curr_value, prev_value)))
{
prev_value= curr_value;
first= FALSE;
@@ -816,23 +1037,48 @@ bool partition_info::check_list_constants()
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
goto end;
}
- } while (++i < no_list_values);
+ } while (++i < num_list_values);
}
result= FALSE;
end:
DBUG_RETURN(result);
}
+/**
+ Check if we allow DATA/INDEX DIRECTORY, if not warn and set them to NULL.
+
+ @param thd THD also containing sql_mode (looks from MODE_NO_DIR_IN_CREATE).
+ @param part_elem partition_element to check.
+*/
+static void warn_if_dir_in_part_elem(THD *thd, partition_element *part_elem)
+{
+#ifdef HAVE_READLINK
+ if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
+#endif
+ {
+ if (part_elem->data_file_name)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
+ "DATA DIRECTORY");
+ if (part_elem->index_file_name)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
+ "INDEX DIRECTORY");
+ part_elem->data_file_name= part_elem->index_file_name= NULL;
+ }
+}
+
/*
This code is used early in the CREATE TABLE and ALTER TABLE process.
SYNOPSIS
check_partition_info()
+ thd Thread object
+ eng_type Return value for used engine in partitions
file A reference to a handler of the table
info Create info
- engine_type Return value for used engine in partitions
- check_partition_function Should we check the partition function
+ add_or_reorg_part Is it ALTER TABLE ADD/REORGANIZE command
RETURN VALUE
TRUE Error, something went wrong
@@ -848,7 +1094,7 @@ end:
bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
handler *file, HA_CREATE_INFO *info,
- bool check_partition_function)
+ bool add_or_reorg_part)
{
handlerton *table_engine= default_engine_type;
uint i, tot_partitions;
@@ -859,11 +1105,11 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
DBUG_PRINT("info", ("default table_engine = %s",
ha_resolve_storage_engine_name(table_engine)));
- if (check_partition_function)
+ if (!add_or_reorg_part)
{
int err= 0;
- if (part_type != HASH_PARTITION || !list_of_part_fields)
+ if (!list_of_part_fields)
{
DBUG_ASSERT(part_expr);
err= part_expr->walk(&Item::check_partition_func_processor, 0,
@@ -877,9 +1123,12 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
goto end;
}
+ if (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
+ fix_parser_data(thd))
+ goto end;
}
if (unlikely(!is_sub_partitioned() &&
- !(use_default_subpartitions && use_default_no_subpartitions)))
+ !(use_default_subpartitions && use_default_num_subpartitions)))
{
my_error(ER_SUBPARTITION_ERROR, MYF(0));
goto end;
@@ -937,6 +1186,12 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
}
}
+ if (part_field_list.elements > 0 &&
+ (same_name= has_unique_fields()))
+ {
+ my_error(ER_SAME_NAME_PARTITION_FIELD, MYF(0), same_name);
+ goto end;
+ }
if ((same_name= has_unique_names()))
{
my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name);
@@ -945,30 +1200,17 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
i= 0;
{
List_iterator<partition_element> part_it(partitions);
- uint no_parts_not_set= 0;
- uint prev_no_subparts_not_set= no_subparts + 1;
+ uint num_parts_not_set= 0;
+ uint prev_num_subparts_not_set= num_subparts + 1;
do
{
partition_element *part_elem= part_it++;
-#ifdef HAVE_READLINK
- if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
-#endif
- {
- if (part_elem->data_file_name)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
- "DATA DIRECTORY");
- if (part_elem->index_file_name)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
- "INDEX DIRECTORY");
- part_elem->data_file_name= part_elem->index_file_name= NULL;
- }
+ warn_if_dir_in_part_elem(thd, part_elem);
if (!is_sub_partitioned())
{
if (part_elem->engine_type == NULL)
{
- no_parts_not_set++;
+ num_parts_not_set++;
part_elem->engine_type= default_engine_type;
}
if (check_table_name(part_elem->partition_name,
@@ -983,12 +1225,13 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
else
{
uint j= 0;
- uint no_subparts_not_set= 0;
+ uint num_subparts_not_set= 0;
List_iterator<partition_element> sub_it(part_elem->subpartitions);
partition_element *sub_elem;
do
{
sub_elem= sub_it++;
+ warn_if_dir_in_part_elem(thd, sub_elem);
if (check_table_name(sub_elem->partition_name,
strlen(sub_elem->partition_name), FALSE))
{
@@ -1002,44 +1245,45 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
else
{
sub_elem->engine_type= default_engine_type;
- no_subparts_not_set++;
+ num_subparts_not_set++;
}
}
DBUG_PRINT("info", ("part = %d sub = %d engine = %s", i, j,
ha_resolve_storage_engine_name(sub_elem->engine_type)));
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
- if (prev_no_subparts_not_set == (no_subparts + 1) &&
- (no_subparts_not_set == 0 || no_subparts_not_set == no_subparts))
- prev_no_subparts_not_set= no_subparts_not_set;
+ if (prev_num_subparts_not_set == (num_subparts + 1) &&
+ (num_subparts_not_set == 0 ||
+ num_subparts_not_set == num_subparts))
+ prev_num_subparts_not_set= num_subparts_not_set;
if (!table_engine_set &&
- prev_no_subparts_not_set != no_subparts_not_set)
+ prev_num_subparts_not_set != num_subparts_not_set)
{
- DBUG_PRINT("info", ("no_subparts_not_set = %u no_subparts = %u",
- no_subparts_not_set, no_subparts));
+ DBUG_PRINT("info", ("num_subparts_not_set = %u num_subparts = %u",
+ num_subparts_not_set, num_subparts));
my_error(ER_MIX_HANDLER_ERROR, MYF(0));
goto end;
}
if (part_elem->engine_type == NULL)
{
- if (no_subparts_not_set == 0)
+ if (num_subparts_not_set == 0)
part_elem->engine_type= sub_elem->engine_type;
else
{
- no_parts_not_set++;
+ num_parts_not_set++;
part_elem->engine_type= default_engine_type;
}
}
}
- } while (++i < no_parts);
+ } while (++i < num_parts);
if (!table_engine_set &&
- no_parts_not_set != 0 &&
- no_parts_not_set != no_parts)
+ num_parts_not_set != 0 &&
+ num_parts_not_set != num_parts)
{
- DBUG_PRINT("info", ("no_parts_not_set = %u no_parts = %u",
- no_parts_not_set, no_subparts));
+ DBUG_PRINT("info", ("num_parts_not_set = %u num_parts = %u",
+ num_parts_not_set, num_subparts));
my_error(ER_MIX_HANDLER_ERROR, MYF(0));
goto end;
}
@@ -1062,10 +1306,12 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
list constants.
*/
- if (fixed)
+ if (add_or_reorg_part)
{
- if (unlikely((part_type == RANGE_PARTITION && check_range_constants()) ||
- (part_type == LIST_PARTITION && check_list_constants())))
+ if (unlikely((part_type == RANGE_PARTITION &&
+ check_range_constants(thd)) ||
+ (part_type == LIST_PARTITION &&
+ check_list_constants(thd))))
goto end;
}
result= FALSE;
@@ -1084,32 +1330,113 @@ end:
RETURN VALUES
*/
-void partition_info::print_no_partition_found(TABLE *table)
+void partition_info::print_no_partition_found(TABLE *table_arg)
{
char buf[100];
char *buf_ptr= (char*)&buf;
TABLE_LIST table_list;
bzero(&table_list, sizeof(table_list));
- table_list.db= table->s->db.str;
- table_list.table_name= table->s->table_name.str;
+ table_list.db= table_arg->s->db.str;
+ table_list.table_name= table_arg->s->table_name.str;
if (check_single_table_access(current_thd,
SELECT_ACL, &table_list, TRUE))
+ {
my_message(ER_NO_PARTITION_FOR_GIVEN_VALUE,
ER(ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), MYF(0));
+ }
else
{
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
- if (part_expr->null_value)
- buf_ptr= (char*)"NULL";
+ if (column_list)
+ buf_ptr= (char*)"from column_list";
else
- longlong2str(err_value, buf,
- part_expr->unsigned_flag ? 10 : -10);
+ {
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table_arg, table_arg->read_set);
+ if (part_expr->null_value)
+ buf_ptr= (char*)"NULL";
+ else
+ longlong2str(err_value, buf,
+ part_expr->unsigned_flag ? 10 : -10);
+ dbug_tmp_restore_column_map(table_arg->read_set, old_map);
+ }
my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr);
- dbug_tmp_restore_column_map(table->read_set, old_map);
}
}
+
+
+/*
+ Set fields related to partition expression
+ SYNOPSIS
+ set_part_expr()
+ start_token Start of partition function string
+ item_ptr Pointer to item tree
+ end_token End of partition function string
+ is_subpart Subpartition indicator
+ RETURN VALUES
+ TRUE Memory allocation error
+ FALSE Success
+*/
+
+bool partition_info::set_part_expr(char *start_token, Item *item_ptr,
+ char *end_token, bool is_subpart)
+{
+ uint expr_len= end_token - start_token;
+ char *func_string= (char*) sql_memdup(start_token, expr_len);
+
+ if (!func_string)
+ {
+ mem_alloc_error(expr_len);
+ return TRUE;
+ }
+ if (is_subpart)
+ {
+ list_of_subpart_fields= FALSE;
+ subpart_expr= item_ptr;
+ subpart_func_string= func_string;
+ subpart_func_len= expr_len;
+ }
+ else
+ {
+ list_of_part_fields= FALSE;
+ part_expr= item_ptr;
+ part_func_string= func_string;
+ part_func_len= expr_len;
+ }
+ return FALSE;
+}
+
+
+/*
+ Check that partition fields and subpartition fields are not too long
+
+ SYNOPSIS
+ check_partition_field_length()
+
+ RETURN VALUES
+ TRUE Total length was too big
+ FALSE Length is ok
+*/
+
+bool partition_info::check_partition_field_length()
+{
+ uint store_length= 0;
+ uint i;
+ DBUG_ENTER("partition_info::check_partition_field_length");
+
+ for (i= 0; i < num_part_fields; i++)
+ store_length+= get_partition_field_store_length(part_field_array[i]);
+ if (store_length > MAX_KEY_LENGTH)
+ DBUG_RETURN(TRUE);
+ store_length= 0;
+ for (i= 0; i < num_subpart_fields; i++)
+ store_length+= get_partition_field_store_length(subpart_field_array[i]);
+ if (store_length > MAX_KEY_LENGTH)
+ DBUG_RETURN(TRUE);
+ DBUG_RETURN(FALSE);
+}
+
+
/*
Set up buffers and arrays for fields requiring preparation
SYNOPSIS
@@ -1219,46 +1546,6 @@ bool partition_info::set_up_charset_field_preps()
}
subpart_charset_field_array[i]= NULL;
}
- if (tot_fields)
- {
- uint k;
- size= tot_fields*sizeof(char**);
- if (!(char_ptrs= (uchar**)sql_calloc(size)))
- goto error;
- full_part_field_buffers= char_ptrs;
- if (!(char_ptrs= (uchar**)sql_calloc(size)))
- goto error;
- restore_full_part_field_ptrs= char_ptrs;
- size= (tot_fields + 1) * sizeof(char**);
- if (!(char_ptrs= (uchar**)sql_calloc(size)))
- goto error;
- full_part_charset_field_array= (Field**)char_ptrs;
- for (i= 0; i < tot_part_fields; i++)
- {
- full_part_charset_field_array[i]= part_charset_field_array[i];
- full_part_field_buffers[i]= part_field_buffers[i];
- }
- k= tot_part_fields;
- for (i= 0; i < tot_subpart_fields; i++)
- {
- uint j;
- bool found= FALSE;
- field= subpart_charset_field_array[i];
-
- for (j= 0; j < tot_part_fields; j++)
- {
- if (field == part_charset_field_array[i])
- found= TRUE;
- }
- if (!found)
- {
- full_part_charset_field_array[k]= subpart_charset_field_array[i];
- full_part_field_buffers[k]= subpart_field_buffers[i];
- k++;
- }
- }
- full_part_charset_field_array[k]= NULL;
- }
DBUG_RETURN(FALSE);
error:
mem_alloc_error(size);
@@ -1320,4 +1607,682 @@ id_err:
}
+/**
+ Check what kind of error to report
+
+ @param use_subpart_expr Use the subpart_expr instead of part_expr
+ @param part_str Name of partition to report error (or NULL)
+*/
+void partition_info::report_part_expr_error(bool use_subpart_expr)
+{
+ Item *expr= part_expr;
+ DBUG_ENTER("partition_info::report_part_expr_error");
+ if (use_subpart_expr)
+ expr= subpart_expr;
+
+ if (expr->type() == Item::FIELD_ITEM)
+ {
+ partition_type type= part_type;
+ bool list_of_fields= list_of_part_fields;
+ Item_field *item_field= (Item_field*) expr;
+ /*
+ The expression consists of a single field.
+ It must be of integer type unless KEY or COLUMNS partitioning.
+ */
+ if (use_subpart_expr)
+ {
+ type= subpart_type;
+ list_of_fields= list_of_subpart_fields;
+ }
+ if (!column_list &&
+ item_field->field &&
+ item_field->field->result_type() != INT_RESULT &&
+ !(type == HASH_PARTITION && list_of_fields))
+ {
+ my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
+ item_field->name);
+ DBUG_VOID_RETURN;
+ }
+ }
+ if (use_subpart_expr)
+ my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), "SUBPARTITION");
+ else
+ my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), "PARTITION");
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Create a new column value in current list with maxvalue
+ Called from parser
+
+ SYNOPSIS
+ add_max_value()
+ RETURN
+ TRUE Error
+ FALSE Success
+*/
+
+int partition_info::add_max_value()
+{
+ DBUG_ENTER("partition_info::add_max_value");
+
+ part_column_list_val *col_val;
+ if (!(col_val= add_column_value()))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ col_val->max_value= TRUE;
+ DBUG_RETURN(FALSE);
+}
+
+/*
+ Create a new column value in current list
+ Called from parser
+
+ SYNOPSIS
+ add_column_value()
+ RETURN
+ >0 A part_column_list_val object which have been
+ inserted into its list
+ 0 Memory allocation failure
+*/
+
+part_column_list_val *partition_info::add_column_value()
+{
+ uint max_val= num_columns ? num_columns : MAX_REF_PARTS;
+ DBUG_ENTER("add_column_value");
+ DBUG_PRINT("enter", ("num_columns = %u, curr_list_object %u, max_val = %u",
+ num_columns, curr_list_object, max_val));
+ if (curr_list_object < max_val)
+ {
+ curr_list_val->added_items++;
+ DBUG_RETURN(&curr_list_val->col_val_array[curr_list_object++]);
+ }
+ if (!num_columns && part_type == LIST_PARTITION)
+ {
+ /*
+ We're trying to add more than MAX_REF_PARTS, this can happen
+ in ALTER TABLE using List partitions where the first partition
+ uses VALUES IN (1,2,3...,17) where the number of fields in
+ the list is more than MAX_REF_PARTS, in this case we know
+ that the number of columns must be 1 and we thus reorganize
+ into the structure used for 1 column. After this we call
+ ourselves recursively which should always succeed.
+ */
+ if (!reorganize_into_single_field_col_val())
+ {
+ DBUG_RETURN(add_column_value());
+ }
+ DBUG_RETURN(NULL);
+ }
+ if (column_list)
+ {
+ my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
+ }
+ else
+ {
+ if (part_type == RANGE_PARTITION)
+ my_error(ER_TOO_MANY_VALUES_ERROR, MYF(0), "RANGE");
+ else
+ my_error(ER_TOO_MANY_VALUES_ERROR, MYF(0), "LIST");
+ }
+ DBUG_RETURN(NULL);
+}
+
+
+/*
+ Initialise part_elem_value object at setting of a new object
+ (Helper functions to functions called by parser)
+
+ SYNOPSIS
+ init_col_val
+ col_val Column value object to be initialised
+ item Item object representing column value
+
+ RETURN VALUES
+ TRUE Failure
+ FALSE Success
+*/
+void partition_info::init_col_val(part_column_list_val *col_val, Item *item)
+{
+ DBUG_ENTER("partition_info::init_col_val");
+
+ col_val->item_expression= item;
+ col_val->null_value= item->null_value;
+ if (item->result_type() == INT_RESULT)
+ {
+ /*
+ This could be both column_list partitioning and function
+ partitioning, but it doesn't hurt to set the function
+ partitioning flags about unsignedness.
+ */
+ curr_list_val->value= item->val_int();
+ curr_list_val->unsigned_flag= TRUE;
+ if (!item->unsigned_flag &&
+ curr_list_val->value < 0)
+ curr_list_val->unsigned_flag= FALSE;
+ if (!curr_list_val->unsigned_flag)
+ curr_part_elem->signed_flag= TRUE;
+ }
+ col_val->part_info= NULL;
+ DBUG_VOID_RETURN;
+}
+/*
+ Add a column value in VALUES LESS THAN or VALUES IN
+ (Called from parser)
+
+ SYNOPSIS
+ add_column_list_value()
+ lex Parser's lex object
+ thd Thread object
+ item Item object representing column value
+
+ RETURN VALUES
+ TRUE Failure
+ FALSE Success
+*/
+bool partition_info::add_column_list_value(THD *thd, Item *item)
+{
+ part_column_list_val *col_val;
+ Name_resolution_context *context= &thd->lex->current_select->context;
+ TABLE_LIST *save_list= context->table_list;
+ const char *save_where= thd->where;
+ DBUG_ENTER("partition_info::add_column_list_value");
+
+ if (part_type == LIST_PARTITION &&
+ num_columns == 1U)
+ {
+ if (init_column_part())
+ {
+ DBUG_RETURN(TRUE);
+ }
+ }
+
+ context->table_list= 0;
+ if (column_list)
+ thd->where= "field list";
+ else
+ thd->where= "partition function";
+
+ if (item->walk(&Item::check_partition_func_processor, 0,
+ NULL))
+ {
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ if (item->fix_fields(thd, (Item**)0) ||
+ ((context->table_list= save_list), FALSE) ||
+ (!item->const_item()))
+ {
+ context->table_list= save_list;
+ thd->where= save_where;
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ thd->where= save_where;
+
+ if (!(col_val= add_column_value()))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ init_col_val(col_val, item);
+ DBUG_RETURN(FALSE);
+}
+
+/*
+ Initialise part_info object for receiving a set of column values
+ for a partition, called when parser reaches VALUES LESS THAN or
+ VALUES IN.
+
+ SYNOPSIS
+ init_column_part()
+ lex Parser's lex object
+
+ RETURN VALUES
+ TRUE Failure
+ FALSE Success
+*/
+bool partition_info::init_column_part()
+{
+ partition_element *p_elem= curr_part_elem;
+ part_column_list_val *col_val_array;
+ part_elem_value *list_val;
+ uint loc_num_columns;
+ DBUG_ENTER("partition_info::init_column_part");
+
+ if (!(list_val=
+ (part_elem_value*)sql_calloc(sizeof(part_elem_value))) ||
+ p_elem->list_val_list.push_back(list_val))
+ {
+ mem_alloc_error(sizeof(part_elem_value));
+ DBUG_RETURN(TRUE);
+ }
+ if (num_columns)
+ loc_num_columns= num_columns;
+ else
+ loc_num_columns= MAX_REF_PARTS;
+ if (!(col_val_array=
+ (part_column_list_val*)sql_calloc(loc_num_columns *
+ sizeof(part_column_list_val))))
+ {
+ mem_alloc_error(loc_num_columns * sizeof(part_elem_value));
+ DBUG_RETURN(TRUE);
+ }
+ list_val->col_val_array= col_val_array;
+ list_val->added_items= 0;
+ curr_list_val= list_val;
+ curr_list_object= 0;
+ DBUG_RETURN(FALSE);
+}
+
+/*
+ In the case of ALTER TABLE ADD/REORGANIZE PARTITION for LIST
+ partitions we can specify list values as:
+ VALUES IN (v1, v2,,,, v17) if we're using the first partitioning
+ variant with a function or a column list partitioned table with
+ one partition field. In this case the parser knows not the
+ number of columns start with and allocates MAX_REF_PARTS in the
+ array. If we try to allocate something beyond MAX_REF_PARTS we
+ will call this function to reorganize into a structure with
+ num_columns = 1. Also when the parser knows that we used LIST
+ partitioning and we used a VALUES IN like above where number of
+ values was smaller than MAX_REF_PARTS or equal, then we will
+ reorganize after discovering this in the parser.
+
+ SYNOPSIS
+ reorganize_into_single_field_col_val()
+
+ RETURN VALUES
+ TRUE Failure
+ FALSE Success
+*/
+int partition_info::reorganize_into_single_field_col_val()
+{
+ part_column_list_val *col_val, *new_col_val;
+ part_elem_value *val= curr_list_val;
+ uint loc_num_columns= num_columns;
+ uint i;
+ DBUG_ENTER("partition_info::reorganize_into_single_field_col_val");
+
+ num_columns= 1;
+ val->added_items= 1U;
+ col_val= &val->col_val_array[0];
+ init_col_val(col_val, col_val->item_expression);
+ for (i= 1; i < loc_num_columns; i++)
+ {
+ col_val= &val->col_val_array[i];
+ DBUG_ASSERT(part_type == LIST_PARTITION);
+ if (init_column_part())
+ {
+ DBUG_RETURN(TRUE);
+ }
+ if (!(new_col_val= add_column_value()))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ memcpy(new_col_val, col_val, sizeof(*col_val));
+ init_col_val(new_col_val, col_val->item_expression);
+ }
+ curr_list_val= val;
+ DBUG_RETURN(FALSE);
+}
+
+/*
+ This function handles the case of function-based partitioning.
+ It fixes some data structures created in the parser and puts
+ them in the format required by the rest of the partitioning
+ code.
+
+ SYNOPSIS
+ fix_partition_values()
+ thd Thread object
+ col_val Array of one value
+ part_elem The partition instance
+ part_id Id of partition instance
+
+ RETURN VALUES
+ TRUE Failure
+ FALSE Success
+*/
+int partition_info::fix_partition_values(THD *thd,
+ part_elem_value *val,
+ partition_element *part_elem,
+ uint part_id)
+{
+ part_column_list_val *col_val= val->col_val_array;
+ DBUG_ENTER("partition_info::fix_partition_values");
+
+ if (col_val->fixed)
+ {
+ DBUG_RETURN(FALSE);
+ }
+ if (val->added_items != 1)
+ {
+ my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ if (col_val->max_value)
+ {
+ /* The parser ensures we're not LIST partitioned here */
+ DBUG_ASSERT(part_type == RANGE_PARTITION);
+ if (defined_max_value)
+ {
+ my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ if (part_id == (num_parts - 1))
+ {
+ defined_max_value= TRUE;
+ part_elem->max_value= TRUE;
+ part_elem->range_value= LONGLONG_MAX;
+ }
+ else
+ {
+ my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ }
+ else
+ {
+ Item *item_expr= col_val->item_expression;
+ if ((val->null_value= item_expr->null_value))
+ {
+ if (part_elem->has_null_value)
+ {
+ my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ part_elem->has_null_value= TRUE;
+ }
+ else if (item_expr->result_type() != INT_RESULT)
+ {
+ my_error(ER_VALUES_IS_NOT_INT_TYPE_ERROR, MYF(0),
+ part_elem->partition_name);
+ DBUG_RETURN(TRUE);
+ }
+ if (part_type == RANGE_PARTITION)
+ {
+ if (part_elem->has_null_value)
+ {
+ my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ part_elem->range_value= val->value;
+ }
+ }
+ col_val->fixed= 2;
+ DBUG_RETURN(FALSE);
+}
+
+/*
+ Get column item with a proper character set according to the field
+
+ SYNOPSIS
+ get_column_item()
+ item Item object to start with
+ field Field for which the item will be compared to
+
+ RETURN VALUES
+ NULL Error
+ item Returned item
+*/
+
+Item* partition_info::get_column_item(Item *item, Field *field)
+{
+ if (field->result_type() == STRING_RESULT &&
+ item->collation.collation != field->charset())
+ {
+ if (!(item= convert_charset_partition_constant(item,
+ field->charset())))
+ {
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+ return NULL;
+ }
+ }
+ return item;
+}
+
+
+/*
+ Evaluate VALUES functions for column list values
+ SYNOPSIS
+ fix_column_value_functions()
+ thd Thread object
+ col_val List of column values
+ part_id Partition id we are fixing
+
+ RETURN VALUES
+ TRUE Error
+ FALSE Success
+ DESCRIPTION
+ Fix column VALUES and store in memory array adapted to the data type
+*/
+
+bool partition_info::fix_column_value_functions(THD *thd,
+ part_elem_value *val,
+ uint part_id)
+{
+ uint n_columns= part_field_list.elements;
+ bool result= FALSE;
+ uint i;
+ part_column_list_val *col_val= val->col_val_array;
+ DBUG_ENTER("partition_info::fix_column_value_functions");
+
+ if (col_val->fixed > 1)
+ {
+ DBUG_RETURN(FALSE);
+ }
+ for (i= 0; i < n_columns; col_val++, i++)
+ {
+ Item *column_item= col_val->item_expression;
+ Field *field= part_field_array[i];
+ col_val->part_info= this;
+ col_val->partition_id= part_id;
+ if (col_val->max_value)
+ col_val->column_value= NULL;
+ else
+ {
+ col_val->column_value= NULL;
+ if (!col_val->null_value)
+ {
+ uchar *val_ptr;
+ uint len= field->pack_length();
+ ulong save_sql_mode;
+ bool save_got_warning;
+
+ if (!(column_item= get_column_item(column_item,
+ field)))
+ {
+ result= TRUE;
+ goto end;
+ }
+ save_sql_mode= thd->variables.sql_mode;
+ thd->variables.sql_mode= 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));
+ result= TRUE;
+ goto end;
+ }
+ thd->got_warning= save_got_warning;
+ thd->variables.sql_mode= save_sql_mode;
+ if (!(val_ptr= (uchar*) sql_calloc(len)))
+ {
+ mem_alloc_error(len);
+ result= TRUE;
+ goto end;
+ }
+ col_val->column_value= val_ptr;
+ memcpy(val_ptr, field->ptr, len);
+ }
+ }
+ col_val->fixed= 2;
+ }
+end:
+ DBUG_RETURN(result);
+}
+
+/*
+ The parser generates generic data structures, we need to set them up
+ as the rest of the code expects to find them. This is in reality part
+ of the syntax check of the parser code.
+
+ It is necessary to call this function in the case of a CREATE TABLE
+ statement, in this case we do it early in the check_partition_info
+ function.
+
+ It is necessary to call this function for ALTER TABLE where we
+ assign a completely new partition structure, in this case we do it
+ in prep_alter_part_table after discovering that the partition
+ structure is entirely redefined.
+
+ It's necessary to call this method also for ALTER TABLE ADD/REORGANIZE
+ of partitions, in this we call it in prep_alter_part_table after
+ making some initial checks but before going deep to check the partition
+ info, we also assign the column_list variable before calling this function
+ here.
+
+ Finally we also call it immediately after returning from parsing the
+ partitioning text found in the frm file.
+
+ This function mainly fixes the VALUES parts, these are handled differently
+ whether or not we use column list partitioning. Since the parser doesn't
+ know which we are using we need to set-up the old data structures after
+ the parser is complete when we know if what type of partitioning the
+ base table is using.
+
+ For column lists we will handle this in the fix_column_value_function.
+ For column lists it is sufficient to verify that the number of columns
+ and number of elements are in synch with each other. So only partitioning
+ using functions need to be set-up to their data structures.
+
+ SYNOPSIS
+ fix_parser_data()
+ thd Thread object
+
+ RETURN VALUES
+ TRUE Failure
+ FALSE Success
+*/
+
+int partition_info::fix_parser_data(THD *thd)
+{
+ List_iterator<partition_element> it(partitions);
+ partition_element *part_elem;
+ uint num_elements;
+ uint i= 0, j, k;
+ DBUG_ENTER("partition_info::fix_parser_data");
+
+ if (!(part_type == RANGE_PARTITION ||
+ part_type == LIST_PARTITION))
+ {
+ /* Nothing to do for HASH/KEY partitioning */
+ DBUG_RETURN(FALSE);
+ }
+ do
+ {
+ part_elem= it++;
+ List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
+ j= 0;
+ num_elements= part_elem->list_val_list.elements;
+ DBUG_ASSERT(part_type == RANGE_PARTITION ?
+ num_elements == 1U : TRUE);
+ do
+ {
+ part_elem_value *val= list_val_it++;
+ if (column_list)
+ {
+ if (val->added_items != num_columns)
+ {
+ my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ for (k= 0; k < num_columns; k++)
+ {
+ part_column_list_val *col_val= &val->col_val_array[k];
+ if (col_val->null_value && part_type == RANGE_PARTITION)
+ {
+ my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+ else
+ {
+ if (fix_partition_values(thd, val, part_elem, i))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ if (val->null_value)
+ {
+ /*
+ Null values aren't required in the value part, they are kept per
+ partition instance, only LIST partitions have NULL values.
+ */
+ list_val_it.remove();
+ }
+ }
+ } while (++j < num_elements);
+ } while (++i < num_parts);
+ DBUG_RETURN(FALSE);
+}
+
+void partition_info::print_debug(const char *str, uint *value)
+{
+ DBUG_ENTER("print_debug");
+ if (value)
+ DBUG_PRINT("info", ("parser: %s, val = %u", str, *value));
+ else
+ DBUG_PRINT("info", ("parser: %s", str));
+ DBUG_VOID_RETURN;
+}
+#else /* WITH_PARTITION_STORAGE_ENGINE */
+ /*
+ For builds without partitioning we need to define these functions
+ since we they are called from the parser. The parser cannot
+ remove code parts using ifdef, but the code parts cannot be called
+ so we simply need to add empty functions to make the linker happy.
+ */
+part_column_list_val *partition_info::add_column_value()
+{
+ return NULL;
+}
+
+bool partition_info::set_part_expr(char *start_token, Item *item_ptr,
+ char *end_token, bool is_subpart)
+{
+ (void)start_token;
+ (void)item_ptr;
+ (void)end_token;
+ (void)is_subpart;
+ return FALSE;
+}
+
+int partition_info::reorganize_into_single_field_col_val()
+{
+ return 0;
+}
+
+bool partition_info::init_column_part()
+{
+ return FALSE;
+}
+
+bool partition_info::add_column_list_value(THD *thd, Item *item)
+{
+ return FALSE;
+}
+int partition_info::add_max_value()
+{
+ return 0;
+}
+
+void partition_info::print_debug(const char *str, uint *value)
+{
+}
+
#endif /* WITH_PARTITION_STORAGE_ENGINE */
diff --git a/sql/partition_info.h b/sql/partition_info.h
index 9f438e8260b..6ae210d9574 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -1,4 +1,7 @@
-/* Copyright 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+#ifndef PARTITION_INFO_INCLUDED
+#define PARTITION_INFO_INCLUDED
+
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -64,10 +67,9 @@ public:
/*
When we have various string fields we might need some preparation
before and clean-up after calling the get_part_id_func's. We need
- one such method for get_partition_id and one for
- get_part_partition_id and one for get_subpartition_id.
+ one such method for get_part_partition_id and one for
+ get_subpartition_id.
*/
- get_part_id_func get_partition_id_charset;
get_part_id_func get_part_partition_id_charset;
get_subpart_id_func get_subpartition_id_charset;
@@ -81,7 +83,6 @@ public:
without duplicates, NULL-terminated.
*/
Field **full_part_field_array;
- Field **full_part_charset_field_array;
/*
Set of all fields used in partition and subpartition expression.
Required for testing of partition fields in write_set when
@@ -97,10 +98,8 @@ public:
*/
uchar **part_field_buffers;
uchar **subpart_field_buffers;
- uchar **full_part_field_buffers;
uchar **restore_part_field_ptrs;
uchar **restore_subpart_field_ptrs;
- uchar **restore_full_part_field_ptrs;
Item *part_expr;
Item *subpart_expr;
@@ -124,6 +123,8 @@ public:
union {
longlong *range_int_array;
LIST_PART_ENTRY *list_array;
+ part_column_list_val *range_col_array;
+ part_column_list_val *list_col_array;
};
/********************************************
@@ -150,10 +151,12 @@ public:
char *part_func_string;
char *subpart_func_string;
- const char *part_state;
-
partition_element *curr_part_elem;
partition_element *current_partition;
+ part_elem_value *curr_list_val;
+ uint curr_list_object;
+ uint num_columns;
+
/*
These key_map's are used for Partitioning to enable quick decisions
on whether we can derive more information about which partition to
@@ -163,26 +166,24 @@ public:
key_map some_fields_in_PF;
handlerton *default_engine_type;
- Item_result part_result_type;
partition_type part_type;
partition_type subpart_type;
uint part_info_len;
- uint part_state_len;
uint part_func_len;
uint subpart_func_len;
- uint no_parts;
- uint no_subparts;
+ uint num_parts;
+ uint num_subparts;
uint count_curr_subparts;
uint part_error_code;
- uint no_list_values;
+ uint num_list_values;
- uint no_part_fields;
- uint no_subpart_fields;
- uint no_full_part_fields;
+ uint num_part_fields;
+ uint num_subpart_fields;
+ uint num_full_part_fields;
uint has_null_part_id;
/*
@@ -193,9 +194,9 @@ public:
uint16 linear_hash_mask;
bool use_default_partitions;
- bool use_default_no_partitions;
+ bool use_default_num_partitions;
bool use_default_subpartitions;
- bool use_default_no_subpartitions;
+ bool use_default_num_subpartitions;
bool default_partitions_setup;
bool defined_max_value;
bool list_of_part_fields;
@@ -205,7 +206,7 @@ public:
bool is_auto_partitioned;
bool from_openfrm;
bool has_null_value;
-
+ bool column_list;
partition_info()
: get_partition_id(NULL), get_part_partition_id(NULL),
@@ -214,34 +215,30 @@ public:
part_charset_field_array(NULL),
subpart_charset_field_array(NULL),
full_part_field_array(NULL),
- full_part_charset_field_array(NULL),
part_field_buffers(NULL), subpart_field_buffers(NULL),
- full_part_field_buffers(NULL),
restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL),
- restore_full_part_field_ptrs(NULL),
part_expr(NULL), subpart_expr(NULL), item_free_list(NULL),
first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL),
list_array(NULL), err_value(0),
part_info_string(NULL),
part_func_string(NULL), subpart_func_string(NULL),
- part_state(NULL),
curr_part_elem(NULL), current_partition(NULL),
+ curr_list_object(0), num_columns(0),
default_engine_type(NULL),
- part_result_type(INT_RESULT),
part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION),
- part_info_len(0), part_state_len(0),
+ part_info_len(0),
part_func_len(0), subpart_func_len(0),
- no_parts(0), no_subparts(0),
+ num_parts(0), num_subparts(0),
count_curr_subparts(0), part_error_code(0),
- no_list_values(0), no_part_fields(0), no_subpart_fields(0),
- no_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0),
- use_default_partitions(TRUE), use_default_no_partitions(TRUE),
- use_default_subpartitions(TRUE), use_default_no_subpartitions(TRUE),
+ num_list_values(0), num_part_fields(0), num_subpart_fields(0),
+ num_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0),
+ use_default_partitions(TRUE), use_default_num_partitions(TRUE),
+ use_default_subpartitions(TRUE), use_default_num_subpartitions(TRUE),
default_partitions_setup(FALSE), defined_max_value(FALSE),
list_of_part_fields(FALSE), list_of_subpart_fields(FALSE),
linear_hash_ind(FALSE), fixed(FALSE),
is_auto_partitioned(FALSE), from_openfrm(FALSE),
- has_null_value(FALSE)
+ has_null_value(FALSE), column_list(FALSE)
{
all_fields_in_PF.clear_all();
all_fields_in_PPF.clear_all();
@@ -264,27 +261,49 @@ public:
/* Returns the total number of partitions on the leaf level */
uint get_tot_partitions()
{
- return no_parts * (is_sub_partitioned() ? no_subparts : 1);
+ return num_parts * (is_sub_partitioned() ? num_subparts : 1);
}
bool set_up_defaults_for_partitioning(handler *file, HA_CREATE_INFO *info,
uint start_no);
+ char *has_unique_fields();
char *has_unique_names();
bool check_engine_mix(handlerton *engine_type, bool default_engine);
- bool check_range_constants();
- bool check_list_constants();
+ bool check_range_constants(THD *thd);
+ bool check_list_constants(THD *thd);
bool check_partition_info(THD *thd, handlerton **eng_type,
handler *file, HA_CREATE_INFO *info,
bool check_partition_function);
void print_no_partition_found(TABLE *table);
+ void print_debug(const char *str, uint*);
+ Item* get_column_item(Item *item, Field *field);
+ int fix_partition_values(THD *thd,
+ part_elem_value *val,
+ partition_element *part_elem,
+ uint part_id);
+ bool fix_column_value_functions(THD *thd,
+ part_elem_value *val,
+ uint part_id);
+ int fix_parser_data(THD *thd);
+ int add_max_value();
+ void init_col_val(part_column_list_val *col_val, Item *item);
+ int reorganize_into_single_field_col_val();
+ part_column_list_val *add_column_value();
+ bool set_part_expr(char *start_token, Item *item_ptr,
+ char *end_token, bool is_subpart);
+ static int compare_column_values(const void *a, const void *b);
bool set_up_charset_field_preps();
+ bool check_partition_field_length();
+ bool init_column_part();
+ bool add_column_list_value(THD *thd, Item *item);
+ void set_show_version_string(String *packet);
+ void report_part_expr_error(bool use_subpart_expr);
private:
static int list_part_cmp(const void* a, const void* b);
- static int list_part_cmp_unsigned(const void* a, const void* b);
bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info,
uint start_no);
bool set_up_default_subpartitions(handler *file, HA_CREATE_INFO *info);
- char *create_default_partition_names(uint part_no, uint no_parts,
+ char *create_default_partition_names(uint part_no, uint num_parts,
uint start_no);
char *create_subpartition_name(uint subpart_no, const char *part_name);
bool has_unique_name(partition_element *element);
@@ -310,7 +329,9 @@ void init_all_partitions_iterator(partition_info *part_info,
PARTITION_ITERATOR *part_iter)
{
part_iter->part_nums.start= part_iter->part_nums.cur= 0;
- part_iter->part_nums.end= part_info->no_parts;
+ part_iter->part_nums.end= part_info->num_parts;
part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
part_iter->get_next= get_next_partition_id_range;
}
+
+#endif /* PARTITION_INFO_INCLUDED */
diff --git a/sql/password.c b/sql/password.c
index 9204c660b77..3b69705cc87 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -58,6 +58,7 @@
*****************************************************************************/
+#include <password.h>
#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
@@ -222,13 +223,13 @@ void scramble_323(char *to, const char *message, const char *password)
*/
my_bool
-check_scramble_323(const char *scrambled, const char *message,
+check_scramble_323(const unsigned char *scrambled, const char *message,
ulong *hash_pass)
{
struct rand_struct rand_st;
ulong hash_message[2];
- char buff[16],*to,extra; /* Big enough for check */
- const char *pos;
+ uchar buff[16],*to,extra; /* Big enough for check */
+ const uchar *pos;
hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
@@ -243,7 +244,7 @@ check_scramble_323(const char *scrambled, const char *message,
to=buff;
while (*scrambled)
{
- if (*scrambled++ != (char) (*to++ ^ extra))
+ if (*scrambled++ != (uchar) (*to++ ^ extra))
return 1; /* Wrong password */
}
return 0;
@@ -509,7 +510,7 @@ scramble(char *to, const char *message, const char *password)
*/
my_bool
-check_scramble(const char *scramble_arg, const char *message,
+check_scramble(const uchar *scramble_arg, const char *message,
const uint8 *hash_stage2)
{
SHA1_CONTEXT sha1_context;
@@ -522,7 +523,7 @@ check_scramble(const char *scramble_arg, const char *message,
mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
mysql_sha1_result(&sha1_context, buf);
/* encrypt scramble */
- my_crypt((char *) buf, buf, (const uchar *) scramble_arg, SCRAMBLE_LENGTH);
+ my_crypt((char *) buf, buf, scramble_arg, SCRAMBLE_LENGTH);
/* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
mysql_sha1_reset(&sha1_context);
mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
diff --git a/sql/procedure.cc b/sql/procedure.cc
index c993ba976ac..66e09a42cb4 100644
--- a/sql/procedure.cc
+++ b/sql/procedure.cc
@@ -20,7 +20,7 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
#include "procedure.h"
#include "sql_analyse.h" // Includes procedure
#ifdef USE_PROC_RANGE
diff --git a/sql/procedure.h b/sql/procedure.h
index ceb586766b1..f34eb228f28 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -1,3 +1,6 @@
+#ifndef PROCEDURE_INCLUDED
+#define PROCEDURE_INCLUDED
+
/* Copyright (C) 2000-2005 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -20,10 +23,18 @@
#pragma interface /* gcc class implementation */
#endif
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "sql_class.h" /* select_result, set_var.h: THD */
+#include "set_var.h" /* Item */
+
#define PROC_NO_SORT 1 /**< Bits in flags */
#define PROC_GROUP 2 /**< proc must have group */
-/* Procedure items used by procedures to store values for send_fields */
+/* Procedure items used by procedures to store values for send_result_set_metadata */
class Item_proc :public Item
{
@@ -149,3 +160,5 @@ public:
Procedure *setup_procedure(THD *thd,ORDER *proc_param,select_result *result,
List<Item> &field_list,int *error);
+
+#endif /* PROCEDURE_INCLUDED */
diff --git a/sql/protocol.cc b/sql/protocol.cc
index db5e15b2acd..03b151e4346 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -24,17 +24,21 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "protocol.h"
+#include "sql_class.h" // THD
#include <stdarg.h>
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
/* Declared non-static only because of the embedded library. */
-bool net_send_error_packet(THD *thd, uint sql_errno, const char *err);
-bool net_send_ok(THD *, uint, uint, ha_rows, ulonglong, const char *);
-bool net_send_eof(THD *thd, uint server_status, uint total_warn_count);
+bool net_send_error_packet(THD *, uint, const char *, const char *);
+/* Declared non-static only because of the embedded library. */
+bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *);
+/* Declared non-static only because of the embedded library. */
+bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count);
#ifndef EMBEDDED_LIBRARY
-static bool write_eof_packet(THD *thd, NET *net,
- uint server_status, uint total_warn_count);
+static bool write_eof_packet(THD *, NET *, uint, uint);
#endif
#ifndef EMBEDDED_LIBRARY
@@ -58,6 +62,64 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length)
}
+
+
+/*
+ net_store_data() - extended version with character set conversion.
+
+ It is optimized for short strings whose length after
+ conversion is garanteed to be less than 251, which accupies
+ exactly one byte to store length. It allows not to use
+ the "convert" member as a temporary buffer, conversion
+ is done directly to the "packet" member.
+ The limit 251 is good enough to optimize send_result_set_metadata()
+ because column, table, database names fit into this limit.
+*/
+
+#ifndef EMBEDDED_LIBRARY
+bool Protocol::net_store_data(const uchar *from, size_t length,
+ CHARSET_INFO *from_cs, CHARSET_INFO *to_cs)
+{
+ uint dummy_errors;
+ /* Calculate maxumum possible result length */
+ uint conv_length= to_cs->mbmaxlen * length / from_cs->mbminlen;
+ if (conv_length > 250)
+ {
+ /*
+ For strings with conv_length greater than 250 bytes
+ we don't know how many bytes we will need to store length: one or two,
+ because we don't know result length until conversion is done.
+ For example, when converting from utf8 (mbmaxlen=3) to latin1,
+ conv_length=300 means that the result length can vary between 100 to 300.
+ length=100 needs one byte, length=300 needs to bytes.
+
+ Thus conversion directly to "packet" is not worthy.
+ Let's use "convert" as a temporary buffer.
+ */
+ return (convert->copy((const char*) from, length, from_cs,
+ to_cs, &dummy_errors) ||
+ net_store_data((const uchar*) convert->ptr(), convert->length()));
+ }
+
+ ulong packet_length= packet->length();
+ ulong new_length= packet_length + conv_length + 1;
+
+ if (new_length > packet->alloced_length() && packet->realloc(new_length))
+ return 1;
+
+ char *length_pos= (char*) packet->ptr() + packet_length;
+ char *to= length_pos + 1;
+
+ to+= copy_and_convert(to, conv_length, to_cs,
+ (const char*) from, length, from_cs, &dummy_errors);
+
+ net_store_length((uchar*) length_pos, to - length_pos - 1);
+ packet->length((uint) (to - packet->ptr()));
+ return 0;
+}
+#endif
+
+
/**
Send a error string to client.
@@ -80,29 +142,33 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length)
@retval TRUE An error occurred and the message wasn't sent properly
*/
-bool net_send_error(THD *thd, uint sql_errno, const char *err)
+bool net_send_error(THD *thd, uint sql_errno, const char *err,
+ const char* sqlstate)
{
+ bool error;
DBUG_ENTER("net_send_error");
DBUG_ASSERT(!thd->spcont);
DBUG_ASSERT(sql_errno);
- DBUG_ASSERT(err && err[0]);
+ DBUG_ASSERT(err);
DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, err));
- bool error;
+
+ if (sqlstate == NULL)
+ sqlstate= mysql_errno_to_sqlstate(sql_errno);
/*
It's one case when we can push an error even though there
is an OK or EOF already.
*/
- thd->main_da.can_overwrite_status= TRUE;
+ thd->stmt_da->can_overwrite_status= TRUE;
/* Abort multi-result sets */
thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
- error= net_send_error_packet(thd, sql_errno, err);
+ error= net_send_error_packet(thd, sql_errno, err, sqlstate);
- thd->main_da.can_overwrite_status= FALSE;
+ thd->stmt_da->can_overwrite_status= FALSE;
DBUG_RETURN(error);
}
@@ -124,7 +190,7 @@ bool net_send_error(THD *thd, uint sql_errno, const char *err)
@param thd Thread handler
@param server_status The server status
- @param total_warn_count Total number of warnings
+ @param statement_warn_count Total number of warnings
@param affected_rows Number of rows changed by statement
@param id Auto_increment id for first row (if used)
@param message Message to send to the client (Used by mysql_status)
@@ -138,13 +204,13 @@ bool net_send_error(THD *thd, uint sql_errno, const char *err)
#ifndef EMBEDDED_LIBRARY
bool
net_send_ok(THD *thd,
- uint server_status, uint total_warn_count,
- ha_rows affected_rows, ulonglong id, const char *message)
+ uint server_status, uint statement_warn_count,
+ ulonglong affected_rows, ulonglong id, const char *message)
{
NET *net= &thd->net;
uchar buff[MYSQL_ERRMSG_SIZE+10],*pos;
bool error= FALSE;
- DBUG_ENTER("my_ok");
+ DBUG_ENTER("net_send_ok");
if (! net->vio) // hack for re-parsing queries
{
@@ -162,12 +228,12 @@ net_send_ok(THD *thd,
(ulong) affected_rows,
(ulong) id,
(uint) (server_status & 0xffff),
- (uint) total_warn_count));
+ (uint) statement_warn_count));
int2store(pos, server_status);
pos+=2;
/* We can only return up to 65535 warnings in two bytes */
- uint tmp= min(total_warn_count, 65535);
+ uint tmp= min(statement_warn_count, 65535);
int2store(pos, tmp);
pos+= 2;
}
@@ -176,7 +242,7 @@ net_send_ok(THD *thd,
int2store(pos, server_status);
pos+=2;
}
- thd->main_da.can_overwrite_status= TRUE;
+ thd->stmt_da->can_overwrite_status= TRUE;
if (message && message[0])
pos= net_store_data(pos, (uchar*) message, strlen(message));
@@ -184,7 +250,8 @@ net_send_ok(THD *thd,
if (!error)
error= net_flush(net);
- thd->main_da.can_overwrite_status= FALSE;
+
+ thd->stmt_da->can_overwrite_status= FALSE;
DBUG_PRINT("info", ("OK sent, so no more error sending allowed"));
DBUG_RETURN(error);
@@ -208,7 +275,7 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */
@param thd Thread handler
@param server_status The server status
- @param total_warn_count Total number of warnings
+ @param statement_warn_count Total number of warnings
@return
@retval FALSE The message was successfully sent
@@ -216,7 +283,7 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */
*/
bool
-net_send_eof(THD *thd, uint server_status, uint total_warn_count)
+net_send_eof(THD *thd, uint server_status, uint statement_warn_count)
{
NET *net= &thd->net;
bool error= FALSE;
@@ -224,11 +291,11 @@ net_send_eof(THD *thd, uint server_status, uint total_warn_count)
/* Set to TRUE if no active vio, to work well in case of --init-file */
if (net->vio != 0)
{
- thd->main_da.can_overwrite_status= TRUE;
- error= write_eof_packet(thd, net, server_status, total_warn_count);
+ thd->stmt_da->can_overwrite_status= TRUE;
+ error= write_eof_packet(thd, net, server_status, statement_warn_count);
if (!error)
error= net_flush(net);
- thd->main_da.can_overwrite_status= FALSE;
+ thd->stmt_da->can_overwrite_status= FALSE;
DBUG_PRINT("info", ("EOF sent, so no more error sending allowed"));
}
DBUG_RETURN(error);
@@ -242,7 +309,7 @@ net_send_eof(THD *thd, uint server_status, uint total_warn_count)
@param thd The thread handler
@param net The network handler
@param server_status The server status
- @param total_warn_count The number of warnings
+ @param statement_warn_count The number of warnings
@return
@@ -252,7 +319,7 @@ net_send_eof(THD *thd, uint server_status, uint total_warn_count)
static bool write_eof_packet(THD *thd, NET *net,
uint server_status,
- uint total_warn_count)
+ uint statement_warn_count)
{
bool error;
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
@@ -262,7 +329,7 @@ static bool write_eof_packet(THD *thd, NET *net,
Don't send warn count during SP execution, as the warn_list
is cleared between substatements, and mysqltest gets confused
*/
- uint tmp= min(total_warn_count, 65535);
+ uint tmp= min(statement_warn_count, 65535);
buff[0]= 254;
int2store(buff+1, tmp);
/*
@@ -282,24 +349,6 @@ static bool write_eof_packet(THD *thd, NET *net,
}
/**
- Please client to send scrambled_password in old format.
-
- @param thd thread handle
-
- @retval
- 0 ok
- @retval
- !0 error
-*/
-
-bool send_old_password_request(THD *thd)
-{
- NET *net= &thd->net;
- return my_net_write(net, eof_buff, 1) || net_flush(net);
-}
-
-
-/**
@param thd Thread handler
@param sql_errno The error code to send
@param err A pointer to the error message
@@ -309,13 +358,18 @@ bool send_old_password_request(THD *thd)
@retval TRUE An error occurred and the messages wasn't sent properly
*/
-bool net_send_error_packet(THD *thd, uint sql_errno, const char *err)
+bool net_send_error_packet(THD *thd, uint sql_errno, const char *err,
+ const char* sqlstate)
+
{
NET *net= &thd->net;
uint length;
/*
buff[]: sql_errno:2 + ('#':1 + SQLSTATE_LENGTH:5) + MYSQL_ERRMSG_SIZE:512
*/
+ uint error;
+ uchar converted_err[MYSQL_ERRMSG_SIZE];
+ uint32 converted_err_len;
uchar buff[2+1+SQLSTATE_LENGTH+MYSQL_ERRMSG_SIZE], *pos;
DBUG_ENTER("send_error_packet");
@@ -330,27 +384,26 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err)
DBUG_RETURN(FALSE);
}
- if (net->return_errno)
- { // new client code; Add errno before message
- int2store(buff,sql_errno);
- pos= buff+2;
- if (thd->client_capabilities & CLIENT_PROTOCOL_41)
- {
- /* The first # is to make the protocol backward compatible */
- buff[2]= '#';
- pos= (uchar*) strmov((char*) buff+3, mysql_errno_to_sqlstate(sql_errno));
- }
- length= (uint) (strmake((char*) pos, err, MYSQL_ERRMSG_SIZE-1) -
- (char*) buff);
- err= (char*) buff;
- }
- else
+ int2store(buff,sql_errno);
+ pos= buff+2;
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
- length=(uint) strlen(err);
- set_if_smaller(length,MYSQL_ERRMSG_SIZE-1);
+ /* The first # is to make the protocol backward compatible */
+ buff[2]= '#';
+ pos= (uchar*) strmov((char*) buff+3, sqlstate);
}
+
+ converted_err_len= convert_error_message((char*)converted_err,
+ sizeof(converted_err),
+ thd->variables.character_set_results,
+ err, strlen(err),
+ system_charset_info, &error);
+ length= (uint) (strmake((char*) pos, (char*)converted_err,
+ MYSQL_ERRMSG_SIZE - 1) - (char*) buff);
+ err= (char*) buff;
+
DBUG_RETURN(net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) err,
- length));
+ length));
}
#endif /* EMBEDDED_LIBRARY */
@@ -414,6 +467,12 @@ static uchar *net_store_length_fast(uchar *packet, uint length)
packet is "buffered" in the diagnostics area and sent to the client
in the end of statement.
+ @note This method defines a template, but delegates actual
+ sending of data to virtual Protocol::send_{ok,eof,error}. This
+ allows for implementation of protocols that "intercept" ok/eof/error
+ messages, and store them in memory, etc, instead of sending to
+ the client.
+
@pre The diagnostics area is assigned or disabled. It can not be empty
-- we assume that every SQL statement or COM_* command
generates OK, ERROR, or EOF status.
@@ -428,47 +487,94 @@ static uchar *net_store_length_fast(uchar *packet, uint length)
Diagnostics_area::is_sent is set for debugging purposes only.
*/
-void net_end_statement(THD *thd)
+void Protocol::end_statement()
{
- DBUG_ASSERT(! thd->main_da.is_sent);
+ DBUG_ENTER("Protocol::end_statement");
+ DBUG_ASSERT(! thd->stmt_da->is_sent);
+ bool error= FALSE;
/* Can not be true, but do not take chances in production. */
- if (thd->main_da.is_sent)
- return;
-
- bool error= FALSE;
+ if (thd->stmt_da->is_sent)
+ DBUG_VOID_RETURN;
- switch (thd->main_da.status()) {
+ switch (thd->stmt_da->status()) {
case Diagnostics_area::DA_ERROR:
/* The query failed, send error to log and abort bootstrap. */
- error= net_send_error(thd,
- thd->main_da.sql_errno(),
- thd->main_da.message());
+ error= send_error(thd->stmt_da->sql_errno(),
+ thd->stmt_da->message(),
+ thd->stmt_da->get_sqlstate());
break;
case Diagnostics_area::DA_EOF:
- error= net_send_eof(thd,
- thd->main_da.server_status(),
- thd->main_da.total_warn_count());
+ error= send_eof(thd->server_status,
+ thd->stmt_da->statement_warn_count());
break;
case Diagnostics_area::DA_OK:
- error= net_send_ok(thd,
- thd->main_da.server_status(),
- thd->main_da.total_warn_count(),
- thd->main_da.affected_rows(),
- thd->main_da.last_insert_id(),
- thd->main_da.message());
+ error= send_ok(thd->server_status,
+ thd->stmt_da->statement_warn_count(),
+ thd->stmt_da->affected_rows(),
+ thd->stmt_da->last_insert_id(),
+ thd->stmt_da->message());
break;
case Diagnostics_area::DA_DISABLED:
break;
case Diagnostics_area::DA_EMPTY:
default:
DBUG_ASSERT(0);
- error= net_send_ok(thd, thd->server_status, thd->total_warn_count,
- 0, 0, NULL);
+ error= send_ok(thd->server_status, 0, 0, 0, NULL);
break;
}
if (!error)
- thd->main_da.is_sent= TRUE;
+ thd->stmt_da->is_sent= TRUE;
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ A default implementation of "OK" packet response to the client.
+
+ Currently this implementation is re-used by both network-oriented
+ protocols -- the binary and text one. They do not differ
+ in their OK packet format, which allows for a significant simplification
+ on client side.
+*/
+
+bool Protocol::send_ok(uint server_status, uint statement_warn_count,
+ ulonglong affected_rows, ulonglong last_insert_id,
+ const char *message)
+{
+ DBUG_ENTER("Protocol::send_ok");
+
+ DBUG_RETURN(net_send_ok(thd, server_status, statement_warn_count,
+ affected_rows, last_insert_id, message));
+}
+
+
+/**
+ A default implementation of "EOF" packet response to the client.
+
+ Binary and text protocol do not differ in their EOF packet format.
+*/
+
+bool Protocol::send_eof(uint server_status, uint statement_warn_count)
+{
+ DBUG_ENTER("Protocol::send_eof");
+
+ DBUG_RETURN(net_send_eof(thd, server_status, statement_warn_count));
+}
+
+
+/**
+ A default implementation of "ERROR" packet response to the client.
+
+ Binary and text protocol do not differ in ERROR packet format.
+*/
+
+bool Protocol::send_error(uint sql_errno, const char *err_msg,
+ const char *sql_state)
+{
+ DBUG_ENTER("Protocol::send_error");
+
+ DBUG_RETURN(net_send_error_packet(thd, sql_errno, err_msg, sql_state));
}
@@ -535,9 +641,9 @@ bool Protocol::flush()
{
#ifndef EMBEDDED_LIBRARY
bool error;
- thd->main_da.can_overwrite_status= TRUE;
+ thd->stmt_da->can_overwrite_status= TRUE;
error= net_flush(&thd->net);
- thd->main_da.can_overwrite_status= FALSE;
+ thd->stmt_da->can_overwrite_status= FALSE;
return error;
#else
return 0;
@@ -564,16 +670,16 @@ bool Protocol::flush()
1 Error (Note that in this case the error is not sent to the
client)
*/
-bool Protocol::send_fields(List<Item> *list, uint flags)
+bool Protocol::send_result_set_metadata(List<Item> *list, uint flags)
{
List_iterator_fast<Item> it(*list);
Item *item;
- uchar buff[80];
+ uchar buff[MAX_FIELD_WIDTH];
String tmp((char*) buff,sizeof(buff),&my_charset_bin);
Protocol_text prot(thd);
String *local_packet= prot.storage_packet();
CHARSET_INFO *thd_charset= thd->variables.character_set_results;
- DBUG_ENTER("send_fields");
+ DBUG_ENTER("send_result_set_metadata");
if (flags & SEND_NUM_ROWS)
{ // Packet with number of elements
@@ -619,17 +725,16 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
/* Store fixed length fields */
pos= (char*) local_packet->ptr()+local_packet->length();
*pos++= 12; // Length of packed fields
- if (item->collation.collation == &my_charset_bin || thd_charset == NULL)
+ if (item->charset_for_protocol() == &my_charset_bin || thd_charset == NULL)
{
/* No conversion */
- int2store(pos, field.charsetnr);
+ int2store(pos, item->charset_for_protocol()->number);
int4store(pos+2, field.length);
}
else
{
/* With conversion */
- ulonglong max_length;
- uint32 field_length;
+ uint32 field_length, max_length;
int2store(pos, thd_charset->number);
/*
For TEXT/BLOB columns, field_length describes the maximum data
@@ -652,9 +757,8 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
field.type <= MYSQL_TYPE_BLOB) ?
field.length / item->collation.collation->mbminlen :
field.length / item->collation.collation->mbmaxlen;
- max_length*= thd_charset->mbmaxlen;
- field_length= (max_length > UINT_MAX32) ?
- UINT_MAX32 : (uint32) max_length;
+ field_length= char_to_byte_length_safe(max_length,
+ thd_charset->mbmaxlen);
int4store(pos + 2, field_length);
}
pos[6]= field.type;
@@ -673,31 +777,14 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
local_packet->realloc(local_packet->length()+10))
goto err;
pos= (char*) local_packet->ptr()+local_packet->length();
-
-#ifdef TO_BE_DELETED_IN_6
- if (!(thd->client_capabilities & CLIENT_LONG_FLAG))
- {
- pos[0]=3;
- int3store(pos+1,field.length);
- pos[4]=1;
- pos[5]=field.type;
- pos[6]=2;
- pos[7]= (char) field.flags;
- pos[8]= (char) field.decimals;
- pos+= 9;
- }
- else
-#endif
- {
- pos[0]=3;
- int3store(pos+1,field.length);
- pos[4]=1;
- pos[5]=field.type;
- pos[6]=3;
- int2store(pos+7,field.flags);
- pos[9]= (char) field.decimals;
- pos+= 10;
- }
+ pos[0]=3;
+ int3store(pos+1,field.length);
+ pos[4]=1;
+ pos[5]=field.type;
+ pos[6]=3;
+ int2store(pos+7,field.flags);
+ pos[9]= (char) field.decimals;
+ pos+= 10;
}
local_packet->length((uint) (pos - local_packet->ptr()));
if (flags & SEND_DEFAULTS)
@@ -717,10 +804,10 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
Send no warning information, as it will be sent at statement end.
*/
if (write_eof_packet(thd, &thd->net, thd->server_status,
- thd->total_warn_count))
+ thd->warning_info->statement_warn_count()))
DBUG_RETURN(1);
}
- DBUG_RETURN(prepare_for_send(list));
+ DBUG_RETURN(prepare_for_send(list->elements));
err:
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
@@ -739,6 +826,47 @@ bool Protocol::write()
/**
+ Send one result set row.
+
+ @param row_items a collection of column values for that row
+
+ @return Error status.
+ @retval TRUE Error.
+ @retval FALSE Success.
+*/
+
+bool Protocol::send_result_set_row(List<Item> *row_items)
+{
+ char buffer[MAX_FIELD_WIDTH];
+ String str_buffer(buffer, sizeof (buffer), &my_charset_bin);
+ List_iterator_fast<Item> it(*row_items);
+
+ DBUG_ENTER("Protocol::send_result_set_row");
+
+ for (Item *item= it++; item; item= it++)
+ {
+ if (item->send(this, &str_buffer))
+ {
+ // If we're out of memory, reclaim some, to help us recover.
+ this->free();
+ DBUG_RETURN(TRUE);
+ }
+ /* Item::send() may generate an error. If so, abort the loop. */
+ if (thd->is_error())
+ DBUG_RETURN(TRUE);
+
+ /*
+ Reset str_buffer to its original state, as it may have been altered in
+ Item::send().
+ */
+ str_buffer.set(buffer, sizeof(buffer), &my_charset_bin);
+ }
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
Send \\0 end terminated string.
@param from NullS or \\0 terminated string
@@ -784,7 +912,6 @@ bool Protocol::store(I_List<i_string>* str_list)
return store((char*) tmp.ptr(), len, tmp.charset());
}
-
/****************************************************************************
Functions to handle the simple (default) protocol where everything is
This protocol is the one that is used by default between the MySQL server
@@ -827,10 +954,10 @@ bool Protocol::store_string_aux(const char *from, size_t length,
fromcs != &my_charset_bin &&
tocs != &my_charset_bin)
{
- uint dummy_errors;
- return (convert->copy(from, length, fromcs, tocs, &dummy_errors) ||
- net_store_data((uchar*) convert->ptr(), convert->length()));
+ /* Store with conversion */
+ return net_store_data((uchar*) from, length, fromcs, tocs);
}
+ /* Store without conversion */
return net_store_data((uchar*) from, length);
}
@@ -1057,6 +1184,53 @@ bool Protocol_text::store_time(MYSQL_TIME *tm)
return net_store_data((uchar*) buff, length);
}
+/**
+ Assign OUT-parameters to user variables.
+
+ @param sp_params List of PS/SP parameters (both input and output).
+
+ @return Error status.
+ @retval FALSE Success.
+ @retval TRUE Error.
+*/
+
+bool Protocol_text::send_out_parameters(List<Item_param> *sp_params)
+{
+ DBUG_ASSERT(sp_params->elements ==
+ thd->lex->prepared_stmt_params.elements);
+
+ List_iterator_fast<Item_param> item_param_it(*sp_params);
+ List_iterator_fast<LEX_STRING> user_var_name_it(thd->lex->prepared_stmt_params);
+
+ while (true)
+ {
+ Item_param *item_param= item_param_it++;
+ LEX_STRING *user_var_name= user_var_name_it++;
+
+ if (!item_param || !user_var_name)
+ break;
+
+ if (!item_param->get_out_param_info())
+ continue; // It's an IN-parameter.
+
+ Item_func_set_user_var *suv=
+ new Item_func_set_user_var(*user_var_name, item_param);
+ /*
+ Item_func_set_user_var is not fixed after construction, call
+ fix_fields().
+ */
+ if (suv->fix_fields(thd, NULL))
+ return TRUE;
+
+ if (suv->check(FALSE))
+ return TRUE;
+
+ if (suv->update())
+ return TRUE;
+ }
+
+ return FALSE;
+}
/****************************************************************************
Functions to handle the binary protocol used with prepared statements
@@ -1077,14 +1251,13 @@ bool Protocol_text::store_time(MYSQL_TIME *tm)
[..]..[[length]data] data
****************************************************************************/
-bool Protocol_binary::prepare_for_send(List<Item> *item_list)
+bool Protocol_binary::prepare_for_send(uint num_columns)
{
- Protocol::prepare_for_send(item_list);
+ Protocol::prepare_for_send(num_columns);
bit_fields= (field_count+9)/8;
- if (packet->alloc(bit_fields+1))
- return 1;
+ return packet->alloc(bit_fields+1);
+
/* prepare_for_resend will be called after this one */
- return 0;
}
@@ -1272,3 +1445,80 @@ bool Protocol_binary::store_time(MYSQL_TIME *tm)
buff[0]=(char) length; // Length is stored first
return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
}
+
+/**
+ Send a result set with OUT-parameter values by means of PS-protocol.
+
+ @param sp_params List of PS/SP parameters (both input and output).
+
+ @return Error status.
+ @retval FALSE Success.
+ @retval TRUE Error.
+*/
+
+bool Protocol_binary::send_out_parameters(List<Item_param> *sp_params)
+{
+ if (!(thd->client_capabilities & CLIENT_PS_MULTI_RESULTS))
+ {
+ /* The client does not support OUT-parameters. */
+ return FALSE;
+ }
+
+ List<Item> out_param_lst;
+
+ {
+ List_iterator_fast<Item_param> item_param_it(*sp_params);
+
+ while (true)
+ {
+ Item_param *item_param= item_param_it++;
+
+ if (!item_param)
+ break;
+
+ if (!item_param->get_out_param_info())
+ continue; // It's an IN-parameter.
+
+ if (out_param_lst.push_back(item_param))
+ return TRUE;
+ }
+ }
+
+ if (!out_param_lst.elements)
+ return FALSE;
+
+ /*
+ We have to set SERVER_PS_OUT_PARAMS in THD::server_status, because it
+ is used in send_result_set_metadata().
+ */
+
+ thd->server_status|= SERVER_PS_OUT_PARAMS | SERVER_MORE_RESULTS_EXISTS;
+
+ /* Send meta-data. */
+ if (send_result_set_metadata(&out_param_lst, SEND_NUM_ROWS | SEND_EOF))
+ return TRUE;
+
+ /* Send data. */
+
+ prepare_for_resend();
+
+ if (send_result_set_row(&out_param_lst))
+ return TRUE;
+
+ if (write())
+ return TRUE;
+
+ /* Restore THD::server_status. */
+ thd->server_status&= ~SERVER_PS_OUT_PARAMS;
+
+ /*
+ Reset SERVER_MORE_RESULTS_EXISTS bit, because this is the last packet
+ for sure.
+ */
+ thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
+
+ /* Send EOF-packet. */
+ net_send_eof(thd, thd->server_status, 0);
+
+ return FALSE;
+}
diff --git a/sql/protocol.h b/sql/protocol.h
index 251ba6fbc33..1c86c6d6c49 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -1,3 +1,6 @@
+#ifndef PROTOCOL_INCLUDED
+#define PROTOCOL_INCLUDED
+
/* Copyright (C) 2002-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -17,9 +20,13 @@
#pragma interface /* gcc class implementation */
#endif
+#include "sql_error.h"
+#include "my_decimal.h" /* my_decimal */
class i_string;
+class Field;
class THD;
+class Item_param;
typedef struct st_mysql_field MYSQL_FIELD;
typedef struct st_mysql_rows MYSQL_ROWS;
@@ -42,8 +49,20 @@ protected:
MYSQL_FIELD *next_mysql_field;
MEM_ROOT *alloc;
#endif
+ bool net_store_data(const uchar *from, size_t length,
+ CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
bool store_string_aux(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
+
+ virtual bool send_ok(uint server_status, uint statement_warn_count,
+ ulonglong affected_rows, ulonglong last_insert_id,
+ const char *message);
+
+ virtual bool send_eof(uint server_status, uint statement_warn_count);
+
+ virtual bool send_error(uint sql_errno, const char *err_msg,
+ const char *sql_state);
+
public:
Protocol() {}
Protocol(THD *thd_arg) { init(thd_arg); }
@@ -51,7 +70,8 @@ public:
void init(THD* thd_arg);
enum { SEND_NUM_ROWS= 1, SEND_DEFAULTS= 2, SEND_EOF= 4 };
- virtual bool send_fields(List<Item> *list, uint flags);
+ virtual bool send_result_set_metadata(List<Item> *list, uint flags);
+ bool send_result_set_row(List<Item> *row_items);
bool store(I_List<i_string> *str_list);
bool store(const char *from, CHARSET_INFO *cs);
@@ -69,9 +89,9 @@ public:
inline bool store(String *str)
{ return store((char*) str->ptr(), str->length(), str->charset()); }
- virtual bool prepare_for_send(List<Item> *item_list)
+ virtual bool prepare_for_send(uint num_columns)
{
- field_count=item_list->elements;
+ field_count= num_columns;
return 0;
}
virtual bool flush();
@@ -93,6 +113,8 @@ public:
virtual bool store_date(MYSQL_TIME *time)=0;
virtual bool store_time(MYSQL_TIME *time)=0;
virtual bool store(Field *field)=0;
+
+ virtual bool send_out_parameters(List<Item_param> *sp_params)=0;
#ifdef EMBEDDED_LIBRARY
int begin_dataset();
virtual void remove_last_row() {}
@@ -101,13 +123,15 @@ public:
#endif
enum enum_protocol_type
{
- PROTOCOL_TEXT= 0, PROTOCOL_BINARY= 1
/*
- before adding here or change the values, consider that it is cast to a
- bit in sql_cache.cc.
+ Before adding a new type, please make sure
+ there is enough storage for it in Query_cache_query_flags.
*/
+ PROTOCOL_TEXT= 0, PROTOCOL_BINARY= 1, PROTOCOL_LOCAL= 2
};
virtual enum enum_protocol_type type()= 0;
+
+ void end_statement();
};
@@ -134,6 +158,8 @@ public:
virtual bool store(float nr, uint32 decimals, String *buffer);
virtual bool store(double from, uint32 decimals, String *buffer);
virtual bool store(Field *field);
+
+ virtual bool send_out_parameters(List<Item_param> *sp_params);
#ifdef EMBEDDED_LIBRARY
void remove_last_row();
#endif
@@ -148,7 +174,7 @@ private:
public:
Protocol_binary() {}
Protocol_binary(THD *thd_arg) :Protocol(thd_arg) {}
- virtual bool prepare_for_send(List<Item> *item_list);
+ virtual bool prepare_for_send(uint num_columns);
virtual void prepare_for_resend();
#ifdef EMBEDDED_LIBRARY
virtual bool write();
@@ -169,14 +195,17 @@ public:
virtual bool store(float nr, uint32 decimals, String *buffer);
virtual bool store(double from, uint32 decimals, String *buffer);
virtual bool store(Field *field);
+
+ virtual bool send_out_parameters(List<Item_param> *sp_params);
+
virtual enum enum_protocol_type type() { return PROTOCOL_BINARY; };
};
void send_warning(THD *thd, uint sql_errno, const char *err=0);
-bool net_send_error(THD *thd, uint sql_errno=0, const char *err=0);
-void net_end_statement(THD *thd);
-bool send_old_password_request(THD *thd);
+bool net_send_error(THD *thd, uint sql_errno, const char *err,
+ const char* sqlstate);
uchar *net_store_data(uchar *to,const uchar *from, size_t length);
uchar *net_store_data(uchar *to,int32 from);
uchar *net_store_data(uchar *to,longlong from);
+#endif /* PROTOCOL_INCLUDED */
diff --git a/sql/records.cc b/sql/records.cc
index b809bcf1b91..d713c34dffe 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -13,6 +13,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#ifdef USE_PRAGMA_INTERFACE
+#pragma implementation /* gcc class implementation */
+#endif
/**
@file
@@ -21,7 +24,13 @@
Functions for easy reading of records, possible through a cache
*/
-#include "mysql_priv.h"
+#include "records.h"
+#include "sql_priv.h"
+#include "records.h"
+#include "filesort.h" // filesort_free_buffers
+#include "opt_range.h" // SQL_SELECT
+#include "sql_class.h" // THD
+
static int rr_quick(READ_RECORD *info);
int rr_sequential(READ_RECORD *info);
@@ -33,12 +42,14 @@ static int rr_from_cache(READ_RECORD *info);
static int init_rr_cache(THD *thd, READ_RECORD *info);
static int rr_cmp(uchar *a,uchar *b);
static int rr_index_first(READ_RECORD *info);
+static int rr_index_last(READ_RECORD *info);
static int rr_index(READ_RECORD *info);
+static int rr_index_desc(READ_RECORD *info);
/**
- Initialize READ_RECORD structure to perform full index scan (in forward
- direction) using read_record.read_record() interface.
+ Initialize READ_RECORD structure to perform full index scan in desired
+ direction using read_record.read_record() interface
This function has been added at late stage and is used only by
UPDATE/DELETE. Other statements perform index scans using
@@ -50,10 +61,11 @@ static int rr_index(READ_RECORD *info);
@param print_error If true, call table->file->print_error() if an error
occurs (except for end-of-records error)
@param idx index to scan
+ @param reverse Scan in the reverse direction
*/
void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
- bool print_error, uint idx)
+ bool print_error, uint idx, bool reverse)
{
empty_record(table);
bzero((char*) info,sizeof(*info));
@@ -68,7 +80,7 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
if (!table->file->inited)
table->file->ha_index_init(idx, 1);
/* read_record will be changed to rr_index in rr_index_first */
- info->read_record= rr_index_first;
+ info->read_record= reverse ? rr_index_last : rr_index_first;
}
@@ -173,7 +185,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE &&
!table->sort.addon_field)
- VOID(table->file->extra(HA_EXTRA_MMAP));
+ (void) table->file->extra(HA_EXTRA_MMAP);
if (table->sort.addon_field)
{
@@ -270,11 +282,12 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
!(table->s->db_options_in_use & HA_OPTION_PACK_RECORD) ||
(use_record_cache < 0 &&
!(table->file->ha_table_flags() & HA_NOT_DELETE_WITH_CACHE))))
- VOID(table->file->extra_opt(HA_EXTRA_CACHE,
- thd->variables.read_buff_size));
+ (void) table->file->extra_opt(HA_EXTRA_CACHE,
+ thd->variables.read_buff_size);
}
/* Condition pushdown to storage engine */
- if (thd->variables.engine_condition_pushdown &&
+ if ((thd->variables.optimizer_switch &
+ OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN) &&
select && select->cond &&
(select->cond->used_tables() & table->map) &&
!table->file->pushed_cond)
@@ -289,7 +302,7 @@ void end_read_record(READ_RECORD *info)
{ /* free cache if used */
if (info->cache)
{
- my_free_lock((char*) info->cache,MYF(0));
+ my_free_lock(info->cache);
info->cache=0;
}
if (info->table)
@@ -364,6 +377,29 @@ static int rr_index_first(READ_RECORD *info)
/**
+ Reads last row in an index scan.
+
+ @param info Scan info
+
+ @retval
+ 0 Ok
+ @retval
+ -1 End of records
+ @retval
+ 1 Error
+*/
+
+static int rr_index_last(READ_RECORD *info)
+{
+ int tmp= info->file->index_last(info->record);
+ info->read_record= rr_index_desc;
+ if (tmp)
+ tmp= rr_handle_error(info, tmp);
+ return tmp;
+}
+
+
+/**
Reads index sequentially after first row.
Read the next index record (in forward direction) and translate return
@@ -388,6 +424,31 @@ static int rr_index(READ_RECORD *info)
}
+/**
+ Reads index sequentially from the last row to the first.
+
+ Read the prev index record (in backward direction) and translate return
+ value.
+
+ @param info Scan info
+
+ @retval
+ 0 Ok
+ @retval
+ -1 End of records
+ @retval
+ 1 Error
+*/
+
+static int rr_index_desc(READ_RECORD *info)
+{
+ int tmp= info->file->index_prev(info->record);
+ if (tmp)
+ tmp= rr_handle_error(info, tmp);
+ return tmp;
+}
+
+
int rr_sequential(READ_RECORD *info)
{
int tmp;
diff --git a/sql/records.h b/sql/records.h
new file mode 100644
index 00000000000..95464a11b4b
--- /dev/null
+++ b/sql/records.h
@@ -0,0 +1,79 @@
+#ifndef SQL_RECORDS_H
+#define SQL_RECORDS_H
+/* Copyright (C) 2008 Sun/MySQL
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+#include <my_global.h> /* for uint typedefs */
+
+struct st_join_table;
+class handler;
+struct TABLE;
+class THD;
+class SQL_SELECT;
+
+/**
+ A context for reading through a single table using a chosen access method:
+ index read, scan, etc, use of cache, etc.
+
+ Use by:
+ READ_RECORD read_record;
+ init_read_record(&read_record, ...);
+ while (read_record.read_record())
+ {
+ ...
+ }
+ end_read_record();
+*/
+
+struct READ_RECORD
+{
+ typedef int (*Read_func)(READ_RECORD*);
+ typedef void (*Unlock_row_func)(st_join_table *);
+ typedef int (*Setup_func)(struct st_join_table*);
+
+ TABLE *table; /* Head-form */
+ handler *file;
+ TABLE **forms; /* head and ref forms */
+ Unlock_row_func unlock_row;
+ Read_func read_record;
+ THD *thd;
+ SQL_SELECT *select;
+ uint cache_records;
+ uint ref_length,struct_length,reclength,rec_cache_size,error_offset;
+ uint index;
+ uchar *ref_pos; /* pointer to form->refpos */
+ uchar *record;
+ uchar *rec_buf; /* to read field values after filesort */
+ uchar *cache,*cache_pos,*cache_end,*read_positions;
+ struct st_io_cache *io_cache;
+ bool print_error, ignore_not_found_rows;
+
+public:
+ READ_RECORD() {}
+};
+
+void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
+ SQL_SELECT *select, int use_record_cache,
+ bool print_errors, bool disable_rr_cache);
+void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
+ bool print_error, uint idx, bool reverse);
+void end_read_record(READ_RECORD *info);
+
+void rr_unlock_row(st_join_table *tab);
+
+#endif /* SQL_RECORDS_H */
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index c25d43ea5ba..540b62b9d3b 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2006 MySQL AB & Sasha
+/* Copyright (C) 2001-2006 MySQL AB & Sasha, 2008-2009 Sun Microsystems, Inc
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
@@ -23,24 +23,27 @@
functions like register_slave()) are working.
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_parse.h" // check_access
#ifdef HAVE_REPLICATION
#include "repl_failsafe.h"
+#include "sql_acl.h" // REPL_SLAVE_ACL
#include "sql_repl.h"
#include "slave.h"
#include "rpl_mi.h"
#include "rpl_filter.h"
#include "log_event.h"
+#include "sql_db.h" // mysql_create_db
#include <mysql.h>
#define SLAVE_LIST_CHUNK 128
#define SLAVE_ERRMSG_SIZE (FN_REFLEN+64)
-RPL_STATUS rpl_status=RPL_NULL;
-pthread_mutex_t LOCK_rpl_status;
-pthread_cond_t COND_rpl_status;
+ulong rpl_status=RPL_NULL;
+mysql_mutex_t LOCK_rpl_status;
+mysql_cond_t COND_rpl_status;
HASH slave_list;
const char *rpl_role_type[] = {"MASTER","SLAVE",NullS};
@@ -49,12 +52,9 @@ TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"",
const char* rpl_status_type[]=
{
- "AUTH_MASTER","ACTIVE_SLAVE","IDLE_SLAVE", "LOST_SOLDIER","TROOP_SOLDIER",
+ "AUTH_MASTER","IDLE_SLAVE","ACTIVE_SLAVE","LOST_SOLDIER","TROOP_SOLDIER",
"RECOVERY_CAPTAIN","NULL",NullS
};
-TYPELIB rpl_status_typelib= {array_elements(rpl_status_type)-1,"",
- rpl_status_type, NULL};
-
static Slave_log_event* find_slave_event(IO_CACHE* log,
const char* log_file_name,
@@ -68,53 +68,13 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
functions like register_slave()) are working.
*/
-#if NOT_USED
-static int init_failsafe_rpl_thread(THD* thd)
+void change_rpl_status(ulong from_status, ulong to_status)
{
- DBUG_ENTER("init_failsafe_rpl_thread");
- thd->system_thread = SYSTEM_THREAD_DELAYED_INSERT;
- /*
- thd->bootstrap is to report errors barely to stderr; if this code is
- enable again one day, one should check if bootstrap is still needed (maybe
- this thread has no other error reporting method).
- */
- thd->bootstrap = 1;
- thd->security_ctx->skip_grants();
- my_net_init(&thd->net, 0);
- thd->net.read_timeout = slave_net_timeout;
- thd->max_client_packet_length=thd->net.max_packet;
- pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
- pthread_mutex_unlock(&LOCK_thread_count);
-
- if (init_thr_lock() || thd->store_globals())
- {
- /* purecov: begin inspected */
- close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed?
- statistic_increment(aborted_connects,&LOCK_status);
- one_thread_per_connection_end(thd,0);
- DBUG_RETURN(-1);
- /* purecov: end */
- }
-
- thd->mem_root->free= thd->mem_root->used= 0;
- if (thd->variables.max_join_size == HA_POS_ERROR)
- thd->options|= OPTION_BIG_SELECTS;
-
- thd_proc_info(thd, "Thread initialized");
- thd->version=refresh_version;
- thd->set_time();
- DBUG_RETURN(0);
-}
-#endif
-
-void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status)
-{
- pthread_mutex_lock(&LOCK_rpl_status);
+ mysql_mutex_lock(&LOCK_rpl_status);
if (rpl_status == from_status || rpl_status == RPL_ANY)
rpl_status = to_status;
- pthread_cond_signal(&COND_rpl_status);
- pthread_mutex_unlock(&LOCK_rpl_status);
+ mysql_cond_signal(&COND_rpl_status);
+ mysql_mutex_unlock(&LOCK_rpl_status);
}
@@ -143,16 +103,16 @@ void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
if (thd->server_id)
{
if (need_mutex)
- pthread_mutex_lock(&LOCK_slave_list);
+ mysql_mutex_lock(&LOCK_slave_list);
SLAVE_INFO* old_si;
- if ((old_si = (SLAVE_INFO*)hash_search(&slave_list,
- (uchar*)&thd->server_id, 4)) &&
+ if ((old_si = (SLAVE_INFO*)my_hash_search(&slave_list,
+ (uchar*)&thd->server_id, 4)) &&
(!only_mine || old_si->thd == thd))
- hash_delete(&slave_list, (uchar*)old_si);
+ my_hash_delete(&slave_list, (uchar*)old_si);
if (need_mutex)
- pthread_mutex_unlock(&LOCK_slave_list);
+ mysql_mutex_unlock(&LOCK_slave_list);
}
}
@@ -173,7 +133,7 @@ int register_slave(THD* thd, uchar* packet, uint packet_length)
uchar *p= packet, *p_end= packet + packet_length;
const char *errmsg= "Wrong parameters to function register_slave";
- if (check_access(thd, REPL_SLAVE_ACL, any_db,0,0,0,0))
+ if (check_access(thd, REPL_SLAVE_ACL, any_db, NULL, NULL, 0, 0))
return 1;
if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
goto err2;
@@ -187,20 +147,26 @@ int register_slave(THD* thd, uchar* packet, uint packet_length)
goto err;
si->port= uint2korr(p);
p += 2;
- si->rpl_recovery_rank= uint4korr(p);
+ /*
+ We need to by pass the bytes used in the fake rpl_recovery_rank
+ variable. It was removed in patch for BUG#13963. But this would
+ make a server with that patch unable to connect to an old master.
+ See: BUG#49259
+ */
+ // si->rpl_recovery_rank= uint4korr(p);
p += 4;
if (!(si->master_id= uint4korr(p)))
si->master_id= server_id;
si->thd= thd;
- pthread_mutex_lock(&LOCK_slave_list);
+ mysql_mutex_lock(&LOCK_slave_list);
unregister_slave(thd,0,0);
res= my_hash_insert(&slave_list, (uchar*) si);
- pthread_mutex_unlock(&LOCK_slave_list);
+ mysql_mutex_unlock(&LOCK_slave_list);
return res;
err:
- my_free(si, MYF(MY_WME));
+ my_free(si);
my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); /* purecov: inspected */
err2:
return 1;
@@ -216,23 +182,49 @@ extern "C" uint32
extern "C" void slave_info_free(void *s)
{
- my_free(s, MYF(MY_WME));
+ my_free(s);
}
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_LOCK_slave_list;
+
+static PSI_mutex_info all_slave_list_mutexes[]=
+{
+ { &key_LOCK_slave_list, "LOCK_slave_list", PSI_FLAG_GLOBAL}
+};
+
+static void init_all_slave_list_mutexes(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_slave_list_mutexes);
+ PSI_server->register_mutex(category, all_slave_list_mutexes, count);
+}
+#endif /* HAVE_PSI_INTERFACE */
+
void init_slave_list()
{
- hash_init(&slave_list, system_charset_info, SLAVE_LIST_CHUNK, 0, 0,
- (hash_get_key) slave_list_key, (hash_free_key) slave_info_free, 0);
- pthread_mutex_init(&LOCK_slave_list, MY_MUTEX_INIT_FAST);
+#ifdef HAVE_PSI_INTERFACE
+ init_all_slave_list_mutexes();
+#endif
+
+ my_hash_init(&slave_list, system_charset_info, SLAVE_LIST_CHUNK, 0, 0,
+ (my_hash_get_key) slave_list_key,
+ (my_hash_free_key) slave_info_free, 0);
+ mysql_mutex_init(key_LOCK_slave_list, &LOCK_slave_list, MY_MUTEX_INIT_FAST);
}
void end_slave_list()
{
/* No protection by a mutex needed as we are only called at shutdown */
- if (hash_inited(&slave_list))
+ if (my_hash_inited(&slave_list))
{
- hash_free(&slave_list);
- pthread_mutex_destroy(&LOCK_slave_list);
+ my_hash_free(&slave_list);
+ mysql_mutex_destroy(&LOCK_slave_list);
}
}
@@ -244,7 +236,7 @@ static int find_target_pos(LEX_MASTER_INFO *mi, IO_CACHE *log, char *errmsg)
for (;;)
{
Log_event* ev;
- if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*) 0, 0)))
+ if (!(ev= Log_event::read_log_event(log, (mysql_mutex_t*) 0, 0)))
{
if (log->error > 0)
strmov(errmsg, "Binary log truncated in the middle of event");
@@ -286,7 +278,7 @@ int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
char last_log_name[FN_REFLEN];
IO_CACHE log;
File file = -1, last_file = -1;
- pthread_mutex_t *log_lock;
+ mysql_mutex_t *log_lock;
const char* errmsg_p;
Slave_log_event* sev = 0;
my_off_t last_pos = 0;
@@ -316,7 +308,7 @@ int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
bzero((char*) &log,sizeof(log));
log_lock = mysql_bin_log.get_log_lock();
- pthread_mutex_lock(log_lock);
+ mysql_mutex_lock(log_lock);
for (;;)
{
@@ -348,7 +340,7 @@ int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
goto err;
}
end_io_cache(&log);
- (void) my_close(file, MYF(MY_WME));
+ mysql_file_close(file, MYF(MY_WME));
if (init_io_cache(&log, (file = last_file), IO_SIZE, READ_CACHE, 0, 0,
MYF(MY_WME)))
{
@@ -364,7 +356,7 @@ int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
switch (mysql_bin_log.find_next_log(&linfo, 1)) {
case LOG_INFO_EOF:
if (last_file >= 0)
- (void)my_close(last_file, MYF(MY_WME));
+ mysql_file_close(last_file, MYF(MY_WME));
last_file = -1;
goto found_log;
case 0:
@@ -376,7 +368,7 @@ int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
end_io_cache(&log);
if (last_file >= 0)
- (void) my_close(last_file, MYF(MY_WME));
+ mysql_file_close(last_file, MYF(MY_WME));
last_file = file;
}
@@ -389,15 +381,15 @@ found_log:
mi_inited:
error = 0;
err:
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
end_io_cache(&log);
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
if (file >= 0)
- (void) my_close(file, MYF(MY_WME));
+ mysql_file_close(file, MYF(MY_WME));
if (last_file >= 0 && last_file != file)
- (void) my_close(last_file, MYF(MY_WME));
+ mysql_file_close(last_file, MYF(MY_WME));
DBUG_RETURN(error);
}
@@ -418,7 +410,7 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
for (i = 0; i < 2; i++)
{
- if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*)0, 0)))
+ if (!(ev= Log_event::read_log_event(log, (mysql_mutex_t*)0, 0)))
{
my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
"Error reading event in log '%s'",
@@ -470,7 +462,7 @@ bool show_new_master(THD* thd)
field_list.push_back(new Item_empty_string("Log_name", 20));
field_list.push_back(new Item_return_int("Log_pos", 10,
MYSQL_TYPE_LONGLONG));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
protocol->prepare_for_resend();
@@ -540,29 +532,29 @@ HOSTS";
goto err;
}
- pthread_mutex_lock(&LOCK_slave_list);
+ mysql_mutex_lock(&LOCK_slave_list);
while ((row= mysql_fetch_row(res)))
{
uint32 log_server_id;
SLAVE_INFO* si, *old_si;
log_server_id = atoi(row[0]);
- if ((old_si= (SLAVE_INFO*)hash_search(&slave_list,
- (uchar*)&log_server_id,4)))
+ if ((old_si= (SLAVE_INFO*)my_hash_search(&slave_list,
+ (uchar*)&log_server_id,4)))
si = old_si;
else
{
if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
{
error= "the slave is out of memory";
- pthread_mutex_unlock(&LOCK_slave_list);
+ mysql_mutex_unlock(&LOCK_slave_list);
goto err;
}
si->server_id = log_server_id;
if (my_hash_insert(&slave_list, (uchar*)si))
{
error= "the slave is out of memory";
- pthread_mutex_unlock(&LOCK_slave_list);
+ mysql_mutex_unlock(&LOCK_slave_list);
goto err;
}
}
@@ -576,7 +568,7 @@ HOSTS";
strmake(si->password, row[3], sizeof(si->password)-1);
}
}
- pthread_mutex_unlock(&LOCK_slave_list);
+ mysql_mutex_unlock(&LOCK_slave_list);
err:
if (res)
@@ -592,66 +584,6 @@ err:
}
-#if NOT_USED
-int find_recovery_captain(THD* thd, MYSQL* mysql)
-{
- return 0;
-}
-#endif
-
-#if NOT_USED
-pthread_handler_t handle_failsafe_rpl(void *arg)
-{
- DBUG_ENTER("handle_failsafe_rpl");
- THD *thd = new THD;
- thd->thread_stack = (char*)&thd;
- MYSQL* recovery_captain = 0;
- const char* msg;
-
- pthread_detach_this_thread();
- if (init_failsafe_rpl_thread(thd) || !(recovery_captain=mysql_init(0)))
- {
- sql_print_error("Could not initialize failsafe replication thread");
- goto err;
- }
- pthread_mutex_lock(&LOCK_rpl_status);
- msg= thd->enter_cond(&COND_rpl_status,
- &LOCK_rpl_status, "Waiting for request");
- while (!thd->killed && !abort_loop)
- {
- bool break_req_chain = 0;
- pthread_cond_wait(&COND_rpl_status, &LOCK_rpl_status);
- thd_proc_info(thd, "Processing request");
- while (!break_req_chain)
- {
- switch (rpl_status) {
- case RPL_LOST_SOLDIER:
- if (find_recovery_captain(thd, recovery_captain))
- rpl_status=RPL_TROOP_SOLDIER;
- else
- rpl_status=RPL_RECOVERY_CAPTAIN;
- break_req_chain=1; /* for now until other states are implemented */
- break;
- default:
- break_req_chain=1;
- break;
- }
- }
- }
- thd->exit_cond(msg);
-err:
- if (recovery_captain)
- mysql_close(recovery_captain);
- delete thd;
-
- DBUG_LEAVE; // Must match DBUG_ENTER()
- my_thread_end();
- pthread_exit(0);
- return 0; // Avoid compiler warnings
-}
-#endif
-
-
/**
Execute a SHOW SLAVE HOSTS statement.
@@ -676,20 +608,18 @@ bool show_slave_hosts(THD* thd)
field_list.push_back(new Item_empty_string("Password",20));
}
field_list.push_back(new Item_return_int("Port", 7, MYSQL_TYPE_LONG));
- field_list.push_back(new Item_return_int("Rpl_recovery_rank", 7,
- MYSQL_TYPE_LONG));
field_list.push_back(new Item_return_int("Master_id", 10,
MYSQL_TYPE_LONG));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
- pthread_mutex_lock(&LOCK_slave_list);
+ mysql_mutex_lock(&LOCK_slave_list);
for (uint i = 0; i < slave_list.records; ++i)
{
- SLAVE_INFO* si = (SLAVE_INFO*) hash_element(&slave_list, i);
+ SLAVE_INFO* si = (SLAVE_INFO*) my_hash_element(&slave_list, i);
protocol->prepare_for_resend();
protocol->store((uint32) si->server_id);
protocol->store(si->host, &my_charset_bin);
@@ -699,342 +629,17 @@ bool show_slave_hosts(THD* thd)
protocol->store(si->password, &my_charset_bin);
}
protocol->store((uint32) si->port);
- protocol->store((uint32) si->rpl_recovery_rank);
protocol->store((uint32) si->master_id);
if (protocol->write())
{
- pthread_mutex_unlock(&LOCK_slave_list);
+ mysql_mutex_unlock(&LOCK_slave_list);
DBUG_RETURN(TRUE);
}
}
- pthread_mutex_unlock(&LOCK_slave_list);
+ mysql_mutex_unlock(&LOCK_slave_list);
my_eof(thd);
DBUG_RETURN(FALSE);
}
-
-int connect_to_master(THD *thd, MYSQL* mysql, Master_info* mi)
-{
- DBUG_ENTER("connect_to_master");
-
- if (!mi->host || !*mi->host) /* empty host */
- {
- strmov(mysql->net.last_error, "Master is not configured");
- DBUG_RETURN(1);
- }
- mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
- mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout);
-
-#ifdef HAVE_OPENSSL
- if (mi->ssl)
- {
- mysql_ssl_set(mysql,
- mi->ssl_key[0]?mi->ssl_key:0,
- mi->ssl_cert[0]?mi->ssl_cert:0,
- mi->ssl_ca[0]?mi->ssl_ca:0,
- mi->ssl_capath[0]?mi->ssl_capath:0,
- mi->ssl_cipher[0]?mi->ssl_cipher:0);
- mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
- &mi->ssl_verify_server_cert);
- }
-#endif
-
- mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname);
- mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir);
- if (!mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0,
- mi->port, 0, 0))
- DBUG_RETURN(1);
- mysql->reconnect= 1;
- DBUG_RETURN(0);
-}
-
-
-static inline void cleanup_mysql_results(MYSQL_RES* db_res,
- MYSQL_RES** cur, MYSQL_RES** start)
-{
- for (; cur >= start; --cur)
- {
- if (*cur)
- mysql_free_result(*cur);
- }
- mysql_free_result(db_res);
-}
-
-
-static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db,
- MYSQL_RES *table_res, Master_info *mi)
-{
- MYSQL_ROW row;
- for (row = mysql_fetch_row(table_res); row;
- row = mysql_fetch_row(table_res))
- {
- TABLE_LIST table;
- const char* table_name= row[0];
- int error;
- if (rpl_filter->is_on())
- {
- bzero((char*) &table, sizeof(table)); //just for safe
- table.db= (char*) db;
- table.table_name= (char*) table_name;
- table.updating= 1;
-
- if (!rpl_filter->tables_ok(thd->db, &table))
- continue;
- }
- /* download master's table and overwrite slave's table */
- if ((error= fetch_master_table(thd, db, table_name, mi, mysql, 1)))
- return error;
- }
- return 0;
-}
-
-/**
- Load all MyISAM tables from master to this slave.
-
- REQUIREMENTS
- - No active transaction (flush_relay_log_info would not work in this case).
-
- @todo
- - add special option, not enabled
- by default, to allow inclusion of mysql database into load
- data from master
-*/
-
-bool load_master_data(THD* thd)
-{
- MYSQL mysql;
- MYSQL_RES* master_status_res = 0;
- int error = 0;
- const char* errmsg=0;
- int restart_thread_mask;
- HA_CREATE_INFO create_info;
-
- mysql_init(&mysql);
-
- /*
- We do not want anyone messing with the slave at all for the entire
- duration of the data load.
- */
- pthread_mutex_lock(&LOCK_active_mi);
- lock_slave_threads(active_mi);
- init_thread_mask(&restart_thread_mask,active_mi,0 /*not inverse*/);
- if (restart_thread_mask &&
- (error=terminate_slave_threads(active_mi,restart_thread_mask,
- 1 /*skip lock*/)))
- {
- my_message(error, ER(error), MYF(0));
- unlock_slave_threads(active_mi);
- pthread_mutex_unlock(&LOCK_active_mi);
- return TRUE;
- }
-
- if (connect_to_master(thd, &mysql, active_mi))
- {
- my_error(error= ER_CONNECT_TO_MASTER, MYF(0), mysql_error(&mysql));
- goto err;
- }
-
- // now that we are connected, get all database and tables in each
- {
- MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res;
- uint num_dbs;
-
- if (mysql_real_query(&mysql, STRING_WITH_LEN("SHOW DATABASES")) ||
- !(db_res = mysql_store_result(&mysql)))
- {
- my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
- goto err;
- }
-
- if (!(num_dbs = (uint) mysql_num_rows(db_res)))
- goto err;
- /*
- In theory, the master could have no databases at all
- and run with skip-grant
- */
-
- if (!(table_res = (MYSQL_RES**)thd->alloc(num_dbs * sizeof(MYSQL_RES*))))
- {
- my_message(error = ER_OUTOFMEMORY, ER(ER_OUTOFMEMORY), MYF(0));
- goto err;
- }
-
- /*
- This is a temporary solution until we have online backup
- capabilities - to be replaced once online backup is working
- we wait to issue FLUSH TABLES WITH READ LOCK for as long as we
- can to minimize the lock time.
- */
- if (mysql_real_query(&mysql,
- STRING_WITH_LEN("FLUSH TABLES WITH READ LOCK")) ||
- mysql_real_query(&mysql, STRING_WITH_LEN("SHOW MASTER STATUS")) ||
- !(master_status_res = mysql_store_result(&mysql)))
- {
- my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
- goto err;
- }
-
- /*
- Go through every table in every database, and if the replication
- rules allow replicating it, get it
- */
-
- table_res_end = table_res + num_dbs;
-
- for (cur_table_res = table_res; cur_table_res < table_res_end;
- cur_table_res++)
- {
- // since we know how many rows we have, this can never be NULL
- MYSQL_ROW row = mysql_fetch_row(db_res);
- char* db = row[0];
-
- /*
- Do not replicate databases excluded by rules. We also test
- replicate_wild_*_table rules (replicate_wild_ignore_table='db1.%' will
- be considered as "ignore the 'db1' database as a whole, as it already
- works for CREATE DATABASE and DROP DATABASE).
- Also skip 'mysql' database - in most cases the user will
- mess up and not exclude mysql database with the rules when
- he actually means to - in this case, he is up for a surprise if
- his priv tables get dropped and downloaded from master
- TODO - add special option, not enabled
- by default, to allow inclusion of mysql database into load
- data from master
- */
-
- if (!rpl_filter->db_ok(db) ||
- !rpl_filter->db_ok_with_wild_table(db) ||
- !strcmp(db,"mysql") ||
- is_schema_db(db))
- {
- *cur_table_res = 0;
- continue;
- }
-
- bzero((char*) &create_info, sizeof(create_info));
- create_info.options= HA_LEX_CREATE_IF_NOT_EXISTS;
-
- if (mysql_create_db(thd, db, &create_info, 1))
- {
- cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
- goto err;
- }
- /* Clear the result of mysql_create_db(). */
- thd->main_da.reset_diagnostics_area();
-
- if (mysql_select_db(&mysql, db) ||
- mysql_real_query(&mysql, STRING_WITH_LEN("SHOW TABLES")) ||
- !(*cur_table_res = mysql_store_result(&mysql)))
- {
- my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
- cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
- goto err;
- }
-
- if ((error = fetch_db_tables(thd,&mysql,db,*cur_table_res,active_mi)))
- {
- // we do not report the error - fetch_db_tables handles it
- cleanup_mysql_results(db_res, cur_table_res, table_res);
- goto err;
- }
- }
-
- cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
-
- // adjust replication coordinates from the master
- if (master_status_res)
- {
- MYSQL_ROW row = mysql_fetch_row(master_status_res);
-
- /*
- We need this check because the master may not be running with
- log-bin, but it will still allow us to do all the steps
- of LOAD DATA FROM MASTER - no reason to forbid it, really,
- although it does not make much sense for the user to do it
- */
- if (row && row[0] && row[1])
- {
- /*
- If the slave's master info is not inited, we init it, then we write
- the new coordinates to it. Must call init_master_info() *before*
- setting active_mi, because init_master_info() sets active_mi with
- defaults.
- */
- int error_2;
-
- if (init_master_info(active_mi, master_info_file, relay_log_info_file,
- 0, (SLAVE_IO | SLAVE_SQL)))
- my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
- strmake(active_mi->master_log_name, row[0],
- sizeof(active_mi->master_log_name) -1);
- active_mi->master_log_pos= my_strtoll10(row[1], (char**) 0, &error_2);
- /* at least in recent versions, the condition below should be false */
- if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE)
- active_mi->master_log_pos = BIN_LOG_HEADER_SIZE;
- /*
- Relay log's IO_CACHE may not be inited (even if we are sure that some
- host was specified; there could have been a problem when replication
- started, which led to relay log's IO_CACHE to not be inited.
- */
- if (flush_master_info(active_mi, FALSE, FALSE))
- sql_print_error("Failed to flush master info file");
- }
- mysql_free_result(master_status_res);
- }
-
- if (mysql_real_query(&mysql, STRING_WITH_LEN("UNLOCK TABLES")))
- {
- my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
- goto err;
- }
- }
- thd_proc_info(thd, "purging old relay logs");
- if (purge_relay_logs(&active_mi->rli,thd,
- 0 /* not only reset, but also reinit */,
- &errmsg))
- {
- my_error(ER_RELAY_LOG_FAIL, MYF(0), errmsg);
- unlock_slave_threads(active_mi);
- pthread_mutex_unlock(&LOCK_active_mi);
- return TRUE;
- }
- pthread_mutex_lock(&active_mi->rli.data_lock);
- active_mi->rli.group_master_log_pos = active_mi->master_log_pos;
- strmake(active_mi->rli.group_master_log_name,active_mi->master_log_name,
- sizeof(active_mi->rli.group_master_log_name)-1);
- /*
- Cancel the previous START SLAVE UNTIL, as the fact to download
- a new copy logically makes UNTIL irrelevant.
- */
- active_mi->rli.clear_until_condition();
-
- /*
- No need to update rli.event* coordinates, they will be when the slave
- threads start ; only rli.group* coordinates are necessary here.
- */
- flush_relay_log_info(&active_mi->rli);
- pthread_cond_broadcast(&active_mi->rli.data_cond);
- pthread_mutex_unlock(&active_mi->rli.data_lock);
- thd_proc_info(thd, "starting slave");
- if (restart_thread_mask)
- {
- error=start_slave_threads(0 /* mutex not needed */,
- 1 /* wait for start */,
- active_mi,master_info_file,relay_log_info_file,
- restart_thread_mask);
- }
-
-err:
- unlock_slave_threads(active_mi);
- pthread_mutex_unlock(&LOCK_active_mi);
- thd_proc_info(thd, 0);
-
- mysql_close(&mysql); // safe to call since we always do mysql_init()
- if (!error)
- my_ok(thd);
-
- return error;
-}
-
#endif /* HAVE_REPLICATION */
diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h
index 6ff78067aca..a0c41686696 100644
--- a/sql/repl_failsafe.h
+++ b/sql/repl_failsafe.h
@@ -1,4 +1,7 @@
-/* Copyright (C) 2001-2005 MySQL AB & Sasha
+#ifndef REPL_FAILSAFE_INCLUDED
+#define REPL_FAILSAFE_INCLUDED
+
+/* Copyright (C) 2001-2005 MySQL AB & Sasha, 2008-2009 Sun Microsystems, Inc
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
@@ -19,19 +22,19 @@
#include "my_sys.h"
#include "slave.h"
-typedef enum {RPL_AUTH_MASTER=0,RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE,
+typedef enum {RPL_AUTH_MASTER=0,RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE,
RPL_LOST_SOLDIER,RPL_TROOP_SOLDIER,
RPL_RECOVERY_CAPTAIN,RPL_NULL /* inactive */,
RPL_ANY /* wild card used by change_rpl_status */ } RPL_STATUS;
-extern RPL_STATUS rpl_status;
+extern ulong rpl_status;
-extern pthread_mutex_t LOCK_rpl_status;
-extern pthread_cond_t COND_rpl_status;
-extern TYPELIB rpl_role_typelib, rpl_status_typelib;
+extern mysql_mutex_t LOCK_rpl_status;
+extern mysql_cond_t COND_rpl_status;
+extern TYPELIB rpl_role_typelib;
extern const char* rpl_role_type[], *rpl_status_type[];
pthread_handler_t handle_failsafe_rpl(void *arg);
-void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status);
+void change_rpl_status(ulong from_status, ulong to_status);
int find_recovery_captain(THD* thd, MYSQL* mysql);
int update_slave_list(MYSQL* mysql, Master_info* mi);
@@ -49,3 +52,4 @@ int register_slave(THD* thd, uchar* packet, uint packet_length);
void unregister_slave(THD* thd, bool only_mine, bool need_mutex);
#endif /* HAVE_REPLICATION */
+#endif /* REPL_FAILSAFE_INCLUDED */
diff --git a/sql/replication.h b/sql/replication.h
new file mode 100644
index 00000000000..1c83025e1d6
--- /dev/null
+++ b/sql/replication.h
@@ -0,0 +1,552 @@
+/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef REPLICATION_H
+#define REPLICATION_H
+
+#include <mysql.h>
+
+typedef struct st_mysql MYSQL;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Transaction observer flags.
+*/
+enum Trans_flags {
+ /** Transaction is a real transaction */
+ TRANS_IS_REAL_TRANS = 1
+};
+
+/**
+ Transaction observer parameter
+*/
+typedef struct Trans_param {
+ uint32 server_id;
+ uint32 flags;
+
+ /*
+ The latest binary log file name and position written by current
+ transaction, if binary log is disabled or no log event has been
+ written into binary log file by current transaction (events
+ written into transaction log cache are not counted), these two
+ member will be zero.
+ */
+ const char *log_file;
+ my_off_t log_pos;
+} Trans_param;
+
+/**
+ Observes and extends transaction execution
+*/
+typedef struct Trans_observer {
+ uint32 len;
+
+ /**
+ This callback is called after transaction commit
+
+ This callback is called right after commit to storage engines for
+ transactional tables.
+
+ For non-transactional tables, this is called at the end of the
+ statement, before sending statement status, if the statement
+ succeeded.
+
+ @note The return value is currently ignored by the server.
+
+ @param param The parameter for transaction observers
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*after_commit)(Trans_param *param);
+
+ /**
+ This callback is called after transaction rollback
+
+ This callback is called right after rollback to storage engines
+ for transactional tables.
+
+ For non-transactional tables, this is called at the end of the
+ statement, before sending statement status, if the statement
+ failed.
+
+ @note The return value is currently ignored by the server.
+
+ @param param The parameter for transaction observers
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*after_rollback)(Trans_param *param);
+} Trans_observer;
+
+/**
+ Binlog storage flags
+*/
+enum Binlog_storage_flags {
+ /** Binary log was sync:ed */
+ BINLOG_STORAGE_IS_SYNCED = 1
+};
+
+/**
+ Binlog storage observer parameters
+ */
+typedef struct Binlog_storage_param {
+ uint32 server_id;
+} Binlog_storage_param;
+
+/**
+ Observe binlog logging storage
+*/
+typedef struct Binlog_storage_observer {
+ uint32 len;
+
+ /**
+ This callback is called after binlog has been flushed
+
+ This callback is called after cached events have been flushed to
+ binary log file. Whether the binary log file is synchronized to
+ disk is indicated by the bit BINLOG_STORAGE_IS_SYNCED in @a flags.
+
+ @param param Observer common parameter
+ @param log_file Binlog file name been updated
+ @param log_pos Binlog position after update
+ @param flags flags for binlog storage
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*after_flush)(Binlog_storage_param *param,
+ const char *log_file, my_off_t log_pos,
+ uint32 flags);
+} Binlog_storage_observer;
+
+/**
+ Replication binlog transmitter (binlog dump) observer parameter.
+*/
+typedef struct Binlog_transmit_param {
+ uint32 server_id;
+ uint32 flags;
+} Binlog_transmit_param;
+
+/**
+ Observe and extends the binlog dumping thread.
+*/
+typedef struct Binlog_transmit_observer {
+ uint32 len;
+
+ /**
+ This callback is called when binlog dumping starts
+
+
+ @param param Observer common parameter
+ @param log_file Binlog file name to transmit from
+ @param log_pos Binlog position to transmit from
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*transmit_start)(Binlog_transmit_param *param,
+ const char *log_file, my_off_t log_pos);
+
+ /**
+ This callback is called when binlog dumping stops
+
+ @param param Observer common parameter
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*transmit_stop)(Binlog_transmit_param *param);
+
+ /**
+ This callback is called to reserve bytes in packet header for event transmission
+
+ This callback is called when resetting transmit packet header to
+ reserve bytes for this observer in packet header.
+
+ The @a header buffer is allocated by the server code, and @a size
+ is the size of the header buffer. Each observer can only reserve
+ a maximum size of @a size in the header.
+
+ @param param Observer common parameter
+ @param header Pointer of the header buffer
+ @param size Size of the header buffer
+ @param len Header length reserved by this observer
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*reserve_header)(Binlog_transmit_param *param,
+ unsigned char *header,
+ unsigned long size,
+ unsigned long *len);
+
+ /**
+ This callback is called before sending an event packet to slave
+
+ @param param Observer common parameter
+ @param packet Binlog event packet to send
+ @param len Length of the event packet
+ @param log_file Binlog file name of the event packet to send
+ @param log_pos Binlog position of the event packet to send
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*before_send_event)(Binlog_transmit_param *param,
+ unsigned char *packet, unsigned long len,
+ const char *log_file, my_off_t log_pos );
+
+ /**
+ This callback is called after sending an event packet to slave
+
+ @param param Observer common parameter
+ @param event_buf Binlog event packet buffer sent
+ @param len length of the event packet buffer
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*after_send_event)(Binlog_transmit_param *param,
+ const char *event_buf, unsigned long len);
+
+ /**
+ This callback is called after resetting master status
+
+ This is called when executing the command RESET MASTER, and is
+ used to reset status variables added by observers.
+
+ @param param Observer common parameter
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*after_reset_master)(Binlog_transmit_param *param);
+} Binlog_transmit_observer;
+
+/**
+ Binlog relay IO flags
+*/
+enum Binlog_relay_IO_flags {
+ /** Binary relay log was sync:ed */
+ BINLOG_RELAY_IS_SYNCED = 1
+};
+
+
+/**
+ Replication binlog relay IO observer parameter
+*/
+typedef struct Binlog_relay_IO_param {
+ uint32 server_id;
+
+ /* Master host, user and port */
+ char *host;
+ char *user;
+ unsigned int port;
+
+ char *master_log_name;
+ my_off_t master_log_pos;
+
+ MYSQL *mysql; /* the connection to master */
+} Binlog_relay_IO_param;
+
+/**
+ Observes and extends the service of slave IO thread.
+*/
+typedef struct Binlog_relay_IO_observer {
+ uint32 len;
+
+ /**
+ This callback is called when slave IO thread starts
+
+ @param param Observer common parameter
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*thread_start)(Binlog_relay_IO_param *param);
+
+ /**
+ This callback is called when slave IO thread stops
+
+ @param param Observer common parameter
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*thread_stop)(Binlog_relay_IO_param *param);
+
+ /**
+ This callback is called before slave requesting binlog transmission from master
+
+ This is called before slave issuing BINLOG_DUMP command to master
+ to request binlog.
+
+ @param param Observer common parameter
+ @param flags binlog dump flags
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*before_request_transmit)(Binlog_relay_IO_param *param, uint32 flags);
+
+ /**
+ This callback is called after read an event packet from master
+
+ @param param Observer common parameter
+ @param packet The event packet read from master
+ @param len Length of the event packet read from master
+ @param event_buf The event packet return after process
+ @param event_len The length of event packet return after process
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*after_read_event)(Binlog_relay_IO_param *param,
+ const char *packet, unsigned long len,
+ const char **event_buf, unsigned long *event_len);
+
+ /**
+ This callback is called after written an event packet to relay log
+
+ @param param Observer common parameter
+ @param event_buf Event packet written to relay log
+ @param event_len Length of the event packet written to relay log
+ @param flags flags for relay log
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*after_queue_event)(Binlog_relay_IO_param *param,
+ const char *event_buf, unsigned long event_len,
+ uint32 flags);
+
+ /**
+ This callback is called after reset slave relay log IO status
+
+ @param param Observer common parameter
+
+ @retval 0 Sucess
+ @retval 1 Failure
+ */
+ int (*after_reset_slave)(Binlog_relay_IO_param *param);
+} Binlog_relay_IO_observer;
+
+
+/**
+ Register a transaction observer
+
+ @param observer The transaction observer to register
+ @param p pointer to the internal plugin structure
+
+ @retval 0 Sucess
+ @retval 1 Observer already exists
+*/
+int register_trans_observer(Trans_observer *observer, void *p);
+
+/**
+ Unregister a transaction observer
+
+ @param observer The transaction observer to unregister
+ @param p pointer to the internal plugin structure
+
+ @retval 0 Sucess
+ @retval 1 Observer not exists
+*/
+int unregister_trans_observer(Trans_observer *observer, void *p);
+
+/**
+ Register a binlog storage observer
+
+ @param observer The binlog storage observer to register
+ @param p pointer to the internal plugin structure
+
+ @retval 0 Sucess
+ @retval 1 Observer already exists
+*/
+int register_binlog_storage_observer(Binlog_storage_observer *observer, void *p);
+
+/**
+ Unregister a binlog storage observer
+
+ @param observer The binlog storage observer to unregister
+ @param p pointer to the internal plugin structure
+
+ @retval 0 Sucess
+ @retval 1 Observer not exists
+*/
+int unregister_binlog_storage_observer(Binlog_storage_observer *observer, void *p);
+
+/**
+ Register a binlog transmit observer
+
+ @param observer The binlog transmit observer to register
+ @param p pointer to the internal plugin structure
+
+ @retval 0 Sucess
+ @retval 1 Observer already exists
+*/
+int register_binlog_transmit_observer(Binlog_transmit_observer *observer, void *p);
+
+/**
+ Unregister a binlog transmit observer
+
+ @param observer The binlog transmit observer to unregister
+ @param p pointer to the internal plugin structure
+
+ @retval 0 Sucess
+ @retval 1 Observer not exists
+*/
+int unregister_binlog_transmit_observer(Binlog_transmit_observer *observer, void *p);
+
+/**
+ Register a binlog relay IO (slave IO thread) observer
+
+ @param observer The binlog relay IO observer to register
+ @param p pointer to the internal plugin structure
+
+ @retval 0 Sucess
+ @retval 1 Observer already exists
+*/
+int register_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void *p);
+
+/**
+ Unregister a binlog relay IO (slave IO thread) observer
+
+ @param observer The binlog relay IO observer to unregister
+ @param p pointer to the internal plugin structure
+
+ @retval 0 Sucess
+ @retval 1 Observer not exists
+*/
+int unregister_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void *p);
+
+/**
+ Connect to master
+
+ This function can only used in the slave I/O thread context, and
+ will use the same master information to do the connection.
+
+ @code
+ MYSQL *mysql = mysql_init(NULL);
+ if (rpl_connect_master(mysql))
+ {
+ // do stuff with the connection
+ }
+ mysql_close(mysql); // close the connection
+ @endcode
+
+ @param mysql address of MYSQL structure to use, pass NULL will
+ create a new one
+
+ @return address of MYSQL structure on success, NULL on failure
+*/
+MYSQL *rpl_connect_master(MYSQL *mysql);
+
+/**
+ Set thread entering a condition
+
+ This function should be called before putting a thread to wait for
+ a condition. @a mutex should be held before calling this
+ function. After being waken up, @f thd_exit_cond should be called.
+
+ @param thd The thread entering the condition, NULL means current thread
+ @param cond The condition the thread is going to wait for
+ @param mutex The mutex associated with the condition, this must be
+ held before call this function
+ @param msg The new process message for the thread
+*/
+const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond,
+ mysql_mutex_t *mutex, const char *msg);
+
+/**
+ Set thread leaving a condition
+
+ This function should be called after a thread being waken up for a
+ condition.
+
+ @param thd The thread entering the condition, NULL means current thread
+ @param old_msg The process message, ususally this should be the old process
+ message before calling @f thd_enter_cond
+*/
+void thd_exit_cond(MYSQL_THD thd, const char *old_msg);
+
+/**
+ Get the value of user variable as an integer.
+
+ This function will return the value of variable @a name as an
+ integer. If the original value of the variable is not an integer,
+ the value will be converted into an integer.
+
+ @param name user variable name
+ @param value pointer to return the value
+ @param null_value if not NULL, the function will set it to true if
+ the value of variable is null, set to false if not
+
+ @retval 0 Success
+ @retval 1 Variable not found
+*/
+int get_user_var_int(const char *name,
+ long long int *value, int *null_value);
+
+/**
+ Get the value of user variable as a double precision float number.
+
+ This function will return the value of variable @a name as real
+ number. If the original value of the variable is not a real number,
+ the value will be converted into a real number.
+
+ @param name user variable name
+ @param value pointer to return the value
+ @param null_value if not NULL, the function will set it to true if
+ the value of variable is null, set to false if not
+
+ @retval 0 Success
+ @retval 1 Variable not found
+*/
+int get_user_var_real(const char *name,
+ double *value, int *null_value);
+
+/**
+ Get the value of user variable as a string.
+
+ This function will return the value of variable @a name as
+ string. If the original value of the variable is not a string,
+ the value will be converted into a string.
+
+ @param name user variable name
+ @param value pointer to the value buffer
+ @param len length of the value buffer
+ @param precision precision of the value if it is a float number
+ @param null_value if not NULL, the function will set it to true if
+ the value of variable is null, set to false if not
+
+ @retval 0 Success
+ @retval 1 Variable not found
+*/
+int get_user_var_str(const char *name,
+ char *value, unsigned long len,
+ unsigned int precision, int *null_value);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* REPLICATION_H */
diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc
index 68272c58bb1..42a9a034efd 100644
--- a/sql/rpl_filter.cc
+++ b/sql/rpl_filter.cc
@@ -13,8 +13,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED by other includes
#include "rpl_filter.h"
+#include "hash.h" // my_hash_free
+#include "table.h" // TABLE_LIST
#define TABLE_RULE_HASH_SIZE 16
#define TABLE_RULE_ARR_SIZE 16
@@ -32,9 +35,9 @@ Rpl_filter::Rpl_filter() :
Rpl_filter::~Rpl_filter()
{
if (do_table_inited)
- hash_free(&do_table);
+ my_hash_free(&do_table);
if (ignore_table_inited)
- hash_free(&ignore_table);
+ my_hash_free(&ignore_table);
if (wild_do_table_inited)
free_string_array(&wild_do_table);
if (wild_ignore_table_inited)
@@ -103,12 +106,12 @@ Rpl_filter::tables_ok(const char* db, TABLE_LIST* tables)
len= (uint) (strmov(end, tables->table_name) - hash_key);
if (do_table_inited) // if there are any do's
{
- if (hash_search(&do_table, (uchar*) hash_key, len))
+ if (my_hash_search(&do_table, (uchar*) hash_key, len))
DBUG_RETURN(1);
}
if (ignore_table_inited) // if there are any ignores
{
- if (hash_search(&ignore_table, (uchar*) hash_key, len))
+ if (my_hash_search(&ignore_table, (uchar*) hash_key, len))
DBUG_RETURN(0);
}
if (wild_do_table_inited &&
@@ -380,14 +383,14 @@ void free_table_ent(void* a)
{
TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
- my_free((uchar*) e, MYF(0));
+ my_free(e);
}
void
Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited)
{
- hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
+ my_hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
get_table_key, free_table_ent, 0);
*h_inited = 1;
}
@@ -431,7 +434,7 @@ Rpl_filter::free_string_array(DYNAMIC_ARRAY *a)
{
char* p;
get_dynamic(a, (uchar*) &p, i);
- my_free(p, MYF(MY_WME));
+ my_free(p);
}
delete_dynamic(a);
}
@@ -458,7 +461,7 @@ Rpl_filter::table_rule_ent_hash_to_str(String* s, HASH* h, bool inited)
{
for (uint i= 0; i < h->records; i++)
{
- TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) hash_element(h, i);
+ TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) my_hash_element(h, i);
if (s->length())
s->append(',');
s->append(e->db,e->key_len);
diff --git a/sql/rpl_filter.h b/sql/rpl_filter.h
index ff7e4081bb1..20f5ce8efc4 100644
--- a/sql/rpl_filter.h
+++ b/sql/rpl_filter.h
@@ -17,6 +17,12 @@
#define RPL_FILTER_H
#include "mysql.h"
+#include "sql_list.h" /* I_List */
+#include "hash.h" /* HASH */
+
+class String;
+struct TABLE_LIST;
+typedef struct st_dynamic_array DYNAMIC_ARRAY;
typedef struct st_table_rule_ent
{
diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc
new file mode 100644
index 00000000000..4355942e47f
--- /dev/null
+++ b/sql/rpl_handler.cc
@@ -0,0 +1,558 @@
+/* Copyright (C) 2008 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "sql_priv.h"
+#include "unireg.h"
+
+#include "rpl_mi.h"
+#include "sql_repl.h"
+#include "log_event.h"
+#include "rpl_filter.h"
+#include <my_dir.h>
+#include "rpl_handler.h"
+
+Trans_delegate *transaction_delegate;
+Binlog_storage_delegate *binlog_storage_delegate;
+#ifdef HAVE_REPLICATION
+Binlog_transmit_delegate *binlog_transmit_delegate;
+Binlog_relay_IO_delegate *binlog_relay_io_delegate;
+#endif /* HAVE_REPLICATION */
+
+/*
+ structure to save transaction log filename and position
+*/
+typedef struct Trans_binlog_info {
+ my_off_t log_pos;
+ char log_file[FN_REFLEN];
+} Trans_binlog_info;
+
+static pthread_key(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
+
+int get_user_var_int(const char *name,
+ long long int *value, int *null_value)
+{
+ my_bool null_val;
+ user_var_entry *entry=
+ (user_var_entry*) my_hash_search(&current_thd->user_vars,
+ (uchar*) name, strlen(name));
+ if (!entry)
+ return 1;
+ *value= entry->val_int(&null_val);
+ if (null_value)
+ *null_value= null_val;
+ return 0;
+}
+
+int get_user_var_real(const char *name,
+ double *value, int *null_value)
+{
+ my_bool null_val;
+ user_var_entry *entry=
+ (user_var_entry*) my_hash_search(&current_thd->user_vars,
+ (uchar*) name, strlen(name));
+ if (!entry)
+ return 1;
+ *value= entry->val_real(&null_val);
+ if (null_value)
+ *null_value= null_val;
+ return 0;
+}
+
+int get_user_var_str(const char *name, char *value,
+ size_t len, unsigned int precision, int *null_value)
+{
+ String str;
+ my_bool null_val;
+ user_var_entry *entry=
+ (user_var_entry*) my_hash_search(&current_thd->user_vars,
+ (uchar*) name, strlen(name));
+ if (!entry)
+ return 1;
+ entry->val_str(&null_val, &str, precision);
+ strncpy(value, str.c_ptr(), len);
+ if (null_value)
+ *null_value= null_val;
+ return 0;
+}
+
+int delegates_init()
+{
+ static my_aligned_storage<sizeof(Trans_delegate), MY_ALIGNOF(long)> trans_mem;
+ static my_aligned_storage<sizeof(Binlog_storage_delegate),
+ MY_ALIGNOF(long)> storage_mem;
+#ifdef HAVE_REPLICATION
+ static my_aligned_storage<sizeof(Binlog_transmit_delegate),
+ MY_ALIGNOF(long)> transmit_mem;
+ static my_aligned_storage<sizeof(Binlog_relay_IO_delegate),
+ MY_ALIGNOF(long)> relay_io_mem;
+#endif
+
+ void *place_trans_mem= trans_mem.data;
+ void *place_storage_mem= storage_mem.data;
+
+ transaction_delegate= new (place_trans_mem) Trans_delegate;
+
+ if (!transaction_delegate->is_inited())
+ {
+ sql_print_error("Initialization of transaction delegates failed. "
+ "Please report a bug.");
+ return 1;
+ }
+
+ binlog_storage_delegate= new (place_storage_mem) Binlog_storage_delegate;
+
+ if (!binlog_storage_delegate->is_inited())
+ {
+ sql_print_error("Initialization binlog storage delegates failed. "
+ "Please report a bug.");
+ return 1;
+ }
+
+#ifdef HAVE_REPLICATION
+ void *place_transmit_mem= transmit_mem.data;
+ void *place_relay_io_mem= relay_io_mem.data;
+
+ binlog_transmit_delegate= new (place_transmit_mem) Binlog_transmit_delegate;
+
+ if (!binlog_transmit_delegate->is_inited())
+ {
+ sql_print_error("Initialization of binlog transmit delegates failed. "
+ "Please report a bug.");
+ return 1;
+ }
+
+ binlog_relay_io_delegate= new (place_relay_io_mem) Binlog_relay_IO_delegate;
+
+ if (!binlog_relay_io_delegate->is_inited())
+ {
+ sql_print_error("Initialization binlog relay IO delegates failed. "
+ "Please report a bug.");
+ return 1;
+ }
+#endif
+
+ if (pthread_key_create(&RPL_TRANS_BINLOG_INFO, NULL))
+ {
+ sql_print_error("Error while creating pthread specific data key for replication. "
+ "Please report a bug.");
+ return 1;
+ }
+
+ return 0;
+}
+
+void delegates_destroy()
+{
+ if (transaction_delegate)
+ transaction_delegate->~Trans_delegate();
+ if (binlog_storage_delegate)
+ binlog_storage_delegate->~Binlog_storage_delegate();
+#ifdef HAVE_REPLICATION
+ if (binlog_transmit_delegate)
+ binlog_transmit_delegate->~Binlog_transmit_delegate();
+ if (binlog_relay_io_delegate)
+ binlog_relay_io_delegate->~Binlog_relay_IO_delegate();
+#endif /* HAVE_REPLICATION */
+}
+
+/*
+ This macro is used by almost all the Delegate methods to iterate
+ over all the observers running given callback function of the
+ delegate .
+
+ Add observer plugins to the thd->lex list, after each statement, all
+ plugins add to thd->lex will be automatically unlocked.
+ */
+#define FOREACH_OBSERVER(r, f, thd, args) \
+ param.server_id= thd->server_id; \
+ /*
+ Use a struct to make sure that they are allocated adjacent, check
+ delete_dynamic().
+ */ \
+ struct { \
+ DYNAMIC_ARRAY plugins; \
+ /* preallocate 8 slots */ \
+ plugin_ref plugins_buffer[8]; \
+ } s; \
+ DYNAMIC_ARRAY *plugins= &s.plugins; \
+ plugin_ref *plugins_buffer= s.plugins_buffer; \
+ my_init_dynamic_array2(plugins, sizeof(plugin_ref), \
+ plugins_buffer, 8, 8); \
+ read_lock(); \
+ Observer_info_iterator iter= observer_info_iter(); \
+ Observer_info *info= iter++; \
+ for (; info; info= iter++) \
+ { \
+ plugin_ref plugin= \
+ my_plugin_lock(0, &info->plugin); \
+ if (!plugin) \
+ { \
+ /* plugin is not intialized or deleted, this is not an error */ \
+ r= 0; \
+ break; \
+ } \
+ insert_dynamic(plugins, (uchar *)&plugin); \
+ if (((Observer *)info->observer)->f \
+ && ((Observer *)info->observer)->f args) \
+ { \
+ r= 1; \
+ sql_print_error("Run function '" #f "' in plugin '%s' failed", \
+ info->plugin_int->name.str); \
+ break; \
+ } \
+ } \
+ unlock(); \
+ /*
+ Unlock plugins should be done after we released the Delegate lock
+ to avoid possible deadlock when this is the last user of the
+ plugin, and when we unlock the plugin, it will try to
+ deinitialize the plugin, which will try to lock the Delegate in
+ order to remove the observers.
+ */ \
+ plugin_unlock_list(0, (plugin_ref*)plugins->buffer, \
+ plugins->elements); \
+ delete_dynamic(plugins)
+
+
+int Trans_delegate::after_commit(THD *thd, bool all)
+{
+ Trans_param param;
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0;
+
+ Trans_binlog_info *log_info=
+ my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
+
+ param.log_file= log_info ? log_info->log_file : 0;
+ param.log_pos= log_info ? log_info->log_pos : 0;
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, after_commit, thd, (&param));
+
+ /*
+ This is the end of a real transaction or autocommit statement, we
+ can free the memory allocated for binlog file and position.
+ */
+ if (is_real_trans && log_info)
+ {
+ my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL);
+ my_free(log_info);
+ }
+ return ret;
+}
+
+int Trans_delegate::after_rollback(THD *thd, bool all)
+{
+ Trans_param param;
+ bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
+
+ param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0;
+
+ Trans_binlog_info *log_info=
+ my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
+
+ param.log_file= log_info ? log_info->log_file : 0;
+ param.log_pos= log_info ? log_info->log_pos : 0;
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, after_rollback, thd, (&param));
+
+ /*
+ This is the end of a real transaction or autocommit statement, we
+ can free the memory allocated for binlog file and position.
+ */
+ if (is_real_trans && log_info)
+ {
+ my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL);
+ my_free(log_info);
+ }
+ return ret;
+}
+
+int Binlog_storage_delegate::after_flush(THD *thd,
+ const char *log_file,
+ my_off_t log_pos,
+ bool synced)
+{
+ Binlog_storage_param param;
+ uint32 flags=0;
+ if (synced)
+ flags |= BINLOG_STORAGE_IS_SYNCED;
+
+ Trans_binlog_info *log_info=
+ my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
+
+ if (!log_info)
+ {
+ if(!(log_info=
+ (Trans_binlog_info *)my_malloc(sizeof(Trans_binlog_info), MYF(0))))
+ return 1;
+ my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, log_info);
+ }
+
+ strcpy(log_info->log_file, log_file+dirname_length(log_file));
+ log_info->log_pos = log_pos;
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, after_flush, thd,
+ (&param, log_info->log_file, log_info->log_pos, flags));
+ return ret;
+}
+
+#ifdef HAVE_REPLICATION
+int Binlog_transmit_delegate::transmit_start(THD *thd, ushort flags,
+ const char *log_file,
+ my_off_t log_pos)
+{
+ Binlog_transmit_param param;
+ param.flags= flags;
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, transmit_start, thd, (&param, log_file, log_pos));
+ return ret;
+}
+
+int Binlog_transmit_delegate::transmit_stop(THD *thd, ushort flags)
+{
+ Binlog_transmit_param param;
+ param.flags= flags;
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, transmit_stop, thd, (&param));
+ return ret;
+}
+
+int Binlog_transmit_delegate::reserve_header(THD *thd, ushort flags,
+ String *packet)
+{
+ /* NOTE2ME: Maximum extra header size for each observer, I hope 32
+ bytes should be enough for each Observer to reserve their extra
+ header. If later found this is not enough, we can increase this
+ /HEZX
+ */
+#define RESERVE_HEADER_SIZE 32
+ unsigned char header[RESERVE_HEADER_SIZE];
+ ulong hlen;
+ Binlog_transmit_param param;
+ param.flags= flags;
+ param.server_id= thd->server_id;
+
+ int ret= 0;
+ read_lock();
+ Observer_info_iterator iter= observer_info_iter();
+ Observer_info *info= iter++;
+ for (; info; info= iter++)
+ {
+ plugin_ref plugin=
+ my_plugin_lock(thd, &info->plugin);
+ if (!plugin)
+ {
+ ret= 1;
+ break;
+ }
+ hlen= 0;
+ if (((Observer *)info->observer)->reserve_header
+ && ((Observer *)info->observer)->reserve_header(&param,
+ header,
+ RESERVE_HEADER_SIZE,
+ &hlen))
+ {
+ ret= 1;
+ plugin_unlock(thd, plugin);
+ break;
+ }
+ plugin_unlock(thd, plugin);
+ if (hlen == 0)
+ continue;
+ if (hlen > RESERVE_HEADER_SIZE || packet->append((char *)header, hlen))
+ {
+ ret= 1;
+ break;
+ }
+ }
+ unlock();
+ return ret;
+}
+
+int Binlog_transmit_delegate::before_send_event(THD *thd, ushort flags,
+ String *packet,
+ const char *log_file,
+ my_off_t log_pos)
+{
+ Binlog_transmit_param param;
+ param.flags= flags;
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, before_send_event, thd,
+ (&param, (uchar *)packet->c_ptr(),
+ packet->length(),
+ log_file+dirname_length(log_file), log_pos));
+ return ret;
+}
+
+int Binlog_transmit_delegate::after_send_event(THD *thd, ushort flags,
+ String *packet)
+{
+ Binlog_transmit_param param;
+ param.flags= flags;
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, after_send_event, thd,
+ (&param, packet->c_ptr(), packet->length()));
+ return ret;
+}
+
+int Binlog_transmit_delegate::after_reset_master(THD *thd, ushort flags)
+
+{
+ Binlog_transmit_param param;
+ param.flags= flags;
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, after_reset_master, thd, (&param));
+ return ret;
+}
+
+void Binlog_relay_IO_delegate::init_param(Binlog_relay_IO_param *param,
+ Master_info *mi)
+{
+ param->mysql= mi->mysql;
+ param->user= mi->user;
+ param->host= mi->host;
+ param->port= mi->port;
+ param->master_log_name= mi->master_log_name;
+ param->master_log_pos= mi->master_log_pos;
+}
+
+int Binlog_relay_IO_delegate::thread_start(THD *thd, Master_info *mi)
+{
+ Binlog_relay_IO_param param;
+ init_param(&param, mi);
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, thread_start, thd, (&param));
+ return ret;
+}
+
+
+int Binlog_relay_IO_delegate::thread_stop(THD *thd, Master_info *mi)
+{
+
+ Binlog_relay_IO_param param;
+ init_param(&param, mi);
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, thread_stop, thd, (&param));
+ return ret;
+}
+
+int Binlog_relay_IO_delegate::before_request_transmit(THD *thd,
+ Master_info *mi,
+ ushort flags)
+{
+ Binlog_relay_IO_param param;
+ init_param(&param, mi);
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, before_request_transmit, thd, (&param, (uint32)flags));
+ return ret;
+}
+
+int Binlog_relay_IO_delegate::after_read_event(THD *thd, Master_info *mi,
+ const char *packet, ulong len,
+ const char **event_buf,
+ ulong *event_len)
+{
+ Binlog_relay_IO_param param;
+ init_param(&param, mi);
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, after_read_event, thd,
+ (&param, packet, len, event_buf, event_len));
+ return ret;
+}
+
+int Binlog_relay_IO_delegate::after_queue_event(THD *thd, Master_info *mi,
+ const char *event_buf,
+ ulong event_len,
+ bool synced)
+{
+ Binlog_relay_IO_param param;
+ init_param(&param, mi);
+
+ uint32 flags=0;
+ if (synced)
+ flags |= BINLOG_STORAGE_IS_SYNCED;
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, after_queue_event, thd,
+ (&param, event_buf, event_len, flags));
+ return ret;
+}
+
+int Binlog_relay_IO_delegate::after_reset_slave(THD *thd, Master_info *mi)
+
+{
+ Binlog_relay_IO_param param;
+ init_param(&param, mi);
+
+ int ret= 0;
+ FOREACH_OBSERVER(ret, after_reset_slave, thd, (&param));
+ return ret;
+}
+#endif /* HAVE_REPLICATION */
+
+int register_trans_observer(Trans_observer *observer, void *p)
+{
+ return transaction_delegate->add_observer(observer, (st_plugin_int *)p);
+}
+
+int unregister_trans_observer(Trans_observer *observer, void *p)
+{
+ return transaction_delegate->remove_observer(observer, (st_plugin_int *)p);
+}
+
+int register_binlog_storage_observer(Binlog_storage_observer *observer, void *p)
+{
+ return binlog_storage_delegate->add_observer(observer, (st_plugin_int *)p);
+}
+
+int unregister_binlog_storage_observer(Binlog_storage_observer *observer, void *p)
+{
+ return binlog_storage_delegate->remove_observer(observer, (st_plugin_int *)p);
+}
+
+#ifdef HAVE_REPLICATION
+int register_binlog_transmit_observer(Binlog_transmit_observer *observer, void *p)
+{
+ return binlog_transmit_delegate->add_observer(observer, (st_plugin_int *)p);
+}
+
+int unregister_binlog_transmit_observer(Binlog_transmit_observer *observer, void *p)
+{
+ return binlog_transmit_delegate->remove_observer(observer, (st_plugin_int *)p);
+}
+
+int register_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void *p)
+{
+ return binlog_relay_io_delegate->add_observer(observer, (st_plugin_int *)p);
+}
+
+int unregister_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void *p)
+{
+ return binlog_relay_io_delegate->remove_observer(observer, (st_plugin_int *)p);
+}
+#endif /* HAVE_REPLICATION */
diff --git a/sql/rpl_handler.h b/sql/rpl_handler.h
new file mode 100644
index 00000000000..bf207e53e2d
--- /dev/null
+++ b/sql/rpl_handler.h
@@ -0,0 +1,213 @@
+/* Copyright (C) 2008 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef RPL_HANDLER_H
+#define RPL_HANDLER_H
+
+#include "sql_priv.h"
+#include "rpl_mi.h"
+#include "rpl_rli.h"
+#include "sql_plugin.h"
+#include "replication.h"
+
+class Observer_info {
+public:
+ void *observer;
+ st_plugin_int *plugin_int;
+ plugin_ref plugin;
+
+ Observer_info(void *ob, st_plugin_int *p)
+ :observer(ob), plugin_int(p)
+ {
+ plugin= plugin_int_to_ref(plugin_int);
+ }
+};
+
+class Delegate {
+public:
+ typedef List<Observer_info> Observer_info_list;
+ typedef List_iterator<Observer_info> Observer_info_iterator;
+
+ int add_observer(void *observer, st_plugin_int *plugin)
+ {
+ int ret= FALSE;
+ if (!inited)
+ return TRUE;
+ write_lock();
+ Observer_info_iterator iter(observer_info_list);
+ Observer_info *info= iter++;
+ while (info && info->observer != observer)
+ info= iter++;
+ if (!info)
+ {
+ info= new Observer_info(observer, plugin);
+ if (!info || observer_info_list.push_back(info, &memroot))
+ ret= TRUE;
+ }
+ else
+ ret= TRUE;
+ unlock();
+ return ret;
+ }
+
+ int remove_observer(void *observer, st_plugin_int *plugin)
+ {
+ int ret= FALSE;
+ if (!inited)
+ return TRUE;
+ write_lock();
+ Observer_info_iterator iter(observer_info_list);
+ Observer_info *info= iter++;
+ while (info && info->observer != observer)
+ info= iter++;
+ if (info)
+ iter.remove();
+ else
+ ret= TRUE;
+ unlock();
+ return ret;
+ }
+
+ inline Observer_info_iterator observer_info_iter()
+ {
+ return Observer_info_iterator(observer_info_list);
+ }
+
+ inline bool is_empty()
+ {
+ return observer_info_list.is_empty();
+ }
+
+ inline int read_lock()
+ {
+ if (!inited)
+ return TRUE;
+ return rw_rdlock(&lock);
+ }
+
+ inline int write_lock()
+ {
+ if (!inited)
+ return TRUE;
+ return rw_wrlock(&lock);
+ }
+
+ inline int unlock()
+ {
+ if (!inited)
+ return TRUE;
+ return rw_unlock(&lock);
+ }
+
+ inline bool is_inited()
+ {
+ return inited;
+ }
+
+ Delegate()
+ {
+ inited= FALSE;
+ if (my_rwlock_init(&lock, NULL))
+ return;
+ init_sql_alloc(&memroot, 1024, 0);
+ inited= TRUE;
+ }
+ ~Delegate()
+ {
+ inited= FALSE;
+ rwlock_destroy(&lock);
+ free_root(&memroot, MYF(0));
+ }
+
+private:
+ Observer_info_list observer_info_list;
+ rw_lock_t lock;
+ MEM_ROOT memroot;
+ bool inited;
+};
+
+class Trans_delegate
+ :public Delegate {
+public:
+ typedef Trans_observer Observer;
+ int before_commit(THD *thd, bool all);
+ int before_rollback(THD *thd, bool all);
+ int after_commit(THD *thd, bool all);
+ int after_rollback(THD *thd, bool all);
+};
+
+class Binlog_storage_delegate
+ :public Delegate {
+public:
+ typedef Binlog_storage_observer Observer;
+ int after_flush(THD *thd, const char *log_file,
+ my_off_t log_pos, bool synced);
+};
+
+#ifdef HAVE_REPLICATION
+class Binlog_transmit_delegate
+ :public Delegate {
+public:
+ typedef Binlog_transmit_observer Observer;
+ int transmit_start(THD *thd, ushort flags,
+ const char *log_file, my_off_t log_pos);
+ int transmit_stop(THD *thd, ushort flags);
+ int reserve_header(THD *thd, ushort flags, String *packet);
+ int before_send_event(THD *thd, ushort flags,
+ String *packet, const
+ char *log_file, my_off_t log_pos );
+ int after_send_event(THD *thd, ushort flags,
+ String *packet);
+ int after_reset_master(THD *thd, ushort flags);
+};
+
+class Binlog_relay_IO_delegate
+ :public Delegate {
+public:
+ typedef Binlog_relay_IO_observer Observer;
+ int thread_start(THD *thd, Master_info *mi);
+ int thread_stop(THD *thd, Master_info *mi);
+ int before_request_transmit(THD *thd, Master_info *mi, ushort flags);
+ int after_read_event(THD *thd, Master_info *mi,
+ const char *packet, ulong len,
+ const char **event_buf, ulong *event_len);
+ int after_queue_event(THD *thd, Master_info *mi,
+ const char *event_buf, ulong event_len,
+ bool synced);
+ int after_reset_slave(THD *thd, Master_info *mi);
+private:
+ void init_param(Binlog_relay_IO_param *param, Master_info *mi);
+};
+#endif /* HAVE_REPLICATION */
+
+int delegates_init();
+void delegates_destroy();
+
+extern Trans_delegate *transaction_delegate;
+extern Binlog_storage_delegate *binlog_storage_delegate;
+#ifdef HAVE_REPLICATION
+extern Binlog_transmit_delegate *binlog_transmit_delegate;
+extern Binlog_relay_IO_delegate *binlog_relay_io_delegate;
+#endif /* HAVE_REPLICATION */
+
+/*
+ if there is no observers in the delegate, we can return 0
+ immediately.
+*/
+#define RUN_HOOK(group, hook, args) \
+ (group ##_delegate->is_empty() ? \
+ 0 : group ##_delegate->hook args)
+
+#endif /* RPL_HANDLER_H */
diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc
index b797621d696..52c8b9f0655 100644
--- a/sql/rpl_injector.cc
+++ b/sql/rpl_injector.cc
@@ -13,8 +13,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED by later includes
#include "rpl_injector.h"
+#include "transaction.h"
+#include "sql_parse.h" // begin_trans, end_trans, COMMIT
+#include "sql_base.h" // close_thread_tables
+#include "log_event.h" // Incident_log_event
/*
injector::transaction - member definitions
@@ -35,9 +40,7 @@ injector::transaction::transaction(MYSQL_BIN_LOG *log, THD *thd)
m_start_pos.m_file_name= my_strdup(log_info.log_file_name, MYF(0));
m_start_pos.m_file_pos= log_info.pos;
- begin_trans(m_thd);
-
- thd->set_current_stmt_binlog_row_based();
+ trans_begin(m_thd);
}
injector::transaction::~transaction()
@@ -55,7 +58,7 @@ injector::transaction::~transaction()
*/
*the_memory= '\0';
- my_free(the_memory, MYF(0));
+ my_free(the_memory);
}
/**
@@ -85,11 +88,16 @@ int injector::transaction::commit()
is committed by committing the statement transaction
explicitly.
*/
- error |= ha_autocommit_or_rollback(m_thd, error);
- end_trans(m_thd, error ? ROLLBACK : COMMIT);
+ trans_commit_stmt(m_thd);
+ if (!trans_commit(m_thd))
+ {
+ close_thread_tables(m_thd);
+ m_thd->mdl_context.release_transactional_locks();
+ }
DBUG_RETURN(error);
}
+
int injector::transaction::use_table(server_id_type sid, table tbl)
{
DBUG_ENTER("injector::transaction::use_table");
@@ -113,7 +121,7 @@ int injector::transaction::write_row (server_id_type sid, table tbl,
record_type record)
{
DBUG_ENTER("injector::transaction::write_row(...)");
-
+
int error= check_state(ROW_STATE);
if (error)
DBUG_RETURN(error);
diff --git a/sql/rpl_injector.h b/sql/rpl_injector.h
index 4ece092c5b8..36cb6aaa184 100644
--- a/sql/rpl_injector.h
+++ b/sql/rpl_injector.h
@@ -21,13 +21,13 @@
#include <my_bitmap.h>
#include "rpl_constants.h"
+#include "table.h" /* TABLE */
/* Forward declarations */
class handler;
class MYSQL_BIN_LOG;
-struct st_table;
+struct TABLE;
-typedef st_table TABLE;
/*
Injector to inject rows into the MySQL server.
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index 63f1f21c957..cda876ee764 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -14,76 +14,112 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h> // For HAVE_REPLICATION
-#include "mysql_priv.h"
+#include "sql_priv.h"
#include <my_dir.h>
-
+#include "unireg.h" // REQUIRED by other includes
#include "rpl_mi.h"
+#include "slave.h" // SLAVE_MAX_HEARTBEAT_PERIOD
#ifdef HAVE_REPLICATION
+#define DEFAULT_CONNECT_RETRY 60
// Defined in slave.cc
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val);
+int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val);
+int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f);
-Master_info::Master_info()
+Master_info::Master_info(bool is_slave_recovery)
:Slave_reporting_capability("I/O"),
- ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0), inited(0),
- abort_slave(0),slave_running(0),
- slave_run_id(0)
+ ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0),
+ rli(is_slave_recovery), port(MYSQL_PORT),
+ connect_retry(DEFAULT_CONNECT_RETRY), inited(0), abort_slave(0),
+ slave_running(0), slave_run_id(0), sync_counter(0),
+ heartbeat_period(0), received_heartbeats(0), master_id(0)
{
host[0] = 0; user[0] = 0; password[0] = 0;
ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
ssl_cipher[0]= 0; ssl_key[0]= 0;
+ my_init_dynamic_array(&ignore_server_ids, sizeof(::server_id), 16, 16);
bzero((char*) &file, sizeof(file));
- pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&data_cond, NULL);
- pthread_cond_init(&start_cond, NULL);
- pthread_cond_init(&stop_cond, NULL);
+ mysql_mutex_init(key_master_info_run_lock, &run_lock, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_master_info_data_lock, &data_lock, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_master_info_data_cond, &data_cond, NULL);
+ mysql_cond_init(key_master_info_start_cond, &start_cond, NULL);
+ mysql_cond_init(key_master_info_stop_cond, &stop_cond, NULL);
}
Master_info::~Master_info()
{
- pthread_mutex_destroy(&run_lock);
- pthread_mutex_destroy(&data_lock);
- pthread_cond_destroy(&data_cond);
- pthread_cond_destroy(&start_cond);
- pthread_cond_destroy(&stop_cond);
+ delete_dynamic(&ignore_server_ids);
+ mysql_mutex_destroy(&run_lock);
+ mysql_mutex_destroy(&data_lock);
+ mysql_cond_destroy(&data_cond);
+ mysql_cond_destroy(&start_cond);
+ mysql_cond_destroy(&stop_cond);
+}
+
+/**
+ A comparison function to be supplied as argument to @c sort_dynamic()
+ and @c bsearch()
+
+ @return -1 if first argument is less, 0 if it equal to, 1 if it is greater
+ than the second
+*/
+int change_master_server_id_cmp(ulong *id1, ulong *id2)
+{
+ return *id1 < *id2? -1 : (*id1 > *id2? 1 : 0);
}
-void init_master_info_with_options(Master_info* mi)
+/**
+ Reports if the s_id server has been configured to ignore events
+ it generates with
+
+ CHANGE MASTER IGNORE_SERVER_IDS= ( list of server ids )
+
+ Method is called from the io thread event receiver filtering.
+
+ @param s_id the master server identifier
+
+ @retval TRUE if s_id is in the list of ignored master servers,
+ @retval FALSE otherwise.
+ */
+bool Master_info::shall_ignore_server_id(ulong s_id)
+{
+ if (likely(ignore_server_ids.elements == 1))
+ return (* (ulong*) dynamic_array_ptr(&ignore_server_ids, 0)) == s_id;
+ else
+ return bsearch((const ulong *) &s_id,
+ ignore_server_ids.buffer,
+ ignore_server_ids.elements, sizeof(ulong),
+ (int (*) (const void*, const void*)) change_master_server_id_cmp)
+ != NULL;
+}
+
+void init_master_log_pos(Master_info* mi)
{
- DBUG_ENTER("init_master_info_with_options");
+ DBUG_ENTER("init_master_log_pos");
mi->master_log_name[0] = 0;
mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number
- if (master_host)
- strmake(mi->host, master_host, sizeof(mi->host) - 1);
- if (master_user)
- strmake(mi->user, master_user, sizeof(mi->user) - 1);
- if (master_password)
- strmake(mi->password, master_password, MAX_PASSWORD_LENGTH);
- mi->port = master_port;
- mi->connect_retry = master_connect_retry;
-
- mi->ssl= master_ssl;
- if (master_ssl_ca)
- strmake(mi->ssl_ca, master_ssl_ca, sizeof(mi->ssl_ca)-1);
- if (master_ssl_capath)
- strmake(mi->ssl_capath, master_ssl_capath, sizeof(mi->ssl_capath)-1);
- if (master_ssl_cert)
- strmake(mi->ssl_cert, master_ssl_cert, sizeof(mi->ssl_cert)-1);
- if (master_ssl_cipher)
- strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1);
- if (master_ssl_key)
- strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1);
/* Intentionally init ssl_verify_server_cert to 0, no option available */
mi->ssl_verify_server_cert= 0;
+ /*
+ always request heartbeat unless master_heartbeat_period is set
+ explicitly zero. Here is the default value for heartbeat period
+ if CHANGE MASTER did not specify it. (no data loss in conversion
+ as hb period has a max)
+ */
+ mi->heartbeat_period= (float) min(SLAVE_MAX_HEARTBEAT_PERIOD,
+ (slave_net_timeout/2.0));
+ DBUG_ASSERT(mi->heartbeat_period > (float) 0.001
+ || mi->heartbeat_period == 0);
+
DBUG_VOID_RETURN;
}
@@ -93,9 +129,14 @@ enum {
/* 5.1.16 added value of master_ssl_verify_server_cert */
LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15,
-
+ /* 6.0 added value of master_heartbeat_period */
+ LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16,
+ /* MySQL Cluster 6.3 added master_bind */
+ LINE_FOR_MASTER_BIND = 17,
+ /* 6.0 added value of master_ignore_server_id */
+ LINE_FOR_REPLICATE_IGNORE_SERVER_IDS= 18,
/* Number of lines currently used when saving master info file */
- LINES_IN_MASTER_INFO= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT
+ LINES_IN_MASTER_INFO= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS
};
int init_master_info(Master_info* mi, const char* master_info_fname,
@@ -123,7 +164,29 @@ int init_master_info(Master_info* mi, const char* master_info_fname,
*/
if (thread_mask & SLAVE_SQL)
{
+ bool hot_log= FALSE;
+ /*
+ my_b_seek does an implicit flush_io_cache, so we need to:
+
+ 1. check if this log is active (hot)
+ 2. if it is we keep log_lock until the seek ends, otherwise
+ release it right away.
+
+ If we did not take log_lock, SQL thread might race with IO
+ thread for the IO_CACHE mutex.
+
+ */
+ mysql_mutex_t *log_lock= mi->rli.relay_log.get_log_lock();
+ mysql_mutex_lock(log_lock);
+ hot_log= mi->rli.relay_log.is_active(mi->rli.linfo.log_file_name);
+
+ if (!hot_log)
+ mysql_mutex_unlock(log_lock);
+
my_b_seek(mi->rli.cur_log, (my_off_t) 0);
+
+ if (hot_log)
+ mysql_mutex_unlock(log_lock);
}
DBUG_RETURN(0);
}
@@ -137,7 +200,7 @@ int init_master_info(Master_info* mi, const char* master_info_fname,
keep other threads from reading bogus info
*/
- pthread_mutex_lock(&mi->data_lock);
+ mysql_mutex_lock(&mi->data_lock);
fd = mi->fd;
/* does master.info exist ? */
@@ -146,7 +209,7 @@ int init_master_info(Master_info* mi, const char* master_info_fname,
{
if (abort_if_no_master_info_file)
{
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_RETURN(0);
}
/*
@@ -154,8 +217,9 @@ int init_master_info(Master_info* mi, const char* master_info_fname,
the old descriptor and re-create the old file
*/
if (fd >= 0)
- my_close(fd, MYF(MY_WME));
- if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
+ mysql_file_close(fd, MYF(MY_WME));
+ if ((fd= mysql_file_open(key_file_master_info,
+ fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
{
sql_print_error("Failed to create a new master info file (\
file '%s', errno %d)", fname, my_errno);
@@ -170,7 +234,7 @@ file '%s')", fname);
}
mi->fd = fd;
- init_master_info_with_options(mi);
+ init_master_log_pos(mi);
}
else // file exists
@@ -179,7 +243,8 @@ file '%s')", fname);
reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0);
else
{
- if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
+ if ((fd= mysql_file_open(key_file_master_info,
+ fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
{
sql_print_error("Failed to open the existing master info file (\
file '%s', errno %d)", fname, my_errno);
@@ -197,7 +262,9 @@ file '%s')", fname);
mi->fd = fd;
int port, connect_retry, master_log_pos, lines;
int ssl= 0, ssl_verify_server_cert= 0;
+ float master_heartbeat_period= 0.0;
char *first_non_digit;
+ char dummy_buf[HOSTNAME_LENGTH+1];
/*
Starting from 4.1.x master.info has new format. Now its
@@ -242,36 +309,34 @@ file '%s')", fname);
lines= 7;
if (init_intvar_from_file(&master_log_pos, &mi->file, 4) ||
- init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
- master_host) ||
- init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
- master_user) ||
+ init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, 0) ||
+ init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, "test") ||
init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
- &mi->file, master_password) ||
- init_intvar_from_file(&port, &mi->file, master_port) ||
+ &mi->file, 0) ||
+ init_intvar_from_file(&port, &mi->file, MYSQL_PORT) ||
init_intvar_from_file(&connect_retry, &mi->file,
- master_connect_retry))
+ DEFAULT_CONNECT_RETRY))
goto errwithmsg;
/*
If file has ssl part use it even if we have server without
- SSL support. But these option will be ignored later when
+ SSL support. But these options will be ignored later when
slave will try connect to master, so in this case warning
is printed.
*/
if (lines >= LINES_IN_MASTER_INFO_WITH_SSL)
{
- if (init_intvar_from_file(&ssl, &mi->file, master_ssl) ||
+ if (init_intvar_from_file(&ssl, &mi->file, 0) ||
init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
- &mi->file, master_ssl_ca) ||
+ &mi->file, 0) ||
init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
- &mi->file, master_ssl_capath) ||
+ &mi->file, 0) ||
init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert),
- &mi->file, master_ssl_cert) ||
+ &mi->file, 0) ||
init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher),
- &mi->file, master_ssl_cipher) ||
+ &mi->file, 0) ||
init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key),
- &mi->file, master_ssl_key))
+ &mi->file, 0))
goto errwithmsg;
/*
@@ -281,14 +346,37 @@ file '%s')", fname);
if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT &&
init_intvar_from_file(&ssl_verify_server_cert, &mi->file, 0))
goto errwithmsg;
-
+ /*
+ Starting from 6.0 master_heartbeat_period might be
+ in the file
+ */
+ if (lines >= LINE_FOR_MASTER_HEARTBEAT_PERIOD &&
+ init_floatvar_from_file(&master_heartbeat_period, &mi->file, 0.0))
+ goto errwithmsg;
+ /*
+ Starting from MySQL Cluster 6.3 master_bind might be in the file
+ (this is just a reservation to avoid future upgrade problems)
+ */
+ if (lines >= LINE_FOR_MASTER_BIND &&
+ init_strvar_from_file(dummy_buf, sizeof(dummy_buf), &mi->file, ""))
+ goto errwithmsg;
+ /*
+ Starting from 6.0 list of server_id of ignorable servers might be
+ in the file
+ */
+ if (lines >= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS &&
+ init_dynarray_intvar_from_file(&mi->ignore_server_ids, &mi->file))
+ {
+ sql_print_error("Failed to initialize master info ignore_server_ids");
+ goto errwithmsg;
+ }
}
#ifndef HAVE_OPENSSL
if (ssl)
sql_print_warning("SSL information in the master info file "
- "('%s') are ignored because this MySQL slave was compiled "
- "without SSL support.", fname);
+ "('%s') are ignored because this MySQL slave was "
+ "compiled without SSL support.", fname);
#endif /* HAVE_OPENSSL */
/*
@@ -300,6 +388,7 @@ file '%s')", fname);
mi->connect_retry= (uint) connect_retry;
mi->ssl= (my_bool) ssl;
mi->ssl_verify_server_cert= ssl_verify_server_cert;
+ mi->heartbeat_period= master_heartbeat_period;
}
DBUG_PRINT("master_info",("log_file_name: %s position: %ld",
mi->master_log_name,
@@ -310,11 +399,12 @@ file '%s')", fname);
goto err;
mi->inited = 1;
+ mi->rli.is_relay_log_recovery= FALSE;
// now change cache READ -> WRITE - must do this before flush_master_info
reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1);
if ((error=test(flush_master_info(mi, TRUE, TRUE))))
sql_print_error("Failed to flush master info file");
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_RETURN(error);
errwithmsg:
@@ -323,11 +413,11 @@ errwithmsg:
err:
if (fd >= 0)
{
- my_close(fd, MYF(0));
+ mysql_file_close(fd, MYF(0));
end_io_cache(&mi->file);
}
mi->fd= -1;
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_RETURN(1);
}
@@ -363,21 +453,41 @@ int flush_master_info(Master_info* mi,
*/
if (flush_relay_log_cache)
{
- pthread_mutex_t *log_lock= mi->rli.relay_log.get_log_lock();
+ mysql_mutex_t *log_lock= mi->rli.relay_log.get_log_lock();
IO_CACHE *log_file= mi->rli.relay_log.get_log_file();
if (need_lock_relay_log)
- pthread_mutex_lock(log_lock);
+ mysql_mutex_lock(log_lock);
- safe_mutex_assert_owner(log_lock);
+ mysql_mutex_assert_owner(log_lock);
err= flush_io_cache(log_file);
if (need_lock_relay_log)
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
if (err)
DBUG_RETURN(2);
}
+
+ /*
+ produce a line listing the total number and all the ignored server_id:s
+ */
+ char* ignore_server_ids_buf;
+ {
+ ignore_server_ids_buf=
+ (char *) my_malloc((sizeof(::server_id) * 3 + 1) *
+ (1 + mi->ignore_server_ids.elements), MYF(MY_WME));
+ if (!ignore_server_ids_buf)
+ DBUG_RETURN(1);
+ ulong cur_len= sprintf(ignore_server_ids_buf, "%u",
+ mi->ignore_server_ids.elements);
+ for (ulong i= 0; i < mi->ignore_server_ids.elements; i++)
+ {
+ ulong s_id;
+ get_dynamic(&mi->ignore_server_ids, (uchar*) &s_id, i);
+ cur_len+= sprintf(ignore_server_ids_buf + cur_len, " %lu", s_id);
+ }
+ }
/*
We flushed the relay log BEFORE the master.info file, because if we crash
@@ -395,17 +505,27 @@ int flush_master_info(Master_info* mi,
contents of file). But because of number of lines in the first line
of file we don't care about this garbage.
*/
-
+ char heartbeat_buf[sizeof(mi->heartbeat_period) * 4]; // buffer to suffice always
+ sprintf(heartbeat_buf, "%.3f", mi->heartbeat_period);
my_b_seek(file, 0L);
my_b_printf(file,
- "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n",
+ "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n%s\n",
LINES_IN_MASTER_INFO,
mi->master_log_name, llstr(mi->master_log_pos, lbuf),
mi->host, mi->user,
mi->password, mi->port, mi->connect_retry,
(int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert,
- mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert);
- DBUG_RETURN(-flush_io_cache(file));
+ mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert,
+ heartbeat_buf, "", ignore_server_ids_buf);
+ my_free(ignore_server_ids_buf);
+ err= flush_io_cache(file);
+ if (sync_masterinfo_period && !err &&
+ ++(mi->sync_counter) >= sync_masterinfo_period)
+ {
+ err= my_sync(mi->fd, MYF(MY_WME));
+ mi->sync_counter= 0;
+ }
+ DBUG_RETURN(-err);
}
@@ -419,7 +539,7 @@ void end_master_info(Master_info* mi)
if (mi->fd >= 0)
{
end_io_cache(&mi->file);
- (void)my_close(mi->fd, MYF(MY_WME));
+ mysql_file_close(mi->fd, MYF(MY_WME));
mi->fd = -1;
}
mi->inited = 0;
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
index 023879f84fa..c3734fdf59e 100644
--- a/sql/rpl_mi.h
+++ b/sql/rpl_mi.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -20,10 +20,11 @@
#include "rpl_rli.h"
#include "rpl_reporting.h"
+#include "my_sys.h"
+typedef struct st_mysql MYSQL;
/*****************************************************************************
-
Replication IO Thread
Master_info contains:
@@ -58,8 +59,9 @@
class Master_info : public Slave_reporting_capability
{
public:
- Master_info();
+ Master_info(bool is_slave_recovery);
~Master_info();
+ bool shall_ignore_server_id(ulong s_id);
/* the variables below are needed because we can change masters on the fly */
char master_log_name[FN_REFLEN];
@@ -75,8 +77,8 @@ class Master_info : public Slave_reporting_capability
File fd; // we keep the file open, so we need to remember the file pointer
IO_CACHE file;
- pthread_mutex_t data_lock,run_lock;
- pthread_cond_t data_cond,start_cond,stop_cond;
+ mysql_mutex_t data_lock, run_lock;
+ mysql_cond_t data_cond, start_cond, stop_cond;
THD *io_thd;
MYSQL* mysql;
uint32 file_id; /* for 3.23 load data infile */
@@ -100,9 +102,18 @@ class Master_info : public Slave_reporting_capability
*/
long clock_diff_with_master;
+ /*
+ Keeps track of the number of events before fsyncing.
+ The option --sync-master-info determines how many
+ events should happen before fsyncing.
+ */
+ uint sync_counter;
+ float heartbeat_period; // interface with CHANGE MASTER or master.info
+ ulonglong received_heartbeats; // counter of received heartbeat events
+ DYNAMIC_ARRAY ignore_server_ids;
+ ulong master_id;
};
-
-void init_master_info_with_options(Master_info* mi);
+void init_master_log_pos(Master_info* mi);
int init_master_info(Master_info* mi, const char* master_info_fname,
const char* slave_info_fname,
bool abort_if_no_master_info_file,
@@ -111,5 +122,7 @@ void end_master_info(Master_info* mi);
int flush_master_info(Master_info* mi,
bool flush_relay_log_cache,
bool need_lock_relay_log);
+int change_master_server_id_cmp(ulong *id1, ulong *id2);
+
#endif /* HAVE_REPLICATION */
#endif /* RPL_MI_H */
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
index 3a46bbcd6ee..dd16318303d 100644
--- a/sql/rpl_record.cc
+++ b/sql/rpl_record.cc
@@ -13,7 +13,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
#include "rpl_rli.h"
#include "rpl_record.h"
#include "slave.h" // Need to pull in slave_print_msg
@@ -77,8 +78,6 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
unsigned int null_mask= 1U;
for ( ; (field= *p_field) ; p_field++)
{
- DBUG_PRINT("debug", ("null_mask=%d; null_ptr=%p; row_data=%p; null_byte_count=%d",
- null_mask, null_ptr, row_data, null_byte_count));
if (bitmap_is_set(cols, p_field - table->field))
{
my_ptrdiff_t offset;
@@ -104,11 +103,12 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
#endif
pack_ptr= field->pack(pack_ptr, field->ptr + offset,
field->max_data_length(), TRUE);
- DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;"
+ DBUG_PRINT("debug", ("field: %s; real_type: %d, pack_ptr: 0x%lx;"
" pack_ptr':0x%lx; bytes: %d",
- field->field_name, (ulong) old_pack_ptr,
- (ulong) pack_ptr,
+ field->field_name, field->real_type(),
+ (ulong) old_pack_ptr, (ulong) pack_ptr,
(int) (pack_ptr - old_pack_ptr)));
+ DBUG_DUMP("packed_data", old_pack_ptr, pack_ptr - old_pack_ptr);
}
null_mask <<= 1;
@@ -150,13 +150,20 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
the various member functions of Field and subclasses expect to
write.
- The row is assumed to only consist of the fields for which the corresponding
- bit in bitset @c cols is set; the other parts of the record are left alone.
+ The row is assumed to only consist of the fields for which the
+ corresponding bit in bitset @c cols is set; the other parts of the
+ record are left alone.
At most @c colcnt columns are read: if the table is larger than
that, the remaining fields are not filled in.
- @param rli Relay log info
+ @note The relay log information can be NULL, which means that no
+ checking or comparison with the source table is done, simply
+ because it is not used. This feature is used by MySQL Backup to
+ unpack a row from from the backup image, but can be used for other
+ purposes as well.
+
+ @param rli Relay log info, which can be NULL
@param table Table to unpack into
@param colcnt Number of columns to read from record
@param row_data
@@ -170,10 +177,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
@retval 0 No error
- @retval ER_NO_DEFAULT_FOR_FIELD
- Returned if one of the fields existing on the slave but not on the
- master does not have a default value (and isn't nullable)
-
+ @retval HA_ERR_GENERIC
+ A generic, internal, error caused the unpacking to fail.
*/
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
int
@@ -185,6 +190,7 @@ unpack_row(Relay_log_info const *rli,
{
DBUG_ENTER("unpack_row");
DBUG_ASSERT(row_data);
+ DBUG_ASSERT(table);
size_t const master_null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
int error= 0;
@@ -202,10 +208,38 @@ unpack_row(Relay_log_info const *rli,
// The "current" null bits
unsigned int null_bits= *null_ptr++;
uint i= 0;
- table_def *tabledef= ((Relay_log_info*)rli)->get_tabledef(table);
+ table_def *tabledef= NULL;
+ TABLE *conv_table= NULL;
+ bool table_found= rli && rli->get_table_data(table, &tabledef, &conv_table);
+ DBUG_PRINT("debug", ("Table data: table_found: %d, tabldef: %p, conv_table: %p",
+ table_found, tabledef, conv_table));
+ DBUG_ASSERT(table_found);
+
+ /*
+ If rli is NULL it means that there is no source table and that the
+ row shall just be unpacked without doing any checks. This feature
+ is used by MySQL Backup, but can be used for other purposes as
+ well.
+ */
+ if (rli && !table_found)
+ DBUG_RETURN(HA_ERR_GENERIC);
+
for (field_ptr= begin_ptr ; field_ptr < end_ptr && *field_ptr ; ++field_ptr)
{
- Field *const f= *field_ptr;
+ /*
+ If there is a conversion table, we pick up the field pointer to
+ the conversion table. If the conversion table or the field
+ pointer is NULL, no conversions are necessary.
+ */
+ Field *conv_field=
+ conv_table ? conv_table->field[field_ptr - begin_ptr] : NULL;
+ Field *const f=
+ conv_field ? conv_field : *field_ptr;
+ DBUG_PRINT("debug", ("Conversion %srequired for field '%s' (#%ld)",
+ conv_field ? "" : "not ",
+ (*field_ptr)->field_name,
+ (long) (field_ptr - begin_ptr)));
+ DBUG_ASSERT(f != NULL);
/*
No need to bother about columns that does not exist: they have
@@ -291,6 +325,39 @@ unpack_row(Relay_log_info const *rli,
(int) (pack_ptr - old_pack_ptr)));
}
+ /*
+ If conv_field is set, then we are doing a conversion. In this
+ case, we have unpacked the master data to the conversion
+ table, so we need to copy the value stored in the conversion
+ table into the final table and do the conversion at the same time.
+ */
+ if (conv_field)
+ {
+ Copy_field copy;
+#ifndef DBUG_OFF
+ char source_buf[MAX_FIELD_WIDTH];
+ char value_buf[MAX_FIELD_WIDTH];
+ String source_type(source_buf, sizeof(source_buf), system_charset_info);
+ String value_string(value_buf, sizeof(value_buf), system_charset_info);
+ conv_field->sql_type(source_type);
+ conv_field->val_str(&value_string);
+ DBUG_PRINT("debug", ("Copying field '%s' of type '%s' with value '%s'",
+ (*field_ptr)->field_name,
+ source_type.c_ptr_safe(), value_string.c_ptr_safe()));
+#endif
+ copy.set(*field_ptr, f, TRUE);
+ (*copy.do_copy)(&copy);
+#ifndef DBUG_OFF
+ char target_buf[MAX_FIELD_WIDTH];
+ String target_type(target_buf, sizeof(target_buf), system_charset_info);
+ (*field_ptr)->sql_type(target_type);
+ (*field_ptr)->val_str(&value_string);
+ DBUG_PRINT("debug", ("Value of field '%s' of type '%s' is now '%s'",
+ (*field_ptr)->field_name,
+ target_type.c_ptr_safe(), value_string.c_ptr_safe()));
+#endif
+ }
+
null_mask <<= 1;
}
i++;
@@ -312,8 +379,11 @@ unpack_row(Relay_log_info const *rli,
}
DBUG_ASSERT(null_mask & 0xFF); // One of the 8 LSB should be set
- if (!((null_bits & null_mask) && tabledef->maybe_null(i)))
- pack_ptr+= tabledef->calc_field_size(i, (uchar *) pack_ptr);
+ if (!((null_bits & null_mask) && tabledef->maybe_null(i))) {
+ uint32 len= tabledef->calc_field_size(i, (uchar *) pack_ptr);
+ DBUG_DUMP("field_data", pack_ptr, len);
+ pack_ptr+= len;
+ }
null_mask <<= 1;
}
}
diff --git a/sql/rpl_record.h b/sql/rpl_record.h
index 6e8838f82b3..9b3829a435e 100644
--- a/sql/rpl_record.h
+++ b/sql/rpl_record.h
@@ -17,6 +17,11 @@
#define RPL_RECORD_H
#include <rpl_reporting.h>
+#include "my_global.h" /* uchar */
+
+class Relay_log_info;
+struct TABLE;
+typedef struct st_bitmap MY_BITMAP;
#if !defined(MYSQL_CLIENT)
size_t pack_row(TABLE* table, MY_BITMAP const* cols,
diff --git a/sql/rpl_record_old.cc b/sql/rpl_record_old.cc
index ab4e993ce41..09d5bcacd62 100644
--- a/sql/rpl_record_old.cc
+++ b/sql/rpl_record_old.cc
@@ -1,7 +1,9 @@
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED by other includes
#include "rpl_rli.h"
#include "rpl_record_old.h"
+#include "log_event.h" // Log_event_type
size_t
pack_row_old(TABLE *table, MY_BITMAP const* cols,
diff --git a/sql/rpl_record_old.h b/sql/rpl_record_old.h
index bdaedd56741..71c0ccc17b9 100644
--- a/sql/rpl_record_old.h
+++ b/sql/rpl_record_old.h
@@ -16,6 +16,8 @@
#ifndef RPL_RECORD_OLD_H
#define RPL_RECORD_OLD_H
+#include "log_event.h" /* Log_event_type */
+
#ifndef MYSQL_CLIENT
size_t pack_row_old(TABLE *table, MY_BITMAP const* cols,
uchar *row_data, const uchar *record);
diff --git a/sql/rpl_reporting.cc b/sql/rpl_reporting.cc
index a09140de3c4..051a3609019 100644
--- a/sql/rpl_reporting.cc
+++ b/sql/rpl_reporting.cc
@@ -1,6 +1,30 @@
-#include "mysql_priv.h"
+/* Copyright (C) 2008-2009 Sun Microsystems, Inc
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "sql_priv.h"
#include "rpl_reporting.h"
+#include "log.h" // sql_print_error, sql_print_warning,
+ // sql_print_information
+
+Slave_reporting_capability::Slave_reporting_capability(char const *thread_name)
+ : m_thread_name(thread_name)
+{
+ mysql_mutex_init(key_mutex_slave_reporting_capability_err_lock,
+ &err_lock, MY_MUTEX_INIT_FAST);
+}
void
Slave_reporting_capability::report(loglevel level, int err_code,
@@ -13,7 +37,7 @@ Slave_reporting_capability::report(loglevel level, int err_code,
va_list args;
va_start(args, msg);
- pthread_mutex_lock(&err_lock);
+ mysql_mutex_lock(&err_lock);
switch (level)
{
case ERROR_LEVEL:
@@ -39,7 +63,7 @@ Slave_reporting_capability::report(loglevel level, int err_code,
my_vsnprintf(pbuff, pbuffsize, msg, args);
- pthread_mutex_unlock(&err_lock);
+ mysql_mutex_unlock(&err_lock);
va_end(args);
/* If the msg string ends with '.', do not add a ',' it would be ugly */
@@ -51,5 +75,5 @@ Slave_reporting_capability::report(loglevel level, int err_code,
Slave_reporting_capability::~Slave_reporting_capability()
{
- pthread_mutex_destroy(&err_lock);
+ mysql_mutex_destroy(&err_lock);
}
diff --git a/sql/rpl_reporting.h b/sql/rpl_reporting.h
index ce33407e516..495c74170d2 100644
--- a/sql/rpl_reporting.h
+++ b/sql/rpl_reporting.h
@@ -1,6 +1,23 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 RPL_REPORTING_H
#define RPL_REPORTING_H
+#include "my_sys.h" /* loglevel */
+
/**
Maximum size of an error message from a slave thread.
*/
@@ -17,17 +34,13 @@ class Slave_reporting_capability
{
public:
/** lock used to synchronize m_last_error on 'SHOW SLAVE STATUS' **/
- mutable pthread_mutex_t err_lock;
+ mutable mysql_mutex_t err_lock;
/**
Constructor.
@param thread_name Printable name of the slave thread that is reporting.
*/
- Slave_reporting_capability(char const *thread_name)
- : m_thread_name(thread_name)
- {
- pthread_mutex_init(&err_lock, MY_MUTEX_INIT_FAST);
- }
+ Slave_reporting_capability(char const *thread_name);
/**
Writes a message and, if it's an error message, to Last_Error
@@ -47,9 +60,9 @@ public:
STATUS</code>.
*/
void clear_error() {
- pthread_mutex_lock(&err_lock);
+ mysql_mutex_lock(&err_lock);
m_last_error.clear();
- pthread_mutex_unlock(&err_lock);
+ mysql_mutex_unlock(&err_lock);
}
/**
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 99a42bbe818..a35e7bb1612 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -13,13 +13,19 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
-
+#include "sql_priv.h"
+#include "unireg.h" // HAVE_*
#include "rpl_mi.h"
#include "rpl_rli.h"
+#include "sql_base.h" // close_thread_tables
#include <my_dir.h> // For MY_STAT
#include "sql_repl.h" // For check_binlog_magic
+#include "log_event.h" // Format_description_log_event, Log_event,
+ // FORMAT_DESCRIPTION_LOG_EVENT, ROTATE_EVENT,
+ // PREFIX_SQL_LOAD
#include "rpl_utility.h"
+#include "transaction.h"
+#include "sql_parse.h" // end_trans, ROLLBACK
static int count_relay_log_space(Relay_log_info* rli);
@@ -28,12 +34,13 @@ int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val);
-
-Relay_log_info::Relay_log_info()
+Relay_log_info::Relay_log_info(bool is_slave_recovery)
:Slave_reporting_capability("SQL"),
no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id),
- info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
- cur_log_old_open_count(0), group_relay_log_pos(0), event_relay_log_pos(0),
+ info_fd(-1), cur_log_fd(-1), relay_log(&sync_relaylog_period),
+ sync_counter(0), is_relay_log_recovery(is_slave_recovery),
+ save_temporary_tables(0), cur_log_old_open_count(0), group_relay_log_pos(0),
+ event_relay_log_pos(0),
#if HAVE_purify
is_fake(FALSE),
#endif
@@ -53,13 +60,15 @@ Relay_log_info::Relay_log_info()
bzero((char*) &info_file, sizeof(info_file));
bzero((char*) &cache_buf, sizeof(cache_buf));
cached_charset_invalidate();
- pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&data_cond, NULL);
- pthread_cond_init(&start_cond, NULL);
- pthread_cond_init(&stop_cond, NULL);
- pthread_cond_init(&log_space_cond, NULL);
+ mysql_mutex_init(key_relay_log_info_run_lock, &run_lock, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_relay_log_info_data_lock,
+ &data_lock, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_relay_log_info_log_space_lock,
+ &log_space_lock, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_relay_log_info_data_cond, &data_cond, NULL);
+ mysql_cond_init(key_relay_log_info_start_cond, &start_cond, NULL);
+ mysql_cond_init(key_relay_log_info_stop_cond, &stop_cond, NULL);
+ mysql_cond_init(key_relay_log_info_log_space_cond, &log_space_cond, NULL);
relay_log.init_pthread_objects();
DBUG_VOID_RETURN;
}
@@ -69,13 +78,13 @@ Relay_log_info::~Relay_log_info()
{
DBUG_ENTER("Relay_log_info::~Relay_log_info");
- pthread_mutex_destroy(&run_lock);
- pthread_mutex_destroy(&data_lock);
- pthread_mutex_destroy(&log_space_lock);
- pthread_cond_destroy(&data_cond);
- pthread_cond_destroy(&start_cond);
- pthread_cond_destroy(&stop_cond);
- pthread_cond_destroy(&log_space_cond);
+ mysql_mutex_destroy(&run_lock);
+ mysql_mutex_destroy(&data_lock);
+ mysql_mutex_destroy(&log_space_lock);
+ mysql_cond_destroy(&data_cond);
+ mysql_cond_destroy(&start_cond);
+ mysql_cond_destroy(&stop_cond);
+ mysql_cond_destroy(&log_space_cond);
relay_log.cleanup();
DBUG_VOID_RETURN;
}
@@ -94,7 +103,7 @@ int init_relay_log_info(Relay_log_info* rli,
if (rli->inited) // Set if this function called
DBUG_RETURN(0);
fn_format(fname, info_fname, mysql_data_home, "", 4+32);
- pthread_mutex_lock(&rli->data_lock);
+ mysql_mutex_lock(&rli->data_lock);
info_fd = rli->info_fd;
rli->cur_log_fd = -1;
rli->slave_skip_counter=0;
@@ -109,7 +118,7 @@ int init_relay_log_info(Relay_log_info* rli,
if (fn_format(pattern, PREFIX_SQL_LOAD, pattern, "",
MY_SAFE_PATH | MY_RETURN_REAL_PATH) == NullS)
{
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
sql_print_error("Unable to use slave's temporary directory %s",
slave_load_tmpdir);
DBUG_RETURN(1);
@@ -138,7 +147,7 @@ int init_relay_log_info(Relay_log_info* rli,
if (opt_relay_logname &&
opt_relay_logname[strlen(opt_relay_logname) - 1] == FN_LIBCHAR)
{
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
sql_print_error("Path '%s' is a directory name, please specify \
a file name for --relay-log option", opt_relay_logname);
DBUG_RETURN(1);
@@ -150,7 +159,7 @@ a file name for --relay-log option", opt_relay_logname);
opt_relaylog_index_name[strlen(opt_relaylog_index_name) - 1]
== FN_LIBCHAR)
{
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
sql_print_error("Path '%s' is a directory name, please specify \
a file name for --relay-log-index option", opt_relaylog_index_name);
DBUG_RETURN(1);
@@ -187,7 +196,7 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
(max_relay_log_size ? max_relay_log_size :
max_binlog_size), 1, TRUE))
{
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
sql_print_error("Failed in open_log() called from init_relay_log_info()");
DBUG_RETURN(1);
}
@@ -202,12 +211,13 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
the old descriptor and re-create the old file
*/
if (info_fd >= 0)
- my_close(info_fd, MYF(MY_WME));
- if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
+ mysql_file_close(info_fd, MYF(MY_WME));
+ if ((info_fd= mysql_file_open(key_file_relay_log_info,
+ fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
{
sql_print_error("Failed to create a new relay log info file (\
file '%s', errno %d)", fname, my_errno);
- msg= current_thd->main_da.message();
+ msg= current_thd->stmt_da->message();
goto err;
}
if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
@@ -215,7 +225,7 @@ file '%s', errno %d)", fname, my_errno);
{
sql_print_error("Failed to create a cache on relay log info file '%s'",
fname);
- msg= current_thd->main_da.message();
+ msg= current_thd->stmt_da->message();
goto err;
}
@@ -237,7 +247,8 @@ file '%s', errno %d)", fname, my_errno);
else
{
int error=0;
- if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
+ if ((info_fd= mysql_file_open(key_file_relay_log_info,
+ fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
{
sql_print_error("\
Failed to open the existing relay log info file '%s' (errno %d)",
@@ -254,10 +265,10 @@ Failed to open the existing relay log info file '%s' (errno %d)",
if (error)
{
if (info_fd >= 0)
- my_close(info_fd, MYF(0));
+ mysql_file_close(info_fd, MYF(0));
rli->info_fd= -1;
rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
DBUG_RETURN(1);
}
}
@@ -282,6 +293,9 @@ Failed to open the existing relay log info file '%s' (errno %d)",
rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos;
rli->group_master_log_pos= master_log_pos;
+ if (rli->is_relay_log_recovery && init_recovery(rli->mi, &msg))
+ goto err;
+
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
rli->group_relay_log_pos,
@@ -313,24 +327,27 @@ Failed to open the existing relay log info file '%s' (errno %d)",
*/
reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1);
if ((error= flush_relay_log_info(rli)))
- sql_print_error("Failed to flush relay log info file");
+ {
+ msg= "Failed to flush relay log info file";
+ goto err;
+ }
if (count_relay_log_space(rli))
{
msg="Error counting relay log space";
goto err;
}
rli->inited= 1;
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
DBUG_RETURN(error);
err:
sql_print_error("%s", msg);
end_io_cache(&rli->info_file);
if (info_fd >= 0)
- my_close(info_fd, MYF(0));
+ mysql_file_close(info_fd, MYF(0));
rli->info_fd= -1;
rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
DBUG_RETURN(1);
}
@@ -339,7 +356,8 @@ static inline int add_relay_log(Relay_log_info* rli,LOG_INFO* linfo)
{
MY_STAT s;
DBUG_ENTER("add_relay_log");
- if (!my_stat(linfo->log_file_name,&s,MYF(0)))
+ if (!mysql_file_stat(key_file_binlog,
+ linfo->log_file_name, &s, MYF(0)))
{
sql_print_error("log %s listed in the index, but failed to stat",
linfo->log_file_name);
@@ -439,10 +457,10 @@ int init_relay_log_pos(Relay_log_info* rli,const char* log,
DBUG_PRINT("info", ("pos: %lu", (ulong) pos));
*errmsg=0;
- pthread_mutex_t *log_lock=rli->relay_log.get_log_lock();
+ mysql_mutex_t *log_lock= rli->relay_log.get_log_lock();
if (need_data_lock)
- pthread_mutex_lock(&rli->data_lock);
+ mysql_mutex_lock(&rli->data_lock);
/*
Slave threads are not the only users of init_relay_log_pos(). CHANGE MASTER
@@ -462,13 +480,13 @@ int init_relay_log_pos(Relay_log_info* rli,const char* log,
rli->relay_log.description_event_for_exec= new
Format_description_log_event(3);
- pthread_mutex_lock(log_lock);
+ mysql_mutex_lock(log_lock);
/* Close log file and free buffers if it's already open */
if (rli->cur_log_fd >= 0)
{
end_io_cache(&rli->cache_buf);
- my_close(rli->cur_log_fd, MYF(MY_WME));
+ mysql_file_close(rli->cur_log_fd, MYF(MY_WME));
rli->cur_log_fd = -1;
}
@@ -602,12 +620,12 @@ err:
*/
if (!relay_log_purge)
rli->log_space_limit= 0;
- pthread_cond_broadcast(&rli->data_cond);
+ mysql_cond_broadcast(&rli->data_cond);
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
if (need_data_lock)
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
if (!rli->relay_log.description_event_for_exec->is_valid() && !*errmsg)
*errmsg= "Invalid Format_description log event; could be out of memory";
@@ -658,7 +676,7 @@ int Relay_log_info::wait_for_pos(THD* thd, String* log_name,
log_name->c_ptr(), (ulong) log_pos, (ulong) timeout));
set_timespec(abstime,timeout);
- pthread_mutex_lock(&data_lock);
+ mysql_mutex_lock(&data_lock);
msg= thd->enter_cond(&data_cond, &data_lock,
"Waiting for the slave SQL thread to "
"advance position");
@@ -771,26 +789,26 @@ int Relay_log_info::wait_for_pos(THD* thd, String* log_name,
DBUG_PRINT("info",("Waiting for master update"));
/*
- We are going to pthread_cond_(timed)wait(); if the SQL thread stops it
+ We are going to mysql_cond_(timed)wait(); if the SQL thread stops it
will wake us up.
*/
if (timeout > 0)
{
/*
- Note that pthread_cond_timedwait checks for the timeout
+ Note that mysql_cond_timedwait checks for the timeout
before for the condition ; i.e. it returns ETIMEDOUT
if the system time equals or exceeds the time specified by abstime
before the condition variable is signaled or broadcast, _or_ if
the absolute time specified by abstime has already passed at the time
of the call.
- For that reason, pthread_cond_timedwait will do the "timeoutting" job
+ For that reason, mysql_cond_timedwait will do the "timeoutting" job
even if its condition is always immediately signaled (case of a loaded
master).
*/
- error=pthread_cond_timedwait(&data_cond, &data_lock, &abstime);
+ error= mysql_cond_timedwait(&data_cond, &data_lock, &abstime);
}
else
- pthread_cond_wait(&data_cond, &data_lock);
+ mysql_cond_wait(&data_cond, &data_lock);
DBUG_PRINT("info",("Got signal of master update or timed out"));
if (error == ETIMEDOUT || error == ETIME)
{
@@ -826,7 +844,7 @@ void Relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
DBUG_ENTER("Relay_log_info::inc_group_relay_log_pos");
if (!skip_lock)
- pthread_mutex_lock(&data_lock);
+ mysql_mutex_lock(&data_lock);
inc_event_relay_log_pos();
group_relay_log_pos= event_relay_log_pos;
strmake(group_relay_log_name,event_relay_log_name,
@@ -870,9 +888,9 @@ void Relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
{
group_master_log_pos= log_pos;
}
- pthread_cond_broadcast(&data_cond);
+ mysql_cond_broadcast(&data_cond);
if (!skip_lock)
- pthread_mutex_unlock(&data_lock);
+ mysql_mutex_unlock(&data_lock);
DBUG_VOID_RETURN;
}
@@ -941,7 +959,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
DBUG_ASSERT(rli->mi->slave_running == 0);
rli->slave_skip_counter=0;
- pthread_mutex_lock(&rli->data_lock);
+ mysql_mutex_lock(&rli->data_lock);
/*
we close the relay log fd possibly left open by the slave SQL thread,
@@ -952,7 +970,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
if (rli->cur_log_fd >= 0)
{
end_io_cache(&rli->cache_buf);
- my_close(rli->cur_log_fd, MYF(MY_WME));
+ mysql_file_close(rli->cur_log_fd, MYF(MY_WME));
rli->cur_log_fd= -1;
}
@@ -984,7 +1002,7 @@ err:
char buf[22];
#endif
DBUG_PRINT("info",("log_space_total: %s",llstr(rli->log_space_total,buf)));
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
DBUG_RETURN(error);
}
@@ -1036,7 +1054,7 @@ bool Relay_log_info::is_until_satisfied(THD *thd, Log_event *ev)
DBUG_RETURN(FALSE);
log_name= group_master_log_name;
log_pos= (!ev)? group_master_log_pos :
- ((thd->options & OPTION_BEGIN || !ev->log_pos) ?
+ ((thd->variables.option_bits & OPTION_BEGIN || !ev->log_pos) ?
group_master_log_pos : ev->log_pos - ev->data_written);
}
else
@@ -1160,7 +1178,7 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos,
middle of the "transaction". START SLAVE will resume at BEGIN
while the MyISAM table has already been updated.
*/
- if ((sql_thd->options & OPTION_BEGIN) && opt_using_transactions)
+ if ((sql_thd->variables.option_bits & OPTION_BEGIN) && opt_using_transactions)
inc_event_relay_log_pos();
else
{
@@ -1203,19 +1221,19 @@ void Relay_log_info::cleanup_context(THD *thd, bool error)
*/
if (error)
{
- ha_autocommit_or_rollback(thd, 1); // if a "statement transaction"
- end_trans(thd, ROLLBACK); // if a "real transaction"
+ trans_rollback_stmt(thd); // if a "statement transaction"
+ trans_rollback(thd); // if a "real transaction"
}
m_table_map.clear_tables();
- close_thread_tables(thd);
- clear_tables_to_lock();
+ slave_close_thread_tables(thd);
+ if (error)
+ thd->mdl_context.release_transactional_locks();
clear_flag(IN_STMT);
/*
Cleanup for the flags that have been set at do_apply_event.
*/
- thd->options&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
- thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS;
- last_event_start_time= 0;
+ thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
+ thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
DBUG_VOID_RETURN;
}
@@ -1232,9 +1250,33 @@ void Relay_log_info::clear_tables_to_lock()
tables_to_lock=
static_cast<RPL_TABLE_LIST*>(tables_to_lock->next_global);
tables_to_lock_count--;
- my_free(to_free, MYF(MY_WME));
+ my_free(to_free);
}
DBUG_ASSERT(tables_to_lock == NULL && tables_to_lock_count == 0);
}
+void Relay_log_info::slave_close_thread_tables(THD *thd)
+{
+ thd->stmt_da->can_overwrite_status= TRUE;
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ thd->stmt_da->can_overwrite_status= FALSE;
+
+ close_thread_tables(thd);
+ /*
+ - 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->in_multi_stmt_transaction_mode())
+ thd->mdl_context.release_transactional_locks();
+ else
+ thd->mdl_context.release_statement_locks();
+
+ clear_tables_to_lock();
+}
#endif
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 69988fe5995..09b58d4f3a0 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 MySQL AB
+/* Copyright (C) 2005 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -19,9 +19,12 @@
#include "rpl_tblmap.h"
#include "rpl_reporting.h"
#include "rpl_utility.h"
+#include "log.h" /* LOG_INFO, MYSQL_BIN_LOG */
+#include "sql_class.h" /* THD */
struct RPL_TABLE_LIST;
class Master_info;
+extern uint sql_slave_skip_counter;
/****************************************************************************
@@ -106,6 +109,19 @@ public:
*/
IO_CACHE cache_buf,*cur_log;
+ /*
+ Keeps track of the number of transactions that commits
+ before fsyncing. The option --sync-relay-log-info determines
+ how many transactions should commit before fsyncing.
+ */
+ uint sync_counter;
+
+ /*
+ Identifies when the recovery process is going on.
+ See sql/slave.cc:init_recovery for further details.
+ */
+ bool is_relay_log_recovery;
+
/* The following variables are safe to read any time */
/* IO_CACHE of the info file - set only during init or end */
@@ -119,17 +135,17 @@ public:
TABLE *save_temporary_tables;
/*
- standard lock acquistion order to avoid deadlocks:
+ standard lock acquisition order to avoid deadlocks:
run_lock, data_lock, relay_log.LOCK_log, relay_log.LOCK_index
*/
- pthread_mutex_t data_lock,run_lock;
+ mysql_mutex_t data_lock, run_lock;
/*
start_cond is broadcast when SQL thread is started
stop_cond - when stopped
data_cond - when data protected by data_lock changes
*/
- pthread_cond_t start_cond, stop_cond, data_cond;
+ mysql_cond_t start_cond, stop_cond, data_cond;
/* parent Master_info structure */
Master_info *mi;
@@ -211,15 +227,21 @@ public:
volatile uint32 slave_skip_counter;
volatile ulong abort_pos_wait; /* Incremented on change master */
volatile ulong slave_run_id; /* Incremented on slave start */
- pthread_mutex_t log_space_lock;
- pthread_cond_t log_space_cond;
+ mysql_mutex_t log_space_lock;
+ mysql_cond_t log_space_cond;
THD * sql_thd;
#ifndef DBUG_OFF
int events_till_abort;
#endif
- /* if not set, the value of other members of the structure are undefined */
- bool inited;
+ /*
+ inited changes its value within LOCK_active_mi-guarded critical
+ sections at times of start_slave_threads() (0->1) and end_slave() (1->0).
+ Readers may not acquire the mutex while they realize potential concurrency
+ issue.
+ If not set, the value of other members of the structure are undefined.
+ */
+ volatile bool inited;
volatile bool abort_slave;
volatile uint slave_running;
@@ -277,7 +299,7 @@ public:
char slave_patternload_file[FN_REFLEN];
size_t slave_patternload_file_size;
- Relay_log_info();
+ Relay_log_info(bool is_slave_recovery);
~Relay_log_info();
/*
@@ -324,13 +346,21 @@ public:
uint tables_to_lock_count; /* RBR: Count of tables to lock */
table_mapping m_table_map; /* RBR: Mapping table-id to table */
- inline table_def *get_tabledef(TABLE *tbl)
+ bool get_table_data(TABLE *table_arg, table_def **tabledef_var, TABLE **conv_table_var) const
{
- table_def *td= 0;
- for (TABLE_LIST *ptr= tables_to_lock; ptr && !td; ptr= ptr->next_global)
- if (ptr->table == tbl)
- td= &((RPL_TABLE_LIST *)ptr)->m_tabledef;
- return (td);
+ DBUG_ASSERT(tabledef_var && conv_table_var);
+ for (TABLE_LIST *ptr= tables_to_lock ; ptr != NULL ; ptr= ptr->next_global)
+ if (ptr->table == table_arg)
+ {
+ *tabledef_var= &static_cast<RPL_TABLE_LIST*>(ptr)->m_tabledef;
+ *conv_table_var= static_cast<RPL_TABLE_LIST*>(ptr)->m_conv_table;
+ DBUG_PRINT("debug", ("Fetching table data for table %s.%s:"
+ " tabledef: %p, conv_table: %p",
+ table_arg->s->db.str, table_arg->s->table_name.str,
+ *tabledef_var, *conv_table_var));
+ return true;
+ }
+ return false;
}
/*
@@ -343,15 +373,14 @@ public:
bool cached_charset_compare(char *charset) const;
void cleanup_context(THD *, bool);
+ void slave_close_thread_tables(THD *);
void clear_tables_to_lock();
/*
- Used by row-based replication to detect that it should not stop at
- this event, but give it a chance to send more events. The time
- where the last event inside a group started is stored here. If the
- variable is zero, we are not in a group (but may be in a
- transaction).
- */
+ Used to defer stopping the SQL thread to give it a chance
+ to finish up the current group of events.
+ The timestamp is set and reset in @c sql_slave_killed().
+ */
time_t last_event_start_time;
/**
@@ -419,7 +448,7 @@ public:
@retval false Replication thread is currently not inside a group
*/
bool is_in_group() const {
- return (sql_thd->options & OPTION_BEGIN) ||
+ return (sql_thd->variables.option_bits & OPTION_BEGIN) ||
(m_flags & (1UL << IN_STMT));
}
diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc
index 6ef9a8623fe..5a178ffde83 100644
--- a/sql/rpl_tblmap.cc
+++ b/sql/rpl_tblmap.cc
@@ -13,11 +13,15 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "my_global.h" // HAVE_REPLICATION
#ifdef HAVE_REPLICATION
#include "rpl_tblmap.h"
+#ifndef MYSQL_CLIENT
+#include "table.h"
+#endif
#ifdef MYSQL_CLIENT
#define MAYBE_TABLE_NAME(T) ("")
@@ -34,10 +38,10 @@ table_mapping::table_mapping()
No "free_element" function for entries passed here, as the entries are
allocated in a MEM_ROOT (freed as a whole in the destructor), they cannot
be freed one by one.
- Note that below we don't test if hash_init() succeeded. This constructor
- is called at startup only.
+ Note that below we don't test if my_hash_init() succeeded. This
+ constructor is called at startup only.
*/
- (void) hash_init(&m_table_ids,&my_charset_bin,TABLE_ID_HASH_SIZE,
+ (void) my_hash_init(&m_table_ids,&my_charset_bin,TABLE_ID_HASH_SIZE,
offsetof(entry,table_id),sizeof(ulong),
0,0,0);
/* We don't preallocate any block, this is consistent with m_free=0 above */
@@ -49,7 +53,7 @@ table_mapping::~table_mapping()
#ifdef MYSQL_CLIENT
clear_tables();
#endif
- hash_free(&m_table_ids);
+ my_hash_free(&m_table_ids);
free_root(&m_mem_root, MYF(0));
}
@@ -115,7 +119,7 @@ int table_mapping::set_table(ulong table_id, TABLE* table)
#ifdef MYSQL_CLIENT
free_table_map_log_event(e->table);
#endif
- hash_delete(&m_table_ids,(uchar *)e);
+ my_hash_delete(&m_table_ids,(uchar *)e);
}
e->table_id= table_id;
e->table= table;
@@ -138,7 +142,7 @@ int table_mapping::remove_table(ulong table_id)
entry *e= find_entry(table_id);
if (e)
{
- hash_delete(&m_table_ids,(uchar *)e);
+ my_hash_delete(&m_table_ids,(uchar *)e);
/* we add this entry to the chain of free (free for use) entries */
e->next= m_free;
m_free= e;
@@ -156,7 +160,7 @@ void table_mapping::clear_tables()
DBUG_ENTER("table_mapping::clear_tables()");
for (uint i= 0; i < m_table_ids.records; i++)
{
- entry *e= (entry *)hash_element(&m_table_ids, i);
+ entry *e= (entry *)my_hash_element(&m_table_ids, i);
#ifdef MYSQL_CLIENT
free_table_map_log_event(e->table);
#endif
diff --git a/sql/rpl_tblmap.h b/sql/rpl_tblmap.h
index 3b5b10be580..3d24a47d9ae 100644
--- a/sql/rpl_tblmap.h
+++ b/sql/rpl_tblmap.h
@@ -18,8 +18,7 @@
/* Forward declarations */
#ifndef MYSQL_CLIENT
-struct st_table;
-typedef st_table TABLE;
+struct TABLE;
#else
class Table_map_log_event;
typedef Table_map_log_event TABLE;
@@ -53,6 +52,8 @@ void free_table_map_log_event(TABLE *table);
A dedicated MEM_ROOT needs to be used, see below.
*/
+#include "hash.h" /* HASH */
+
class table_mapping {
private:
@@ -91,9 +92,9 @@ private:
entry *find_entry(ulong table_id)
{
- return (entry *)hash_search(&m_table_ids,
- (uchar*)&table_id,
- sizeof(table_id));
+ return (entry *) my_hash_search(&m_table_ids,
+ (uchar*)&table_id,
+ sizeof(table_id));
}
int expand();
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index 6058c473e9f..6f66905eb5d 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -14,7 +14,177 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "rpl_utility.h"
+
+#ifndef MYSQL_CLIENT
+#include "unireg.h" // REQUIRED by later includes
#include "rpl_rli.h"
+#include "sql_select.h"
+
+/**
+ Function to compare two size_t integers for their relative
+ order. Used below.
+ */
+int compare(size_t a, size_t b)
+{
+ if (a < b)
+ return -1;
+ if (b < a)
+ return 1;
+ return 0;
+}
+
+
+/**
+ Max value for an unsigned integer of 'bits' bits.
+
+ The somewhat contorted expression is to avoid overflow.
+ */
+uint32 uint_max(int bits) {
+ return (((1UL << (bits - 1)) - 1) << 1) | 1;
+}
+
+
+/**
+ 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.
+ */
+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:
+ case MYSQL_TYPE_TIME:
+ return 3;
+
+ case MYSQL_TYPE_TIMESTAMP:
+ return 4;
+
+ case MYSQL_TYPE_DATETIME:
+ return 8;
+
+ 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;
+
+ /*
+ 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 uint_max(1 * 8);
+
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ return uint_max(3 * 8);
+
+ case MYSQL_TYPE_BLOB:
+ /*
+ 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 uint_max(metadata * 8);
+
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ return uint_max(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= compare(source_length, target_length);
+ DBUG_PRINT("result", ("%d", result));
+ DBUG_RETURN(result);
+}
/*********************************************************************
* table_def member definitions *
@@ -169,58 +339,720 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const
return length;
}
-/*
+
+/**
+ */
+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:
+ 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:
+ str->set_ascii(STRING_WITH_LEN("time"));
+ break;
+
+ case MYSQL_TYPE_DATETIME:
+ 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:
+ {
+ CHARSET_INFO *cs= str->charset();
+ uint32 length=
+ cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
+ "varchar(%u)", metadata);
+ str->length(length);
+ }
+ break;
+
+ case MYSQL_TYPE_BIT:
+ {
+ CHARSET_INFO *cs= str->charset();
+ int bit_length= 8 * (metadata >> 8) + (metadata & 0xFF);
+ uint32 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();
+ uint32 length=
+ cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
+ "decimal(%d,?)", metadata);
+ str->length(length);
+ }
+ break;
+
+ case MYSQL_TYPE_NEWDECIMAL:
+ {
+ CHARSET_INFO *cs= str->charset();
+ uint32 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:
+ /*
+ 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;
+ }
+ 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);
+ uint32 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 &
+ (ULL(1) << SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY);
+ allow_lossy= slave_type_conversions_options &
+ (ULL(1) << 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");
+#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
+ /*
+ If the real type is the same, we need to check the metadata to
+ decide if conversions are allowed.
+ */
+ if (field->real_type() == source_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 (!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:
+ *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_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_VARCHAR:
+ 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_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_VARCHAR:
+ *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_NEWDATE:
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ DBUG_RETURN(false);
+ }
+ 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.
*/
-int
-table_def::compatible_with(Relay_log_info const *rli_arg, TABLE *table)
+bool
+table_def::compatible_with(THD *thd, Relay_log_info *rli,
+ TABLE *table, TABLE **conv_table_var)
const
{
/*
We only check the initial columns for the tables.
*/
uint const cols_to_check= min(table->s->fields, size());
- int error= 0;
- Relay_log_info const *rli= const_cast<Relay_log_info*>(rli_arg);
-
- TABLE_SHARE const *const tsh= table->s;
+ TABLE *tmp_table= NULL;
for (uint col= 0 ; col < cols_to_check ; ++col)
{
Field *const field= table->field[col];
- if (field->type() != type(col))
- {
- DBUG_ASSERT(col < size() && col < tsh->fields);
- DBUG_ASSERT(tsh->db.str && tsh->table_name.str);
- error= 1;
- char buf[256];
- my_snprintf(buf, sizeof(buf), "Column %d type mismatch - "
- "received type %d, %s.%s has type %d",
- col, type(col), tsh->db.str, tsh->table_name.str,
- field->type());
- rli->report(ERROR_LEVEL, ER_BINLOG_ROW_WRONG_TABLE_DEF,
- ER(ER_BINLOG_ROW_WRONG_TABLE_DEF), buf);
+ 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, 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, rli, 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;
}
- /*
- Check the slave's field size against that of the master.
- */
- if (!error &&
- !field->compatible_field_size(field_metadata(col), rli_arg, m_flags))
+ else
{
- error= 1;
- char buf[256];
- my_snprintf(buf, sizeof(buf), "Column %d size mismatch - "
- "master has size %d, %s.%s on slave has size %d."
- " Master's column size should be <= the slave's "
- "column size.", col,
- field->pack_length_from_metadata(m_field_metadata[col]),
- tsh->db.str, tsh->table_name.str,
- field->row_pack_length());
- rli->report(ERROR_LEVEL, ER_BINLOG_ROW_WRONG_TABLE_DEF,
- ER(ER_BINLOG_ROW_WRONG_TABLE_DEF), buf);
+ DBUG_PRINT("debug", ("Checking column %d -"
+ " field '%s' can not be converted",
+ col, field->field_name));
+ DBUG_ASSERT(col < size() && col < table->s->fields);
+ DBUG_ASSERT(table->s->db.str && table->s->table_name.str);
+ 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);
+ 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,
+ ER(ER_SLAVE_CONVERSION_FAILED),
+ col, db_name, tbl_name,
+ source_type.c_ptr_safe(), target_type.c_ptr_safe());
+ return false;
}
}
- return error;
+#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,
+ source_type.c_ptr_safe(), target_type.c_ptr_safe()));
+ }
+ }
+#endif
+
+ *conv_table_var= tmp_table;
+ return true;
}
+
+/**
+ 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, Relay_log_info *rli, TABLE *target_table) const
+{
+ DBUG_ENTER("table_def::create_conversion_table");
+
+ List<Create_field> field_list;
+
+ for (uint col= 0 ; col < size() ; ++col)
+ {
+ Create_field *field_def=
+ (Create_field*) alloc_root(thd->mem_root, sizeof(Create_field));
+ if (field_list.push_back(field_def))
+ DBUG_RETURN(NULL);
+
+ uint decimals= 0;
+ TYPELIB* interval= NULL;
+ uint pack_length= 0;
+ uint32 max_length=
+ max_display_length_for_field(type(col), field_metadata(col));
+
+ switch(type(col))
+ {
+ int precision;
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ interval= static_cast<Field_enum*>(target_table->field[col])->typelib;
+ pack_length= field_metadata(col) & 0x00ff;
+ break;
+
+ case MYSQL_TYPE_NEWDECIMAL:
+ /*
+ The display length of a DECIMAL type is not the same as the
+ length that should be supplied to make_field, so we correct
+ the length here.
+ */
+ precision= field_metadata(col) >> 8;
+ decimals= field_metadata(col) & 0x00ff;
+ max_length=
+ my_decimal_precision_to_length(precision, decimals, FALSE);
+ break;
+
+ case MYSQL_TYPE_DECIMAL:
+ precision= field_metadata(col);
+ decimals= static_cast<Field_num*>(target_table->field[col])->dec;
+ max_length= field_metadata(col);
+ break;
+
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ pack_length= field_metadata(col) & 0x00ff;
+ break;
+
+ default:
+ break;
+ }
+
+ DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d,"
+ " maybe_null: %d, unsigned_flag: %d, pack_length: %u",
+ type(col), target_table->field[col]->field_name,
+ max_length, decimals, TRUE, FALSE, pack_length));
+ field_def->init_for_tmp_table(type(col),
+ max_length,
+ decimals,
+ TRUE, // maybe_null
+ FALSE, // unsigned_flag
+ pack_length);
+ field_def->charset= target_table->field[col]->charset();
+ field_def->interval= interval;
+ }
+
+ TABLE *conv_table= create_virtual_tmp_table(thd, field_list);
+ if (conv_table == NULL)
+ rli->report(ERROR_LEVEL, ER_SLAVE_CANT_CREATE_CONVERSION,
+ ER(ER_SLAVE_CANT_CREATE_CONVERSION),
+ target_table->s->db.str,
+ target_table->s->table_name.str);
+ DBUG_RETURN(conv_table);
+}
+
+#endif /* MYSQL_CLIENT */
+
+table_def::table_def(unsigned char *types, ulong size,
+ uchar *field_metadata, int metadata_size,
+ uchar *null_bitmap, uint16 flags)
+ : m_size(size), m_type(0), m_field_metadata_size(metadata_size),
+ m_field_metadata(0), m_null_bits(0), m_flags(flags),
+ m_memory(NULL)
+{
+ m_memory= (uchar *)my_multi_malloc(MYF(MY_WME),
+ &m_type, size,
+ &m_field_metadata,
+ size * sizeof(uint16),
+ &m_null_bits, (size + 7) / 8,
+ NULL);
+
+ bzero(m_field_metadata, size * sizeof(uint16));
+
+ if (m_type)
+ memcpy(m_type, types, size);
+ else
+ m_size= 0;
+ /*
+ Extract the data from the table map into the field metadata array
+ iff there is field metadata. The variable metadata_size will be
+ 0 if we are replicating from an older version server since no field
+ metadata was written to the table map. This can also happen if
+ there were no fields in the master that needed extra metadata.
+ */
+ if (m_size && metadata_size)
+ {
+ int index= 0;
+ for (unsigned int i= 0; i < m_size; i++)
+ {
+ switch (m_type[i]) {
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_GEOMETRY:
+ {
+ /*
+ These types store a single byte.
+ */
+ m_field_metadata[i]= field_metadata[index];
+ index++;
+ break;
+ }
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_STRING:
+ {
+ uint16 x= field_metadata[index++] << 8U; // real_type
+ x+= field_metadata[index++]; // pack or field length
+ m_field_metadata[i]= x;
+ break;
+ }
+ case MYSQL_TYPE_BIT:
+ {
+ uint16 x= field_metadata[index++];
+ x = x + (field_metadata[index++] << 8U);
+ m_field_metadata[i]= x;
+ break;
+ }
+ case MYSQL_TYPE_VARCHAR:
+ {
+ /*
+ These types store two bytes.
+ */
+ char *ptr= (char *)&field_metadata[index];
+ m_field_metadata[i]= uint2korr(ptr);
+ index= index + 2;
+ break;
+ }
+ case MYSQL_TYPE_NEWDECIMAL:
+ {
+ uint16 x= field_metadata[index++] << 8U; // precision
+ x+= field_metadata[index++]; // decimals
+ m_field_metadata[i]= x;
+ break;
+ }
+ default:
+ m_field_metadata[i]= 0;
+ break;
+ }
+ }
+ }
+ if (m_size && null_bitmap)
+ memcpy(m_null_bits, null_bitmap, (m_size + 7) / 8);
+}
+
+
+table_def::~table_def()
+{
+ my_free(m_memory);
+#ifndef DBUG_OFF
+ m_type= 0;
+ m_size= 0;
+#endif
+}
+
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index b209c9140d1..25f2a60bece 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -20,7 +20,12 @@
#error "Don't include this C++ header file from a non-C++ file!"
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "m_string.h" /* bzero, memcpy */
+#ifdef MYSQL_SERVER
+#include "table.h" /* TABLE_LIST */
+#endif
+#include "mysql_com.h"
class Relay_log_info;
@@ -38,116 +43,18 @@ class table_def
{
public:
/**
- Convenience declaration of the type of the field type data in a
- table map event.
- */
- typedef unsigned char field_type;
-
- /**
Constructor.
- @param types Array of types
+ @param types Array of types, each stored as a byte
@param size Number of elements in array 'types'
@param field_metadata Array of extra information about fields
@param metadata_size Size of the field_metadata array
@param null_bitmap The bitmap of fields that can be null
*/
- table_def(field_type *types, ulong size, uchar *field_metadata,
- int metadata_size, uchar *null_bitmap, uint16 flags)
- : m_size(size), m_type(0), m_field_metadata_size(metadata_size),
- m_field_metadata(0), m_null_bits(0), m_flags(flags), m_memory(NULL)
- {
- m_memory= (uchar *)my_multi_malloc(MYF(MY_WME),
- &m_type, size,
- &m_field_metadata,
- size * sizeof(uint16),
- &m_null_bits, (size + 7) / 8,
- NULL);
-
- bzero(m_field_metadata, size * sizeof(uint16));
-
- if (m_type)
- memcpy(m_type, types, size);
- else
- m_size= 0;
- /*
- Extract the data from the table map into the field metadata array
- iff there is field metadata. The variable metadata_size will be
- 0 if we are replicating from an older version server since no field
- metadata was written to the table map. This can also happen if
- there were no fields in the master that needed extra metadata.
- */
- if (m_size && metadata_size)
- {
- int index= 0;
- for (unsigned int i= 0; i < m_size; i++)
- {
- switch (m_type[i]) {
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_DOUBLE:
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_GEOMETRY:
- {
- /*
- These types store a single byte.
- */
- m_field_metadata[i]= field_metadata[index];
- index++;
- break;
- }
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_STRING:
- {
- uint16 x= field_metadata[index++] << 8U; // real_type
- x+= field_metadata[index++]; // pack or field length
- m_field_metadata[i]= x;
- break;
- }
- case MYSQL_TYPE_BIT:
- {
- uint16 x= field_metadata[index++];
- x = x + (field_metadata[index++] << 8U);
- m_field_metadata[i]= x;
- break;
- }
- case MYSQL_TYPE_VARCHAR:
- {
- /*
- These types store two bytes.
- */
- char *ptr= (char *)&field_metadata[index];
- m_field_metadata[i]= uint2korr(ptr);
- index= index + 2;
- break;
- }
- case MYSQL_TYPE_NEWDECIMAL:
- {
- uint16 x= field_metadata[index++] << 8U; // precision
- x+= field_metadata[index++]; // decimals
- m_field_metadata[i]= x;
- break;
- }
- default:
- m_field_metadata[i]= 0;
- break;
- }
- }
- }
- if (m_size && null_bitmap)
- memcpy(m_null_bits, null_bitmap, (m_size + 7) / 8);
- }
+ table_def(unsigned char *types, ulong size, uchar *field_metadata,
+ int metadata_size, uchar *null_bitmap, uint16 flags);
- ~table_def() {
- my_free(m_memory, MYF(0));
-#ifndef DBUG_OFF
- m_type= 0;
- m_size= 0;
-#endif
- }
+ ~table_def();
/**
Return the number of fields there is type data for.
@@ -166,10 +73,40 @@ public:
<code>index</code>. Currently, only the type identifier is
returned.
*/
- field_type type(ulong index) const
+ enum_field_types type(ulong index) const
{
DBUG_ASSERT(index < m_size);
- return m_type[index];
+ /*
+ If the source type is MYSQL_TYPE_STRING, it can in reality be
+ either MYSQL_TYPE_STRING, MYSQL_TYPE_ENUM, or MYSQL_TYPE_SET, so
+ we might need to modify the type to get the real type.
+ */
+ enum_field_types source_type= static_cast<enum_field_types>(m_type[index]);
+ uint16 source_metadata= m_field_metadata[index];
+ switch (source_type)
+ {
+ case MYSQL_TYPE_STRING:
+ {
+ int real_type= source_metadata >> 8;
+ if (real_type == MYSQL_TYPE_ENUM || real_type == MYSQL_TYPE_SET)
+ source_type= static_cast<enum_field_types>(real_type);
+ break;
+ }
+
+ /*
+ This type has not been used since before row-based replication,
+ so we can safely assume that it really is MYSQL_TYPE_NEWDATE.
+ */
+ case MYSQL_TYPE_DATE:
+ source_type= MYSQL_TYPE_NEWDATE;
+ break;
+
+ default:
+ /* Do nothing */
+ break;
+ }
+
+ return source_type;
}
@@ -221,23 +158,58 @@ public:
with it.
A table definition is compatible with a table if:
- - the columns types of the table definition is a (not
- necessarily proper) prefix of the column type of the table, or
- - the other way around
+ - The columns types of the table definition is a (not
+ necessarily proper) prefix of the column type of the table.
+ - The other way around.
+
+ - Each column on the master that also exists on the slave can be
+ converted according to the current settings of @c
+ SLAVE_TYPE_CONVERSIONS.
+
+ @param thd
@param rli Pointer to relay log info
@param table Pointer to table to compare with.
+ @param[out] tmp_table_var Pointer to temporary table for holding
+ conversion table.
+
@retval 1 if the table definition is not compatible with @c table
@retval 0 if the table definition is compatible with @c table
*/
#ifndef MYSQL_CLIENT
- int compatible_with(Relay_log_info const *rli, TABLE *table) const;
+ bool compatible_with(THD *thd, Relay_log_info *rli, TABLE *table,
+ TABLE **conv_table_var) const;
+
+ /**
+ Create a virtual in-memory temporary table structure.
+
+ The table structure has records and field array so that a row can
+ be unpacked into the record for further processing.
+
+ In the virtual table, each field that requires conversion will
+ have a non-NULL value, while fields that do not require
+ conversion will have a NULL value.
+
+ Some information that is missing in the events, such as the
+ character set for string types, are taken from the table that the
+ field is going to be pushed into, so the target table that the data
+ eventually need to be pushed into need to be supplied.
+
+ @param thd Thread to allocate memory from.
+ @param rli Relay log info structure, for error reporting.
+ @param target_table Target table for fields.
+
+ @return A pointer to a temporary table with memory allocated in the
+ thread's memroot, NULL if the table could not be created
+ */
+ TABLE *create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *target_table) const;
#endif
+
private:
ulong m_size; // Number of elements in the types array
- field_type *m_type; // Array of type descriptors
+ unsigned char *m_type; // Array of type descriptors
uint m_field_metadata_size;
uint16 *m_field_metadata;
uchar *m_null_bits;
@@ -256,11 +228,12 @@ struct RPL_TABLE_LIST
{
bool m_tabledef_valid;
table_def m_tabledef;
+ TABLE *m_conv_table;
};
/* Anonymous namespace for template functions/classes */
-namespace {
+CPP_UNNAMED_NS_START
/*
Smart pointer that will automatically call my_afree (a macro) when
@@ -287,7 +260,7 @@ namespace {
Obj* get() { return m_ptr; }
};
-}
+CPP_UNNAMED_NS_END
#endif
// NB. number of printed bit values is limited to sizeof(buf) - 1
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
index b05bdf4756f..d61a452b99e 100644
--- a/sql/scheduler.cc
+++ b/sql/scheduler.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007 MySQL AB
+/* Copyright (C) 2007 MySQL AB, 2008-2010 Sun Microsystems, Inc.
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
@@ -21,56 +21,107 @@
#pragma implementation
#endif
-#include <mysql_priv.h>
+#include <sql_priv.h>
+#include "unireg.h" // REQUIRED: for other includes
+#include "scheduler.h"
+#include "sql_connect.h" // init_new_connection_handler_thread
+#include "scheduler.h"
+#include "sql_callback.h"
/*
- 'Dummy' functions to be used when we don't need any handling for a scheduler
- event
- */
+ End connection, in case when we are using 'no-threads'
+*/
+
+static bool no_threads_end(THD *thd, bool put_in_cache)
+{
+ unlink_thd(thd);
+ mysql_mutex_unlock(&LOCK_thread_count);
+ return 1; // Abort handle_one_connection
+}
-static bool init_dummy(void) {return 0;}
-static void post_kill_dummy(THD* thd) {}
-static void end_dummy(void) {}
-static bool end_thread_dummy(THD *thd, bool cache_thread) { return 0; }
+static scheduler_functions one_thread_scheduler_functions=
+{
+ 1, // max_threads
+ NULL, // init
+ init_new_connection_handler_thread, // init_new_connection_thread
+#ifndef EMBEDDED_LIBRARY
+ handle_connection_in_main_thread, // add_connection
+#else
+ NULL, // add_connection
+#endif // EMBEDDED_LIBRARY
+ NULL, // thd_wait_begin
+ NULL, // thd_wait_end
+ NULL, // post_kill_notification
+ no_threads_end, // end_thread
+ NULL, // end
+};
-/*
- Initialize default scheduler with dummy functions so that setup functions
- only need to declare those that are relvant for their usage
+#ifndef EMBEDDED_LIBRARY
+static scheduler_functions one_thread_per_connection_scheduler_functions=
+{
+ 0, // max_threads
+ NULL, // init
+ init_new_connection_handler_thread, // init_new_connection_thread
+ create_thread_to_handle_connection, // add_connection
+ NULL, // thd_wait_begin
+ NULL, // thd_wait_end
+ NULL, // post_kill_notification
+ one_thread_per_connection_end, // end_thread
+ NULL, // end
+};
+#endif // EMBEDDED_LIBRARY
+
+
+scheduler_functions *thread_scheduler= NULL;
+
+/** @internal
+ Helper functions to allow mysys to call the thread scheduler when
+ waiting for locks.
*/
-scheduler_functions::scheduler_functions()
- :init(init_dummy),
- init_new_connection_thread(init_new_connection_handler_thread),
- add_connection(0), // Must be defined
- post_kill_notification(post_kill_dummy),
- end_thread(end_thread_dummy), end(end_dummy)
-{}
+/**@{*/
+static void scheduler_wait_begin(void) {
+ MYSQL_CALLBACK(thread_scheduler,
+ thd_wait_begin, (current_thd, THD_WAIT_ROW_TABLE_LOCK));
+}
+
+static void scheduler_wait_end(void) {
+ MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (current_thd));
+}
+/**@}*/
+/**
+ Common scheduler init function.
+
+ The scheduler is either initialized by calling
+ one_thread_scheduler() or one_thread_per_connection_scheduler() in
+ mysqld.cc, so this init function will always be called.
+ */
+static void scheduler_init() {
+ thr_set_lock_wait_callback(scheduler_wait_begin, scheduler_wait_end);
+}
/*
- End connection, in case when we are using 'no-threads'
+ Initialize scheduler for --thread-handling=one-thread-per-connection
*/
-static bool no_threads_end(THD *thd, bool put_in_cache)
+#ifndef EMBEDDED_LIBRARY
+void one_thread_per_connection_scheduler()
{
- unlink_thd(thd);
- pthread_mutex_unlock(&LOCK_thread_count);
- return 1; // Abort handle_one_connection
+ scheduler_init();
+ one_thread_per_connection_scheduler_functions.max_threads= max_connections;
+ thread_scheduler= &one_thread_per_connection_scheduler_functions;
}
-
+#endif
/*
Initailize scheduler for --thread-handling=no-threads
*/
-void one_thread_scheduler(scheduler_functions* func)
+void one_thread_scheduler()
{
- func->max_threads= 1;
-#ifndef EMBEDDED_LIBRARY
- func->add_connection= handle_connection_in_main_thread;
-#endif
- func->init_new_connection_thread= init_dummy;
- func->end_thread= no_threads_end;
+ scheduler_init();
+ thread_scheduler= &one_thread_scheduler_functions;
}
@@ -78,11 +129,58 @@ void one_thread_scheduler(scheduler_functions* func)
Initialize scheduler for --thread-handling=one-thread-per-connection
*/
-#ifndef EMBEDDED_LIBRARY
-void one_thread_per_connection_scheduler(scheduler_functions* func)
+/*
+ thd_scheduler keeps the link between THD and events.
+ It's embedded in the THD class.
+*/
+
+thd_scheduler::thd_scheduler()
+ : m_psi(NULL), data(NULL)
{
- func->max_threads= max_connections;
- func->add_connection= create_thread_to_handle_connection;
- func->end_thread= one_thread_per_connection_end;
+#ifndef DBUG_OFF
+ dbug_explain[0]= '\0';
+ set_explain= FALSE;
+#endif
}
-#endif /* EMBEDDED_LIBRARY */
+
+
+thd_scheduler::~thd_scheduler()
+{
+}
+
+static scheduler_functions *saved_thread_scheduler;
+static uint saved_thread_handling;
+
+extern "C"
+int my_thread_scheduler_set(scheduler_functions *scheduler)
+{
+ DBUG_ASSERT(scheduler != 0);
+
+ if (scheduler == NULL)
+ return 1;
+
+ saved_thread_scheduler= thread_scheduler;
+ saved_thread_handling= thread_handling;
+ thread_scheduler= scheduler;
+ // Scheduler loaded dynamically
+ thread_handling= SCHEDULER_TYPES_COUNT;
+ return 0;
+}
+
+
+extern "C"
+int my_thread_scheduler_reset()
+{
+ DBUG_ASSERT(saved_thread_scheduler != NULL);
+
+ if (saved_thread_scheduler == NULL)
+ return 1;
+
+ thread_scheduler= saved_thread_scheduler;
+ thread_handling= saved_thread_handling;
+ saved_thread_scheduler= 0;
+ return 0;
+}
+
+
+
diff --git a/sql/scheduler.h b/sql/scheduler.h
index 46bbd300cbb..b5a175434b6 100644
--- a/sql/scheduler.h
+++ b/sql/scheduler.h
@@ -1,3 +1,6 @@
+#ifndef SCHEDULER_INCLUDED
+#define SCHEDULER_INCLUDED
+
/* Copyright (C) 2007 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -25,36 +28,84 @@ class THD;
/* Functions used when manipulating threads */
-class scheduler_functions
+struct scheduler_functions
{
-public:
uint max_threads;
bool (*init)(void);
bool (*init_new_connection_thread)(void);
void (*add_connection)(THD *thd);
+ 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);
- scheduler_functions();
};
+
+/**
+ Scheduler types enumeration.
+
+ The default of --thread-handling is the first one in the
+ thread_handling_names array, this array has to be consistent with
+ the order in this array, so to change default one has to change the
+ first entry in this enum and the first entry in the
+ thread_handling_names array.
+
+ @note The last entry of the enumeration is also used to mark the
+ thread handling as dynamic. In this case the name of the thread
+ handling is fetched from the name of the plugin that implements it.
+*/
enum scheduler_types
{
+ /*
+ The default of --thread-handling is the first one in the
+ thread_handling_names array, this array has to be consistent with
+ the order in this array, so to change default one has to change
+ the first entry in this enum and the first entry in the
+ thread_handling_names array.
+ */
SCHEDULER_ONE_THREAD_PER_CONNECTION=0,
SCHEDULER_NO_THREADS,
- SCHEDULER_POOL_OF_THREADS
+ SCHEDULER_TYPES_COUNT
};
-void one_thread_per_connection_scheduler(scheduler_functions* func);
-void one_thread_scheduler(scheduler_functions* func);
+void one_thread_per_connection_scheduler();
+void one_thread_scheduler();
enum pool_command_op
{
NOT_IN_USE_OP= 0, NORMAL_OP= 1, CONNECT_OP, KILL_OP, DIE_OP
};
-#define HAVE_POOL_OF_THREADS 0 /* For easyer tests */
-#define pool_of_threads_scheduler(A) one_thread_per_connection_scheduler(A)
-
+/*
+ To be used for pool-of-threads (implemeneted differently on various OSs)
+*/
class thd_scheduler
-{};
+{
+public:
+ /*
+ Thread instrumentation for the user job.
+ This member holds the instrumentation while the user job is not run
+ by a thread.
+
+ Note that this member is not conditionally declared
+ (ifdef HAVE_PSI_INTERFACE), because doing so will change the binary
+ layout of THD, which is exposed to plugin code that may be compiled
+ differently.
+ */
+ PSI_thread *m_psi;
+
+ void *data; /* scheduler-specific data structure */
+
+# ifndef DBUG_OFF
+ char dbug_explain[512];
+ bool set_explain;
+# endif
+
+ thd_scheduler();
+ ~thd_scheduler();
+};
+
+extern scheduler_functions *thread_scheduler;
+
+#endif
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 26f97d46d52..4313dcce917 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc.
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
@@ -13,2056 +13,374 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/**
- @file
-
- @brief
- Handling of MySQL SQL variables
-
- @details
- To add a new variable, one has to do the following:
-
- - Use one of the 'sys_var... classes from set_var.h or write a specific
- one for the variable type.
- - Define it in the 'variable definition list' in this file.
- - If the variable is thread specific, add it to 'system_variables' struct.
- If not, add it to mysqld.cc and an declaration in 'mysql_priv.h'
- - If the variable should be changed from the command line, add a definition
- of it in the my_option structure list in mysqld.cc
- - Don't forget to initialize new fields in global_system_variables and
- max_system_variables!
-
- @todo
- Add full support for the variable character_set (for 4.1)
-
- @todo
- When updating myisam_delay_key_write, we should do a 'flush tables'
- of all MyISAM tables to ensure that they are reopen with the
- new attribute.
-
- @note
- Be careful with var->save_result: sys_var::check() only updates
- ulonglong_value; so other members of the union are garbage then; to use
- them you must first assign a value to them (in specific ::check() for
- example).
-*/
-
#ifdef USE_PRAGMA_IMPLEMENTATION
-#pragma implementation // gcc: Class implementation
-#endif
-
-#include "mysql_priv.h"
-#include <mysql.h>
-#include "slave.h"
-#include "rpl_mi.h"
-#include <my_getopt.h>
-#include <thr_alarm.h>
-#include <myisam.h>
-#include <my_dir.h>
-
-#include "events.h"
-
-/* WITH_NDBCLUSTER_STORAGE_ENGINE */
-#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
-extern ulong ndb_cache_check_time;
-extern char opt_ndb_constrbuf[];
-extern ulong ndb_extra_logging;
-#endif
-
-#ifdef HAVE_NDB_BINLOG
-extern ulong ndb_report_thresh_binlog_epoch_slip;
-extern ulong ndb_report_thresh_binlog_mem_usage;
+#pragma implementation
#endif
-extern CHARSET_INFO *character_set_filesystem;
-
+/* variable declarations are in sys_vars.cc now !!! */
+
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_class.h" // set_var.h: session_var_ptr
+#include "set_var.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "mysqld.h" // lc_messages_dir
+#include "sys_vars_shared.h"
+#include "transaction.h"
+#include "sql_locale.h" // my_locale_by_number,
+ // my_locale_by_name
+#include "strfunc.h" // find_set_from_flags, find_set
+#include "sql_parse.h" // check_global_access
+#include "sql_table.h" // reassign_keycache_tables
+#include "sql_time.h" // date_time_format_copy,
+ // date_time_format_make
+#include "derror.h"
+#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" // make_default_log_name
+#include "sql_view.h" // updatable_views_with_limit_typelib
+#include "lock.h" // lock_global_read_lock,
+ // make_global_read_lock_block_commit,
+ // unlock_global_read_lock
static HASH system_variable_hash;
+static PolyLock_mutex PLock_global_system_variables(&LOCK_global_system_variables);
-const char *bool_type_names[]= { "OFF", "ON", NullS };
-TYPELIB bool_typelib=
-{
- array_elements(bool_type_names)-1, "", bool_type_names, NULL
-};
-
-const char *delay_key_write_type_names[]= { "OFF", "ON", "ALL", NullS };
-TYPELIB delay_key_write_typelib=
-{
- array_elements(delay_key_write_type_names)-1, "",
- delay_key_write_type_names, NULL
-};
-
-static const char *slave_exec_mode_names[]= { "STRICT", "IDEMPOTENT", NullS };
-static unsigned int slave_exec_mode_names_len[]= { sizeof("STRICT") - 1,
- sizeof("IDEMPOTENT") - 1, 0 };
-TYPELIB slave_exec_mode_typelib=
-{
- array_elements(slave_exec_mode_names)-1, "",
- slave_exec_mode_names, slave_exec_mode_names_len
-};
-
-static int sys_check_ftb_syntax(THD *thd, set_var *var);
-static bool sys_update_ftb_syntax(THD *thd, set_var * var);
-static void sys_default_ftb_syntax(THD *thd, enum_var_type type);
-static bool sys_update_init_connect(THD*, set_var*);
-static void sys_default_init_connect(THD*, enum_var_type type);
-static bool sys_update_init_slave(THD*, set_var*);
-static void sys_default_init_slave(THD*, enum_var_type type);
-static bool set_option_bit(THD *thd, set_var *var);
-static bool set_option_log_bin_bit(THD *thd, set_var *var);
-static bool set_option_autocommit(THD *thd, set_var *var);
-static int check_log_update(THD *thd, set_var *var);
-static bool set_log_update(THD *thd, set_var *var);
-static int check_pseudo_thread_id(THD *thd, set_var *var);
-void fix_binlog_format_after_update(THD *thd, enum_var_type type);
-static void fix_low_priority_updates(THD *thd, enum_var_type type);
-static int check_tx_isolation(THD *thd, set_var *var);
-static void fix_tx_isolation(THD *thd, enum_var_type type);
-static int check_completion_type(THD *thd, set_var *var);
-static void fix_completion_type(THD *thd, enum_var_type type);
-static void fix_net_read_timeout(THD *thd, enum_var_type type);
-static void fix_net_write_timeout(THD *thd, enum_var_type type);
-static void fix_net_retry_count(THD *thd, enum_var_type type);
-static void fix_max_join_size(THD *thd, enum_var_type type);
-static void fix_query_cache_size(THD *thd, enum_var_type type);
-static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type);
-static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type);
-static void fix_max_binlog_size(THD *thd, enum_var_type type);
-static void fix_max_relay_log_size(THD *thd, enum_var_type type);
-static void fix_max_connections(THD *thd, enum_var_type type);
-static int check_max_delayed_threads(THD *thd, set_var *var);
-static void fix_thd_mem_root(THD *thd, enum_var_type type);
-static void fix_trans_mem_root(THD *thd, enum_var_type type);
-static void fix_server_id(THD *thd, enum_var_type type);
-bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd,
- const char *name, longlong val);
-static KEY_CACHE *create_key_cache(const char *name, uint length);
-void fix_sql_mode_var(THD *thd, enum_var_type type);
-static uchar *get_error_count(THD *thd);
-static uchar *get_warning_count(THD *thd);
-static uchar *get_tmpdir(THD *thd);
-static int sys_check_log_path(THD *thd, set_var *var);
-static bool sys_update_general_log_path(THD *thd, set_var * var);
-static void sys_default_general_log_path(THD *thd, enum_var_type type);
-static bool sys_update_slow_log_path(THD *thd, set_var * var);
-static void sys_default_slow_log_path(THD *thd, enum_var_type type);
-static uchar *get_myisam_mmap_size(THD *thd);
-
-/*
- Variable definition list
-
- These are variables that can be set from the command line, in
- alphabetic order.
-
- The variables are linked into the list. A variable is added to
- it in the constructor (see sys_var class for details).
-*/
-
-static sys_var_chain vars = { NULL, NULL };
-
-static sys_var_thd_ulong
-sys_auto_increment_increment(&vars, "auto_increment_increment",
- &SV::auto_increment_increment, NULL, NULL,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_thd_ulong
-sys_auto_increment_offset(&vars, "auto_increment_offset",
- &SV::auto_increment_offset, NULL, NULL,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-
-static sys_var_bool_ptr sys_automatic_sp_privileges(&vars, "automatic_sp_privileges",
- &sp_automatic_privileges);
-
-static sys_var_const sys_back_log(&vars, "back_log",
- OPT_GLOBAL, SHOW_LONG,
- (uchar*) &back_log);
-static sys_var_const_os_str sys_basedir(&vars, "basedir", mysql_home);
-static sys_var_long_ptr sys_binlog_cache_size(&vars, "binlog_cache_size",
- &binlog_cache_size);
-static sys_var_thd_binlog_format sys_binlog_format(&vars, "binlog_format",
- &SV::binlog_format);
-static sys_var_thd_bool sys_binlog_direct_non_trans_update(&vars, "binlog_direct_non_transactional_updates",
- &SV::binlog_direct_non_trans_update);
-static sys_var_thd_ulong sys_bulk_insert_buff_size(&vars, "bulk_insert_buffer_size",
- &SV::bulk_insert_buff_size);
-static sys_var_const_os sys_character_sets_dir(&vars,
- "character_sets_dir",
- OPT_GLOBAL, SHOW_CHAR,
- (uchar*)
- mysql_charsets_dir);
-static sys_var_character_set_sv
-sys_character_set_server(&vars, "character_set_server",
- &SV::collation_server, &default_charset_info, 0,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-sys_var_const_str sys_charset_system(&vars, "character_set_system",
- (char *)my_charset_utf8_general_ci.name);
-static sys_var_character_set_database
-sys_character_set_database(&vars, "character_set_database",
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_character_set_client
-sys_character_set_client(&vars, "character_set_client",
- &SV::character_set_client,
- &default_charset_info,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_character_set_sv
-sys_character_set_connection(&vars, "character_set_connection",
- &SV::collation_connection,
- &default_charset_info, 0,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_character_set_sv sys_character_set_results(&vars, "character_set_results",
- &SV::character_set_results,
- &default_charset_info, true);
-static sys_var_character_set_sv sys_character_set_filesystem(&vars, "character_set_filesystem",
- &SV::character_set_filesystem,
- &character_set_filesystem);
-static sys_var_thd_ulong sys_completion_type(&vars, "completion_type",
- &SV::completion_type,
- check_completion_type,
- fix_completion_type);
-static sys_var_collation_sv
-sys_collation_connection(&vars, "collation_connection",
- &SV::collation_connection, &default_charset_info,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_collation_sv
-sys_collation_database(&vars, "collation_database", &SV::collation_database,
- &default_charset_info,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_collation_sv
-sys_collation_server(&vars, "collation_server", &SV::collation_server,
- &default_charset_info,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_long_ptr sys_concurrent_insert(&vars, "concurrent_insert",
- &myisam_concurrent_insert);
-static sys_var_long_ptr sys_connect_timeout(&vars, "connect_timeout",
- &connect_timeout);
-static sys_var_const_os_str sys_datadir(&vars, "datadir", mysql_real_data_home);
-#ifndef DBUG_OFF
-static sys_var_thd_dbug sys_dbug(&vars, "debug");
-#endif
-static sys_var_enum sys_delay_key_write(&vars, "delay_key_write",
- &delay_key_write_options,
- &delay_key_write_typelib,
- fix_delay_key_write);
-static sys_var_long_ptr sys_delayed_insert_limit(&vars, "delayed_insert_limit",
- &delayed_insert_limit);
-static sys_var_long_ptr sys_delayed_insert_timeout(&vars, "delayed_insert_timeout",
- &delayed_insert_timeout);
-static sys_var_long_ptr sys_delayed_queue_size(&vars, "delayed_queue_size",
- &delayed_queue_size);
-
-#ifdef HAVE_EVENT_SCHEDULER
-static sys_var_event_scheduler sys_event_scheduler(&vars, "event_scheduler");
-#endif
-
-static sys_var_long_ptr sys_expire_logs_days(&vars, "expire_logs_days",
- &expire_logs_days);
-static sys_var_bool_ptr sys_flush(&vars, "flush", &myisam_flush);
-static sys_var_long_ptr sys_flush_time(&vars, "flush_time", &flush_time);
-static sys_var_str sys_ft_boolean_syntax(&vars, "ft_boolean_syntax",
- sys_check_ftb_syntax,
- sys_update_ftb_syntax,
- sys_default_ftb_syntax,
- ft_boolean_syntax);
-static sys_var_const sys_ft_max_word_len(&vars, "ft_max_word_len",
- OPT_GLOBAL, SHOW_LONG,
- (uchar*) &ft_max_word_len);
-static sys_var_const sys_ft_min_word_len(&vars, "ft_min_word_len",
- OPT_GLOBAL, SHOW_LONG,
- (uchar*) &ft_min_word_len);
-static sys_var_const sys_ft_query_expansion_limit(&vars,
- "ft_query_expansion_limit",
- OPT_GLOBAL, SHOW_LONG,
- (uchar*)
- &ft_query_expansion_limit);
-static sys_var_const sys_ft_stopword_file(&vars, "ft_stopword_file",
- OPT_GLOBAL, SHOW_CHAR_PTR,
- (uchar*) &ft_stopword_file);
-
-static sys_var_const sys_ignore_builtin_innodb(&vars, "ignore_builtin_innodb",
- OPT_GLOBAL, SHOW_BOOL,
- (uchar*) &opt_ignore_builtin_innodb);
-
-sys_var_str sys_init_connect(&vars, "init_connect", 0,
- sys_update_init_connect,
- sys_default_init_connect,0);
-static sys_var_const sys_init_file(&vars, "init_file",
- OPT_GLOBAL, SHOW_CHAR_PTR,
- (uchar*) &opt_init_file);
-sys_var_str sys_init_slave(&vars, "init_slave", 0,
- sys_update_init_slave,
- sys_default_init_slave,0);
-static sys_var_thd_ulong sys_interactive_timeout(&vars, "interactive_timeout",
- &SV::net_interactive_timeout);
-static sys_var_thd_ulong sys_join_buffer_size(&vars, "join_buffer_size",
- &SV::join_buff_size);
-static sys_var_key_buffer_size sys_key_buffer_size(&vars, "key_buffer_size");
-static sys_var_key_cache_long sys_key_cache_block_size(&vars, "key_cache_block_size",
- offsetof(KEY_CACHE,
- param_block_size));
-static sys_var_key_cache_long sys_key_cache_division_limit(&vars, "key_cache_division_limit",
- offsetof(KEY_CACHE,
- param_division_limit));
-static sys_var_key_cache_long sys_key_cache_age_threshold(&vars, "key_cache_age_threshold",
- offsetof(KEY_CACHE,
- param_age_threshold));
-static sys_var_const sys_language(&vars, "language",
- OPT_GLOBAL, SHOW_CHAR,
- (uchar*) language);
-static sys_var_const sys_large_files_support(&vars, "large_files_support",
- OPT_GLOBAL, SHOW_BOOL,
- (uchar*) &opt_large_files);
-static sys_var_const sys_large_page_size(&vars, "large_page_size",
- OPT_GLOBAL, SHOW_INT,
- (uchar*) &opt_large_page_size);
-static sys_var_const sys_large_pages(&vars, "large_pages",
- OPT_GLOBAL, SHOW_MY_BOOL,
- (uchar*) &opt_large_pages);
-static sys_var_bool_ptr sys_local_infile(&vars, "local_infile",
- &opt_local_infile);
-#ifdef HAVE_MLOCKALL
-static sys_var_const sys_locked_in_memory(&vars, "locked_in_memory",
- OPT_GLOBAL, SHOW_MY_BOOL,
- (uchar*) &locked_in_memory);
-#endif
-static sys_var_const sys_log_bin(&vars, "log_bin",
- OPT_GLOBAL, SHOW_BOOL,
- (uchar*) &opt_bin_log);
-static sys_var_trust_routine_creators
-sys_trust_routine_creators(&vars, "log_bin_trust_routine_creators",
- &trust_function_creators);
-static sys_var_bool_ptr
-sys_trust_function_creators(&vars, "log_bin_trust_function_creators",
- &trust_function_creators);
-static sys_var_const sys_log_error(&vars, "log_error",
- OPT_GLOBAL, SHOW_CHAR,
- (uchar*) log_error_file);
-static sys_var_bool_ptr
- sys_log_queries_not_using_indexes(&vars, "log_queries_not_using_indexes",
- &opt_log_queries_not_using_indexes);
-static sys_var_thd_ulong sys_log_warnings(&vars, "log_warnings", &SV::log_warnings);
-static sys_var_microseconds sys_var_long_query_time(&vars, "long_query_time",
- &SV::long_query_time);
-static sys_var_thd_bool sys_low_priority_updates(&vars, "low_priority_updates",
- &SV::low_priority_updates,
- fix_low_priority_updates);
-#ifndef TO_BE_DELETED /* Alias for the low_priority_updates */
-static sys_var_thd_bool sys_sql_low_priority_updates(&vars, "sql_low_priority_updates",
- &SV::low_priority_updates,
- fix_low_priority_updates);
-#endif
-static sys_var_const sys_lower_case_file_system(&vars,
- "lower_case_file_system",
- OPT_GLOBAL, SHOW_MY_BOOL,
- (uchar*)
- &lower_case_file_system);
-static sys_var_const sys_lower_case_table_names(&vars,
- "lower_case_table_names",
- OPT_GLOBAL, SHOW_INT,
- (uchar*)
- &lower_case_table_names);
-static sys_var_thd_ulong_session_readonly sys_max_allowed_packet(&vars, "max_allowed_packet",
- &SV::max_allowed_packet);
-static sys_var_ulonglong_ptr sys_max_binlog_cache_size(&vars, "max_binlog_cache_size",
- &max_binlog_cache_size);
-static sys_var_long_ptr sys_max_binlog_size(&vars, "max_binlog_size",
- &max_binlog_size,
- fix_max_binlog_size);
-static sys_var_long_ptr sys_max_connections(&vars, "max_connections",
- &max_connections,
- fix_max_connections);
-static sys_var_long_ptr sys_max_connect_errors(&vars, "max_connect_errors",
- &max_connect_errors);
-static sys_var_thd_ulong sys_max_insert_delayed_threads(&vars, "max_insert_delayed_threads",
- &SV::max_insert_delayed_threads,
- check_max_delayed_threads,
- fix_max_connections);
-static sys_var_thd_ulong sys_max_delayed_threads(&vars, "max_delayed_threads",
- &SV::max_insert_delayed_threads,
- check_max_delayed_threads,
- fix_max_connections);
-static sys_var_thd_ulong sys_max_error_count(&vars, "max_error_count",
- &SV::max_error_count);
-static sys_var_thd_ulonglong sys_max_heap_table_size(&vars, "max_heap_table_size",
- &SV::max_heap_table_size);
-static sys_var_thd_ulong sys_pseudo_thread_id(&vars, "pseudo_thread_id",
- &SV::pseudo_thread_id,
- check_pseudo_thread_id, 0,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_thd_ha_rows sys_max_join_size(&vars, "max_join_size",
- &SV::max_join_size,
- fix_max_join_size);
-static sys_var_thd_ulong sys_max_seeks_for_key(&vars, "max_seeks_for_key",
- &SV::max_seeks_for_key);
-static sys_var_thd_ulong sys_max_length_for_sort_data(&vars, "max_length_for_sort_data",
- &SV::max_length_for_sort_data);
-#ifndef TO_BE_DELETED /* Alias for max_join_size */
-static sys_var_thd_ha_rows sys_sql_max_join_size(&vars, "sql_max_join_size",
- &SV::max_join_size,
- fix_max_join_size);
-#endif
-static sys_var_long_ptr_global
-sys_max_prepared_stmt_count(&vars, "max_prepared_stmt_count",
- &max_prepared_stmt_count,
- &LOCK_prepared_stmt_count);
-static sys_var_long_ptr sys_max_relay_log_size(&vars, "max_relay_log_size",
- &max_relay_log_size,
- fix_max_relay_log_size);
-static sys_var_thd_ulong sys_max_sort_length(&vars, "max_sort_length",
- &SV::max_sort_length);
-static sys_var_thd_ulong sys_max_sp_recursion_depth(&vars, "max_sp_recursion_depth",
- &SV::max_sp_recursion_depth);
-static sys_var_max_user_conn sys_max_user_connections(&vars, "max_user_connections");
-static sys_var_thd_ulong sys_max_tmp_tables(&vars, "max_tmp_tables",
- &SV::max_tmp_tables);
-static sys_var_long_ptr sys_max_write_lock_count(&vars, "max_write_lock_count",
- &max_write_lock_count);
-static sys_var_thd_ulong sys_min_examined_row_limit(&vars, "min_examined_row_limit",
- &SV::min_examined_row_limit);
-static sys_var_thd_ulong sys_multi_range_count(&vars, "multi_range_count",
- &SV::multi_range_count);
-static sys_var_long_ptr sys_myisam_data_pointer_size(&vars, "myisam_data_pointer_size",
- &myisam_data_pointer_size);
-static sys_var_thd_ulonglong sys_myisam_max_sort_file_size(&vars, "myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1);
-static sys_var_const sys_myisam_recover_options(&vars, "myisam_recover_options",
- OPT_GLOBAL, SHOW_CHAR_PTR,
- (uchar*)
- &myisam_recover_options_str);
-static sys_var_thd_ulong sys_myisam_repair_threads(&vars, "myisam_repair_threads", &SV::myisam_repair_threads);
-static sys_var_thd_ulong sys_myisam_sort_buffer_size(&vars, "myisam_sort_buffer_size", &SV::myisam_sort_buff_size);
-static sys_var_bool_ptr sys_myisam_use_mmap(&vars, "myisam_use_mmap",
- &opt_myisam_use_mmap);
-
-static sys_var_thd_enum sys_myisam_stats_method(&vars, "myisam_stats_method",
- &SV::myisam_stats_method,
- &myisam_stats_method_typelib,
- NULL);
-
-#ifdef __NT__
-/* purecov: begin inspected */
-static sys_var_const sys_named_pipe(&vars, "named_pipe",
- OPT_GLOBAL, SHOW_MY_BOOL,
- (uchar*) &opt_enable_named_pipe);
-/* purecov: end */
-#endif
-static sys_var_thd_ulong_session_readonly sys_net_buffer_length(&vars, "net_buffer_length",
- &SV::net_buffer_length);
-static sys_var_thd_ulong sys_net_read_timeout(&vars, "net_read_timeout",
- &SV::net_read_timeout,
- 0, fix_net_read_timeout);
-static sys_var_thd_ulong sys_net_write_timeout(&vars, "net_write_timeout",
- &SV::net_write_timeout,
- 0, fix_net_write_timeout);
-static sys_var_thd_ulong sys_net_retry_count(&vars, "net_retry_count",
- &SV::net_retry_count,
- 0, fix_net_retry_count);
-static sys_var_thd_bool sys_new_mode(&vars, "new", &SV::new_mode);
-static sys_var_bool_ptr_readonly sys_old_mode(&vars, "old",
- &global_system_variables.old_mode);
-/* these two cannot be static */
-sys_var_thd_bool sys_old_alter_table(&vars, "old_alter_table",
- &SV::old_alter_table);
-sys_var_thd_bool sys_old_passwords(&vars, "old_passwords", &SV::old_passwords);
-static sys_var_const sys_open_files_limit(&vars, "open_files_limit",
- OPT_GLOBAL, SHOW_LONG,
- (uchar*)
- &open_files_limit);
-static sys_var_thd_ulong sys_optimizer_prune_level(&vars, "optimizer_prune_level",
- &SV::optimizer_prune_level);
-static sys_var_thd_ulong sys_optimizer_search_depth(&vars, "optimizer_search_depth",
- &SV::optimizer_search_depth);
-static sys_var_thd_optimizer_switch sys_optimizer_switch(&vars, "optimizer_switch",
- &SV::optimizer_switch);
-static sys_var_const sys_pid_file(&vars, "pid_file",
- OPT_GLOBAL, SHOW_CHAR,
- (uchar*) pidfile_name);
-static sys_var_const_os sys_plugin_dir(&vars, "plugin_dir",
- OPT_GLOBAL, SHOW_CHAR,
- (uchar*) opt_plugin_dir);
-static sys_var_const sys_port(&vars, "port",
- OPT_GLOBAL, SHOW_INT,
- (uchar*) &mysqld_port);
-static sys_var_thd_ulong sys_preload_buff_size(&vars, "preload_buffer_size",
- &SV::preload_buff_size);
-static sys_var_const sys_protocol_version(&vars, "protocol_version",
- OPT_GLOBAL, SHOW_INT,
- (uchar*)
- &protocol_version);
-static sys_var_thd_ulong sys_read_buff_size(&vars, "read_buffer_size",
- &SV::read_buff_size);
-static sys_var_opt_readonly sys_readonly(&vars, "read_only", &opt_readonly);
-static sys_var_thd_ulong sys_read_rnd_buff_size(&vars, "read_rnd_buffer_size",
- &SV::read_rnd_buff_size);
-static sys_var_thd_ulong sys_div_precincrement(&vars, "div_precision_increment",
- &SV::div_precincrement);
-static sys_var_long_ptr sys_rpl_recovery_rank(&vars, "rpl_recovery_rank",
- &rpl_recovery_rank);
-static sys_var_long_ptr sys_query_cache_size(&vars, "query_cache_size",
- &query_cache_size,
- fix_query_cache_size);
-
-static sys_var_thd_ulong sys_range_alloc_block_size(&vars, "range_alloc_block_size",
- &SV::range_alloc_block_size);
-static sys_var_thd_ulong sys_query_alloc_block_size(&vars, "query_alloc_block_size",
- &SV::query_alloc_block_size,
- 0, fix_thd_mem_root);
-static sys_var_thd_ulong sys_query_prealloc_size(&vars, "query_prealloc_size",
- &SV::query_prealloc_size,
- 0, fix_thd_mem_root);
-#ifdef HAVE_SMEM
-/* purecov: begin tested */
-static sys_var_const sys_shared_memory(&vars, "shared_memory",
- OPT_GLOBAL, SHOW_MY_BOOL,
- (uchar*)
- &opt_enable_shared_memory);
-static sys_var_const sys_shared_memory_base_name(&vars,
- "shared_memory_base_name",
- OPT_GLOBAL, SHOW_CHAR_PTR,
- (uchar*)
- &shared_memory_base_name);
-/* purecov: end */
-#endif
-static sys_var_const sys_skip_external_locking(&vars,
- "skip_external_locking",
- OPT_GLOBAL, SHOW_MY_BOOL,
- (uchar*)
- &my_disable_locking);
-static sys_var_const sys_skip_networking(&vars, "skip_networking",
- OPT_GLOBAL, SHOW_BOOL,
- (uchar*) &opt_disable_networking);
-static sys_var_const sys_skip_show_database(&vars, "skip_show_database",
- OPT_GLOBAL, SHOW_BOOL,
- (uchar*) &opt_skip_show_db);
-
-static sys_var_const sys_skip_name_resolve(&vars, "skip_name_resolve",
- OPT_GLOBAL, SHOW_BOOL,
- (uchar*) &opt_skip_name_resolve);
-
-static sys_var_const sys_socket(&vars, "socket",
- OPT_GLOBAL, SHOW_CHAR_PTR,
- (uchar*) &mysqld_unix_port);
-
-#ifdef HAVE_THR_SETCONCURRENCY
-/* purecov: begin tested */
-static sys_var_const sys_thread_concurrency(&vars, "thread_concurrency",
- OPT_GLOBAL, SHOW_LONG,
- (uchar*) &concurrency);
-/* purecov: end */
-#endif
-static sys_var_const sys_thread_stack(&vars, "thread_stack",
- OPT_GLOBAL, SHOW_LONG,
- (uchar*) &my_thread_stack_size);
-static sys_var_readonly_os sys_tmpdir(&vars, "tmpdir", OPT_GLOBAL, SHOW_CHAR, get_tmpdir);
-static sys_var_thd_ulong sys_trans_alloc_block_size(&vars, "transaction_alloc_block_size",
- &SV::trans_alloc_block_size,
- 0, fix_trans_mem_root);
-static sys_var_thd_ulong sys_trans_prealloc_size(&vars, "transaction_prealloc_size",
- &SV::trans_prealloc_size,
- 0, fix_trans_mem_root);
-sys_var_enum_const sys_thread_handling(&vars, "thread_handling",
- &SV::thread_handling,
- &thread_handling_typelib,
- NULL);
-
-#ifdef HAVE_QUERY_CACHE
-static sys_var_long_ptr sys_query_cache_limit(&vars, "query_cache_limit",
- &query_cache.query_cache_limit);
-static sys_var_long_ptr sys_query_cache_min_res_unit(&vars, "query_cache_min_res_unit",
- &query_cache_min_res_unit,
- fix_query_cache_min_res_unit);
-static sys_var_thd_enum sys_query_cache_type(&vars, "query_cache_type",
- &SV::query_cache_type,
- &query_cache_type_typelib);
-static sys_var_thd_bool
-sys_query_cache_wlock_invalidate(&vars, "query_cache_wlock_invalidate",
- &SV::query_cache_wlock_invalidate);
-#endif /* HAVE_QUERY_CACHE */
-static sys_var_bool_ptr sys_secure_auth(&vars, "secure_auth", &opt_secure_auth);
-static sys_var_const_str_ptr sys_secure_file_priv(&vars, "secure_file_priv",
- &opt_secure_file_priv);
-static sys_var_long_ptr sys_server_id(&vars, "server_id", &server_id, fix_server_id);
-static sys_var_bool_ptr sys_slave_compressed_protocol(&vars, "slave_compressed_protocol",
- &opt_slave_compressed_protocol);
-static sys_var_set_slave_mode slave_exec_mode(&vars,
- "slave_exec_mode",
- &slave_exec_mode_options,
- &slave_exec_mode_typelib,
- 0);
-static sys_var_long_ptr sys_slow_launch_time(&vars, "slow_launch_time",
- &slow_launch_time);
-static sys_var_thd_ulong sys_sort_buffer(&vars, "sort_buffer_size",
- &SV::sortbuff_size);
-/*
- sql_mode should *not* have binlog_mode=SESSION_VARIABLE_IN_BINLOG:
- even though it is written to the binlog, the slave ignores the
- MODE_NO_DIR_IN_CREATE variable, so slave's value differs from
- master's (see log_event.cc: Query_log_event::do_apply_event()).
-*/
-static sys_var_thd_sql_mode sys_sql_mode(&vars, "sql_mode",
- &SV::sql_mode);
-#ifdef HAVE_OPENSSL
-extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher,
- *opt_ssl_key;
-static sys_var_const_os_str_ptr sys_ssl_ca(&vars, "ssl_ca", &opt_ssl_ca);
-static sys_var_const_os_str_ptr sys_ssl_capath(&vars, "ssl_capath", &opt_ssl_capath);
-static sys_var_const_os_str_ptr sys_ssl_cert(&vars, "ssl_cert", &opt_ssl_cert);
-static sys_var_const_os_str_ptr sys_ssl_cipher(&vars, "ssl_cipher", &opt_ssl_cipher);
-static sys_var_const_os_str_ptr sys_ssl_key(&vars, "ssl_key", &opt_ssl_key);
-#else
-static sys_var_const_os_str sys_ssl_ca(&vars, "ssl_ca", NULL);
-static sys_var_const_os_str sys_ssl_capath(&vars, "ssl_capath", NULL);
-static sys_var_const_os_str sys_ssl_cert(&vars, "ssl_cert", NULL);
-static sys_var_const_os_str sys_ssl_cipher(&vars, "ssl_cipher", NULL);
-static sys_var_const_os_str sys_ssl_key(&vars, "ssl_key", NULL);
-#endif
-static sys_var_thd_enum
-sys_updatable_views_with_limit(&vars, "updatable_views_with_limit",
- &SV::updatable_views_with_limit,
- &updatable_views_with_limit_typelib);
-
-static sys_var_thd_table_type sys_table_type(&vars, "table_type",
- &SV::table_plugin);
-static sys_var_thd_storage_engine sys_storage_engine(&vars, "storage_engine",
- &SV::table_plugin);
-static sys_var_bool_ptr sys_sync_frm(&vars, "sync_frm", &opt_sync_frm);
-static sys_var_const_str sys_system_time_zone(&vars, "system_time_zone",
- system_time_zone);
-static sys_var_long_ptr sys_table_def_size(&vars, "table_definition_cache",
- &table_def_size);
-static sys_var_long_ptr sys_table_cache_size(&vars, "table_open_cache",
- &table_cache_size);
-static sys_var_long_ptr sys_table_lock_wait_timeout(&vars, "table_lock_wait_timeout",
- &table_lock_wait_timeout);
-
-#if defined(ENABLED_DEBUG_SYNC)
-/* Debug Sync Facility. Implemented in debug_sync.cc. */
-static sys_var_debug_sync sys_debug_sync(&vars, "debug_sync");
-#endif /* defined(ENABLED_DEBUG_SYNC) */
-
-static sys_var_long_ptr sys_thread_cache_size(&vars, "thread_cache_size",
- &thread_cache_size);
-#if HAVE_POOL_OF_THREADS == 1
-sys_var_long_ptr sys_thread_pool_size(&vars, "thread_pool_size",
- &thread_pool_size);
-#endif
-static sys_var_thd_enum sys_tx_isolation(&vars, "tx_isolation",
- &SV::tx_isolation,
- &tx_isolation_typelib,
- fix_tx_isolation,
- check_tx_isolation);
-static sys_var_thd_ulonglong sys_tmp_table_size(&vars, "tmp_table_size",
- &SV::tmp_table_size);
-static sys_var_bool_ptr sys_timed_mutexes(&vars, "timed_mutexes",
- &timed_mutexes);
-static sys_var_const_str sys_version(&vars, "version", server_version);
-static sys_var_const_str sys_version_comment(&vars, "version_comment",
- MYSQL_COMPILATION_COMMENT);
-static sys_var_const_str sys_version_compile_machine(&vars, "version_compile_machine",
- MACHINE_TYPE);
-static sys_var_const_str sys_version_compile_os(&vars, "version_compile_os",
- SYSTEM_TYPE);
-static sys_var_thd_ulong sys_net_wait_timeout(&vars, "wait_timeout",
- &SV::net_wait_timeout);
-
-/* Condition pushdown to storage engine */
-static sys_var_thd_bool
-sys_engine_condition_pushdown(&vars, "engine_condition_pushdown",
- &SV::engine_condition_pushdown);
-
-#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
-/* ndb thread specific variable settings */
-static sys_var_thd_ulong
-sys_ndb_autoincrement_prefetch_sz(&vars, "ndb_autoincrement_prefetch_sz",
- &SV::ndb_autoincrement_prefetch_sz);
-static sys_var_thd_bool
-sys_ndb_force_send(&vars, "ndb_force_send", &SV::ndb_force_send);
-#ifdef HAVE_NDB_BINLOG
-static sys_var_long_ptr
-sys_ndb_report_thresh_binlog_epoch_slip(&vars, "ndb_report_thresh_binlog_epoch_slip",
- &ndb_report_thresh_binlog_epoch_slip);
-static sys_var_long_ptr
-sys_ndb_report_thresh_binlog_mem_usage(&vars, "ndb_report_thresh_binlog_mem_usage",
- &ndb_report_thresh_binlog_mem_usage);
-#endif
-static sys_var_thd_bool
-sys_ndb_use_exact_count(&vars, "ndb_use_exact_count", &SV::ndb_use_exact_count);
-static sys_var_thd_bool
-sys_ndb_use_transactions(&vars, "ndb_use_transactions", &SV::ndb_use_transactions);
-static sys_var_long_ptr
-sys_ndb_cache_check_time(&vars, "ndb_cache_check_time", &ndb_cache_check_time);
-static sys_var_const_str
-sys_ndb_connectstring(&vars, "ndb_connectstring", opt_ndb_constrbuf);
-static sys_var_thd_bool
-sys_ndb_index_stat_enable(&vars, "ndb_index_stat_enable",
- &SV::ndb_index_stat_enable);
-static sys_var_thd_ulong
-sys_ndb_index_stat_cache_entries(&vars, "ndb_index_stat_cache_entries",
- &SV::ndb_index_stat_cache_entries);
-static sys_var_thd_ulong
-sys_ndb_index_stat_update_freq(&vars, "ndb_index_stat_update_freq",
- &SV::ndb_index_stat_update_freq);
-static sys_var_long_ptr
-sys_ndb_extra_logging(&vars, "ndb_extra_logging", &ndb_extra_logging);
-static sys_var_thd_bool
-sys_ndb_use_copying_alter_table(&vars, "ndb_use_copying_alter_table", &SV::ndb_use_copying_alter_table);
-#endif //WITH_NDBCLUSTER_STORAGE_ENGINE
-
-/* Time/date/datetime formats */
-
-static sys_var_thd_date_time_format sys_time_format(&vars, "time_format",
- &SV::time_format,
- MYSQL_TIMESTAMP_TIME);
-static sys_var_thd_date_time_format sys_date_format(&vars, "date_format",
- &SV::date_format,
- MYSQL_TIMESTAMP_DATE);
-static sys_var_thd_date_time_format sys_datetime_format(&vars, "datetime_format",
- &SV::datetime_format,
- MYSQL_TIMESTAMP_DATETIME);
-
-/* Variables that are bits in THD */
-
-sys_var_thd_bit sys_autocommit(&vars, "autocommit", 0,
- set_option_autocommit,
- OPTION_NOT_AUTOCOMMIT,
- 1);
-static sys_var_thd_bit sys_big_tables(&vars, "big_tables", 0,
- set_option_bit,
- OPTION_BIG_TABLES);
-#ifndef TO_BE_DELETED /* Alias for big_tables */
-static sys_var_thd_bit sys_sql_big_tables(&vars, "sql_big_tables", 0,
- set_option_bit,
- OPTION_BIG_TABLES);
-#endif
-static sys_var_thd_bit sys_big_selects(&vars, "sql_big_selects", 0,
- set_option_bit,
- OPTION_BIG_SELECTS);
-static sys_var_thd_bit sys_log_off(&vars, "sql_log_off",
- check_log_update,
- set_option_bit,
- OPTION_LOG_OFF);
-static sys_var_thd_bit sys_log_update(&vars, "sql_log_update",
- check_log_update,
- set_log_update,
- OPTION_BIN_LOG);
-static sys_var_thd_bit sys_log_binlog(&vars, "sql_log_bin",
- check_log_update,
- set_option_log_bin_bit,
- OPTION_BIN_LOG);
-static sys_var_thd_bit sys_sql_warnings(&vars, "sql_warnings", 0,
- set_option_bit,
- OPTION_WARNINGS);
-static sys_var_thd_bit sys_sql_notes(&vars, "sql_notes", 0,
- set_option_bit,
- OPTION_SQL_NOTES);
-static sys_var_thd_bit sys_auto_is_null(&vars, "sql_auto_is_null", 0,
- set_option_bit,
- OPTION_AUTO_IS_NULL, 0,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_thd_bit sys_safe_updates(&vars, "sql_safe_updates", 0,
- set_option_bit,
- OPTION_SAFE_UPDATES);
-static sys_var_thd_bit sys_buffer_results(&vars, "sql_buffer_result", 0,
- set_option_bit,
- OPTION_BUFFER_RESULT);
-static sys_var_thd_bit sys_quote_show_create(&vars, "sql_quote_show_create", 0,
- set_option_bit,
- OPTION_QUOTE_SHOW_CREATE);
-static sys_var_thd_bit sys_foreign_key_checks(&vars, "foreign_key_checks", 0,
- set_option_bit,
- OPTION_NO_FOREIGN_KEY_CHECKS,
- 1, sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_thd_bit sys_unique_checks(&vars, "unique_checks", 0,
- set_option_bit,
- OPTION_RELAXED_UNIQUE_CHECKS,
- 1,
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
-static sys_var_thd_bit sys_profiling(&vars, "profiling", NULL,
- set_option_bit,
- ulonglong(OPTION_PROFILING));
-static sys_var_thd_ulong sys_profiling_history_size(&vars, "profiling_history_size",
- &SV::profiling_history_size);
-#endif
-
-/* Local state variables */
-
-static sys_var_thd_ha_rows sys_select_limit(&vars, "sql_select_limit",
- &SV::select_limit);
-static sys_var_timestamp sys_timestamp(&vars, "timestamp",
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_last_insert_id
-sys_last_insert_id(&vars, "last_insert_id",
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-/*
- identity is an alias for last_insert_id(), so that we are compatible
- with Sybase
+/**
+ Return variable name and length for hashing of variables.
*/
-static sys_var_last_insert_id
-sys_identity(&vars, "identity", sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_thd_lc_time_names
-sys_lc_time_names(&vars, "lc_time_names", sys_var::SESSION_VARIABLE_IN_BINLOG);
-
-/*
- insert_id should *not* be marked as written to the binlog (i.e., it
- should *not* have binlog_status==SESSION_VARIABLE_IN_BINLOG),
- because we want any statement that refers to insert_id explicitly to
- be unsafe. (By "explicitly", we mean using @@session.insert_id,
- whereas insert_id is used "implicitly" when NULL value is inserted
- into an auto_increment column).
-
- We want statements referring explicitly to @@session.insert_id to be
- unsafe, because insert_id is modified internally by the slave sql
- thread when NULL values are inserted in an AUTO_INCREMENT column.
- This modification interfers with the value of the
- @@session.insert_id variable if @@session.insert_id is referred
- explicitly by an insert statement (as is seen by executing "SET
- @@session.insert_id=0; CREATE TABLE t (a INT, b INT KEY
- AUTO_INCREMENT); INSERT INTO t(a) VALUES (@@session.insert_id);" in
- statement-based logging mode: t will be different on master and
- slave).
-*/
-static sys_var_insert_id sys_insert_id(&vars, "insert_id");
-static sys_var_readonly sys_error_count(&vars, "error_count",
- OPT_SESSION,
- SHOW_LONG,
- get_error_count);
-static sys_var_readonly sys_warning_count(&vars, "warning_count",
- OPT_SESSION,
- SHOW_LONG,
- get_warning_count);
-
-static sys_var_rand_seed1 sys_rand_seed1(&vars, "rand_seed1",
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-static sys_var_rand_seed2 sys_rand_seed2(&vars, "rand_seed2",
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-
-static sys_var_thd_ulong sys_default_week_format(&vars, "default_week_format",
- &SV::default_week_format);
-
-sys_var_thd_ulong sys_group_concat_max_len(&vars, "group_concat_max_len",
- &SV::group_concat_max_len);
-
-sys_var_thd_time_zone sys_time_zone(&vars, "time_zone",
- sys_var::SESSION_VARIABLE_IN_BINLOG);
-
-/* Global read-only variable containing hostname */
-static sys_var_const_str sys_hostname(&vars, "hostname", glob_hostname);
-
-#ifndef EMBEDDED_LIBRARY
-static sys_var_const_str_ptr sys_repl_report_host(&vars, "report_host", &report_host);
-static sys_var_const_str_ptr sys_repl_report_user(&vars, "report_user", &report_user);
-static sys_var_const_str_ptr sys_repl_report_password(&vars, "report_password", &report_password);
-
-static uchar *slave_get_report_port(THD *thd)
+static uchar *get_sys_var_length(const sys_var *var, size_t *length,
+ my_bool first)
{
- thd->sys_var_tmp.long_value= report_port;
- return (uchar*) &thd->sys_var_tmp.long_value;
+ *length= var->name.length;
+ return (uchar*) var->name.str;
}
-static sys_var_readonly sys_repl_report_port(&vars, "report_port", OPT_GLOBAL, SHOW_LONG, slave_get_report_port);
-
-#endif
-
-sys_var_thd_bool sys_keep_files_on_create(&vars, "keep_files_on_create",
- &SV::keep_files_on_create);
-/* Read only variables */
-
-static sys_var_have_variable sys_have_compress(&vars, "have_compress", &have_compress);
-static sys_var_have_variable sys_have_crypt(&vars, "have_crypt", &have_crypt);
-static sys_var_have_plugin sys_have_csv(&vars, "have_csv", C_STRING_WITH_LEN("csv"), MYSQL_STORAGE_ENGINE_PLUGIN);
-static sys_var_have_variable sys_have_dlopen(&vars, "have_dynamic_loading", &have_dlopen);
-static sys_var_have_variable sys_have_geometry(&vars, "have_geometry", &have_geometry);
-static sys_var_have_plugin sys_have_innodb(&vars, "have_innodb", C_STRING_WITH_LEN("innodb"), MYSQL_STORAGE_ENGINE_PLUGIN);
-static sys_var_have_plugin sys_have_ndbcluster(&vars, "have_ndbcluster", C_STRING_WITH_LEN("ndbcluster"), MYSQL_STORAGE_ENGINE_PLUGIN);
-static sys_var_have_variable sys_have_openssl(&vars, "have_openssl", &have_ssl);
-static sys_var_have_variable sys_have_ssl(&vars, "have_ssl", &have_ssl);
-static sys_var_have_plugin sys_have_partition_db(&vars, "have_partitioning", C_STRING_WITH_LEN("partition"), MYSQL_STORAGE_ENGINE_PLUGIN);
-static sys_var_have_variable sys_have_query_cache(&vars, "have_query_cache",
- &have_query_cache);
-static sys_var_have_variable sys_have_community_features(&vars, "have_community_features", &have_community_features);
-static sys_var_have_variable sys_have_rtree_keys(&vars, "have_rtree_keys", &have_rtree_keys);
-static sys_var_have_variable sys_have_symlink(&vars, "have_symlink", &have_symlink);
-/* Global read-only variable describing server license */
-static sys_var_const_str sys_license(&vars, "license", STRINGIFY_ARG(LICENSE));
-/* Global variables which enable|disable logging */
-static sys_var_log_state sys_var_general_log(&vars, "general_log", &opt_log,
- QUERY_LOG_GENERAL);
-/* Synonym of "general_log" for consistency with SHOW VARIABLES output */
-static sys_var_log_state sys_var_log(&vars, "log", &opt_log,
- QUERY_LOG_GENERAL);
-static sys_var_log_state sys_var_slow_query_log(&vars, "slow_query_log", &opt_slow_log,
- QUERY_LOG_SLOW);
-/* Synonym of "slow_query_log" for consistency with SHOW VARIABLES output */
-static sys_var_log_state sys_var_log_slow(&vars, "log_slow_queries",
- &opt_slow_log, QUERY_LOG_SLOW);
-sys_var_str sys_var_general_log_path(&vars, "general_log_file", sys_check_log_path,
- sys_update_general_log_path,
- sys_default_general_log_path,
- opt_logname);
-sys_var_str sys_var_slow_log_path(&vars, "slow_query_log_file", sys_check_log_path,
- sys_update_slow_log_path,
- sys_default_slow_log_path,
- opt_slow_logname);
-static sys_var_log_output sys_var_log_output_state(&vars, "log_output", &log_output_options,
- &log_output_typelib, 0);
-static sys_var_readonly sys_myisam_mmap_size(&vars, "myisam_mmap_size",
- OPT_GLOBAL,
- SHOW_LONGLONG,
- get_myisam_mmap_size);
-
+sys_var_chain all_sys_vars = { NULL, NULL };
-bool sys_var::check(THD *thd, set_var *var)
+int sys_var_init()
{
- var->save_result.ulonglong_value= var->value->val_int();
- return 0;
-}
+ DBUG_ENTER("sys_var_init");
-bool sys_var_str::check(THD *thd, set_var *var)
-{
- int res;
- if (!check_func)
- return 0;
-
- if ((res=(*check_func)(thd, var)) < 0)
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0),
- name, var->value->str_value.ptr());
- return res;
-}
-
-/*
- Functions to check and update variables
-*/
-
-
-/*
- Update variables 'init_connect, init_slave'.
-
- In case of 'DEFAULT' value
- (for example: 'set GLOBAL init_connect=DEFAULT')
- 'var' parameter is NULL pointer.
-*/
-
-bool update_sys_var_str(sys_var_str *var_str, rw_lock_t *var_mutex,
- set_var *var)
-{
- char *res= 0, *old_value=(char *)(var ? var->value->str_value.ptr() : 0);
- uint new_length= (var ? var->value->str_value.length() : 0);
- if (!old_value)
- old_value= (char*) "";
- if (!(res= my_strndup(old_value, new_length, MYF(0))))
- return 1;
- /*
- Replace the old value in such a way that the any thread using
- the value will work.
- */
- rw_wrlock(var_mutex);
- old_value= var_str->value;
- var_str->value= res;
- var_str->value_length= new_length;
- var_str->is_os_charset= FALSE;
- rw_unlock(var_mutex);
- my_free(old_value, MYF(MY_ALLOW_ZERO_PTR));
- return 0;
-}
+ /* Must be already initialized. */
+ DBUG_ASSERT(system_charset_info != NULL);
+ if (my_hash_init(&system_variable_hash, system_charset_info, 100, 0,
+ 0, (my_hash_get_key) get_sys_var_length, 0, HASH_UNIQUE))
+ goto error;
-static bool sys_update_init_connect(THD *thd, set_var *var)
-{
- return update_sys_var_str(&sys_init_connect, &LOCK_sys_init_connect, var);
-}
+ if (mysql_add_sys_var_chain(all_sys_vars.first))
+ goto error;
+ DBUG_RETURN(0);
-static void sys_default_init_connect(THD* thd, enum_var_type type)
-{
- update_sys_var_str(&sys_init_connect, &LOCK_sys_init_connect, 0);
+error:
+ fprintf(stderr, "failed to initialize System variables");
+ DBUG_RETURN(1);
}
-
-static bool sys_update_init_slave(THD *thd, set_var *var)
+int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags)
{
- return update_sys_var_str(&sys_init_slave, &LOCK_sys_init_slave, var);
-}
+ uint saved_elements= long_options->elements;
+ DBUG_ENTER("sys_var_add_options");
-static void sys_default_init_slave(THD* thd, enum_var_type type)
-{
- update_sys_var_str(&sys_init_slave, &LOCK_sys_init_slave, 0);
-}
-
-static int sys_check_ftb_syntax(THD *thd, set_var *var)
-{
- if (thd->security_ctx->master_access & SUPER_ACL)
- return (ft_boolean_check_syntax_string((uchar*)
- var->value->str_value.c_ptr()) ?
- -1 : 0);
- else
+ for (sys_var *var=all_sys_vars.first; var; var= var->next)
{
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
- return 1;
+ if (var->register_option(long_options, parse_flags))
+ goto error;
}
-}
-
-static bool sys_update_ftb_syntax(THD *thd, set_var * var)
-{
- strmake(ft_boolean_syntax, var->value->str_value.c_ptr(),
- sizeof(ft_boolean_syntax)-1);
-#ifdef HAVE_QUERY_CACHE
- query_cache.flush();
-#endif /* HAVE_QUERY_CACHE */
-
- return 0;
-}
+ DBUG_RETURN(0);
-static void sys_default_ftb_syntax(THD *thd, enum_var_type type)
-{
- strmake(ft_boolean_syntax, def_ft_boolean_syntax,
- sizeof(ft_boolean_syntax)-1);
+error:
+ fprintf(stderr, "failed to initialize System variables");
+ long_options->elements= saved_elements;
+ DBUG_RETURN(1);
}
-
-/**
- If one sets the LOW_PRIORIY UPDATES flag, we also must change the
- used lock type.
-*/
-
-static void fix_low_priority_updates(THD *thd, enum_var_type type)
+void sys_var_end()
{
- if (type == OPT_GLOBAL)
- thr_upgraded_concurrent_insert_lock=
- (global_system_variables.low_priority_updates ?
- TL_WRITE_LOW_PRIORITY : TL_WRITE);
- else
- thd->update_lock_default= (thd->variables.low_priority_updates ?
- TL_WRITE_LOW_PRIORITY : TL_WRITE);
-}
+ DBUG_ENTER("sys_var_end");
+ my_hash_free(&system_variable_hash);
-static void
-fix_myisam_max_sort_file_size(THD *thd, enum_var_type type)
-{
- myisam_max_temp_length=
- (my_off_t) global_system_variables.myisam_max_sort_file_size;
-}
+ for (sys_var *var=all_sys_vars.first; var; var= var->next)
+ var->cleanup();
-/**
- Set the OPTION_BIG_SELECTS flag if max_join_size == HA_POS_ERROR.
-*/
-
-static void fix_max_join_size(THD *thd, enum_var_type type)
-{
- if (type != OPT_GLOBAL)
- {
- if (thd->variables.max_join_size == HA_POS_ERROR)
- thd->options|= OPTION_BIG_SELECTS;
- else
- thd->options&= ~OPTION_BIG_SELECTS;
- }
+ DBUG_VOID_RETURN;
}
-
/**
- Can't change the 'next' tx_isolation while we are already in
- a transaction
-*/
-static int check_tx_isolation(THD *thd, set_var *var)
-{
- if (var->type == OPT_DEFAULT && (thd->server_status & SERVER_STATUS_IN_TRANS))
- {
- my_error(ER_CANT_CHANGE_TX_ISOLATION, MYF(0));
- return 1;
- }
- return 0;
-}
-
-/*
- If one doesn't use the SESSION modifier, the isolation level
- is only active for the next command.
-*/
-static void fix_tx_isolation(THD *thd, enum_var_type type)
-{
- if (type == OPT_SESSION)
- thd->session_tx_isolation= ((enum_tx_isolation)
- thd->variables.tx_isolation);
-}
-
-static void fix_completion_type(THD *thd __attribute__((unused)),
- enum_var_type type __attribute__((unused))) {}
-
-static int check_completion_type(THD *thd, set_var *var)
-{
- longlong val= var->value->val_int();
- if (val < 0 || val > 2)
- {
- char buf[64];
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name, llstr(val, buf));
- return 1;
- }
- return 0;
-}
-
-
-/*
- If we are changing the thread variable, we have to copy it to NET too
-*/
-
-#ifdef HAVE_REPLICATION
-static void fix_net_read_timeout(THD *thd, enum_var_type type)
+ sys_var constructor
+
+ @param chain variables are linked into chain for mysql_add_sys_var_chain()
+ @param name_arg the name of the variable. @sa my_option::name
+ @param comment shown in mysqld --help, @sa my_option::comment
+ @param flags_arg or'ed flag_enum values
+ @param off offset of the global variable value from the
+ &global_system_variables.
+ @param getopt_id -1 for no command-line option, otherwise @sa my_option::id
+ @param getopt_arg_type @sa my_option::arg_type
+ @param show_val_type_arg what value_ptr() returns for sql_show.cc
+ @param def_val default value, @sa my_option::def_value
+ @param lock mutex or rw_lock that protects the global variable
+ *in addition* to LOCK_global_system_variables.
+ @param binlog_status_enum @sa binlog_status_enum
+ @param on_check_func a function to be called at the end of sys_var::check,
+ put your additional checks here
+ @param on_update_func a function to be called at the end of sys_var::update,
+ any post-update activity should happen here
+ @param deprecated_version if not 0 - when this variable will go away
+ @param substitute if not 0 - what one should use instead when this
+ deprecated variable
+ @param parse_flag either PARSE_EARLY or PARSE_NORMAL
+*/
+sys_var::sys_var(sys_var_chain *chain, const char *name_arg,
+ const char *comment, int flags_arg, ptrdiff_t off,
+ int getopt_id, enum get_opt_arg_type getopt_arg_type,
+ SHOW_TYPE show_val_type_arg, longlong def_val,
+ PolyLock *lock, enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func,
+ on_update_function on_update_func,
+ uint deprecated_version, const char *substitute,
+ int parse_flag) :
+ next(0),
+ binlog_status(binlog_status_arg),
+ flags(flags_arg), m_parse_flag(parse_flag), show_val_type(show_val_type_arg),
+ guard(lock), offset(off), on_check(on_check_func), on_update(on_update_func),
+ is_os_charset(FALSE)
{
- if (type != OPT_GLOBAL)
- my_net_set_read_timeout(&thd->net, thd->variables.net_read_timeout);
-}
-
-
-static void fix_net_write_timeout(THD *thd, enum_var_type type)
-{
- if (type != OPT_GLOBAL)
- my_net_set_write_timeout(&thd->net, thd->variables.net_write_timeout);
-}
-
-static void fix_net_retry_count(THD *thd, enum_var_type type)
-{
- if (type != OPT_GLOBAL)
- thd->net.retry_count=thd->variables.net_retry_count;
-}
-#else /* HAVE_REPLICATION */
-static void fix_net_read_timeout(THD *thd __attribute__((unused)),
- enum_var_type type __attribute__((unused)))
-{}
-static void fix_net_write_timeout(THD *thd __attribute__((unused)),
- enum_var_type type __attribute__((unused)))
-{}
-static void fix_net_retry_count(THD *thd __attribute__((unused)),
- enum_var_type type __attribute__((unused)))
-{}
-#endif /* HAVE_REPLICATION */
-
-
-static void fix_query_cache_size(THD *thd, enum_var_type type)
-{
-#ifdef HAVE_QUERY_CACHE
- ulong new_cache_size= query_cache.resize(query_cache_size);
-
/*
- Note: query_cache_size is a global variable reflecting the
- requested cache size. See also query_cache_size_arg
+ There is a limitation in handle_options() related to short options:
+ - either all short options should be declared when parsing in multiple stages,
+ - or none should be declared.
+ Because a lot of short options are used in the normal parsing phase
+ for mysqld, we enforce here that no short option is present
+ in the first (PARSE_EARLY) stage.
+ See handle_options() for details.
*/
+ DBUG_ASSERT(parse_flag == PARSE_NORMAL || getopt_id <= 0 || getopt_id >= 255);
- if (query_cache_size != new_cache_size)
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_QC_RESIZE, ER(ER_WARN_QC_RESIZE),
- query_cache_size, new_cache_size);
-
- query_cache_size= new_cache_size;
-#endif
-}
+ name.str= name_arg;
+ name.length= strlen(name_arg);
+ DBUG_ASSERT(name.length <= NAME_CHAR_LEN);
+ bzero(&option, sizeof(option));
+ option.name= name_arg;
+ option.id= getopt_id;
+ option.comment= comment;
+ option.arg_type= getopt_arg_type;
+ option.value= (uchar **)global_var_ptr();
+ option.def_value= def_val;
-#ifdef HAVE_QUERY_CACHE
-static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type)
-{
- query_cache_min_res_unit=
- query_cache.set_min_res_unit(query_cache_min_res_unit);
-}
-#endif
+ deprecated.version= deprecated_version;
+ deprecated.substitute= substitute;
+ DBUG_ASSERT((deprecated_version != 0) || (substitute == 0));
+ DBUG_ASSERT(deprecated_version % 100 == 0);
+ DBUG_ASSERT(!deprecated_version || MYSQL_VERSION_ID < deprecated_version);
-
-extern void fix_delay_key_write(THD *thd, enum_var_type type)
-{
- switch ((enum_delay_key_write) delay_key_write_options) {
- case DELAY_KEY_WRITE_NONE:
- myisam_delay_key_write=0;
- break;
- case DELAY_KEY_WRITE_ON:
- myisam_delay_key_write=1;
- break;
- case DELAY_KEY_WRITE_ALL:
- myisam_delay_key_write=1;
- ha_open_options|= HA_OPEN_DELAY_KEY_WRITE;
- break;
- }
-}
-
-bool sys_var_set::update(THD *thd, set_var *var)
-{
- *value= var->save_result.ulong_value;
- return 0;
+ if (chain->last)
+ chain->last->next= this;
+ else
+ chain->first= this;
+ chain->last= this;
}
-uchar *sys_var_set::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
+bool sys_var::update(THD *thd, set_var *var)
{
- char buff[256];
- String tmp(buff, sizeof(buff), &my_charset_latin1);
- ulong length;
- ulong val= *value;
-
- tmp.length(0);
- for (uint i= 0; val; val>>= 1, i++)
+ enum_var_type type= var->type;
+ if (type == OPT_GLOBAL || scope() == GLOBAL)
{
- if (val & 1)
- {
- tmp.append(enum_names->type_names[i],
- enum_names->type_lengths[i]);
- tmp.append(',');
- }
+ /*
+ Yes, both locks need to be taken before an update, just as
+ both are taken to get a value. If we'll take only 'guard' here,
+ then value_ptr() for strings won't be safe in SHOW VARIABLES anymore,
+ to make it safe we'll need value_ptr_unlock().
+ */
+ AutoWLock lock1(&PLock_global_system_variables);
+ AutoWLock lock2(guard);
+ return global_update(thd, var) ||
+ (on_update && on_update(this, thd, OPT_GLOBAL));
}
-
- if ((length= tmp.length()))
- length--;
- return (uchar*) thd->strmake(tmp.ptr(), length);
+ else
+ return session_update(thd, var) ||
+ (on_update && on_update(this, thd, OPT_SESSION));
}
-void sys_var_set_slave_mode::set_default(THD *thd, enum_var_type type)
+uchar *sys_var::session_value_ptr(THD *thd, LEX_STRING *base)
{
- slave_exec_mode_options= SLAVE_EXEC_MODE_STRICT;
+ return session_var_ptr(thd);
}
-bool sys_var_set_slave_mode::check(THD *thd, set_var *var)
+uchar *sys_var::global_value_ptr(THD *thd, LEX_STRING *base)
{
- bool rc= sys_var_set::check(thd, var);
- if (!rc && (var->save_result.ulong_value & SLAVE_EXEC_MODE_STRICT) &&
- (var->save_result.ulong_value & SLAVE_EXEC_MODE_IDEMPOTENT))
- {
- rc= true;
- my_error(ER_SLAVE_AMBIGOUS_EXEC_MODE, MYF(0), "");
- }
- return rc;
+ return global_var_ptr();
}
-bool sys_var_set_slave_mode::update(THD *thd, set_var *var)
-{
- bool rc;
- pthread_mutex_lock(&LOCK_global_system_variables);
- rc= sys_var_set::update(thd, var);
- pthread_mutex_unlock(&LOCK_global_system_variables);
- return rc;
-}
-
-void fix_slave_exec_mode(void)
+bool sys_var::check(THD *thd, set_var *var)
{
- DBUG_ENTER("fix_slave_exec_mode");
-
- if ((slave_exec_mode_options & SLAVE_EXEC_MODE_STRICT) &&
- (slave_exec_mode_options & SLAVE_EXEC_MODE_IDEMPOTENT))
+ do_deprecated_warning(thd);
+ if ((var->value && do_check(thd, var))
+ || (on_check && on_check(this, thd, var)))
{
- sql_print_error("Ambiguous slave modes combination. STRICT will be used");
- slave_exec_mode_options&= ~SLAVE_EXEC_MODE_IDEMPOTENT;
- }
- if (!(slave_exec_mode_options & SLAVE_EXEC_MODE_IDEMPOTENT))
- slave_exec_mode_options|= SLAVE_EXEC_MODE_STRICT;
- DBUG_VOID_RETURN;
-}
-
+ if (!thd->is_error())
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
-bool sys_var_thd_binlog_format::check(THD *thd, set_var *var) {
- /*
- All variables that affect writing to binary log (either format or
- turning logging on and off) use the same checking. We call the
- superclass ::check function to assign the variable correctly, and
- then check the value.
- */
- bool result= sys_var_thd_enum::check(thd, var);
- if (!result)
- result= check_log_update(thd, var);
- return result;
+ if (!var->value)
+ {
+ str.set(STRING_WITH_LEN("DEFAULT"), &my_charset_latin1);
+ res= &str;
+ }
+ else if (!(res=var->value->val_str(&str)))
+ {
+ str.set(STRING_WITH_LEN("NULL"), &my_charset_latin1);
+ res= &str;
+ }
+ ErrConvString err(res);
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
+ }
+ return true;
+ }
+ return false;
}
-
-bool sys_var_thd_binlog_format::is_readonly() const
+uchar *sys_var::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{
- /*
- Under certain circumstances, the variable is read-only (unchangeable):
- */
- THD *thd= current_thd;
- /*
- If RBR and open temporary tables, their CREATE TABLE may not be in the
- binlog, so we can't toggle to SBR in this connection.
- The test below will also prevent SET GLOBAL, well it was not easy to test
- if global or not here.
- And this test will also prevent switching from RBR to RBR (a no-op which
- should not happen too often).
-
- If we don't have row-based replication compiled in, the variable
- is always read-only.
- */
- if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW) &&
- thd->temporary_tables)
+ if (type == OPT_GLOBAL || scope() == GLOBAL)
{
- my_error(ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR, MYF(0));
- return 1;
+ mysql_mutex_assert_owner(&LOCK_global_system_variables);
+ AutoRLock lock(guard);
+ return global_value_ptr(thd, base);
}
- /*
- if in a stored function/trigger, it's too late to change mode
- */
- if (thd->in_sub_stmt)
- {
- my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
- return 1;
- }
- return sys_var_thd_enum::is_readonly();
+ else
+ return session_value_ptr(thd, base);
}
-
-void fix_binlog_format_after_update(THD *thd, enum_var_type type)
+bool sys_var::set_default(THD *thd, enum_var_type type)
{
- thd->reset_current_stmt_binlog_row_based();
-}
+ LEX_STRING empty={0,0};
+ set_var var(type, 0, &empty, 0);
+ if (type == OPT_GLOBAL || scope() == GLOBAL)
+ global_save_default(thd, &var);
+ else
+ session_save_default(thd, &var);
-static void fix_max_binlog_size(THD *thd, enum_var_type type)
-{
- DBUG_ENTER("fix_max_binlog_size");
- DBUG_PRINT("info",("max_binlog_size=%lu max_relay_log_size=%lu",
- max_binlog_size, max_relay_log_size));
- mysql_bin_log.set_max_size(max_binlog_size);
-#ifdef HAVE_REPLICATION
- if (!max_relay_log_size)
- active_mi->rli.relay_log.set_max_size(max_binlog_size);
-#endif
- DBUG_VOID_RETURN;
-}
-
-static void fix_max_relay_log_size(THD *thd, enum_var_type type)
-{
- DBUG_ENTER("fix_max_relay_log_size");
- DBUG_PRINT("info",("max_binlog_size=%lu max_relay_log_size=%lu",
- max_binlog_size, max_relay_log_size));
-#ifdef HAVE_REPLICATION
- active_mi->rli.relay_log.set_max_size(max_relay_log_size ?
- max_relay_log_size: max_binlog_size);
-#endif
- DBUG_VOID_RETURN;
+ return check(thd, &var) || update(thd, &var);
}
-
-static int check_max_delayed_threads(THD *thd, set_var *var)
+void sys_var::do_deprecated_warning(THD *thd)
{
- longlong val= var->value->val_int();
- if (var->type != OPT_GLOBAL && val != 0 &&
- val != (longlong) global_system_variables.max_insert_delayed_threads)
+ if (deprecated.version)
{
- char buf[64];
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name, llstr(val, buf));
- return 1;
+ char buf1[NAME_CHAR_LEN + 3], buf2[10];
+ strxnmov(buf1, sizeof(buf1)-1, "@@", name.str, 0);
+ my_snprintf(buf2, sizeof(buf2), "%d.%d", deprecated.version/100/100,
+ deprecated.version/100%100);
+ uint errmsg= deprecated.substitute
+ ? ER_WARN_DEPRECATED_SYNTAX_WITH_VER
+ : ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT;
+ if (thd)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX, ER(errmsg),
+ buf1, buf2, deprecated.substitute);
+ else
+ sql_print_warning(ER_DEFAULT(errmsg), buf1, buf2, deprecated.substitute);
}
- return 0;
-}
-
-static void fix_max_connections(THD *thd, enum_var_type type)
-{
-#ifndef EMBEDDED_LIBRARY
- resize_thr_alarm(max_connections +
- global_system_variables.max_insert_delayed_threads + 10);
-#endif
-}
-
-
-static void fix_thd_mem_root(THD *thd, enum_var_type type)
-{
- if (type != OPT_GLOBAL)
- reset_root_defaults(thd->mem_root,
- thd->variables.query_alloc_block_size,
- thd->variables.query_prealloc_size);
}
-
-static void fix_trans_mem_root(THD *thd, enum_var_type type)
-{
-#ifdef USING_TRANSACTIONS
- if (type != OPT_GLOBAL)
- reset_root_defaults(&thd->transaction.mem_root,
- thd->variables.trans_alloc_block_size,
- thd->variables.trans_prealloc_size);
-#endif
-}
-
-
-static void fix_server_id(THD *thd, enum_var_type type)
-{
- server_id_supplied = 1;
- thd->server_id= server_id;
-}
-
-
/**
Throw warning (error in STRICT mode) if value for variable needed bounding.
- Only call from check(), not update(), because an error in update() would be
- bad mojo. Plug-in interface also uses this.
+ Plug-in interface also uses this.
- @param thd thread handle
- @param fixed did we have to correct the value? (throw warn/err if so)
- @param unsignd is value's type unsigned?
- @param name variable's name
- @param val variable's value
+ @param thd thread handle
+ @param name variable's name
+ @param fixed did we have to correct the value? (throw warn/err if so)
+ @param is_unsigned is value's type unsigned?
+ @param v variable's value
- @retval TRUE on error, FALSE otherwise (warning or OK)
+ @retval true on error, false otherwise (warning or ok)
*/
-bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd,
- const char *name, longlong val)
+bool throw_bounds_warning(THD *thd, const char *name,
+ bool fixed, bool is_unsigned, longlong v)
{
- if (fixed)
+ if (fixed || (!is_unsigned && v < 0))
{
char buf[22];
- if (unsignd)
- ullstr((ulonglong) val, buf);
+ if (is_unsigned)
+ ullstr((ulonglong) v, buf);
else
- llstr(val, buf);
+ llstr(v, buf);
if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES)
{
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf);
- return TRUE;
+ return true;
}
-
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE), name, buf);
}
- return FALSE;
-}
-
-
-/**
- Get unsigned system-variable.
- Negative value does not wrap around, but becomes zero.
- Check user-supplied value for a systemvariable against bounds.
- If we needed to adjust the value, throw a warning or error depending
- on SQL-mode.
-
- @param thd thread handle
- @param var the system-variable to get
- @param user_max a limit given with --maximum-variable-name=... or 0
- @param var_type function will bound on systems where necessary.
-
- @retval TRUE on error, FALSE otherwise (warning or OK)
- */
-static bool get_unsigned(THD *thd, set_var *var, ulonglong user_max,
- ulong var_type)
-{
- int warnings= 0;
- ulonglong unadjusted;
- const struct my_option *limits= var->var->option_limits;
- struct my_option fallback;
-
- /* get_unsigned() */
- if (var->value->unsigned_flag)
- var->save_result.ulonglong_value= (ulonglong) var->value->val_int();
- else
- {
- longlong v= var->value->val_int();
- var->save_result.ulonglong_value= (ulonglong) ((v < 0) ? 0 : v);
- if (v < 0)
- {
- warnings++;
- if (throw_bounds_warning(thd, TRUE, FALSE, var->var->name, v))
- return TRUE; /* warning was promoted to error, give up */
- }
- }
-
- unadjusted= var->save_result.ulonglong_value;
-
- /* max, if any */
-
- if ((user_max > 0) && (unadjusted > user_max))
- {
- var->save_result.ulonglong_value= user_max;
-
- if ((warnings == 0) && throw_bounds_warning(thd, TRUE, TRUE,
- var->var->name,
- (longlong) unadjusted))
- return TRUE;
-
- warnings++;
- }
-
- /*
- if the sysvar doesn't have a proper bounds record but the check
- function would like bounding to ULONG where its size differs from
- that of ULONGLONG, we make up a bogus limits record here and let
- the usual suspects handle the actual limiting.
- */
-
- if (!limits && var_type != GET_ULL)
- {
- bzero(&fallback, sizeof(fallback));
- fallback.var_type= var_type;
- limits= &fallback;
- }
-
- /* fix_unsigned() */
- if (limits)
- {
- my_bool fixed;
-
- var->save_result.ulonglong_value= getopt_ull_limit_value(var->save_result.
- ulonglong_value,
- limits, &fixed);
-
- if ((warnings == 0) && throw_bounds_warning(thd, fixed, TRUE,
- var->var->name,
- (longlong) unadjusted))
- return TRUE;
- }
-
- return FALSE;
-}
-
-
-sys_var_long_ptr::
-sys_var_long_ptr(sys_var_chain *chain, const char *name_arg, ulong *value_ptr_arg,
- sys_after_update_func after_update_arg)
- :sys_var_long_ptr_global(chain, name_arg, value_ptr_arg,
- &LOCK_global_system_variables, after_update_arg)
-{}
-
-
-bool sys_var_long_ptr_global::check(THD *thd, set_var *var)
-{
- return get_unsigned(thd, var, 0, GET_ULONG);
-}
-
-bool sys_var_long_ptr_global::update(THD *thd, set_var *var)
-{
- pthread_mutex_lock(guard);
- *value= (ulong) var->save_result.ulonglong_value;
- pthread_mutex_unlock(guard);
- return 0;
-}
-
-
-void sys_var_long_ptr_global::set_default(THD *thd, enum_var_type type)
-{
- my_bool not_used;
- pthread_mutex_lock(guard);
- *value= (ulong) getopt_ull_limit_value((ulong) option_limits->def_value,
- option_limits, &not_used);
- pthread_mutex_unlock(guard);
-}
-
-
-bool sys_var_ulonglong_ptr::check(THD *thd, set_var *var)
-{
- return get_unsigned(thd, var, 0, GET_ULL);
-}
-
-
-bool sys_var_ulonglong_ptr::update(THD *thd, set_var *var)
-{
- ulonglong tmp= var->save_result.ulonglong_value;
- pthread_mutex_lock(&LOCK_global_system_variables);
- *value= (ulonglong) tmp;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- return 0;
-}
-
-
-void sys_var_ulonglong_ptr::set_default(THD *thd, enum_var_type type)
-{
- my_bool not_used;
- pthread_mutex_lock(&LOCK_global_system_variables);
- *value= getopt_ull_limit_value((ulonglong) option_limits->def_value,
- option_limits, &not_used);
- pthread_mutex_unlock(&LOCK_global_system_variables);
-}
-
-
-bool sys_var_bool_ptr::update(THD *thd, set_var *var)
-{
- *value= (my_bool) var->save_result.ulong_value;
- return 0;
-}
-
-
-void sys_var_bool_ptr::set_default(THD *thd, enum_var_type type)
-{
- *value= (my_bool) option_limits->def_value;
-}
-
-
-bool sys_var_enum::update(THD *thd, set_var *var)
-{
- *value= (uint) var->save_result.ulong_value;
- return 0;
-}
-
-
-uchar *sys_var_enum::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
-{
- return (uchar*) enum_names->type_names[*value];
-}
-
-
-uchar *sys_var_enum_const::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- return (uchar*) enum_names->type_names[global_system_variables.*offset];
-}
-
-bool sys_var_thd_ulong::check(THD *thd, set_var *var)
-{
- if (get_unsigned(thd, var, max_system_variables.*offset, GET_ULONG))
- return TRUE;
- DBUG_ASSERT(var->save_result.ulonglong_value <= ULONG_MAX);
- return ((check_func && (*check_func)(thd, var)));
-}
-
-bool sys_var_thd_ulong::update(THD *thd, set_var *var)
-{
- if (var->type == OPT_GLOBAL)
- global_system_variables.*offset= (ulong) var->save_result.ulonglong_value;
- else
- thd->variables.*offset= (ulong) var->save_result.ulonglong_value;
-
- return 0;
-}
-
-
-void sys_var_thd_ulong::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- {
- my_bool not_used;
- /* We will not come here if option_limits is not set */
- global_system_variables.*offset=
- (ulong) getopt_ull_limit_value((ulong) option_limits->def_value,
- option_limits, &not_used);
- }
- else
- thd->variables.*offset= global_system_variables.*offset;
-}
-
-
-uchar *sys_var_thd_ulong::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- if (type == OPT_GLOBAL)
- return (uchar*) &(global_system_variables.*offset);
- return (uchar*) &(thd->variables.*offset);
-}
-
-
-bool sys_var_thd_ha_rows::check(THD *thd, set_var *var)
-{
- return get_unsigned(thd, var, max_system_variables.*offset,
-#ifdef BIG_TABLES
- GET_ULL
-#else
- GET_ULONG
-#endif
- );
-}
-
-
-bool sys_var_thd_ha_rows::update(THD *thd, set_var *var)
-{
- if (var->type == OPT_GLOBAL)
- {
- /* Lock is needed to make things safe on 32 bit systems */
- pthread_mutex_lock(&LOCK_global_system_variables);
- global_system_variables.*offset= (ha_rows)
- var->save_result.ulonglong_value;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- thd->variables.*offset= (ha_rows) var->save_result.ulonglong_value;
- return 0;
-}
-
-
-void sys_var_thd_ha_rows::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- {
- my_bool not_used;
- /* We will not come here if option_limits is not set */
- pthread_mutex_lock(&LOCK_global_system_variables);
- global_system_variables.*offset=
- (ha_rows) getopt_ull_limit_value((ha_rows) option_limits->def_value,
- option_limits, &not_used);
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- thd->variables.*offset= global_system_variables.*offset;
-}
-
-
-uchar *sys_var_thd_ha_rows::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- if (type == OPT_GLOBAL)
- return (uchar*) &(global_system_variables.*offset);
- return (uchar*) &(thd->variables.*offset);
-}
-
-bool sys_var_thd_ulonglong::check(THD *thd, set_var *var)
-{
- return get_unsigned(thd, var, max_system_variables.*offset, GET_ULL);
-}
-
-bool sys_var_thd_ulonglong::update(THD *thd, set_var *var)
-{
- if (var->type == OPT_GLOBAL)
- {
- /* Lock is needed to make things safe on 32 bit systems */
- pthread_mutex_lock(&LOCK_global_system_variables);
- global_system_variables.*offset= (ulonglong)
- var->save_result.ulonglong_value;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- thd->variables.*offset= (ulonglong) var->save_result.ulonglong_value;
- return 0;
-}
-
-
-void sys_var_thd_ulonglong::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- {
- my_bool not_used;
- pthread_mutex_lock(&LOCK_global_system_variables);
- global_system_variables.*offset=
- getopt_ull_limit_value((ulonglong) option_limits->def_value,
- option_limits, &not_used);
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- thd->variables.*offset= global_system_variables.*offset;
-}
-
-
-uchar *sys_var_thd_ulonglong::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- if (type == OPT_GLOBAL)
- return (uchar*) &(global_system_variables.*offset);
- return (uchar*) &(thd->variables.*offset);
-}
-
-
-bool sys_var_thd_bool::update(THD *thd, set_var *var)
-{
- if (var->type == OPT_GLOBAL)
- global_system_variables.*offset= (my_bool) var->save_result.ulong_value;
- else
- thd->variables.*offset= (my_bool) var->save_result.ulong_value;
- return 0;
-}
-
-
-void sys_var_thd_bool::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.*offset= (my_bool) option_limits->def_value;
- else
- thd->variables.*offset= global_system_variables.*offset;
-}
-
-
-uchar *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- if (type == OPT_GLOBAL)
- return (uchar*) &(global_system_variables.*offset);
- return (uchar*) &(thd->variables.*offset);
-}
-
-
-bool sys_var::check_enum(THD *thd, set_var *var, const TYPELIB *enum_names)
-{
- char buff[STRING_BUFFER_USUAL_SIZE];
- const char *value;
- String str(buff, sizeof(buff), system_charset_info), *res;
-
- if (var->value->result_type() == STRING_RESULT)
- {
- if (!(res=var->value->val_str(&str)) ||
- ((long) (var->save_result.ulong_value=
- (ulong) find_type(enum_names, res->ptr(),
- res->length(),1)-1)) < 0)
- {
- value= res ? res->c_ptr() : "NULL";
- goto err;
- }
- }
- else
- {
- ulonglong tmp=var->value->val_int();
- if (tmp >= enum_names->count)
- {
- llstr(tmp,buff);
- value=buff; // Wrong value is here
- goto err;
- }
- var->save_result.ulong_value= (ulong) tmp; // Save for update
- }
- return 0;
-
-err:
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, value);
- return 1;
+ return false;
}
-
-bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names)
+bool throw_bounds_warning(THD *thd, const char *name, bool fixed, double v)
{
- bool not_used;
- char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
- uint error_len= 0;
- String str(buff, sizeof(buff), system_charset_info), *res;
-
- if (var->value->result_type() == STRING_RESULT)
- {
- if (!(res= var->value->val_str(&str)))
- {
- strmov(buff, "NULL");
- goto err;
- }
-
- if (!m_allow_empty_value &&
- res->length() == 0)
- {
- buff[0]= 0;
- goto err;
- }
-
- var->save_result.ulong_value= ((ulong)
- find_set(enum_names, res->c_ptr(),
- res->length(),
- NULL,
- &error, &error_len,
- &not_used));
- if (error_len)
- {
- strmake(buff, error, min(sizeof(buff) - 1, error_len));
- goto err;
- }
- }
- else
+ if (fixed)
{
- ulonglong tmp= var->value->val_int();
+ char buf[64];
- if (!m_allow_empty_value &&
- tmp == 0)
- {
- buff[0]= '0';
- buff[1]= 0;
- goto err;
- }
+ my_gcvt(v, MY_GCVT_ARG_DOUBLE, sizeof(buf) - 1, buf, NULL);
- /*
- For when the enum is made to contain 64 elements, as 1ULL<<64 is
- undefined, we guard with a "count<64" test.
- */
- if (unlikely((tmp >= ((ULL(1)) << enum_names->count)) &&
- (enum_names->count < 64)))
+ if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES)
{
- llstr(tmp, buff);
- goto err;
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf);
+ return true;
}
- var->save_result.ulong_value= (ulong) tmp; // Save for update
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE,
+ ER(ER_TRUNCATED_WRONG_VALUE), name, buf);
}
- return 0;
-
-err:
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buff);
- return 1;
+ return false;
}
-
CHARSET_INFO *sys_var::charset(THD *thd)
{
- return is_os_charset ? thd->variables.character_set_filesystem :
+ return is_os_charset ? thd->variables.character_set_filesystem :
system_charset_info;
}
-
-bool sys_var_thd_enum::update(THD *thd, set_var *var)
-{
- if (var->type == OPT_GLOBAL)
- global_system_variables.*offset= var->save_result.ulong_value;
- else
- thd->variables.*offset= var->save_result.ulong_value;
- return 0;
-}
-
-
-void sys_var_thd_enum::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.*offset= (ulong) option_limits->def_value;
- else
- thd->variables.*offset= global_system_variables.*offset;
-}
-
-
-uchar *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- ulong tmp= ((type == OPT_GLOBAL) ?
- global_system_variables.*offset :
- thd->variables.*offset);
- return (uchar*) enum_names->type_names[tmp];
-}
-
-bool sys_var_thd_bit::check(THD *thd, set_var *var)
-{
- return (check_enum(thd, var, &bool_typelib) ||
- (check_func && (*check_func)(thd, var)));
-}
-
-bool sys_var_thd_bit::update(THD *thd, set_var *var)
-{
- int res= (*update_func)(thd, var);
- return res;
-}
-
-
-uchar *sys_var_thd_bit::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- /*
- If reverse is 0 (default) return 1 if bit is set.
- If reverse is 1, return 0 if bit is set
- */
- thd->sys_var_tmp.my_bool_value= ((thd->options & bit_flag) ?
- !reverse : reverse);
- return (uchar*) &thd->sys_var_tmp.my_bool_value;
-}
-
-
-/** Update a date_time format variable based on given value. */
-
-void sys_var_thd_date_time_format::update2(THD *thd, enum_var_type type,
- DATE_TIME_FORMAT *new_value)
-{
- DATE_TIME_FORMAT *old;
- DBUG_ENTER("sys_var_date_time_format::update2");
- DBUG_DUMP("positions", (uchar*) new_value->positions,
- sizeof(new_value->positions));
-
- if (type == OPT_GLOBAL)
- {
- pthread_mutex_lock(&LOCK_global_system_variables);
- old= (global_system_variables.*offset);
- (global_system_variables.*offset)= new_value;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- {
- old= (thd->variables.*offset);
- (thd->variables.*offset)= new_value;
- }
- my_free((char*) old, MYF(MY_ALLOW_ZERO_PTR));
- DBUG_VOID_RETURN;
-}
-
-
-bool sys_var_thd_date_time_format::update(THD *thd, set_var *var)
-{
- DATE_TIME_FORMAT *new_value;
- /* We must make a copy of the last value to get it into normal memory */
- new_value= date_time_format_copy((THD*) 0,
- var->save_result.date_time_format);
- if (!new_value)
- return 1; // Out of memory
- update2(thd, var->type, new_value); // Can't fail
- return 0;
-}
-
-
-bool sys_var_thd_date_time_format::check(THD *thd, set_var *var)
-{
- char buff[STRING_BUFFER_USUAL_SIZE];
- String str(buff,sizeof(buff), system_charset_info), *res;
- DATE_TIME_FORMAT *format;
-
- if (!(res=var->value->val_str(&str)))
- res= &my_empty_string;
-
- if (!(format= date_time_format_make(date_time_type,
- res->ptr(), res->length())))
- {
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, res->c_ptr());
- return 1;
- }
-
- /*
- We must copy result to thread space to not get a memory leak if
- update is aborted
- */
- var->save_result.date_time_format= date_time_format_copy(thd, format);
- my_free((char*) format, MYF(0));
- return var->save_result.date_time_format == 0;
-}
-
-
-void sys_var_thd_date_time_format::set_default(THD *thd, enum_var_type type)
-{
- DATE_TIME_FORMAT *res= 0;
-
- if (type == OPT_GLOBAL)
- {
- const char *format;
- if ((format= opt_date_time_formats[date_time_type]))
- res= date_time_format_make(date_time_type, format, strlen(format));
- }
- else
- {
- /* Make copy with malloc */
- res= date_time_format_copy((THD *) 0, global_system_variables.*offset);
- }
-
- if (res) // Should always be true
- update2(thd, type, res);
-}
-
-
-uchar *sys_var_thd_date_time_format::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- if (type == OPT_GLOBAL)
- {
- char *res;
- /*
- We do a copy here just to be sure things will work even if someone
- is modifying the original string while the copy is accessed
- (Can't happen now in SQL SHOW, but this is a good safety for the future)
- */
- res= thd->strmake((global_system_variables.*offset)->format.str,
- (global_system_variables.*offset)->format.length);
- return (uchar*) res;
- }
- return (uchar*) (thd->variables.*offset)->format.str;
-}
-
-
typedef struct old_names_map_st
{
const char *old_name;
const char *new_name;
} my_old_conv;
-static my_old_conv old_conv[]=
-{
- { "cp1251_koi8" , "cp1251" },
- { "cp1250_latin2" , "cp1250" },
- { "kam_latin2" , "keybcs2" },
- { "mac_latin2" , "MacRoman" },
- { "macce_latin2" , "MacCE" },
- { "pc2_latin2" , "pclatin2" },
- { "vga_latin2" , "pclatin1" },
- { "koi8_cp1251" , "koi8r" },
- { "win1251ukr_koi8_ukr" , "win1251ukr" },
- { "koi8_ukr_win1251ukr" , "koi8u" },
- { NULL , NULL }
+static my_old_conv old_conv[]=
+{
+ { "cp1251_koi8" , "cp1251" },
+ { "cp1250_latin2" , "cp1250" },
+ { "kam_latin2" , "keybcs2" },
+ { "mac_latin2" , "MacRoman" },
+ { "macce_latin2" , "MacCE" },
+ { "pc2_latin2" , "pclatin2" },
+ { "vga_latin2" , "pclatin1" },
+ { "koi8_cp1251" , "koi8r" },
+ { "win1251ukr_koi8_ukr" , "win1251ukr" },
+ { "koi8_ukr_win1251ukr" , "koi8u" },
+ { NULL , NULL }
};
CHARSET_INFO *get_old_charset_by_name(const char *name)
{
my_old_conv *conv;
-
+
for (conv= old_conv; conv->old_name; conv++)
{
if (!my_strcasecmp(&my_charset_latin1, name, conv->old_name))
@@ -2071,1129 +389,6 @@ CHARSET_INFO *get_old_charset_by_name(const char *name)
return NULL;
}
-
-bool sys_var_collation::check(THD *thd, set_var *var)
-{
- CHARSET_INFO *tmp;
- LINT_INIT(tmp);
-
- if (var->value->result_type() == STRING_RESULT)
- {
- char buff[STRING_BUFFER_USUAL_SIZE];
- String str(buff,sizeof(buff), system_charset_info), *res;
- if (!(res=var->value->val_str(&str)))
- {
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL");
- return 1;
- }
- if (!(tmp=get_charset_by_name(res->c_ptr(),MYF(0))))
- {
- my_error(ER_UNKNOWN_COLLATION, MYF(0), res->c_ptr());
- return 1;
- }
- }
- else // INT_RESULT
- {
- if (!(tmp=get_charset((int) var->value->val_int(),MYF(0))))
- {
- char buf[20];
- int10_to_str((int) var->value->val_int(), buf, -10);
- my_error(ER_UNKNOWN_COLLATION, MYF(0), buf);
- return 1;
- }
- }
- var->save_result.charset= tmp; // Save for update
- return 0;
-}
-
-
-bool sys_var_character_set::check(THD *thd, set_var *var)
-{
- CHARSET_INFO *tmp;
- LINT_INIT(tmp);
-
- if (var->value->result_type() == STRING_RESULT)
- {
- char buff[STRING_BUFFER_USUAL_SIZE];
- String str(buff,sizeof(buff), system_charset_info), *res;
- if (!(res=var->value->val_str(&str)))
- {
- if (!nullable)
- {
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL");
- return 1;
- }
- tmp= NULL;
- }
- else if (!(tmp=get_charset_by_csname(res->c_ptr(),MY_CS_PRIMARY,MYF(0))) &&
- !(tmp=get_old_charset_by_name(res->c_ptr())))
- {
- my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), res->c_ptr());
- return 1;
- }
- }
- else // INT_RESULT
- {
- if (!(tmp=get_charset((int) var->value->val_int(),MYF(0))))
- {
- char buf[20];
- int10_to_str((int) var->value->val_int(), buf, -10);
- my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), buf);
- return 1;
- }
- }
- var->save_result.charset= tmp; // Save for update
- return 0;
-}
-
-
-bool sys_var_character_set::update(THD *thd, set_var *var)
-{
- ci_ptr(thd,var->type)[0]= var->save_result.charset;
- thd->update_charset();
- return 0;
-}
-
-
-uchar *sys_var_character_set::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- CHARSET_INFO *cs= ci_ptr(thd,type)[0];
- return cs ? (uchar*) cs->csname : (uchar*) NULL;
-}
-
-
-void sys_var_character_set_sv::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.*offset= *global_default;
- else
- {
- thd->variables.*offset= global_system_variables.*offset;
- thd->update_charset();
- }
-}
-CHARSET_INFO **sys_var_character_set_sv::ci_ptr(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- return &(global_system_variables.*offset);
- else
- return &(thd->variables.*offset);
-}
-
-
-bool sys_var_character_set_client::check(THD *thd, set_var *var)
-{
- if (sys_var_character_set_sv::check(thd, var))
- return 1;
- /* Currently, UCS-2 cannot be used as a client character set */
- if (var->save_result.charset->mbminlen > 1)
- {
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name,
- var->save_result.charset->csname);
- return 1;
- }
- return 0;
-}
-
-
-CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd,
- enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- return &global_system_variables.collation_database;
- else
- return &thd->variables.collation_database;
-}
-
-
-void sys_var_character_set_database::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.collation_database= default_charset_info;
- else
- {
- thd->variables.collation_database= thd->db_charset;
- thd->update_charset();
- }
-}
-
-
-bool sys_var_collation_sv::update(THD *thd, set_var *var)
-{
- if (var->type == OPT_GLOBAL)
- global_system_variables.*offset= var->save_result.charset;
- else
- {
- thd->variables.*offset= var->save_result.charset;
- thd->update_charset();
- }
- return 0;
-}
-
-
-void sys_var_collation_sv::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.*offset= *global_default;
- else
- {
- thd->variables.*offset= global_system_variables.*offset;
- thd->update_charset();
- }
-}
-
-
-uchar *sys_var_collation_sv::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- CHARSET_INFO *cs= ((type == OPT_GLOBAL) ?
- global_system_variables.*offset : thd->variables.*offset);
- return cs ? (uchar*) cs->name : (uchar*) "NULL";
-}
-
-
-LEX_STRING default_key_cache_base= {(char *) "default", 7 };
-
-static KEY_CACHE zero_key_cache;
-
-KEY_CACHE *get_key_cache(LEX_STRING *cache_name)
-{
- safe_mutex_assert_owner(&LOCK_global_system_variables);
- if (!cache_name || ! cache_name->length)
- cache_name= &default_key_cache_base;
- return ((KEY_CACHE*) find_named(&key_caches,
- cache_name->str, cache_name->length, 0));
-}
-
-
-uchar *sys_var_key_cache_param::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- KEY_CACHE *key_cache= get_key_cache(base);
- if (!key_cache)
- key_cache= &zero_key_cache;
- return (uchar*) key_cache + offset ;
-}
-
-
-bool sys_var_key_buffer_size::check(THD *thd, set_var *var)
-{
- return get_unsigned(thd, var, 0, GET_ULL);
-}
-
-
-bool sys_var_key_buffer_size::update(THD *thd, set_var *var)
-{
- ulonglong tmp= var->save_result.ulonglong_value;
- LEX_STRING *base_name= &var->base;
- KEY_CACHE *key_cache;
- bool error= 0;
-
- /* If no basename, assume it's for the key cache named 'default' */
- if (!base_name->length)
- base_name= &default_key_cache_base;
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- key_cache= get_key_cache(base_name);
-
- if (!key_cache)
- {
- /* Key cache didn't exist */
- if (!tmp) // Tried to delete cache
- goto end; // Ok, nothing to do
- if (!(key_cache= create_key_cache(base_name->str, base_name->length)))
- {
- error= 1;
- goto end;
- }
- }
-
- /*
- Abort if some other thread is changing the key cache
- TODO: This should be changed so that we wait until the previous
- assignment is done and then do the new assign
- */
- if (key_cache->in_init)
- goto end;
-
- if (!tmp) // Zero size means delete
- {
- if (key_cache == dflt_key_cache)
- {
- error= 1;
- my_error(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, MYF(0));
- goto end; // Ignore default key cache
- }
-
- if (key_cache->key_cache_inited) // If initied
- {
- /*
- Move tables using this key cache to the default key cache
- and clear the old key cache.
- */
- NAMED_LIST *list;
- key_cache= (KEY_CACHE *) find_named(&key_caches, base_name->str,
- base_name->length, &list);
- key_cache->in_init= 1;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- error= reassign_keycache_tables(thd, key_cache, dflt_key_cache);
- pthread_mutex_lock(&LOCK_global_system_variables);
- key_cache->in_init= 0;
- }
- /*
- We don't delete the key cache as some running threads my still be
- in the key cache code with a pointer to the deleted (empty) key cache
- */
- goto end;
- }
-
- key_cache->param_buff_size= (ulonglong) tmp;
-
- /* If key cache didn't exist initialize it, else resize it */
- key_cache->in_init= 1;
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
- if (!key_cache->key_cache_inited)
- error= (bool) (ha_init_key_cache("", key_cache));
- else
- error= (bool)(ha_resize_key_cache(key_cache));
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- key_cache->in_init= 0;
-
-end:
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
- var->save_result.ulonglong_value = SIZE_T_MAX;
-
- return error;
-}
-
-
-bool sys_var_key_cache_long::check(THD *thd, set_var *var)
-{
- return get_unsigned(thd, var, 0, GET_ULONG);
-}
-
-
-/**
- @todo
- Abort if some other thread is changing the key cache.
- This should be changed so that we wait until the previous
- assignment is done and then do the new assign
-*/
-bool sys_var_key_cache_long::update(THD *thd, set_var *var)
-{
- LEX_STRING *base_name= &var->base;
- bool error= 0;
-
- if (!base_name->length)
- base_name= &default_key_cache_base;
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- KEY_CACHE *key_cache= get_key_cache(base_name);
-
- if (!key_cache && !(key_cache= create_key_cache(base_name->str,
- base_name->length)))
- {
- error= 1;
- goto end;
- }
-
- /*
- Abort if some other thread is changing the key cache
- TODO: This should be changed so that we wait until the previous
- assignment is done and then do the new assign
- */
- if (key_cache->in_init)
- goto end;
-
- *((ulong*) (((char*) key_cache) + offset))= (ulong)
- var->save_result.ulonglong_value;
-
- /*
- Don't create a new key cache if it didn't exist
- (key_caches are created only when the user sets block_size)
- */
- key_cache->in_init= 1;
-
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
- error= (bool) (ha_resize_key_cache(key_cache));
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- key_cache->in_init= 0;
-
-end:
- pthread_mutex_unlock(&LOCK_global_system_variables);
- return error;
-}
-
-
-bool sys_var_log_state::update(THD *thd, set_var *var)
-{
- bool res;
-
- if (this == &sys_var_log)
- WARN_DEPRECATED(thd, "7.0", "@@log", "'@@general_log'");
- else if (this == &sys_var_log_slow)
- WARN_DEPRECATED(thd, "7.0", "@@log_slow_queries", "'@@slow_query_log'");
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- if (!var->save_result.ulong_value)
- {
- logger.deactivate_log_handler(thd, log_type);
- res= false;
- }
- else
- res= logger.activate_log_handler(thd, log_type);
- pthread_mutex_unlock(&LOCK_global_system_variables);
- return res;
-}
-
-void sys_var_log_state::set_default(THD *thd, enum_var_type type)
-{
- if (this == &sys_var_log)
- WARN_DEPRECATED(thd, "7.0", "@@log", "'@@general_log'");
- else if (this == &sys_var_log_slow)
- WARN_DEPRECATED(thd, "7.0", "@@log_slow_queries", "'@@slow_query_log'");
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- logger.deactivate_log_handler(thd, log_type);
- pthread_mutex_unlock(&LOCK_global_system_variables);
-}
-
-
-static int sys_check_log_path(THD *thd, set_var *var)
-{
- char path[FN_REFLEN], buff[FN_REFLEN];
- MY_STAT f_stat;
- String str(buff, sizeof(buff), system_charset_info), *res;
- const char *log_file_str;
- size_t path_length;
-
- if (!(res= var->value->val_str(&str)))
- goto err;
-
- log_file_str= res->c_ptr();
- bzero(&f_stat, sizeof(MY_STAT));
-
- path_length= unpack_filename(path, log_file_str);
-
- if (!path_length)
- {
- /* File name is empty. */
-
- goto err;
- }
-
- if (my_stat(path, &f_stat, MYF(0)))
- {
- /*
- A file system object exists. Check if argument is a file and we have
- 'write' permission.
- */
-
- if (!MY_S_ISREG(f_stat.st_mode) ||
- !(f_stat.st_mode & MY_S_IWRITE))
- goto err;
-
- return 0;
- }
-
- /* Get dirname of the file path. */
- (void) dirname_part(path, log_file_str, &path_length);
-
- /* Dirname is empty if file path is relative. */
- if (!path_length)
- return 0;
-
- /*
- Check if directory exists and we have permission to create file and
- write to file.
- */
- if (my_access(path, (F_OK|W_OK)))
- goto err;
-
- return 0;
-
-err:
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name,
- res ? log_file_str : "NULL");
- return 1;
-}
-
-
-bool update_sys_var_str_path(THD *thd, sys_var_str *var_str,
- set_var *var, const char *log_ext,
- bool log_state, uint log_type)
-{
- MYSQL_QUERY_LOG *file_log;
- char buff[FN_REFLEN];
- char *res= 0, *old_value=(char *)(var ? var->value->str_value.ptr() : 0);
- bool result= 0;
- uint str_length= (var ? var->value->str_value.length() : 0);
-
- switch (log_type) {
- case QUERY_LOG_SLOW:
- file_log= logger.get_slow_log_file_handler();
- break;
- case QUERY_LOG_GENERAL:
- file_log= logger.get_log_file_handler();
- break;
- default:
- MY_ASSERT_UNREACHABLE();
- }
-
- if (!old_value)
- {
- old_value= make_default_log_name(buff, log_ext);
- str_length= strlen(old_value);
- }
- if (!(res= my_strndup(old_value, str_length, MYF(MY_FAE+MY_WME))))
- {
- result= 1;
- goto err;
- }
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- logger.lock_exclusive();
-
- if (file_log && log_state)
- file_log->close(0);
- old_value= var_str->value;
- var_str->value= res;
- var_str->value_length= str_length;
- my_free(old_value, MYF(MY_ALLOW_ZERO_PTR));
- if (file_log && log_state)
- {
- switch (log_type) {
- case QUERY_LOG_SLOW:
- file_log->open_slow_log(sys_var_slow_log_path.value);
- break;
- case QUERY_LOG_GENERAL:
- file_log->open_query_log(sys_var_general_log_path.value);
- break;
- default:
- DBUG_ASSERT(0);
- }
- }
-
- logger.unlock();
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
-err:
- return result;
-}
-
-
-static bool sys_update_general_log_path(THD *thd, set_var * var)
-{
- return update_sys_var_str_path(thd, &sys_var_general_log_path,
- var, ".log", opt_log, QUERY_LOG_GENERAL);
-}
-
-
-static void sys_default_general_log_path(THD *thd, enum_var_type type)
-{
- (void) update_sys_var_str_path(thd, &sys_var_general_log_path,
- 0, ".log", opt_log, QUERY_LOG_GENERAL);
-}
-
-
-static bool sys_update_slow_log_path(THD *thd, set_var * var)
-{
- return update_sys_var_str_path(thd, &sys_var_slow_log_path,
- var, "-slow.log", opt_slow_log,
- QUERY_LOG_SLOW);
-}
-
-
-static void sys_default_slow_log_path(THD *thd, enum_var_type type)
-{
- (void) update_sys_var_str_path(thd, &sys_var_slow_log_path,
- 0, "-slow.log", opt_slow_log,
- QUERY_LOG_SLOW);
-}
-
-
-bool sys_var_log_output::update(THD *thd, set_var *var)
-{
- pthread_mutex_lock(&LOCK_global_system_variables);
- logger.lock_exclusive();
- logger.init_slow_log(var->save_result.ulong_value);
- logger.init_general_log(var->save_result.ulong_value);
- *value= var->save_result.ulong_value;
- logger.unlock();
- pthread_mutex_unlock(&LOCK_global_system_variables);
- return 0;
-}
-
-
-void sys_var_log_output::set_default(THD *thd, enum_var_type type)
-{
- pthread_mutex_lock(&LOCK_global_system_variables);
- logger.lock_exclusive();
- logger.init_slow_log(LOG_FILE);
- logger.init_general_log(LOG_FILE);
- *value= LOG_FILE;
- logger.unlock();
- pthread_mutex_unlock(&LOCK_global_system_variables);
-}
-
-
-uchar *sys_var_log_output::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- char buff[256];
- String tmp(buff, sizeof(buff), &my_charset_latin1);
- ulong length;
- ulong val= *value;
-
- tmp.length(0);
- for (uint i= 0; val; val>>= 1, i++)
- {
- if (val & 1)
- {
- tmp.append(log_output_typelib.type_names[i],
- log_output_typelib.type_lengths[i]);
- tmp.append(',');
- }
- }
-
- if ((length= tmp.length()))
- length--;
- return (uchar*) thd->strmake(tmp.ptr(), length);
-}
-
-
-/*****************************************************************************
- Functions to handle SET NAMES and SET CHARACTER SET
-*****************************************************************************/
-
-int set_var_collation_client::check(THD *thd)
-{
- /* Currently, UCS-2 cannot be used as a client character set */
- if (character_set_client->mbminlen > 1)
- {
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
- character_set_client->csname);
- return 1;
- }
- return 0;
-}
-
-int set_var_collation_client::update(THD *thd)
-{
- thd->variables.character_set_client= character_set_client;
- thd->variables.character_set_results= character_set_results;
- thd->variables.collation_connection= collation_connection;
- thd->update_charset();
- thd->protocol_text.init(thd);
- thd->protocol_binary.init(thd);
- return 0;
-}
-
-/****************************************************************************/
-
-bool sys_var_timestamp::check(THD *thd, set_var *var)
-{
- time_t val;
- var->save_result.ulonglong_value= var->value->val_int();
- val= (time_t) var->save_result.ulonglong_value;
- if (val < (time_t) MY_TIME_T_MIN || val > (time_t) MY_TIME_T_MAX)
- {
- my_message(ER_UNKNOWN_ERROR,
- "This version of MySQL doesn't support dates later than 2038",
- MYF(0));
- return TRUE;
- }
- return FALSE;
-}
-
-
-bool sys_var_timestamp::update(THD *thd, set_var *var)
-{
- thd->set_time((time_t) var->save_result.ulonglong_value);
- return FALSE;
-}
-
-
-void sys_var_timestamp::set_default(THD *thd, enum_var_type type)
-{
- thd->user_time=0;
-}
-
-
-uchar *sys_var_timestamp::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- thd->sys_var_tmp.long_value= (long) thd->start_time;
- return (uchar*) &thd->sys_var_tmp.long_value;
-}
-
-
-bool sys_var_last_insert_id::update(THD *thd, set_var *var)
-{
- thd->first_successful_insert_id_in_prev_stmt=
- var->save_result.ulonglong_value;
- return 0;
-}
-
-
-uchar *sys_var_last_insert_id::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- /*
- this tmp var makes it robust againt change of type of
- read_first_successful_insert_id_in_prev_stmt().
- */
- thd->sys_var_tmp.ulonglong_value=
- thd->read_first_successful_insert_id_in_prev_stmt();
- return (uchar*) &thd->sys_var_tmp.ulonglong_value;
-}
-
-
-bool sys_var_insert_id::update(THD *thd, set_var *var)
-{
- thd->force_one_auto_inc_interval(var->save_result.ulonglong_value);
- return 0;
-}
-
-
-uchar *sys_var_insert_id::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- thd->sys_var_tmp.ulonglong_value=
- thd->auto_inc_intervals_forced.minimum();
- return (uchar*) &thd->sys_var_tmp.ulonglong_value;
-}
-
-
-bool sys_var_rand_seed1::update(THD *thd, set_var *var)
-{
- thd->rand.seed1= (ulong) var->save_result.ulonglong_value;
- return 0;
-}
-
-bool sys_var_rand_seed2::update(THD *thd, set_var *var)
-{
- thd->rand.seed2= (ulong) var->save_result.ulonglong_value;
- return 0;
-}
-
-
-bool sys_var_thd_time_zone::check(THD *thd, set_var *var)
-{
- char buff[MAX_TIME_ZONE_NAME_LENGTH];
- String str(buff, sizeof(buff), &my_charset_latin1);
- String *res= var->value->val_str(&str);
-
- if (!(var->save_result.time_zone= my_tz_find(thd, res)))
- {
- my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), res ? res->c_ptr() : "NULL");
- return 1;
- }
- return 0;
-}
-
-
-bool sys_var_thd_time_zone::update(THD *thd, set_var *var)
-{
- /* We are using Time_zone object found during check() phase. */
- if (var->type == OPT_GLOBAL)
- {
- pthread_mutex_lock(&LOCK_global_system_variables);
- global_system_variables.time_zone= var->save_result.time_zone;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- thd->variables.time_zone= var->save_result.time_zone;
- return 0;
-}
-
-
-uchar *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- /*
- We can use ptr() instead of c_ptr() here because String contaning
- time zone name is guaranteed to be zero ended.
- */
- if (type == OPT_GLOBAL)
- return (uchar *)(global_system_variables.time_zone->get_name()->ptr());
- else
- {
- /*
- This is an ugly fix for replication: we don't replicate properly queries
- invoking system variables' values to update tables; but
- CONVERT_TZ(,,@@session.time_zone) is so popular that we make it
- replicable (i.e. we tell the binlog code to store the session
- timezone). If it's the global value which was used we can't replicate
- (binlog code stores session value only).
- */
- thd->time_zone_used= 1;
- return (uchar *)(thd->variables.time_zone->get_name()->ptr());
- }
-}
-
-
-void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type)
-{
- pthread_mutex_lock(&LOCK_global_system_variables);
- if (type == OPT_GLOBAL)
- {
- if (default_tz_name)
- {
- String str(default_tz_name, &my_charset_latin1);
- /*
- We are guaranteed to find this time zone since its existence
- is checked during start-up.
- */
- global_system_variables.time_zone= my_tz_find(thd, &str);
- }
- else
- global_system_variables.time_zone= my_tz_SYSTEM;
- }
- else
- thd->variables.time_zone= global_system_variables.time_zone;
- pthread_mutex_unlock(&LOCK_global_system_variables);
-}
-
-
-bool sys_var_max_user_conn::check(THD *thd, set_var *var)
-{
- if (var->type == OPT_GLOBAL)
- return sys_var_thd::check(thd, var);
- else
- {
- /*
- Per-session values of max_user_connections can't be set directly.
- May be we should have a separate error message for this?
- */
- my_error(ER_GLOBAL_VARIABLE, MYF(0), name);
- return TRUE;
- }
-}
-
-bool sys_var_max_user_conn::update(THD *thd, set_var *var)
-{
- DBUG_ASSERT(var->type == OPT_GLOBAL);
- pthread_mutex_lock(&LOCK_global_system_variables);
- max_user_connections= (uint)var->save_result.ulonglong_value;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- return 0;
-}
-
-
-void sys_var_max_user_conn::set_default(THD *thd, enum_var_type type)
-{
- DBUG_ASSERT(type == OPT_GLOBAL);
- pthread_mutex_lock(&LOCK_global_system_variables);
- max_user_connections= (ulong) option_limits->def_value;
- pthread_mutex_unlock(&LOCK_global_system_variables);
-}
-
-
-uchar *sys_var_max_user_conn::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- if (type != OPT_GLOBAL &&
- thd->user_connect && thd->user_connect->user_resources.user_conn)
- return (uchar*) &(thd->user_connect->user_resources.user_conn);
- return (uchar*) &(max_user_connections);
-}
-
-
-bool sys_var_thd_ulong_session_readonly::check(THD *thd, set_var *var)
-{
- if (var->type != OPT_GLOBAL)
- {
- my_error(ER_VARIABLE_IS_READONLY, MYF(0), "SESSION", name, "GLOBAL");
- return TRUE;
- }
-
- return sys_var_thd_ulong::check(thd, var);
-}
-
-
-bool sys_var_thd_lc_time_names::check(THD *thd, set_var *var)
-{
- MY_LOCALE *locale_match;
-
- if (var->value->result_type() == INT_RESULT)
- {
- if (!(locale_match= my_locale_by_number((uint) var->value->val_int())))
- {
- char buf[20];
- int10_to_str((int) var->value->val_int(), buf, -10);
- my_printf_error(ER_UNKNOWN_ERROR, "Unknown locale: '%s'", MYF(0), buf);
- return 1;
- }
- }
- else // STRING_RESULT
- {
- char buff[6];
- String str(buff, sizeof(buff), &my_charset_latin1), *res;
- if (!(res=var->value->val_str(&str)))
- {
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL");
- return 1;
- }
- const char *locale_str= res->c_ptr();
- if (!(locale_match= my_locale_by_name(locale_str)))
- {
- my_printf_error(ER_UNKNOWN_ERROR,
- "Unknown locale: '%s'", MYF(0), locale_str);
- return 1;
- }
- }
-
- var->save_result.locale_value= locale_match;
- return 0;
-}
-
-
-bool sys_var_thd_lc_time_names::update(THD *thd, set_var *var)
-{
- if (var->type == OPT_GLOBAL)
- global_system_variables.lc_time_names= var->save_result.locale_value;
- else
- thd->variables.lc_time_names= var->save_result.locale_value;
- return 0;
-}
-
-
-uchar *sys_var_thd_lc_time_names::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- return type == OPT_GLOBAL ?
- (uchar *) global_system_variables.lc_time_names->name :
- (uchar *) thd->variables.lc_time_names->name;
-}
-
-
-void sys_var_thd_lc_time_names::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.lc_time_names= my_default_lc_time_names;
- else
- thd->variables.lc_time_names= global_system_variables.lc_time_names;
-}
-
-/*
- Handling of microseoncds given as seconds.part_seconds
-
- NOTES
- The argument to long query time is in seconds in decimal
- which is converted to ulonglong integer holding microseconds for storage.
- This is used for handling long_query_time
-*/
-
-bool sys_var_microseconds::update(THD *thd, set_var *var)
-{
- double num= var->value->val_real();
- longlong microseconds;
- if (num > (double) option_limits->max_value)
- num= (double) option_limits->max_value;
- if (num < (double) option_limits->min_value)
- num= (double) option_limits->min_value;
- microseconds= (longlong) (num * 1000000.0 + 0.5);
- if (var->type == OPT_GLOBAL)
- {
- pthread_mutex_lock(&LOCK_global_system_variables);
- (global_system_variables.*offset)= microseconds;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- thd->variables.*offset= microseconds;
- return 0;
-}
-
-
-void sys_var_microseconds::set_default(THD *thd, enum_var_type type)
-{
- longlong microseconds= (longlong) (option_limits->def_value * 1000000.0);
- if (type == OPT_GLOBAL)
- {
- pthread_mutex_lock(&LOCK_global_system_variables);
- global_system_variables.*offset= microseconds;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- thd->variables.*offset= microseconds;
-}
-
-
-uchar *sys_var_microseconds::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- thd->tmp_double_value= (double) ((type == OPT_GLOBAL) ?
- global_system_variables.*offset :
- thd->variables.*offset) / 1000000.0;
- return (uchar*) &thd->tmp_double_value;
-}
-
-
-/*
- Functions to update thd->options bits
-*/
-
-static bool set_option_bit(THD *thd, set_var *var)
-{
- sys_var_thd_bit *sys_var= ((sys_var_thd_bit*) var->var);
- if ((var->save_result.ulong_value != 0) == sys_var->reverse)
- thd->options&= ~sys_var->bit_flag;
- else
- thd->options|= sys_var->bit_flag;
- return 0;
-}
-
-/*
- Functions to be only used to update thd->options OPTION_BIN_LOG bit
-*/
-static bool set_option_log_bin_bit(THD *thd, set_var *var)
-{
- set_option_bit(thd, var);
- if (!thd->in_sub_stmt)
- thd->sql_log_bin_toplevel= thd->options & OPTION_BIN_LOG;
- return 0;
-}
-
-static bool set_option_autocommit(THD *thd, set_var *var)
-{
- /* The test is negative as the flag we use is NOT autocommit */
-
- ulonglong org_options= thd->options;
-
- if (var->save_result.ulong_value != 0)
- thd->options&= ~((sys_var_thd_bit*) var->var)->bit_flag;
- else
- thd->options|= ((sys_var_thd_bit*) var->var)->bit_flag;
-
- if ((org_options ^ thd->options) & OPTION_NOT_AUTOCOMMIT)
- {
- if ((org_options & OPTION_NOT_AUTOCOMMIT))
- {
- /* We changed to auto_commit mode */
- if (thd->transaction.xid_state.xa_state != XA_NOTR)
- {
- thd->options= org_options;
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- return 1;
- }
- thd->options&= ~(ulonglong) (OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->server_status|= SERVER_STATUS_AUTOCOMMIT;
- if (ha_commit(thd))
- return 1;
- }
- else
- {
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT;
- }
- }
- return 0;
-}
-
-static int check_log_update(THD *thd, set_var *var)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!(thd->security_ctx->master_access & SUPER_ACL))
- {
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
- return 1;
- }
-#endif
- return 0;
-}
-
-static bool set_log_update(THD *thd, set_var *var)
-{
- /*
- The update log is not supported anymore since 5.0.
- See sql/mysqld.cc/, comments in function init_server_components() for an
- explaination of the different warnings we send below
- */
-
- if (opt_sql_bin_update)
- {
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_UPDATE_LOG_DEPRECATED_TRANSLATED,
- ER(ER_UPDATE_LOG_DEPRECATED_TRANSLATED));
- }
- else
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_UPDATE_LOG_DEPRECATED_IGNORED,
- ER(ER_UPDATE_LOG_DEPRECATED_IGNORED));
- set_option_bit(thd, var);
- return 0;
-}
-
-
-static int check_pseudo_thread_id(THD *thd, set_var *var)
-{
- var->save_result.ulonglong_value= var->value->val_int();
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (thd->security_ctx->master_access & SUPER_ACL)
- return 0;
- else
- {
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
- return 1;
- }
-#else
- return 0;
-#endif
-}
-
-static uchar *get_warning_count(THD *thd)
-{
- thd->sys_var_tmp.long_value=
- (thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] +
- thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] +
- thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]);
- return (uchar*) &thd->sys_var_tmp.long_value;
-}
-
-static uchar *get_error_count(THD *thd)
-{
- thd->sys_var_tmp.long_value=
- thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR];
- return (uchar*) &thd->sys_var_tmp.long_value;
-}
-
-
-/**
- Get the tmpdir that was specified or chosen by default.
-
- This is necessary because if the user does not specify a temporary
- directory via the command line, one is chosen based on the environment
- or system defaults. But we can't just always use mysql_tmpdir, because
- that is actually a call to my_tmpdir() which cycles among possible
- temporary directories.
-
- @param thd thread handle
-
- @retval
- ptr pointer to NUL-terminated string
-*/
-static uchar *get_tmpdir(THD *thd)
-{
- if (opt_mysql_tmpdir)
- return (uchar *)opt_mysql_tmpdir;
- return (uchar*)mysql_tmpdir;
-}
-
-static uchar *get_myisam_mmap_size(THD *thd)
-{
- return (uchar *)&myisam_mmap_size;
-}
-
-
/****************************************************************************
Main handling of variables:
- Initialisation
@@ -3202,132 +397,86 @@ static uchar *get_myisam_mmap_size(THD *thd)
****************************************************************************/
/**
- Find variable name in option my_getopt structure used for
- command line args.
+ Add variables to the dynamic hash of system variables
- @param opt option structure array to search in
- @param name variable name
+ @param first Pointer to first system variable to add
@retval
- 0 Error
- @retval
- ptr pointer to option structure
-*/
-
-static struct my_option *find_option(struct my_option *opt, const char *name)
-{
- uint length=strlen(name);
- for (; opt->name; opt++)
- {
- if (!getopt_compare_strings(opt->name, name, length) &&
- !opt->name[length])
- {
- /*
- Only accept the option if one can set values through it.
- If not, there is no default value or limits in the option.
- */
- return (opt->value) ? opt : 0;
- }
- }
- return 0;
-}
-
-
-/**
- Return variable name and length for hashing of variables.
-*/
-
-static uchar *get_sys_var_length(const sys_var *var, size_t *length,
- my_bool first)
-{
- *length= var->name_length;
- return (uchar*) var->name;
-}
-
-
-/*
- Add variables to the dynamic hash of system variables
-
- SYNOPSIS
- mysql_add_sys_var_chain()
- first Pointer to first system variable to add
- long_opt (optional)command line arguments may be tied for limit checks.
-
- RETURN VALUES
0 SUCCESS
+ @retval
otherwise FAILURE
*/
-int mysql_add_sys_var_chain(sys_var *first, struct my_option *long_options)
+int mysql_add_sys_var_chain(sys_var *first)
{
sys_var *var;
-
+
/* A write lock should be held on LOCK_system_variables_hash */
-
+
for (var= first; var; var= var->next)
{
- var->name_length= strlen(var->name);
/* this fails if there is a conflicting variable name. see HASH_UNIQUE */
if (my_hash_insert(&system_variable_hash, (uchar*) var))
+ {
+ fprintf(stderr, "*** duplicate variable name '%s' ?\n", var->name.str);
goto error;
- if (long_options)
- var->option_limits= find_option(long_options, var->name);
+ }
}
return 0;
error:
for (; first != var; first= first->next)
- hash_delete(&system_variable_hash, (uchar*) first);
+ my_hash_delete(&system_variable_hash, (uchar*) first);
return 1;
}
-
-
+
+
/*
Remove variables to the dynamic hash of system variables
-
+
SYNOPSIS
mysql_del_sys_var_chain()
first Pointer to first system variable to remove
-
+
RETURN VALUES
0 SUCCESS
otherwise FAILURE
*/
-
+
int mysql_del_sys_var_chain(sys_var *first)
{
int result= 0;
-
+
/* A write lock should be held on LOCK_system_variables_hash */
-
+
for (sys_var *var= first; var; var= var->next)
- result|= hash_delete(&system_variable_hash, (uchar*) var);
+ result|= my_hash_delete(&system_variable_hash, (uchar*) var);
return result;
}
-
-
+
+
static int show_cmp(SHOW_VAR *a, SHOW_VAR *b)
{
return strcmp(a->name, b->name);
}
-
-
-/*
+
+
+/**
Constructs an array of system variables for display to the user.
-
- SYNOPSIS
- enumerate_sys_vars()
- thd current thread
- sorted If TRUE, the system variables should be sorted
-
- RETURN VALUES
+
+ @param thd current thread
+ @param sorted If TRUE, the system variables should be sorted
+ @param type OPT_GLOBAL or OPT_SESSION for SHOW GLOBAL|SESSION VARIABLES
+
+ @retval
pointer Array of SHOW_VAR elements for display
+ @retval
NULL FAILURE
*/
-SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted)
+SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type)
{
int count= system_variable_hash.records, i;
int size= sizeof(SHOW_VAR) * (count + 1);
@@ -3339,8 +488,13 @@ SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted)
for (i= 0; i < count; i++)
{
- sys_var *var= (sys_var*) hash_element(&system_variable_hash, i);
- show->name= var->name;
+ sys_var *var= (sys_var*) my_hash_element(&system_variable_hash, i);
+
+ // don't show session-only variables in SHOW GLOBAL VARIABLES
+ if (type == OPT_GLOBAL && var->check_type(type))
+ continue;
+
+ show->name= var->name.str;
show->value= (char*) var;
show->type= SHOW_SYS;
show++;
@@ -3348,79 +502,29 @@ SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted)
/* sort into order */
if (sorted)
- my_qsort(result, count, sizeof(SHOW_VAR),
+ my_qsort(result, show-result, sizeof(SHOW_VAR),
(qsort_cmp) show_cmp);
-
+
/* make last element empty */
bzero(show, sizeof(SHOW_VAR));
}
return result;
}
-
-/*
- Initialize the system variables
-
- SYNOPSIS
- set_var_init()
-
- RETURN VALUES
- 0 SUCCESS
- otherwise FAILURE
-*/
-
-int set_var_init()
-{
- uint count= 0;
- DBUG_ENTER("set_var_init");
-
- for (sys_var *var=vars.first; var; var= var->next, count++) ;
-
- if (hash_init(&system_variable_hash, system_charset_info, count, 0,
- 0, (hash_get_key) get_sys_var_length, 0, HASH_UNIQUE))
- goto error;
-
- vars.last->next= NULL;
- if (mysql_add_sys_var_chain(vars.first, my_long_options))
- goto error;
-
- /*
- Special cases
- Needed because MySQL can't find the limits for a variable it it has
- a different name than the command line option.
- As these variables are deprecated, this code will disappear soon...
- */
- sys_sql_max_join_size.option_limits= sys_max_join_size.option_limits;
-
- DBUG_RETURN(0);
-
-error:
- fprintf(stderr, "failed to initialize system variables");
- DBUG_RETURN(1);
-}
-
-
-void set_var_free()
-{
- hash_free(&system_variable_hash);
-}
-
-
/**
Find a user set-table variable.
- @param str Name of system variable to find
+ @param str Name of system variable to find
@param length Length of variable. zero means that we should use strlen()
on the variable
- @param no_error Refuse to emit an error, even if one occurred.
@retval
- pointer pointer to variable definitions
+ pointer pointer to variable definitions
@retval
- 0 Unknown variable (error message is given)
+ 0 Unknown variable (error message is given)
*/
-sys_var *intern_find_sys_var(const char *str, uint length, bool no_error)
+sys_var *intern_find_sys_var(const char *str, uint length)
{
sys_var *var;
@@ -3428,11 +532,8 @@ sys_var *intern_find_sys_var(const char *str, uint length, bool no_error)
This function is only called from the sql_plugin.cc.
A lock on LOCK_system_variable_hash should be held
*/
- var= (sys_var*) hash_search(&system_variable_hash,
- (uchar*) str, length ? length : strlen(str));
- if (!(var || no_error))
- my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
-
+ var= (sys_var*) my_hash_search(&system_variable_hash,
+ (uchar*) str, length ? length : strlen(str));
return var;
}
@@ -3446,13 +547,13 @@ sys_var *intern_find_sys_var(const char *str, uint length, bool no_error)
This should ensure that in all normal cases none all or variables are
updated.
- @param THD Thread id
+ @param THD Thread id
@param var_list List of variables to update
@retval
- 0 ok
+ 0 ok
@retval
- 1 ERROR, message sent (normally no variables was updated)
+ 1 ERROR, message sent (normally no variables was updated)
@retval
-1 ERROR, message not sent
*/
@@ -3481,72 +582,45 @@ err:
DBUG_RETURN(error);
}
+/*****************************************************************************
+ Functions to handle SET mysql_internal_variable=const_expr
+*****************************************************************************/
/**
- Say if all variables set by a SET support the ONE_SHOT keyword
- (currently, only character set and collation do; later timezones
- will).
+ Verify that the supplied value is correct.
- @param var_list List of variables to update
+ @param thd Thread handler
- @note
- It has a "not_" because it makes faster tests (no need to "!")
-
- @retval
- 0 all variables of the list support ONE_SHOT
- @retval
- 1 at least one does not support ONE_SHOT
-*/
-
-bool not_all_support_one_shot(List<set_var_base> *var_list)
-{
- List_iterator_fast<set_var_base> it(*var_list);
- set_var_base *var;
- while ((var= it++))
- {
- if (var->no_support_one_shot())
- return 1;
- }
- return 0;
-}
-
-
-/*****************************************************************************
- Functions to handle SET mysql_internal_variable=const_expr
-*****************************************************************************/
+ @return status code
+ @retval -1 Failure
+ @retval 0 Success
+ */
int set_var::check(THD *thd)
{
if (var->is_readonly())
{
- my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), var->name, "read only");
+ my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), var->name.str, "read only");
return -1;
}
if (var->check_type(type))
{
int err= type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE;
- my_error(err, MYF(0), var->name);
+ my_error(err, MYF(0), var->name.str);
return -1;
}
if ((type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)))
return 1;
/* value is a NULL pointer if we are using SET ... = DEFAULT */
if (!value)
- {
- if (var->check_default(type))
- {
- my_error(ER_NO_DEFAULT, MYF(0), var->name);
- return -1;
- }
return 0;
- }
if ((!value->fixed &&
value->fix_fields(thd, &value)) || value->check_cols(1))
return -1;
if (var->check_update_type(value->result_type()))
{
- my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var->name);
+ my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var->name.str);
return -1;
}
return var->check(thd, this) ? -1 : 0;
@@ -3556,12 +630,12 @@ int set_var::check(THD *thd)
/**
Check variable, but without assigning value (used by PS).
- @param thd thread handler
+ @param thd thread handler
@retval
- 0 ok
+ 0 ok
@retval
- 1 ERROR, message sent (normally no variables was updated)
+ 1 ERROR, message sent (normally no variables was updated)
@retval
-1 ERROR, message not sent
*/
@@ -3586,7 +660,7 @@ int set_var::light_check(THD *thd)
Update variable
@param thd thread handler
- @returns 0|1 ok or ERROR
+ @returns 0|1 ok or ERROR
@note ERROR can be only due to abnormal operations involving
the server's execution evironment such as
@@ -3596,13 +670,7 @@ int set_var::light_check(THD *thd)
*/
int set_var::update(THD *thd)
{
- if (!value)
- var->set_default(thd, type);
- else if (var->update(thd, this))
- return -1; // should never happen
- if (var->after_update)
- (*var->after_update)(thd, type);
- return 0;
+ return value ? var->update(thd, this) : var->set_default(thd, type);
}
@@ -3617,19 +685,19 @@ int set_var_user::check(THD *thd)
0 can be passed as last argument (reference on item)
*/
return (user_var_item->fix_fields(thd, (Item**) 0) ||
- user_var_item->check(0)) ? -1 : 0;
+ user_var_item->check(0)) ? -1 : 0;
}
/**
Check variable, but without assigning value (used by PS).
- @param thd thread handler
+ @param thd thread handler
@retval
- 0 ok
+ 0 ok
@retval
- 1 ERROR, message sent (normally no variables was updated)
+ 1 ERROR, message sent (normally no variables was updated)
@retval
-1 ERROR, message not sent
*/
@@ -3678,9 +746,9 @@ int set_var_password::check(THD *thd)
}
if (!user->user.str)
{
- DBUG_ASSERT(thd->security_ctx->priv_user);
- user->user.str= (char *) thd->security_ctx->priv_user;
- user->user.length= strlen(thd->security_ctx->priv_user);
+ DBUG_ASSERT(thd->security_ctx->user);
+ user->user.str= (char *) thd->security_ctx->user;
+ user->user.length= strlen(thd->security_ctx->user);
}
/* Returns 1 as the function sends error to client */
return check_change_password(thd, user->host.str, user->user.str,
@@ -3695,623 +763,36 @@ int set_var_password::update(THD *thd)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Returns 1 as the function sends error to client */
return change_password(thd, user->host.str, user->user.str, password) ?
- 1 : 0;
+ 1 : 0;
#else
return 0;
#endif
}
-/****************************************************************************
- Functions to handle table_type
-****************************************************************************/
-
-/* Based upon sys_var::check_enum() */
-
-bool sys_var_thd_storage_engine::check(THD *thd, set_var *var)
-{
- char buff[STRING_BUFFER_USUAL_SIZE];
- const char *value;
- String str(buff, sizeof(buff), &my_charset_latin1), *res;
-
- var->save_result.plugin= NULL;
- if (var->value->result_type() == STRING_RESULT)
- {
- LEX_STRING engine_name;
- handlerton *hton;
- if (!(res=var->value->val_str(&str)) ||
- !(engine_name.str= (char *)res->ptr()) ||
- !(engine_name.length= res->length()) ||
- !(var->save_result.plugin= ha_resolve_by_name(thd, &engine_name)) ||
- !(hton= plugin_data(var->save_result.plugin, handlerton *)) ||
- ha_checktype(thd, ha_legacy_type(hton), 1, 0) != hton)
- {
- value= res ? res->c_ptr() : "NULL";
- goto err;
- }
- return 0;
- }
- value= "unknown";
-
-err:
- my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), value);
- return 1;
-}
-
-
-uchar *sys_var_thd_storage_engine::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- uchar* result;
- handlerton *hton;
- LEX_STRING *engine_name;
- plugin_ref plugin= thd->variables.*offset;
- if (type == OPT_GLOBAL)
- plugin= my_plugin_lock(thd, &(global_system_variables.*offset));
- hton= plugin_data(plugin, handlerton*);
- engine_name= &hton2plugin[hton->slot]->name;
- result= (uchar *) thd->strmake(engine_name->str, engine_name->length);
- if (type == OPT_GLOBAL)
- plugin_unlock(thd, plugin);
- return result;
-}
-
-
-void sys_var_thd_storage_engine::set_default(THD *thd, enum_var_type type)
-{
- plugin_ref old_value, new_value, *value;
- if (type == OPT_GLOBAL)
- {
- value= &(global_system_variables.*offset);
- new_value= ha_lock_engine(NULL, myisam_hton);
- }
- else
- {
- value= &(thd->variables.*offset);
- new_value= my_plugin_lock(NULL, &(global_system_variables.*offset));
- }
- DBUG_ASSERT(new_value);
- old_value= *value;
- *value= new_value;
- plugin_unlock(NULL, old_value);
-}
-
-
-bool sys_var_thd_storage_engine::update(THD *thd, set_var *var)
-{
- plugin_ref *value= &(global_system_variables.*offset), old_value;
- if (var->type != OPT_GLOBAL)
- value= &(thd->variables.*offset);
- old_value= *value;
- if (old_value != var->save_result.plugin)
- {
- *value= my_plugin_lock(NULL, &var->save_result.plugin);
- plugin_unlock(NULL, old_value);
- }
- return 0;
-}
-
-void sys_var_thd_table_type::warn_deprecated(THD *thd)
-{
- WARN_DEPRECATED(thd, "6.0", "@@table_type", "'@@storage_engine'");
-}
-
-void sys_var_thd_table_type::set_default(THD *thd, enum_var_type type)
-{
- warn_deprecated(thd);
- sys_var_thd_storage_engine::set_default(thd, type);
-}
-
-bool sys_var_thd_table_type::update(THD *thd, set_var *var)
-{
- warn_deprecated(thd);
- return sys_var_thd_storage_engine::update(thd, var);
-}
-
-
-/****************************************************************************
- Functions to handle sql_mode
-****************************************************************************/
-
-/**
- Make string representation of mode.
-
- @param[in] thd thread handler
- @param[in] val sql_mode value
- @param[out] len pointer on length of string
-
- @return
- pointer to string with sql_mode representation
-*/
-
-bool
-sys_var_thd_sql_mode::
-symbolic_mode_representation(THD *thd, ulonglong val, LEX_STRING *rep)
-{
- char buff[STRING_BUFFER_USUAL_SIZE*8];
- String tmp(buff, sizeof(buff), &my_charset_latin1);
-
- tmp.length(0);
-
- for (uint i= 0; val; val>>= 1, i++)
- {
- if (val & 1)
- {
- tmp.append(sql_mode_typelib.type_names[i],
- sql_mode_typelib.type_lengths[i]);
- tmp.append(',');
- }
- }
-
- if (tmp.length())
- tmp.length(tmp.length() - 1); /* trim the trailing comma */
-
- rep->str= thd->strmake(tmp.ptr(), tmp.length());
-
- rep->length= rep->str ? tmp.length() : 0;
-
- return rep->length != tmp.length();
-}
-
-
-uchar *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- LEX_STRING sql_mode;
- ulonglong val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
- thd->variables.*offset);
- (void) symbolic_mode_representation(thd, val, &sql_mode);
- return (uchar *) sql_mode.str;
-}
-
-
-void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.*offset= 0;
- else
- thd->variables.*offset= global_system_variables.*offset;
-}
-
-
-void fix_sql_mode_var(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.sql_mode=
- fix_sql_mode(global_system_variables.sql_mode);
- else
- {
- thd->variables.sql_mode= fix_sql_mode(thd->variables.sql_mode);
- /*
- Update thd->server_status
- */
- if (thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
- thd->server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
- else
- thd->server_status&= ~SERVER_STATUS_NO_BACKSLASH_ESCAPES;
- }
-}
-
-/** Map database specific bits to function bits. */
-
-ulong fix_sql_mode(ulong sql_mode)
-{
- /*
- Note that we dont set
- MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | MODE_NO_FIELD_OPTIONS
- to allow one to get full use of MySQL in this mode.
- */
-
- if (sql_mode & MODE_ANSI)
- {
- sql_mode|= (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
- MODE_IGNORE_SPACE);
- /*
- MODE_ONLY_FULL_GROUP_BY removed from ANSI mode because it is currently
- overly restrictive (see BUG#8510).
- */
- }
- if (sql_mode & MODE_ORACLE)
- sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
- MODE_IGNORE_SPACE |
- MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
- MODE_NO_FIELD_OPTIONS | MODE_NO_AUTO_CREATE_USER);
- if (sql_mode & MODE_MSSQL)
- sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
- MODE_IGNORE_SPACE |
- MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
- MODE_NO_FIELD_OPTIONS);
- if (sql_mode & MODE_POSTGRESQL)
- sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
- MODE_IGNORE_SPACE |
- MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
- MODE_NO_FIELD_OPTIONS);
- if (sql_mode & MODE_DB2)
- sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
- MODE_IGNORE_SPACE |
- MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
- MODE_NO_FIELD_OPTIONS);
- if (sql_mode & MODE_MAXDB)
- sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
- MODE_IGNORE_SPACE |
- MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
- MODE_NO_FIELD_OPTIONS | MODE_NO_AUTO_CREATE_USER);
- if (sql_mode & MODE_MYSQL40)
- sql_mode|= MODE_HIGH_NOT_PRECEDENCE;
- if (sql_mode & MODE_MYSQL323)
- sql_mode|= MODE_HIGH_NOT_PRECEDENCE;
- if (sql_mode & MODE_TRADITIONAL)
- sql_mode|= (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES |
- MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_ERROR_FOR_DIVISION_BY_ZERO | MODE_NO_AUTO_CREATE_USER);
- return sql_mode;
-}
-
-
-bool
-sys_var_thd_optimizer_switch::
-symbolic_mode_representation(THD *thd, ulonglong val, LEX_STRING *rep)
-{
- char buff[STRING_BUFFER_USUAL_SIZE*8];
- String tmp(buff, sizeof(buff), &my_charset_latin1);
- int i;
- ulonglong bit;
- tmp.length(0);
-
- for (i= 0, bit=1; bit != OPTIMIZER_SWITCH_LAST; i++, bit= bit << 1)
- {
- tmp.append(optimizer_switch_typelib.type_names[i],
- optimizer_switch_typelib.type_lengths[i]);
- tmp.append('=');
- tmp.append((val & bit)? "on":"off");
- tmp.append(',');
- }
-
- if (tmp.length())
- tmp.length(tmp.length() - 1); /* trim the trailing comma */
-
- rep->str= thd->strmake(tmp.ptr(), tmp.length());
-
- rep->length= rep->str ? tmp.length() : 0;
-
- return rep->length != tmp.length();
-}
-
-
-uchar *sys_var_thd_optimizer_switch::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- LEX_STRING opts;
- ulonglong val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
- thd->variables.*offset);
- (void) symbolic_mode_representation(thd, val, &opts);
- return (uchar *) opts.str;
-}
-
-
-/*
- Check (and actually parse) string representation of @@optimizer_switch.
-*/
-
-bool sys_var_thd_optimizer_switch::check(THD *thd, set_var *var)
-{
- bool not_used;
- char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
- uint error_len= 0;
- String str(buff, sizeof(buff), system_charset_info), *res;
-
- if (!(res= var->value->val_str(&str)))
- {
- strmov(buff, "NULL");
- goto err;
- }
-
- if (res->length() == 0)
- {
- buff[0]= 0;
- goto err;
- }
-
- var->save_result.ulong_value=
- (ulong)find_set_from_flags(&optimizer_switch_typelib,
- optimizer_switch_typelib.count,
- thd->variables.optimizer_switch,
- global_system_variables.optimizer_switch,
- res->c_ptr_safe(), res->length(), NULL,
- &error, &error_len, &not_used);
- if (error_len)
- {
- strmake(buff, error, min(sizeof(buff) - 1, error_len));
- goto err;
- }
- return FALSE;
-err:
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buff);
- return TRUE;
-}
-
-
-void sys_var_thd_optimizer_switch::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.*offset= OPTIMIZER_SWITCH_DEFAULT;
- else
- thd->variables.*offset= global_system_variables.*offset;
-}
-
-/****************************************************************************
- Named list handling
-****************************************************************************/
-
-uchar* find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
- NAMED_LIST **found)
-{
- I_List_iterator<NAMED_LIST> it(*list);
- NAMED_LIST *element;
- while ((element= it++))
- {
- if (element->cmp(name, length))
- {
- if (found)
- *found= element;
- return element->data;
- }
- }
- return 0;
-}
-
-
-void delete_elements(I_List<NAMED_LIST> *list,
- void (*free_element)(const char *name, uchar*))
-{
- NAMED_LIST *element;
- DBUG_ENTER("delete_elements");
- while ((element= list->get()))
- {
- (*free_element)(element->name, element->data);
- delete element;
- }
- DBUG_VOID_RETURN;
-}
-
-
-/* Key cache functions */
-
-static KEY_CACHE *create_key_cache(const char *name, uint length)
-{
- KEY_CACHE *key_cache;
- DBUG_ENTER("create_key_cache");
- DBUG_PRINT("enter",("name: %.*s", length, name));
-
- if ((key_cache= (KEY_CACHE*) my_malloc(sizeof(KEY_CACHE),
- MYF(MY_ZEROFILL | MY_WME))))
- {
- if (!new NAMED_LIST(&key_caches, name, length, (uchar*) key_cache))
- {
- my_free((char*) key_cache, MYF(0));
- key_cache= 0;
- }
- else
- {
- /*
- Set default values for a key cache
- The values in dflt_key_cache_var is set by my_getopt() at startup
-
- We don't set 'buff_size' as this is used to enable the key cache
- */
- key_cache->param_block_size= dflt_key_cache_var.param_block_size;
- key_cache->param_division_limit= dflt_key_cache_var.param_division_limit;
- key_cache->param_age_threshold= dflt_key_cache_var.param_age_threshold;
- }
- }
- DBUG_RETURN(key_cache);
-}
-
-
-KEY_CACHE *get_or_create_key_cache(const char *name, uint length)
-{
- LEX_STRING key_cache_name;
- KEY_CACHE *key_cache;
-
- key_cache_name.str= (char *) name;
- key_cache_name.length= length;
- pthread_mutex_lock(&LOCK_global_system_variables);
- if (!(key_cache= get_key_cache(&key_cache_name)))
- key_cache= create_key_cache(name, length);
- pthread_mutex_unlock(&LOCK_global_system_variables);
- return key_cache;
-}
-
-
-void free_key_cache(const char *name, KEY_CACHE *key_cache)
-{
- ha_end_key_cache(key_cache);
- my_free((char*) key_cache, MYF(0));
-}
-
+/*****************************************************************************
+ Functions to handle SET NAMES and SET CHARACTER SET
+*****************************************************************************/
-bool process_key_caches(process_key_cache_t func)
+int set_var_collation_client::check(THD *thd)
{
- I_List_iterator<NAMED_LIST> it(key_caches);
- NAMED_LIST *element;
-
- while ((element= it++))
+ /* Currently, UCS-2 cannot be used as a client character set */
+ if (character_set_client->mbminlen > 1)
{
- KEY_CACHE *key_cache= (KEY_CACHE *) element->data;
- func(element->name, key_cache);
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
+ character_set_client->csname);
+ return 1;
}
return 0;
}
-
-void sys_var_trust_routine_creators::warn_deprecated(THD *thd)
-{
- WARN_DEPRECATED(thd, VER_CELOSIA, "@@log_bin_trust_routine_creators",
- "'@@log_bin_trust_function_creators'");
-}
-
-void sys_var_trust_routine_creators::set_default(THD *thd, enum_var_type type)
-{
- warn_deprecated(thd);
- sys_var_bool_ptr::set_default(thd, type);
-}
-
-bool sys_var_trust_routine_creators::update(THD *thd, set_var *var)
-{
- warn_deprecated(thd);
- return sys_var_bool_ptr::update(thd, var);
-}
-
-bool sys_var_opt_readonly::update(THD *thd, set_var *var)
-{
- bool result;
-
- DBUG_ENTER("sys_var_opt_readonly::update");
-
- /* Prevent self dead-lock */
- if (thd->locked_tables || thd->active_transaction())
- {
- my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
- DBUG_RETURN(true);
- }
-
- if (thd->global_read_lock)
- {
- /*
- This connection already holds the global read lock.
- This can be the case with:
- - FLUSH TABLES WITH READ LOCK
- - SET GLOBAL READ_ONLY = 1
- */
- result= sys_var_bool_ptr::update(thd, var);
- DBUG_RETURN(result);
- }
-
- /*
- Perform a 'FLUSH TABLES WITH READ LOCK'.
- This is a 3 step process:
- - [1] lock_global_read_lock()
- - [2] close_cached_tables()
- - [3] make_global_read_lock_block_commit()
- [1] prevents new connections from obtaining tables locked for write.
- [2] waits until all existing connections close their tables.
- [3] prevents transactions from being committed.
- */
-
- if (lock_global_read_lock(thd))
- DBUG_RETURN(true);
-
- /*
- This call will be blocked by any connection holding a READ or WRITE lock.
- Ideally, we want to wait only for pending WRITE locks, but since:
- con 1> LOCK TABLE T FOR READ;
- con 2> LOCK TABLE T FOR WRITE; (blocked by con 1)
- con 3> SET GLOBAL READ ONLY=1; (blocked by con 2)
- can cause to wait on a read lock, it's required for the client application
- to unlock everything, and acceptable for the server to wait on all locks.
- */
- if ((result= close_cached_tables(thd, NULL, FALSE, TRUE, TRUE)))
- goto end_with_read_lock;
-
- if ((result= make_global_read_lock_block_commit(thd)))
- goto end_with_read_lock;
-
- /* Change the opt_readonly system variable, safe because the lock is held */
- result= sys_var_bool_ptr::update(thd, var);
-
-end_with_read_lock:
- /* Release the lock */
- unlock_global_read_lock(thd);
- DBUG_RETURN(result);
-}
-
-
-#ifndef DBUG_OFF
-/* even session variable here requires SUPER, because of -#o,file */
-bool sys_var_thd_dbug::check(THD *thd, set_var *var)
-{
- return check_global_access(thd, SUPER_ACL);
-}
-
-bool sys_var_thd_dbug::update(THD *thd, set_var *var)
+int set_var_collation_client::update(THD *thd)
{
- char buf[256];
- String str(buf, sizeof(buf), system_charset_info), *res;
-
- res= var->value->val_str(&str);
-
- if (var->type == OPT_GLOBAL)
- DBUG_SET_INITIAL(res ? res->c_ptr() : "");
- else
- DBUG_SET(res ? res->c_ptr() : "");
-
+ thd->variables.character_set_client= character_set_client;
+ thd->variables.character_set_results= character_set_results;
+ thd->variables.collation_connection= collation_connection;
+ thd->update_charset();
+ thd->protocol_text.init(thd);
+ thd->protocol_binary.init(thd);
return 0;
}
-
-uchar *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
-{
- char buf[256];
- if (type == OPT_GLOBAL)
- DBUG_EXPLAIN_INITIAL(buf, sizeof(buf));
- else
- DBUG_EXPLAIN(buf, sizeof(buf));
- return (uchar*) thd->strdup(buf);
-}
-#endif /* DBUG_OFF */
-
-
-#ifdef HAVE_EVENT_SCHEDULER
-bool sys_var_event_scheduler::check(THD *thd, set_var *var)
-{
- return check_enum(thd, var, &Events::var_typelib);
-}
-
-/*
- The update method of the global variable event_scheduler.
- If event_scheduler is switched from 0 to 1 then the scheduler main
- thread is resumed and if from 1 to 0 the scheduler thread is suspended
-
- SYNOPSIS
- sys_var_event_scheduler::update()
- thd Thread context (unused)
- var The new value
-
- Returns
- FALSE OK
- TRUE Error
-*/
-
-bool
-sys_var_event_scheduler::update(THD *thd, set_var *var)
-{
- int res;
- /* here start the thread if not running. */
- DBUG_ENTER("sys_var_event_scheduler::update");
- DBUG_PRINT("info", ("new_value: %d", (int) var->save_result.ulong_value));
-
- enum Events::enum_opt_event_scheduler
- new_state=
- (enum Events::enum_opt_event_scheduler) var->save_result.ulong_value;
-
- res= Events::switch_event_scheduler_state(new_state);
-
- DBUG_RETURN((bool) res);
-}
-
-
-uchar *sys_var_event_scheduler::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- return (uchar *) Events::get_opt_event_scheduler_str();
-}
-#endif
-
-/****************************************************************************
- Used templates
-****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List<set_var_base>;
-template class List_iterator_fast<set_var_base>;
-template class I_List_iterator<NAMED_LIST>;
-#endif
diff --git a/sql/set_var.h b/sql/set_var.h
index f2d2e5d2693..2972b430e48 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -1,4 +1,6 @@
-/* Copyright (C) 2002-2006 MySQL AB
+#ifndef SET_VAR_INCLUDED
+#define SET_VAR_INCLUDED
+/* Copyright (C) 2000-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc.
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
@@ -13,31 +15,27 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* Classes to support the SET command */
+/**
+ @file
+ "public" interface to sys_var - server configuration variables.
+*/
#ifdef USE_PRAGMA_INTERFACE
-#pragma interface /* gcc class implementation */
+#pragma interface /* gcc class implementation */
#endif
-/****************************************************************************
- Variables that are changable runtime are declared using the
- following classes
-****************************************************************************/
+#include <my_getopt.h>
class sys_var;
class set_var;
-class sys_var_pluginvar; /* opaque */
-typedef struct system_variables SV;
-typedef struct my_locale_st MY_LOCALE;
+class sys_var_pluginvar;
+class PolyLock;
+class Item_func_set_user_var;
-extern TYPELIB bool_typelib, delay_key_write_typelib, sql_mode_typelib,
- optimizer_switch_typelib, slave_exec_mode_typelib;
+// This include needs to be here since item.h requires enum_var_type :-P
+#include "item.h" /* Item */
-typedef int (*sys_check_func)(THD *, set_var *);
-typedef bool (*sys_update_func)(THD *, set_var *);
-typedef void (*sys_after_update_func)(THD *,enum_var_type);
-typedef void (*sys_set_default_func)(THD *, enum_var_type);
-typedef uchar *(*sys_value_ptr_func)(THD *thd);
+extern TYPELIB bool_typelib;
struct sys_var_chain
{
@@ -45,1275 +43,175 @@ struct sys_var_chain
sys_var *last;
};
+int mysql_add_sys_var_chain(sys_var *chain);
+int mysql_del_sys_var_chain(sys_var *chain);
+
+/**
+ A class representing one system variable - that is something
+ that can be accessed as @@global.variable_name or @@session.variable_name,
+ visible in SHOW xxx VARIABLES and in INFORMATION_SCHEMA.xxx_VARIABLES,
+ optionally it can be assigned to, optionally it can have a command-line
+ counterpart with the same name.
+*/
class sys_var
{
public:
-
- /**
- Enumeration type to indicate for a system variable whether it will be written to the binlog or not.
- */
- enum Binlog_status_enum
- {
- /* The variable value is not in the binlog. */
- NOT_IN_BINLOG,
- /* The value of the @@session variable is in the binlog. */
- SESSION_VARIABLE_IN_BINLOG
- /*
- Currently, no @@global variable is ever in the binlog, so we
- don't need an enumeration value for that.
- */
- };
-
sys_var *next;
- struct my_option *option_limits; /* Updated by by set_var_init() */
- uint name_length; /* Updated by by set_var_init() */
- const char *name;
-
- sys_after_update_func after_update;
- bool no_support_one_shot;
- /*
- true if the value is in character_set_filesystem,
- false otherwise.
- Note that we can't use a pointer to the charset as the system var is
- instantiated in global scope and the charset pointers are initialized
- later.
- */
- bool is_os_charset;
- sys_var(const char *name_arg, sys_after_update_func func= NULL,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :name(name_arg), after_update(func), no_support_one_shot(1),
- is_os_charset (FALSE),
- binlog_status(binlog_status_arg),
- m_allow_empty_value(TRUE)
- {}
- virtual ~sys_var() {}
- void chain_sys_var(sys_var_chain *chain_arg)
- {
- if (chain_arg->last)
- chain_arg->last->next= this;
- else
- chain_arg->first= this;
- chain_arg->last= this;
- }
- virtual bool check(THD *thd, set_var *var);
- bool check_enum(THD *thd, set_var *var, const TYPELIB *enum_names);
- bool check_set(THD *thd, set_var *var, TYPELIB *enum_names);
- bool is_written_to_binlog(enum_var_type type)
- {
- return (type == OPT_SESSION || type == OPT_DEFAULT) &&
- (binlog_status == SESSION_VARIABLE_IN_BINLOG);
- }
- virtual bool update(THD *thd, set_var *var)=0;
- virtual void set_default(THD *thd_arg, enum_var_type type) {}
- virtual SHOW_TYPE show_type() { return SHOW_UNDEF; }
- virtual uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- { return 0; }
- virtual bool check_type(enum_var_type type)
- { return type != OPT_GLOBAL; } /* Error if not GLOBAL */
- virtual bool check_update_type(Item_result type)
- { return type != INT_RESULT; } /* Assume INT */
- virtual bool check_default(enum_var_type type)
- { return option_limits == 0; }
- virtual bool is_struct() { return 0; }
- virtual bool is_readonly() const { return 0; }
- CHARSET_INFO *charset(THD *thd);
- virtual sys_var_pluginvar *cast_pluginvar() { return 0; }
-
-protected:
- void set_allow_empty_value(bool allow_empty_value)
- {
- m_allow_empty_value= allow_empty_value;
- }
-
-private:
- const Binlog_status_enum binlog_status;
-
- bool m_allow_empty_value;
-};
-
-
-/*
- A base class for all variables that require its access to
- be guarded with a mutex.
-*/
+ LEX_CSTRING name;
+ enum flag_enum { GLOBAL, SESSION, ONLY_SESSION, SCOPE_MASK=1023,
+ READONLY=1024, ALLOCATED=2048 };
+ static const int PARSE_EARLY= 1;
+ static const int PARSE_NORMAL= 2;
+ /**
+ Enumeration type to indicate for a system variable whether
+ it will be written to the binlog or not.
+ */
+ enum binlog_status_enum { VARIABLE_NOT_IN_BINLOG,
+ SESSION_VARIABLE_IN_BINLOG } binlog_status;
-class sys_var_global: public sys_var
-{
protected:
- pthread_mutex_t *guard;
-public:
- sys_var_global(const char *name_arg, sys_after_update_func after_update_arg,
- pthread_mutex_t *guard_arg)
- :sys_var(name_arg, after_update_arg), guard(guard_arg) {}
-};
-
-
-/*
- A global-only ulong variable that requires its access to be
- protected with a mutex.
-*/
-
-class sys_var_long_ptr_global: public sys_var_global
-{
-public:
- ulong *value;
- sys_var_long_ptr_global(sys_var_chain *chain, const char *name_arg,
- ulong *value_ptr_arg,
- pthread_mutex_t *guard_arg,
- sys_after_update_func after_update_arg= NULL)
- :sys_var_global(name_arg, after_update_arg, guard_arg),
- value(value_ptr_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_LONG; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- { return (uchar*) value; }
-};
-
-
-/*
- A global ulong variable that is protected by LOCK_global_system_variables
-*/
-
-class sys_var_long_ptr :public sys_var_long_ptr_global
-{
-public:
- sys_var_long_ptr(sys_var_chain *chain, const char *name_arg, ulong *value_ptr,
- sys_after_update_func after_update_arg= NULL);
-};
-
-
-class sys_var_ulonglong_ptr :public sys_var
-{
-public:
- ulonglong *value;
- sys_var_ulonglong_ptr(sys_var_chain *chain, const char *name_arg, ulonglong *value_ptr_arg)
- :sys_var(name_arg),value(value_ptr_arg)
- { chain_sys_var(chain); }
- sys_var_ulonglong_ptr(sys_var_chain *chain, const char *name_arg, ulonglong *value_ptr_arg,
- sys_after_update_func func)
- :sys_var(name_arg,func), value(value_ptr_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_LONGLONG; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- { return (uchar*) value; }
-};
-
-
-class sys_var_bool_ptr :public sys_var
-{
-public:
- my_bool *value;
- sys_var_bool_ptr(sys_var_chain *chain, const char *name_arg, my_bool *value_arg)
- :sys_var(name_arg),value(value_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var)
- {
- return check_enum(thd, var, &bool_typelib);
- }
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_MY_BOOL; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- { return (uchar*) value; }
- bool check_update_type(Item_result type) { return 0; }
-};
-
-
-class sys_var_bool_ptr_readonly :public sys_var_bool_ptr
-{
-public:
- sys_var_bool_ptr_readonly(sys_var_chain *chain, const char *name_arg,
- my_bool *value_arg)
- :sys_var_bool_ptr(chain, name_arg, value_arg)
- {}
- bool is_readonly() const { return 1; }
-};
-
-
-class sys_var_str :public sys_var
-{
-public:
- char *value; // Pointer to allocated string
- uint value_length;
- sys_check_func check_func;
- sys_update_func update_func;
- sys_set_default_func set_default_func;
- sys_var_str(sys_var_chain *chain, const char *name_arg,
- sys_check_func check_func_arg,
- sys_update_func update_func_arg,
- sys_set_default_func set_default_func_arg,
- char *value_arg)
- :sys_var(name_arg), value(value_arg), check_func(check_func_arg),
- update_func(update_func_arg),set_default_func(set_default_func_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var)
- {
- return (*update_func)(thd, var);
- }
- void set_default(THD *thd, enum_var_type type)
- {
- (*set_default_func)(thd, type);
- }
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- { return (uchar*) value; }
- bool check_update_type(Item_result type)
- {
- return type != STRING_RESULT; /* Only accept strings */
- }
- bool check_default(enum_var_type type) { return 0; }
-};
-
-
-class sys_var_const_str :public sys_var
-{
-public:
- char *value; // Pointer to const value
- sys_var_const_str(sys_var_chain *chain, const char *name_arg,
- const char *value_arg)
- :sys_var(name_arg), value((char*) value_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var)
- {
- return 1;
- }
- bool update(THD *thd, set_var *var)
- {
- return 1;
- }
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- {
- return (uchar*) value;
- }
- bool check_update_type(Item_result type)
- {
- return 1;
- }
- bool check_default(enum_var_type type) { return 1; }
- bool is_readonly() const { return 1; }
-};
-
-
-class sys_var_const_os_str: public sys_var_const_str
-{
-public:
- sys_var_const_os_str(sys_var_chain *chain, const char *name_arg,
- const char *value_arg)
- :sys_var_const_str(chain, name_arg, value_arg)
- {
- is_os_charset= TRUE;
- }
-};
-
-
-class sys_var_const_str_ptr :public sys_var
-{
-public:
- char **value; // Pointer to const value
- sys_var_const_str_ptr(sys_var_chain *chain, const char *name_arg, char **value_arg)
- :sys_var(name_arg),value(value_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var)
- {
- return 1;
- }
- bool update(THD *thd, set_var *var)
- {
- return 1;
- }
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- {
- return (uchar*) *value;
- }
- bool check_update_type(Item_result type)
- {
- return 1;
- }
- bool check_default(enum_var_type type) { return 1; }
- bool is_readonly() const { return 1; }
-};
-
-
-class sys_var_const_os_str_ptr :public sys_var_const_str_ptr
-{
-public:
- sys_var_const_os_str_ptr(sys_var_chain *chain, const char *name_arg,
- char **value_arg)
- :sys_var_const_str_ptr(chain, name_arg, value_arg)
- {
- is_os_charset= TRUE;
- }
-};
-
-
-class sys_var_enum :public sys_var
-{
- uint *value;
- TYPELIB *enum_names;
-public:
- sys_var_enum(sys_var_chain *chain, const char *name_arg, uint *value_arg,
- TYPELIB *typelib, sys_after_update_func func)
- :sys_var(name_arg,func), value(value_arg), enum_names(typelib)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var)
- {
- return check_enum(thd, var, enum_names);
- }
- bool update(THD *thd, set_var *var);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- bool check_update_type(Item_result type) { return 0; }
-};
-
-
-class sys_var_enum_const :public sys_var
-{
- ulong SV::*offset;
- TYPELIB *enum_names;
-public:
- sys_var_enum_const(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg,
- TYPELIB *typelib, sys_after_update_func func)
- :sys_var(name_arg,func), offset(offset_arg), enum_names(typelib)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var) { return 1; }
- bool update(THD *thd, set_var *var) { return 1; }
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool check_update_type(Item_result type) { return 1; }
- bool is_readonly() const { return 1; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
+ typedef bool (*on_check_function)(sys_var *self, THD *thd, set_var *var);
+ typedef bool (*on_update_function)(sys_var *self, THD *thd, enum_var_type type);
+
+ int flags; ///< or'ed flag_enum values
+ int m_parse_flag; ///< either PARSE_EARLY or PARSE_NORMAL.
+ const SHOW_TYPE show_val_type; ///< what value_ptr() returns for sql_show.cc
+ my_option option; ///< min, max, default values are stored here
+ PolyLock *guard; ///< *second* lock that protects the variable
+ ptrdiff_t offset; ///< offset to the value from global_system_variables
+ on_check_function on_check;
+ on_update_function on_update;
+ struct { uint version; const char *substitute; } deprecated;
+ bool is_os_charset; ///< true if the value is in character_set_filesystem
+
+public:
+ sys_var(sys_var_chain *chain, const char *name_arg, const char *comment,
+ int flag_args, ptrdiff_t off, int getopt_id,
+ enum get_opt_arg_type getopt_arg_type, SHOW_TYPE show_val_type_arg,
+ longlong def_val, PolyLock *lock, enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func, on_update_function on_update_func,
+ uint deprecated_version, const char *substitute, int parse_flag);
+ virtual ~sys_var() {}
-class sys_var_thd :public sys_var
-{
-public:
- sys_var_thd(const char *name_arg,
- sys_after_update_func func= NULL,
- Binlog_status_enum binlog_status= NOT_IN_BINLOG)
- :sys_var(name_arg, func, binlog_status)
- {}
- bool check_type(enum_var_type type) { return 0; }
- bool check_default(enum_var_type type)
- {
- return type == OPT_GLOBAL && !option_limits;
- }
-};
-
+ /**
+ All the cleanup procedures should be performed here
+ */
+ virtual void cleanup() {}
+ /**
+ downcast for sys_var_pluginvar. Returns this if it's an instance
+ of sys_var_pluginvar, and 0 otherwise.
+ */
+ virtual sys_var_pluginvar *cast_pluginvar() { return 0; }
-class sys_var_thd_ulong :public sys_var_thd
-{
- sys_check_func check_func;
-public:
- ulong SV::*offset;
- sys_var_thd_ulong(sys_var_chain *chain, const char *name_arg,
- ulong SV::*offset_arg,
- sys_check_func c_func= NULL,
- sys_after_update_func au_func= NULL,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :sys_var_thd(name_arg, au_func, binlog_status_arg), check_func(c_func),
- offset(offset_arg)
- { chain_sys_var(chain); }
bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_LONG; }
uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-
-class sys_var_thd_ha_rows :public sys_var_thd
-{
-public:
- ha_rows SV::*offset;
- sys_var_thd_ha_rows(sys_var_chain *chain, const char *name_arg,
- ha_rows SV::*offset_arg)
- :sys_var_thd(name_arg), offset(offset_arg)
- { chain_sys_var(chain); }
- sys_var_thd_ha_rows(sys_var_chain *chain, const char *name_arg,
- ha_rows SV::*offset_arg,
- sys_after_update_func func)
- :sys_var_thd(name_arg,func), offset(offset_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var);
+ bool set_default(THD *thd, enum_var_type type);
bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_HA_ROWS; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-class sys_var_thd_ulonglong :public sys_var_thd
-{
-public:
- ulonglong SV::*offset;
- bool only_global;
- sys_var_thd_ulonglong(sys_var_chain *chain, const char *name_arg,
- ulonglong SV::*offset_arg)
- :sys_var_thd(name_arg), offset(offset_arg)
- { chain_sys_var(chain); }
- sys_var_thd_ulonglong(sys_var_chain *chain, const char *name_arg,
- ulonglong SV::*offset_arg,
- sys_after_update_func func, bool only_global_arg)
- :sys_var_thd(name_arg, func), offset(offset_arg),
- only_global(only_global_arg)
- { chain_sys_var(chain); }
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_LONGLONG; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- bool check(THD *thd, set_var *var);
- bool check_default(enum_var_type type)
- {
- return type == OPT_GLOBAL && !option_limits;
- }
+ SHOW_TYPE show_type() { return show_val_type; }
+ int scope() const { return flags & SCOPE_MASK; }
+ CHARSET_INFO *charset(THD *thd);
+ bool is_readonly() const { return flags & READONLY; }
+ /**
+ the following is only true for keycache variables,
+ that support the syntax @@keycache_name.variable_name
+ */
+ bool is_struct() { return option.var_type & GET_ASK_ADDR; }
+ bool is_written_to_binlog(enum_var_type type)
+ { return type != OPT_GLOBAL && binlog_status == SESSION_VARIABLE_IN_BINLOG; }
+ virtual bool check_update_type(Item_result type) = 0;
bool check_type(enum_var_type type)
{
- return (only_global && type != OPT_GLOBAL);
- }
-};
-
-
-class sys_var_thd_bool :public sys_var_thd
-{
-public:
- my_bool SV::*offset;
- sys_var_thd_bool(sys_var_chain *chain, const char *name_arg, my_bool SV::*offset_arg)
- :sys_var_thd(name_arg), offset(offset_arg)
- { chain_sys_var(chain); }
- sys_var_thd_bool(sys_var_chain *chain, const char *name_arg, my_bool SV::*offset_arg,
- sys_after_update_func func)
- :sys_var_thd(name_arg,func), offset(offset_arg)
- { chain_sys_var(chain); }
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_MY_BOOL; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- bool check(THD *thd, set_var *var)
- {
- return check_enum(thd, var, &bool_typelib);
- }
- bool check_update_type(Item_result type) { return 0; }
-};
-
-
-class sys_var_thd_enum :public sys_var_thd
-{
-protected:
- ulong SV::*offset;
- TYPELIB *enum_names;
- sys_check_func check_func;
-public:
- sys_var_thd_enum(sys_var_chain *chain, const char *name_arg,
- ulong SV::*offset_arg, TYPELIB *typelib,
- sys_after_update_func func= NULL,
- sys_check_func check= NULL)
- :sys_var_thd(name_arg, func), offset(offset_arg),
- enum_names(typelib), check_func(check)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var)
- {
- int ret= 0;
- if (check_func)
- ret= (*check_func)(thd, var);
- return ret ? ret : check_enum(thd, var, enum_names);
- }
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- bool check_update_type(Item_result type) { return 0; }
-};
-
-
-class sys_var_thd_optimizer_switch :public sys_var_thd_enum
-{
-public:
- sys_var_thd_optimizer_switch(sys_var_chain *chain, const char *name_arg,
- ulong SV::*offset_arg)
- :sys_var_thd_enum(chain, name_arg, offset_arg, &optimizer_switch_typelib)
- {}
- bool check(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- static bool symbolic_mode_representation(THD *thd, ulonglong sql_mode,
- LEX_STRING *rep);
-};
-
-extern void fix_sql_mode_var(THD *thd, enum_var_type type);
-
-class sys_var_thd_sql_mode :public sys_var_thd_enum
-{
-public:
- sys_var_thd_sql_mode(sys_var_chain *chain, const char *name_arg,
- ulong SV::*offset_arg)
- :sys_var_thd_enum(chain, name_arg, offset_arg, &sql_mode_typelib,
- fix_sql_mode_var)
- {}
- bool check(THD *thd, set_var *var)
- {
- return check_set(thd, var, enum_names);
- }
- void set_default(THD *thd, enum_var_type type);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- static bool symbolic_mode_representation(THD *thd, ulonglong sql_mode,
- LEX_STRING *rep);
-};
-
-
-class sys_var_thd_storage_engine :public sys_var_thd
-{
-protected:
- plugin_ref SV::*offset;
-public:
- sys_var_thd_storage_engine(sys_var_chain *chain, const char *name_arg,
- plugin_ref SV::*offset_arg)
- :sys_var_thd(name_arg), offset(offset_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool check_update_type(Item_result type)
- {
- return type != STRING_RESULT; /* Only accept strings */
- }
- void set_default(THD *thd, enum_var_type type);
- bool update(THD *thd, set_var *var);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-class sys_var_thd_table_type :public sys_var_thd_storage_engine
-{
-public:
- sys_var_thd_table_type(sys_var_chain *chain, const char *name_arg,
- plugin_ref SV::*offset_arg)
- :sys_var_thd_storage_engine(chain, name_arg, offset_arg)
- {}
- void warn_deprecated(THD *thd);
- void set_default(THD *thd, enum_var_type type);
- bool update(THD *thd, set_var *var);
-};
-
-class sys_var_thd_bit :public sys_var_thd
-{
- sys_check_func check_func;
- sys_update_func update_func;
-public:
- ulonglong bit_flag;
- bool reverse;
- sys_var_thd_bit(sys_var_chain *chain, const char *name_arg,
- sys_check_func c_func, sys_update_func u_func,
- ulonglong bit, bool reverse_arg=0,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :sys_var_thd(name_arg, NULL, binlog_status_arg), check_func(c_func),
- update_func(u_func), bit_flag(bit), reverse(reverse_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- bool check_update_type(Item_result type) { return 0; }
- bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
- SHOW_TYPE show_type() { return SHOW_MY_BOOL; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-#ifndef DBUG_OFF
-class sys_var_thd_dbug :public sys_var_thd
-{
-public:
- sys_var_thd_dbug(sys_var_chain *chain, const char *name_arg)
- :sys_var_thd(name_arg)
- { chain_sys_var(chain); }
- bool check_update_type(Item_result type) { return type != STRING_RESULT; }
- bool check(THD *thd, set_var *var);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type) { DBUG_POP(); }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *b);
-};
-#endif /* DBUG_OFF */
-
-#if defined(ENABLED_DEBUG_SYNC)
-/* Debug Sync Facility. Implemented in debug_sync.cc. */
-class sys_var_debug_sync :public sys_var_thd
-{
-public:
- sys_var_debug_sync(sys_var_chain *chain, const char *name_arg)
- :sys_var_thd(name_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool check_update_type(Item_result type) { return type != STRING_RESULT; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-#endif /* defined(ENABLED_DEBUG_SYNC) */
-
-/* some variables that require special handling */
-
-class sys_var_timestamp :public sys_var
-{
-public:
- sys_var_timestamp(sys_var_chain *chain, const char *name_arg,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :sys_var(name_arg, NULL, binlog_status_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
- bool check_default(enum_var_type type) { return 0; }
- SHOW_TYPE show_type() { return SHOW_LONG; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-
-class sys_var_last_insert_id :public sys_var
-{
-public:
- sys_var_last_insert_id(sys_var_chain *chain, const char *name_arg,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :sys_var(name_arg, NULL, binlog_status_arg)
- { chain_sys_var(chain); }
- bool update(THD *thd, set_var *var);
- bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
- SHOW_TYPE show_type() { return SHOW_LONGLONG; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-
-class sys_var_insert_id :public sys_var
-{
-public:
- sys_var_insert_id(sys_var_chain *chain, const char *name_arg)
- :sys_var(name_arg)
- { chain_sys_var(chain); }
- bool update(THD *thd, set_var *var);
- bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
- SHOW_TYPE show_type() { return SHOW_LONGLONG; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-
-class sys_var_rand_seed1 :public sys_var
-{
-public:
- sys_var_rand_seed1(sys_var_chain *chain, const char *name_arg,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :sys_var(name_arg, NULL, binlog_status_arg)
- { chain_sys_var(chain); }
- bool update(THD *thd, set_var *var);
- bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
-};
-
-class sys_var_rand_seed2 :public sys_var
-{
-public:
- sys_var_rand_seed2(sys_var_chain *chain, const char *name_arg,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :sys_var(name_arg, NULL, binlog_status_arg)
- { chain_sys_var(chain); }
- bool update(THD *thd, set_var *var);
- bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
-};
-
-
-class sys_var_collation :public sys_var_thd
-{
-public:
- sys_var_collation(const char *name_arg,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :sys_var_thd(name_arg, NULL, binlog_status_arg)
- {
- no_support_one_shot= 0;
- }
- bool check(THD *thd, set_var *var);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool check_update_type(Item_result type)
- {
- return ((type != STRING_RESULT) && (type != INT_RESULT));
- }
- bool check_default(enum_var_type type) { return 0; }
- virtual void set_default(THD *thd, enum_var_type type)= 0;
-};
-
-class sys_var_character_set :public sys_var_thd
-{
-public:
- bool nullable;
- sys_var_character_set(const char *name_arg, bool is_nullable= 0,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :sys_var_thd(name_arg, NULL, binlog_status_arg), nullable(is_nullable)
- {
- /*
- In fact only almost all variables derived from sys_var_character_set
- support ONE_SHOT; character_set_results doesn't. But that's good enough.
- */
- no_support_one_shot= 0;
- }
- bool check(THD *thd, set_var *var);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool check_update_type(Item_result type)
- {
- return ((type != STRING_RESULT) && (type != INT_RESULT));
- }
- bool check_default(enum_var_type type) { return 0; }
- bool update(THD *thd, set_var *var);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- virtual void set_default(THD *thd, enum_var_type type)= 0;
- virtual CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type)= 0;
-};
-
-class sys_var_character_set_sv :public sys_var_character_set
-{
- CHARSET_INFO *SV::*offset;
- CHARSET_INFO **global_default;
-public:
- sys_var_character_set_sv(sys_var_chain *chain, const char *name_arg,
- CHARSET_INFO *SV::*offset_arg,
- CHARSET_INFO **global_default_arg,
- bool is_nullable= 0,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- : sys_var_character_set(name_arg, is_nullable, binlog_status_arg),
- offset(offset_arg), global_default(global_default_arg)
- { chain_sys_var(chain); }
- void set_default(THD *thd, enum_var_type type);
- CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type);
-};
-
-
-class sys_var_character_set_client: public sys_var_character_set_sv
-{
-public:
- sys_var_character_set_client(sys_var_chain *chain, const char *name_arg,
- CHARSET_INFO *SV::*offset_arg,
- CHARSET_INFO **global_default_arg,
- Binlog_status_enum binlog_status_arg)
- : sys_var_character_set_sv(chain, name_arg, offset_arg, global_default_arg,
- 0, binlog_status_arg)
- { }
- bool check(THD *thd, set_var *var);
-};
-
-
-class sys_var_character_set_database :public sys_var_character_set
-{
-public:
- sys_var_character_set_database(sys_var_chain *chain, const char *name_arg,
- Binlog_status_enum binlog_status_arg=
- NOT_IN_BINLOG)
- : sys_var_character_set(name_arg, 0, binlog_status_arg)
- { chain_sys_var(chain); }
- void set_default(THD *thd, enum_var_type type);
- CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type);
-};
-
-class sys_var_collation_sv :public sys_var_collation
-{
- CHARSET_INFO *SV::*offset;
- CHARSET_INFO **global_default;
-public:
- sys_var_collation_sv(sys_var_chain *chain, const char *name_arg,
- CHARSET_INFO *SV::*offset_arg,
- CHARSET_INFO **global_default_arg,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :sys_var_collation(name_arg, binlog_status_arg),
- offset(offset_arg), global_default(global_default_arg)
- {
- chain_sys_var(chain);
- }
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-
-class sys_var_key_cache_param :public sys_var
-{
-protected:
- size_t offset;
-public:
- sys_var_key_cache_param(sys_var_chain *chain, const char *name_arg,
- size_t offset_arg)
- :sys_var(name_arg), offset(offset_arg)
- { chain_sys_var(chain); }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- bool check_default(enum_var_type type) { return 1; }
- bool is_struct() { return 1; }
-};
-
-
-class sys_var_key_buffer_size :public sys_var_key_cache_param
-{
-public:
- sys_var_key_buffer_size(sys_var_chain *chain, const char *name_arg)
- :sys_var_key_cache_param(chain, name_arg,
- offsetof(KEY_CACHE, param_buff_size))
- {}
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- SHOW_TYPE show_type() { return SHOW_LONGLONG; }
-};
-
-
-class sys_var_key_cache_long :public sys_var_key_cache_param
-{
-public:
- sys_var_key_cache_long(sys_var_chain *chain, const char *name_arg, size_t offset_arg)
- :sys_var_key_cache_param(chain, name_arg, offset_arg)
- {}
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- SHOW_TYPE show_type() { return SHOW_LONG; }
-};
-
-
-class sys_var_thd_date_time_format :public sys_var_thd
-{
- DATE_TIME_FORMAT *SV::*offset;
- timestamp_type date_time_type;
-public:
- sys_var_thd_date_time_format(sys_var_chain *chain, const char *name_arg,
- DATE_TIME_FORMAT *SV::*offset_arg,
- timestamp_type date_time_type_arg)
- :sys_var_thd(name_arg), offset(offset_arg),
- date_time_type(date_time_type_arg)
- { chain_sys_var(chain); }
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool check_update_type(Item_result type)
- {
- return type != STRING_RESULT; /* Only accept strings */
- }
- bool check_default(enum_var_type type) { return 0; }
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- void update2(THD *thd, enum_var_type type, DATE_TIME_FORMAT *new_value);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- void set_default(THD *thd, enum_var_type type);
-};
-
-
-class sys_var_log_state :public sys_var_bool_ptr
-{
- uint log_type;
-public:
- sys_var_log_state(sys_var_chain *chain, const char *name_arg, my_bool *value_arg,
- uint log_type_arg)
- :sys_var_bool_ptr(chain, name_arg, value_arg), log_type(log_type_arg) {}
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
-};
-
-
-class sys_var_set :public sys_var
-{
-protected:
- ulong *value;
- TYPELIB *enum_names;
-public:
- sys_var_set(sys_var_chain *chain, const char *name_arg, ulong *value_arg,
- TYPELIB *typelib, sys_after_update_func func)
- :sys_var(name_arg, func), value(value_arg), enum_names(typelib)
- { chain_sys_var(chain); }
- virtual bool check(THD *thd, set_var *var)
- {
- return check_set(thd, var, enum_names);
- }
- virtual void set_default(THD *thd, enum_var_type type)
- {
- *value= 0;
- }
- bool update(THD *thd, set_var *var);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- bool check_update_type(Item_result type) { return 0; }
- SHOW_TYPE show_type() { return SHOW_CHAR; }
-};
-
-class sys_var_set_slave_mode :public sys_var_set
-{
-public:
- sys_var_set_slave_mode(sys_var_chain *chain, const char *name_arg,
- ulong *value_arg,
- TYPELIB *typelib, sys_after_update_func func) :
- sys_var_set(chain, name_arg, value_arg, typelib, func) {}
- void set_default(THD *thd, enum_var_type type);
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
-};
-
-class sys_var_log_output :public sys_var
-{
- ulong *value;
- TYPELIB *enum_names;
-public:
- sys_var_log_output(sys_var_chain *chain, const char *name_arg, ulong *value_arg,
- TYPELIB *typelib, sys_after_update_func func)
- :sys_var(name_arg,func), value(value_arg), enum_names(typelib)
- {
- chain_sys_var(chain);
- set_allow_empty_value(FALSE);
- }
- virtual bool check(THD *thd, set_var *var)
- {
- return check_set(thd, var, enum_names);
- }
- bool update(THD *thd, set_var *var);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- bool check_update_type(Item_result type) { return 0; }
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
-};
-
-
-/* Variable that you can only read from */
-
-class sys_var_readonly: public sys_var
-{
-public:
- enum_var_type var_type;
- SHOW_TYPE show_type_value;
- sys_value_ptr_func value_ptr_func;
- sys_var_readonly(sys_var_chain *chain, const char *name_arg, enum_var_type type,
- SHOW_TYPE show_type_arg,
- sys_value_ptr_func value_ptr_func_arg)
- :sys_var(name_arg), var_type(type),
- show_type_value(show_type_arg), value_ptr_func(value_ptr_func_arg)
- { chain_sys_var(chain); }
- bool update(THD *thd, set_var *var) { return 1; }
- bool check_default(enum_var_type type) { return 1; }
- bool check_type(enum_var_type type) { return type != var_type; }
- bool check_update_type(Item_result type) { return 1; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- {
- return (*value_ptr_func)(thd);
- }
- SHOW_TYPE show_type() { return show_type_value; }
- bool is_readonly() const { return 1; }
-};
-
-
-class sys_var_readonly_os: public sys_var_readonly
-{
-public:
- sys_var_readonly_os(sys_var_chain *chain, const char *name_arg, enum_var_type type,
- SHOW_TYPE show_type_arg,
- sys_value_ptr_func value_ptr_func_arg)
- :sys_var_readonly(chain, name_arg, type, show_type_arg, value_ptr_func_arg)
- {
- is_os_charset= TRUE;
- }
-};
-
-
-/**
- Global-only, read-only variable. E.g. command line option.
-*/
-
-class sys_var_const: public sys_var
-{
-public:
- enum_var_type var_type;
- SHOW_TYPE show_type_value;
- uchar *ptr;
- sys_var_const(sys_var_chain *chain, const char *name_arg, enum_var_type type,
- SHOW_TYPE show_type_arg, uchar *ptr_arg)
- :sys_var(name_arg), var_type(type),
- show_type_value(show_type_arg), ptr(ptr_arg)
- { chain_sys_var(chain); }
- bool update(THD *thd, set_var *var) { return 1; }
- bool check_default(enum_var_type type) { return 1; }
- bool check_type(enum_var_type type) { return type != var_type; }
- bool check_update_type(Item_result type) { return 1; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- {
- return ptr;
+ switch (scope())
+ {
+ case GLOBAL: return type != OPT_GLOBAL;
+ case SESSION: return false; // always ok
+ case ONLY_SESSION: return type == OPT_GLOBAL;
+ }
+ return true; // keep gcc happy
}
- SHOW_TYPE show_type() { return show_type_value; }
- bool is_readonly() const { return 1; }
-};
-
-
-class sys_var_const_os: public sys_var_const
-{
-public:
- enum_var_type var_type;
- SHOW_TYPE show_type_value;
- uchar *ptr;
- sys_var_const_os(sys_var_chain *chain, const char *name_arg,
- enum_var_type type,
- SHOW_TYPE show_type_arg, uchar *ptr_arg)
- :sys_var_const(chain, name_arg, type, show_type_arg, ptr_arg)
+ bool register_option(DYNAMIC_ARRAY *array, int parse_flags)
{
- is_os_charset= TRUE;
+ return (option.id != -1) && (m_parse_flag & parse_flags) &&
+ insert_dynamic(array, (uchar*)&option);
}
-};
-
-class sys_var_have_option: public sys_var
-{
+private:
+ virtual bool do_check(THD *thd, set_var *var) = 0;
+ /**
+ save the session default value of the variable in var
+ */
+ virtual void session_save_default(THD *thd, set_var *var) = 0;
+ /**
+ save the global default value of the variable in var
+ */
+ virtual void global_save_default(THD *thd, set_var *var) = 0;
+ virtual bool session_update(THD *thd, set_var *var) = 0;
+ virtual bool global_update(THD *thd, set_var *var) = 0;
+ void do_deprecated_warning(THD *thd);
protected:
- virtual SHOW_COMP_OPTION get_option() = 0;
-public:
- sys_var_have_option(sys_var_chain *chain, const char *variable_name):
- sys_var(variable_name)
- { chain_sys_var(chain); }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- {
- return (uchar*) show_comp_option_name[get_option()];
- }
- bool update(THD *thd, set_var *var) { return 1; }
- bool check_default(enum_var_type type) { return 1; }
- bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
- bool check_update_type(Item_result type) { return 1; }
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool is_readonly() const { return 1; }
-};
-
-
-class sys_var_have_variable: public sys_var_have_option
-{
- SHOW_COMP_OPTION *have_variable;
-
-public:
- sys_var_have_variable(sys_var_chain *chain, const char *variable_name,
- SHOW_COMP_OPTION *have_variable_arg):
- sys_var_have_option(chain, variable_name),
- have_variable(have_variable_arg)
- { }
- SHOW_COMP_OPTION get_option() { return *have_variable; }
-};
-
-
-class sys_var_have_plugin: public sys_var_have_option
-{
- const char *plugin_name_str;
- const uint plugin_name_len;
- const int plugin_type;
-
-public:
- sys_var_have_plugin(sys_var_chain *chain, const char *variable_name,
- const char *plugin_name_str_arg, uint plugin_name_len_arg,
- int plugin_type_arg):
- sys_var_have_option(chain, variable_name),
- plugin_name_str(plugin_name_str_arg), plugin_name_len(plugin_name_len_arg),
- plugin_type(plugin_type_arg)
- { }
- /* the following method is declared in sql_plugin.cc */
- SHOW_COMP_OPTION get_option();
-};
-
-
-class sys_var_thd_time_zone :public sys_var_thd
-{
-public:
- sys_var_thd_time_zone(sys_var_chain *chain, const char *name_arg,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- :sys_var_thd(name_arg, NULL, binlog_status_arg)
- {
- no_support_one_shot= 0;
- chain_sys_var(chain);
- }
- bool check(THD *thd, set_var *var);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool check_update_type(Item_result type)
- {
- return type != STRING_RESULT; /* Only accept strings */
- }
- bool check_default(enum_var_type type) { return 0; }
- bool update(THD *thd, set_var *var);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- virtual void set_default(THD *thd, enum_var_type type);
-};
-
-
-class sys_var_max_user_conn : public sys_var_thd
-{
-public:
- sys_var_max_user_conn(sys_var_chain *chain, const char *name_arg):
- sys_var_thd(name_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- bool check_default(enum_var_type type)
- {
- return type != OPT_GLOBAL || !option_limits;
- }
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_INT; }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-
-/**
- * @brief This is a specialization of sys_var_thd_ulong that implements a
- read-only session variable. The class overrides check() and check_default()
- to achieve the read-only property for the session part of the variable.
- */
-class sys_var_thd_ulong_session_readonly : public sys_var_thd_ulong
-{
-public:
- sys_var_thd_ulong_session_readonly(sys_var_chain *chain_arg,
- const char *name_arg, ulong SV::*offset_arg,
- sys_check_func c_func= NULL,
- sys_after_update_func au_func= NULL,
- Binlog_status_enum bl_status_arg= NOT_IN_BINLOG):
- sys_var_thd_ulong(chain_arg, name_arg, offset_arg, c_func, au_func, bl_status_arg)
- { }
- bool check(THD *thd, set_var *var);
- bool check_default(enum_var_type type)
- {
- return type != OPT_GLOBAL || !option_limits;
- }
-};
-
-
-class sys_var_microseconds :public sys_var_thd
-{
- ulonglong SV::*offset;
-public:
- sys_var_microseconds(sys_var_chain *chain, const char *name_arg,
- ulonglong SV::*offset_arg):
- sys_var_thd(name_arg), offset(offset_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var) {return 0;}
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE show_type() { return SHOW_DOUBLE; }
- bool check_update_type(Item_result type)
- {
- return (type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT);
- }
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-
-class sys_var_trust_routine_creators :public sys_var_bool_ptr
-{
- /* We need a derived class only to have a warn_deprecated() */
-public:
- sys_var_trust_routine_creators(sys_var_chain *chain,
- const char *name_arg, my_bool *value_arg) :
- sys_var_bool_ptr(chain, name_arg, value_arg) {};
- void warn_deprecated(THD *thd);
- void set_default(THD *thd, enum_var_type type);
- bool update(THD *thd, set_var *var);
-};
-
-
-/**
- Handler for setting the system variable --read-only.
-*/
-
-class sys_var_opt_readonly :public sys_var_bool_ptr
-{
-public:
- sys_var_opt_readonly(sys_var_chain *chain, const char *name_arg,
- my_bool *value_arg) :
- sys_var_bool_ptr(chain, name_arg, value_arg) {};
- ~sys_var_opt_readonly() {};
- bool update(THD *thd, set_var *var);
-};
-
+ /**
+ A pointer to a value of the variable for SHOW.
+ It must be of show_val_type type (bool for SHOW_BOOL, int for SHOW_INT,
+ longlong for SHOW_LONGLONG, etc).
+ */
+ virtual uchar *session_value_ptr(THD *thd, LEX_STRING *base);
+ virtual uchar *global_value_ptr(THD *thd, LEX_STRING *base);
-class sys_var_thd_lc_time_names :public sys_var_thd
-{
-public:
- sys_var_thd_lc_time_names(sys_var_chain *chain, const char *name_arg,
- Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG)
- : sys_var_thd(name_arg, NULL, binlog_status_arg)
- {
-#if MYSQL_VERSION_ID < 50000
- no_support_one_shot= 0;
-#endif
- chain_sys_var(chain);
- }
- bool check(THD *thd, set_var *var);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool check_update_type(Item_result type)
- {
- return ((type != STRING_RESULT) && (type != INT_RESULT));
- }
- bool check_default(enum_var_type type) { return 0; }
- bool update(THD *thd, set_var *var);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- virtual void set_default(THD *thd, enum_var_type type);
-};
+ /**
+ A pointer to a storage area of the variable, to the raw data.
+ Typically it's the same as session_value_ptr(), but it's different,
+ for example, for ENUM, that is printed as a string, but stored as a number.
+ */
+ uchar *session_var_ptr(THD *thd)
+ { return ((uchar*)&(thd->variables)) + offset; }
-#ifdef HAVE_EVENT_SCHEDULER
-class sys_var_event_scheduler :public sys_var_long_ptr
-{
- /* We need a derived class only to have a warn_deprecated() */
-public:
- sys_var_event_scheduler(sys_var_chain *chain, const char *name_arg) :
- sys_var_long_ptr(chain, name_arg, NULL, NULL) {};
- bool update(THD *thd, set_var *var);
- uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- SHOW_TYPE show_type() { return SHOW_CHAR; }
- bool check(THD *thd, set_var *var);
- bool check_update_type(Item_result type)
- {
- return type != STRING_RESULT && type != INT_RESULT;
- }
+ uchar *global_var_ptr()
+ { return ((uchar*)&global_system_variables) + offset; }
};
-#endif
-extern void fix_binlog_format_after_update(THD *thd, enum_var_type type);
-
-class sys_var_thd_binlog_format :public sys_var_thd_enum
-{
-public:
- sys_var_thd_binlog_format(sys_var_chain *chain, const char *name_arg,
- ulong SV::*offset_arg)
- :sys_var_thd_enum(chain, name_arg, offset_arg,
- &binlog_format_typelib,
- fix_binlog_format_after_update)
- {};
- bool check(THD *thd, set_var *var);
- bool is_readonly() const;
-};
+#include "sql_plugin.h" /* SHOW_HA_ROWS, SHOW_MY_BOOL */
/****************************************************************************
Classes for parsing of the SET command
****************************************************************************/
+/**
+ A base class for everything that can be set with SET command.
+ It's similar to Items, an instance of this is created by the parser
+ for every assigmnent in SET (or elsewhere, e.g. in SELECT).
+*/
class set_var_base :public Sql_alloc
{
public:
set_var_base() {}
virtual ~set_var_base() {}
- virtual int check(THD *thd)=0; /* To check privileges etc. */
- virtual int update(THD *thd)=0; /* To set the value */
- /* light check for PS */
- virtual int light_check(THD *thd) { return check(thd); }
- virtual bool no_support_one_shot() { return 1; }
+ virtual int check(THD *thd)=0; /* To check privileges etc. */
+ virtual int update(THD *thd)=0; /* To set the value */
+ virtual int light_check(THD *thd) { return check(thd); } /* for PS */
};
-/* MySQL internal variables, like query_cache_size */
-
+/**
+ set_var_base descendant for assignments to the system variables.
+*/
class set_var :public set_var_base
{
public:
- sys_var *var;
- Item *value;
+ sys_var *var; ///< system variable to be updated
+ Item *value; ///< the expression that provides the new value of the variable
enum_var_type type;
- union
- {
- CHARSET_INFO *charset;
- ulong ulong_value;
- ulonglong ulonglong_value;
- plugin_ref plugin;
- DATE_TIME_FORMAT *date_time_format;
- Time_zone *time_zone;
- MY_LOCALE *locale_value;
+ union ///< temp storage to hold a value between sys_var::check and ::update
+ {
+ ulonglong ulonglong_value; ///< for all integer, set, enum sysvars
+ double double_value; ///< for Sys_var_double
+ plugin_ref plugin; ///< for Sys_var_plugin
+ Time_zone *time_zone; ///< for Sys_var_tz
+ LEX_STRING string_value; ///< for Sys_var_charptr and others
+ void *ptr; ///< for Sys_var_struct
} save_result;
- LEX_STRING base; /* for structs */
+ LEX_STRING base; /**< for structured variables, like keycache_name.variable_name */
set_var(enum_var_type type_arg, sys_var *var_arg,
const LEX_STRING *base_name_arg, Item *value_arg)
@@ -1326,10 +224,10 @@ public:
if (value_arg && value_arg->type() == Item::FIELD_ITEM)
{
Item_field *item= (Item_field*) value_arg;
- if (!(value=new Item_string(item->field_name,
- (uint) strlen(item->field_name),
- item->collation.collation)))
- value=value_arg; /* Give error message later */
+ if (!(value=new Item_string(item->field_name,
+ (uint) strlen(item->field_name),
+ system_charset_info))) // names are utf8
+ value=value_arg; /* Give error message later */
}
else
value=value_arg;
@@ -1337,12 +235,10 @@ public:
int check(THD *thd);
int update(THD *thd);
int light_check(THD *thd);
- bool no_support_one_shot() { return var->no_support_one_shot; }
};
/* User variables like @my_own_variable */
-
class set_var_user: public set_var_base
{
Item_func_set_user_var *user_var_item;
@@ -1379,8 +275,8 @@ class set_var_collation_client: public set_var_base
CHARSET_INFO *collation_connection;
public:
set_var_collation_client(CHARSET_INFO *client_coll_arg,
- CHARSET_INFO *connection_coll_arg,
- CHARSET_INFO *result_coll_arg)
+ CHARSET_INFO *connection_coll_arg,
+ CHARSET_INFO *result_coll_arg)
:character_set_client(client_coll_arg),
character_set_results(result_coll_arg),
collation_connection(connection_coll_arg)
@@ -1390,83 +286,38 @@ public:
};
-extern "C"
-{
- typedef int (*process_key_cache_t) (const char *, KEY_CACHE *);
-}
-
-/* Named lists (used for keycaches) */
+/* optional things, have_* variables */
+extern SHOW_COMP_OPTION have_csv, have_innodb;
+extern SHOW_COMP_OPTION have_ndbcluster, have_partitioning;
+extern SHOW_COMP_OPTION have_profiling;
-class NAMED_LIST :public ilink
-{
- const char *name;
- uint name_length;
-public:
- uchar* data;
-
- NAMED_LIST(I_List<NAMED_LIST> *links, const char *name_arg,
- uint name_length_arg, uchar* data_arg)
- :name_length(name_length_arg), data(data_arg)
- {
- name= my_strndup(name_arg, name_length, MYF(MY_WME));
- links->push_back(this);
- }
- inline bool cmp(const char *name_cmp, uint length)
- {
- return length == name_length && !memcmp(name, name_cmp, length);
- }
- ~NAMED_LIST()
- {
- my_free((uchar*) name, MYF(0));
- }
- friend bool process_key_caches(process_key_cache_t func);
- friend void delete_elements(I_List<NAMED_LIST> *list,
- void (*free_element)(const char*, uchar*));
-};
-
-/* updated in sql_acl.cc */
-
-extern sys_var_thd_bool sys_old_alter_table;
-extern sys_var_thd_bool sys_old_passwords;
-extern LEX_STRING default_key_cache_base;
-
-/* For sql_yacc */
-struct sys_var_with_base
-{
- sys_var *var;
- LEX_STRING base_name;
-};
+extern SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen;
+extern SHOW_COMP_OPTION have_query_cache;
+extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
+extern SHOW_COMP_OPTION have_crypt;
+extern SHOW_COMP_OPTION have_compress;
/*
Prototypes for helper functions
*/
-int set_var_init();
-void set_var_free();
-SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted);
-int mysql_add_sys_var_chain(sys_var *chain, struct my_option *long_options);
-int mysql_del_sys_var_chain(sys_var *chain);
+SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type);
+
sys_var *find_sys_var(THD *thd, const char *str, uint length=0);
int sql_set_variables(THD *thd, List<set_var_base> *var_list);
-bool not_all_support_one_shot(List<set_var_base> *var_list);
-void fix_delay_key_write(THD *thd, enum_var_type type);
-void fix_slave_exec_mode(void);
-ulong fix_sql_mode(ulong sql_mode);
-extern sys_var_const_str sys_charset_system;
-extern sys_var_str sys_init_connect;
-extern sys_var_str sys_init_slave;
-extern sys_var_thd_time_zone sys_time_zone;
-extern sys_var_thd_bit sys_autocommit;
+
+bool fix_delay_key_write(sys_var *self, THD *thd, enum_var_type type);
+
+ulong expand_sql_mode(ulonglong sql_mode);
+bool sql_mode_string_representation(THD *thd, ulong sql_mode, LEX_STRING *ls);
+
+extern sys_var *Sys_autocommit_ptr;
+
CHARSET_INFO *get_old_charset_by_name(const char *old_name);
-uchar* find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
- NAMED_LIST **found);
-extern sys_var_str sys_var_general_log_path, sys_var_slow_log_path;
+int sys_var_init();
+int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags);
+void sys_var_end(void);
+
+#endif
-/* key_cache functions */
-KEY_CACHE *get_key_cache(LEX_STRING *cache_name);
-KEY_CACHE *get_or_create_key_cache(const char *name, uint length);
-void free_key_cache(const char *name, KEY_CACHE *key_cache);
-bool process_key_caches(process_key_cache_t func);
-void delete_elements(I_List<NAMED_LIST> *list,
- void (*free_element)(const char*, uchar*));
diff --git a/sql/sha2.cc b/sql/sha2.cc
new file mode 100644
index 00000000000..1a9de86f2e0
--- /dev/null
+++ b/sql/sha2.cc
@@ -0,0 +1,68 @@
+/* Copyright (C) 2007 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/**
+ @file
+ A compatibility layer to our built-in SSL implementation, to mimic the
+ oft-used external library, OpenSSL.
+*/
+
+#include <my_global.h>
+#include <sha2.h>
+
+#ifdef HAVE_YASSL
+
+/*
+ If TaoCrypt::SHA512 or ::SHA384 are not defined (but ::SHA256 is), it's
+ probably that neither of config.h's SIZEOF_LONG or SIZEOF_LONG_LONG are
+ 64 bits long. At present, both OpenSSL and YaSSL require 64-bit integers
+ for SHA-512. (The SIZEOF_* definitions come from autoconf's config.h .)
+*/
+
+# define GEN_YASSL_SHA2_BRIDGE(size) \
+unsigned char* SHA##size(const unsigned char *input_ptr, size_t input_length, \
+ char unsigned *output_ptr) { \
+ TaoCrypt::SHA##size hasher; \
+ \
+ hasher.Update(input_ptr, input_length); \
+ hasher.Final(output_ptr); \
+ return(output_ptr); \
+}
+
+
+/**
+ @fn SHA512
+ @fn SHA384
+ @fn SHA256
+ @fn SHA224
+
+ Instantiate an hash object, fill in the cleartext value, compute the digest,
+ and extract the result from the object.
+
+ (Generate the functions. See similar .h code for the prototypes.)
+*/
+# ifndef OPENSSL_NO_SHA512
+GEN_YASSL_SHA2_BRIDGE(512);
+GEN_YASSL_SHA2_BRIDGE(384);
+# else
+# warning Some SHA2 functionality is missing. See OPENSSL_NO_SHA512.
+# endif
+GEN_YASSL_SHA2_BRIDGE(256);
+GEN_YASSL_SHA2_BRIDGE(224);
+
+# undef GEN_YASSL_SHA2_BRIDGE
+
+#endif /* HAVE_YASSL */
diff --git a/sql/share/.cvsignore b/sql/share/.cvsignore
deleted file mode 100644
index 282522db034..00000000000
--- a/sql/share/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/sql/share/CMakeLists.txt b/sql/share/CMakeLists.txt
new file mode 100644
index 00000000000..f8fd51fda23
--- /dev/null
+++ b/sql/share/CMakeLists.txt
@@ -0,0 +1,54 @@
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License 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
+
+SET (dirs
+danish
+german
+slovak
+dutch
+greek
+norwegian
+spanish
+english
+hungarian
+norwegian-ny
+swedish
+italian
+polish
+ukrainian
+japanese
+portuguese
+romanian
+estonian
+korean
+russian
+czech
+french
+serbian
+)
+
+SET(files
+ errmsg-utf8.txt
+)
+
+FOREACH (dir ${dirs})
+ INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${dir}
+ DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server)
+ENDFOREACH()
+INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/charsets DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server
+ PATTERN "languages.html" EXCLUDE
+)
+
+INSTALL(FILES ${files} DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server)
diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am
deleted file mode 100644
index 68b393e619f..00000000000
--- a/sql/share/Makefile.am
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright (C) 2000 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-## Process this file with automake to create Makefile.in
-
-EXTRA_DIST= errmsg.txt
-
-dist-hook:
- for dir in charsets @AVAILABLE_LANGUAGES@; do \
- test -d $(distdir)/$$dir || mkdir $(distdir)/$$dir; \
- $(INSTALL_DATA) $(srcdir)/$$dir/*.* $(distdir)/$$dir; \
- done; \
- sleep 1 ; touch $(srcdir)/*/errmsg.sys
- $(INSTALL_DATA) $(srcdir)/charsets/README $(distdir)/charsets
- $(INSTALL_DATA) $(srcdir)/charsets/Index.xml $(distdir)/charsets
-
-all-local: english/errmsg.sys
-
-# Use the english errmsg.sys as a flag that all errmsg.sys needs to be
-# created. Normally these are created by extra/Makefile
-
-english/errmsg.sys: errmsg.txt
- rm -f $(top_builddir)/include/mysqld_error.h
- (cd $(top_builddir)/extra && $(MAKE))
-
-install-data-local:
- for lang in @AVAILABLE_LANGUAGES@; \
- do \
- $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/$$lang; \
- $(INSTALL_DATA) $(srcdir)/$$lang/errmsg.sys \
- $(DESTDIR)$(pkgdatadir)/$$lang/errmsg.sys; \
- done
- $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/charsets
- $(INSTALL_DATA) $(srcdir)/errmsg.txt \
- $(DESTDIR)$(pkgdatadir)/errmsg.txt; \
- $(INSTALL_DATA) $(srcdir)/charsets/README $(DESTDIR)$(pkgdatadir)/charsets/README
- $(INSTALL_DATA) $(srcdir)/charsets/*.xml $(DESTDIR)$(pkgdatadir)/charsets
-
-# FIXME maybe shouldn't remove, could be needed by other installation?
-uninstall-local:
- @RM@ -f -r $(DESTDIR)$(pkgdatadir)
-
-distclean-local:
- @RM@ -f */errmsg.sys
-
-# Do nothing
-link_sources:
-
-# Don't update the files from bitkeeper
-%::SCCS/s.%
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
new file mode 100644
index 00000000000..b0dc4d9195b
--- /dev/null
+++ b/sql/share/errmsg-utf8.txt
@@ -0,0 +1,6396 @@
+languages czech=cze latin2, danish=dan latin1, dutch=nla latin1, english=eng latin1, estonian=est latin7, french=fre latin1, german=ger latin1, greek=greek greek, hungarian=hun latin2, italian=ita latin1, japanese=jpn ujis, japanese-sjis=jps sjis, korean=kor euckr, norwegian-ny=norwegian-ny latin1, norwegian=nor latin1, polish=pol latin2, portuguese=por latin1, romanian=rum latin2, russian=rus koi8r, serbian=serbian cp1250, slovak=slo latin2, spanish=spa latin1, swedish=swe latin1, ukrainian=ukr koi8u;
+
+default-language eng
+
+start-error-number 1000
+
+ER_HASHCHK
+ eng "hashchk"
+ER_NISAMCHK
+ eng "isamchk"
+ER_NO
+ cze "NE"
+ dan "NEJ"
+ nla "NEE"
+ eng "NO"
+ est "EI"
+ fre "NON"
+ ger "Nein"
+ greek "ΟΧΙ"
+ hun "NEM"
+ kor "아니오"
+ nor "NEI"
+ norwegian-ny "NEI"
+ pol "NIE"
+ por "NÃO"
+ rum "NU"
+ rus "ÐЕТ"
+ serbian "NE"
+ slo "NIE"
+ ukr "ÐІ"
+ER_YES
+ cze "ANO"
+ dan "JA"
+ nla "JA"
+ eng "YES"
+ est "JAH"
+ fre "OUI"
+ ger "Ja"
+ greek "ÎΑΙ"
+ hun "IGEN"
+ ita "SI"
+ kor "예"
+ nor "JA"
+ norwegian-ny "JA"
+ pol "TAK"
+ por "SIM"
+ rum "DA"
+ rus "ДÐ"
+ serbian "DA"
+ slo "Ãno"
+ spa "SI"
+ ukr "ТÐК"
+ER_CANT_CREATE_FILE
+ cze "Nemohu vytvo-Břit soubor '%-.200s' (chybový kód: %d)"
+ dan "Kan ikke oprette filen '%-.200s' (Fejlkode: %d)"
+ nla "Kan file '%-.200s' niet aanmaken (Errcode: %d)"
+ eng "Can't create file '%-.200s' (errno: %d)"
+ est "Ei suuda luua faili '%-.200s' (veakood: %d)"
+ fre "Ne peut créer le fichier '%-.200s' (Errcode: %d)"
+ ger "Kann Datei '%-.200s' nicht erzeugen (Fehler: %d)"
+ greek "ΑδÏνατη η δημιουÏγία του αÏχείου '%-.200s' (κωδικός λάθους: %d)"
+ hun "A '%-.200s' file nem hozhato letre (hibakod: %d)"
+ ita "Impossibile creare il file '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ファイルãŒä½œã‚Œã¾ã›ã‚“ (errno: %d)"
+ kor "í™”ì¼ '%-.200s'를 만들지 못했습니다. (ì—러번호: %d)"
+ nor "Kan ikke opprette fila '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje opprette fila '%-.200s' (Feilkode: %d)"
+ pol "Nie można stworzyć pliku '%-.200s' (Kod błędu: %d)"
+ por "Não pode criar o arquivo '%-.200s' (erro no. %d)"
+ rum "Nu pot sa creez fisierul '%-.200s' (Eroare: %d)"
+ rus "Ðевозможно Ñоздать файл '%-.200s' (ошибка: %d)"
+ serbian "Ne mogu da kreiram file '%-.200s' (errno: %d)"
+ slo "Nemôžem vytvoriť súbor '%-.200s' (chybový kód: %d)"
+ spa "No puedo crear archivo '%-.200s' (Error: %d)"
+ swe "Kan inte skapa filen '%-.200s' (Felkod: %d)"
+ ukr "Ðе можу Ñтворити файл '%-.200s' (помилка: %d)"
+ER_CANT_CREATE_TABLE
+ cze "Nemohu vytvo-Břit tabulku '%-.200s' (chybový kód: %d)"
+ dan "Kan ikke oprette tabellen '%-.200s' (Fejlkode: %d)"
+ nla "Kan tabel '%-.200s' niet aanmaken (Errcode: %d)"
+ eng "Can't create table '%-.200s' (errno: %d)"
+ jps "'%-.200s' テーブルãŒä½œã‚Œã¾ã›ã‚“.(errno: %d)",
+ est "Ei suuda luua tabelit '%-.200s' (veakood: %d)"
+ fre "Ne peut créer la table '%-.200s' (Errcode: %d)"
+ ger "Kann Tabelle '%-.200s' nicht erzeugen (Fehler: %d)"
+ greek "ΑδÏνατη η δημιουÏγία του πίνακα '%-.200s' (κωδικός λάθους: %d)"
+ hun "A '%-.200s' tabla nem hozhato letre (hibakod: %d)"
+ ita "Impossibile creare la tabella '%-.200s' (errno: %d)"
+ jpn "'%-.200s' テーブルãŒä½œã‚Œã¾ã›ã‚“.(errno: %d)"
+ kor "í…Œì´ë¸” '%-.200s'를 만들지 못했습니다. (ì—러번호: %d)"
+ nor "Kan ikke opprette tabellen '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje opprette tabellen '%-.200s' (Feilkode: %d)"
+ pol "Nie można stworzyć tabeli '%-.200s' (Kod błędu: %d)"
+ por "Não pode criar a tabela '%-.200s' (erro no. %d)"
+ rum "Nu pot sa creez tabla '%-.200s' (Eroare: %d)"
+ rus "Ðевозможно Ñоздать таблицу '%-.200s' (ошибка: %d)"
+ serbian "Ne mogu da kreiram tabelu '%-.200s' (errno: %d)"
+ slo "Nemôžem vytvoriť tabuľku '%-.200s' (chybový kód: %d)"
+ spa "No puedo crear tabla '%-.200s' (Error: %d)"
+ swe "Kan inte skapa tabellen '%-.200s' (Felkod: %d)"
+ ukr "Ðе можу Ñтворити таблицю '%-.200s' (помилка: %d)"
+ER_CANT_CREATE_DB
+ cze "Nemohu vytvo-Břit databázi '%-.192s' (chybový kód: %d)"
+ dan "Kan ikke oprette databasen '%-.192s' (Fejlkode: %d)"
+ nla "Kan database '%-.192s' niet aanmaken (Errcode: %d)"
+ eng "Can't create database '%-.192s' (errno: %d)"
+ jps "'%-.192s' データベースãŒä½œã‚Œã¾ã›ã‚“ (errno: %d)",
+ est "Ei suuda luua andmebaasi '%-.192s' (veakood: %d)"
+ fre "Ne peut créer la base '%-.192s' (Erreur %d)"
+ ger "Kann Datenbank '%-.192s' nicht erzeugen (Fehler: %d)"
+ greek "ΑδÏνατη η δημιουÏγία της βάσης δεδομένων '%-.192s' (κωδικός λάθους: %d)"
+ hun "Az '%-.192s' adatbazis nem hozhato letre (hibakod: %d)"
+ ita "Impossibile creare il database '%-.192s' (errno: %d)"
+ jpn "'%-.192s' データベースãŒä½œã‚Œã¾ã›ã‚“ (errno: %d)"
+ kor "ë°ì´íƒ€ë² ì´ìŠ¤ '%-.192s'를 만들지 못했습니다.. (ì—러번호: %d)"
+ nor "Kan ikke opprette databasen '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje opprette databasen '%-.192s' (Feilkode: %d)"
+ pol "Nie można stworzyć bazy danych '%-.192s' (Kod błędu: %d)"
+ por "Não pode criar o banco de dados '%-.192s' (erro no. %d)"
+ rum "Nu pot sa creez baza de date '%-.192s' (Eroare: %d)"
+ rus "Ðевозможно Ñоздать базу данных '%-.192s' (ошибка: %d)"
+ serbian "Ne mogu da kreiram bazu '%-.192s' (errno: %d)"
+ slo "Nemôžem vytvoriť databázu '%-.192s' (chybový kód: %d)"
+ spa "No puedo crear base de datos '%-.192s' (Error: %d)"
+ swe "Kan inte skapa databasen '%-.192s' (Felkod: %d)"
+ ukr "Ðе можу Ñтворити базу данних '%-.192s' (помилка: %d)"
+ER_DB_CREATE_EXISTS
+ cze "Nemohu vytvo-Břit databázi '%-.192s'; databáze již existuje"
+ dan "Kan ikke oprette databasen '%-.192s'; databasen eksisterer"
+ nla "Kan database '%-.192s' niet aanmaken; database bestaat reeds"
+ eng "Can't create database '%-.192s'; database exists"
+ jps "'%-.192s' データベースãŒä½œã‚Œã¾ã›ã‚“.æ—¢ã«ãã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãŒå­˜åœ¨ã—ã¾ã™",
+ est "Ei suuda luua andmebaasi '%-.192s': andmebaas juba eksisteerib"
+ fre "Ne peut créer la base '%-.192s'; elle existe déjà"
+ ger "Kann Datenbank '%-.192s' nicht erzeugen. Datenbank existiert bereits"
+ greek "ΑδÏνατη η δημιουÏγία της βάσης δεδομένων '%-.192s'; Η βάση δεδομένων υπάÏχει ήδη"
+ hun "Az '%-.192s' adatbazis nem hozhato letre Az adatbazis mar letezik"
+ ita "Impossibile creare il database '%-.192s'; il database esiste"
+ jpn "'%-.192s' データベースãŒä½œã‚Œã¾ã›ã‚“.æ—¢ã«ãã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãŒå­˜åœ¨ã—ã¾ã™"
+ kor "ë°ì´íƒ€ë² ì´ìŠ¤ '%-.192s'를 만들지 못했습니다.. ë°ì´íƒ€ë² ì´ìŠ¤ê°€ 존재함"
+ nor "Kan ikke opprette databasen '%-.192s'; databasen eksisterer"
+ norwegian-ny "Kan ikkje opprette databasen '%-.192s'; databasen eksisterer"
+ pol "Nie można stworzyć bazy danych '%-.192s'; baza danych już istnieje"
+ por "Não pode criar o banco de dados '%-.192s'; este banco de dados já existe"
+ rum "Nu pot sa creez baza de date '%-.192s'; baza de date exista deja"
+ rus "Ðевозможно Ñоздать базу данных '%-.192s'. База данных уже ÑущеÑтвует"
+ serbian "Ne mogu da kreiram bazu '%-.192s'; baza već postoji."
+ slo "Nemôžem vytvoriť databázu '%-.192s'; databáza existuje"
+ spa "No puedo crear base de datos '%-.192s'; la base de datos ya existe"
+ swe "Databasen '%-.192s' existerar redan"
+ ukr "Ðе можу Ñтворити базу данних '%-.192s'. База данних Ñ–Ñнує"
+ER_DB_DROP_EXISTS
+ cze "Nemohu zru-Bšit databázi '%-.192s', databáze neexistuje"
+ dan "Kan ikke slette (droppe) '%-.192s'; databasen eksisterer ikke"
+ nla "Kan database '%-.192s' niet verwijderen; database bestaat niet"
+ eng "Can't drop database '%-.192s'; database doesn't exist"
+ jps "'%-.192s' データベースを破棄ã§ãã¾ã›ã‚“. ãã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãŒãªã„ã®ã§ã™.",
+ est "Ei suuda kustutada andmebaasi '%-.192s': andmebaasi ei eksisteeri"
+ fre "Ne peut effacer la base '%-.192s'; elle n'existe pas"
+ ger "Kann Datenbank '%-.192s' nicht löschen; Datenbank nicht vorhanden"
+ greek "ΑδÏνατη η διαγÏαφή της βάσης δεδομένων '%-.192s'. Η βάση δεδομένων δεν υπάÏχει"
+ hun "A(z) '%-.192s' adatbazis nem szuntetheto meg. Az adatbazis nem letezik"
+ ita "Impossibile cancellare '%-.192s'; il database non esiste"
+ jpn "'%-.192s' データベースを破棄ã§ãã¾ã›ã‚“. ãã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãŒãªã„ã®ã§ã™."
+ kor "ë°ì´íƒ€ë² ì´ìŠ¤ '%-.192s'를 제거하지 못했습니다. ë°ì´íƒ€ë² ì´ìŠ¤ê°€ 존재하지 ì•ŠìŒ "
+ nor "Kan ikke fjerne (drop) '%-.192s'; databasen eksisterer ikke"
+ norwegian-ny "Kan ikkje fjerne (drop) '%-.192s'; databasen eksisterer ikkje"
+ pol "Nie można usun?ć bazy danych '%-.192s'; baza danych nie istnieje"
+ por "Não pode eliminar o banco de dados '%-.192s'; este banco de dados não existe"
+ rum "Nu pot sa drop baza de date '%-.192s'; baza da date este inexistenta"
+ rus "Ðевозможно удалить базу данных '%-.192s'. Такой базы данных нет"
+ serbian "Ne mogu da izbrišem bazu '%-.192s'; baza ne postoji."
+ slo "Nemôžem zmazať databázu '%-.192s'; databáza neexistuje"
+ spa "No puedo eliminar base de datos '%-.192s'; la base de datos no existe"
+ swe "Kan inte radera databasen '%-.192s'; databasen finns inte"
+ ukr "Ðе можу видалити базу данних '%-.192s'. База данних не Ñ–Ñнує"
+ER_DB_DROP_DELETE
+ cze "Chyba p-Bři rušení databáze (nemohu vymazat '%-.192s', chyba %d)"
+ dan "Fejl ved sletning (drop) af databasen (kan ikke slette '%-.192s', Fejlkode %d)"
+ nla "Fout bij verwijderen database (kan '%-.192s' niet verwijderen, Errcode: %d)"
+ eng "Error dropping database (can't delete '%-.192s', errno: %d)"
+ jps "データベース破棄エラー ('%-.192s' を削除ã§ãã¾ã›ã‚“, errno: %d)",
+ est "Viga andmebaasi kustutamisel (ei suuda kustutada faili '%-.192s', veakood: %d)"
+ fre "Ne peut effacer la base '%-.192s' (erreur %d)"
+ ger "Fehler beim Löschen der Datenbank ('%-.192s' kann nicht gelöscht werden, Fehler: %d)"
+ greek "ΠαÏουσιάστηκε Ï€Ïόβλημα κατά τη διαγÏαφή της βάσης δεδομένων (αδÏνατη η διαγÏαφή '%-.192s', κωδικός λάθους: %d)"
+ hun "Adatbazis megszuntetesi hiba ('%-.192s' nem torolheto, hibakod: %d)"
+ ita "Errore durante la cancellazione del database (impossibile cancellare '%-.192s', errno: %d)"
+ jpn "データベース破棄エラー ('%-.192s' を削除ã§ãã¾ã›ã‚“, errno: %d)"
+ kor "ë°ì´íƒ€ë² ì´ìŠ¤ 제거 ì—러('%-.192s'를 삭제할 수 ì—†ì니다, ì—러번호: %d)"
+ nor "Feil ved fjerning (drop) av databasen (kan ikke slette '%-.192s', feil %d)"
+ norwegian-ny "Feil ved fjerning (drop) av databasen (kan ikkje slette '%-.192s', feil %d)"
+ pol "Bł?d podczas usuwania bazy danych (nie można usun?ć '%-.192s', bł?d %d)"
+ por "Erro ao eliminar banco de dados (não pode eliminar '%-.192s' - erro no. %d)"
+ rum "Eroare dropuind baza de date (nu pot sa sterg '%-.192s', Eroare: %d)"
+ rus "Ошибка при удалении базы данных (невозможно удалить '%-.192s', ошибка: %d)"
+ serbian "Ne mogu da izbrišem bazu (ne mogu da izbrišem '%-.192s', errno: %d)"
+ slo "Chyba pri mazaní databázy (nemôžem zmazať '%-.192s', chybový kód: %d)"
+ spa "Error eliminando la base de datos(no puedo borrar '%-.192s', error %d)"
+ swe "Fel vid radering av databasen (Kan inte radera '%-.192s'. Felkod: %d)"
+ ukr "Ðе можу видалити базу данних (Ðе можу видалити '%-.192s', помилка: %d)"
+ER_DB_DROP_RMDIR
+ cze "Chyba p-Bři rušení databáze (nemohu vymazat adresář '%-.192s', chyba %d)"
+ dan "Fejl ved sletting af database (kan ikke slette folderen '%-.192s', Fejlkode %d)"
+ nla "Fout bij verwijderen database (kan rmdir '%-.192s' niet uitvoeren, Errcode: %d)"
+ eng "Error dropping database (can't rmdir '%-.192s', errno: %d)"
+ jps "データベース破棄エラー ('%-.192s' ã‚’ rmdir ã§ãã¾ã›ã‚“, errno: %d)",
+ est "Viga andmebaasi kustutamisel (ei suuda kustutada kataloogi '%-.192s', veakood: %d)"
+ fre "Erreur en effaçant la base (rmdir '%-.192s', erreur %d)"
+ ger "Fehler beim Löschen der Datenbank (Verzeichnis '%-.192s' kann nicht gelöscht werden, Fehler: %d)"
+ greek "ΠαÏουσιάστηκε Ï€Ïόβλημα κατά τη διαγÏαφή της βάσης δεδομένων (αδÏνατη η διαγÏαφή του φακέλλου '%-.192s', κωδικός λάθους: %d)"
+ hun "Adatbazis megszuntetesi hiba ('%-.192s' nem szuntetheto meg, hibakod: %d)"
+ ita "Errore durante la cancellazione del database (impossibile rmdir '%-.192s', errno: %d)"
+ jpn "データベース破棄エラー ('%-.192s' ã‚’ rmdir ã§ãã¾ã›ã‚“, errno: %d)"
+ kor "ë°ì´íƒ€ë² ì´ìŠ¤ 제거 ì—러(rmdir '%-.192s'를 í•  수 ì—†ì니다, ì—러번호: %d)"
+ nor "Feil ved sletting av database (kan ikke slette katalogen '%-.192s', feil %d)"
+ norwegian-ny "Feil ved sletting av database (kan ikkje slette katalogen '%-.192s', feil %d)"
+ pol "Bł?d podczas usuwania bazy danych (nie można wykonać rmdir '%-.192s', bł?d %d)"
+ por "Erro ao eliminar banco de dados (não pode remover diretório '%-.192s' - erro no. %d)"
+ rum "Eroare dropuind baza de date (nu pot sa rmdir '%-.192s', Eroare: %d)"
+ rus "Ðевозможно удалить базу данных (невозможно удалить каталог '%-.192s', ошибка: %d)"
+ serbian "Ne mogu da izbrišem bazu (ne mogu da izbrišem direktorijum '%-.192s', errno: %d)"
+ slo "Chyba pri mazaní databázy (nemôžem vymazať adresár '%-.192s', chybový kód: %d)"
+ spa "Error eliminando la base de datos (No puedo borrar directorio '%-.192s', error %d)"
+ swe "Fel vid radering av databasen (Kan inte radera biblioteket '%-.192s'. Felkod: %d)"
+ ukr "Ðе можу видалити базу данних (Ðе можу видалити теку '%-.192s', помилка: %d)"
+ER_CANT_DELETE_FILE
+ cze "Chyba p-Bři výmazu '%-.192s' (chybový kód: %d)"
+ dan "Fejl ved sletning af '%-.192s' (Fejlkode: %d)"
+ nla "Fout bij het verwijderen van '%-.192s' (Errcode: %d)"
+ eng "Error on delete of '%-.192s' (errno: %d)"
+ jps "'%-.192s' ã®å‰Šé™¤ãŒã‚¨ãƒ©ãƒ¼ (errno: %d)",
+ est "Viga '%-.192s' kustutamisel (veakood: %d)"
+ fre "Erreur en effaçant '%-.192s' (Errcode: %d)"
+ ger "Fehler beim Löschen von '%-.192s' (Fehler: %d)"
+ greek "ΠαÏουσιάστηκε Ï€Ïόβλημα κατά τη διαγÏαφή '%-.192s' (κωδικός λάθους: %d)"
+ hun "Torlesi hiba: '%-.192s' (hibakod: %d)"
+ ita "Errore durante la cancellazione di '%-.192s' (errno: %d)"
+ jpn "'%-.192s' ã®å‰Šé™¤ãŒã‚¨ãƒ©ãƒ¼ (errno: %d)"
+ kor "'%-.192s' ì‚­ì œ 중 ì—러 (ì—러번호: %d)"
+ nor "Feil ved sletting av '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Feil ved sletting av '%-.192s' (Feilkode: %d)"
+ pol "Bł?d podczas usuwania '%-.192s' (Kod błędu: %d)"
+ por "Erro na remoção de '%-.192s' (erro no. %d)"
+ rum "Eroare incercind sa delete '%-.192s' (Eroare: %d)"
+ rus "Ошибка при удалении '%-.192s' (ошибка: %d)"
+ serbian "Greška pri brisanju '%-.192s' (errno: %d)"
+ slo "Chyba pri mazaní '%-.192s' (chybový kód: %d)"
+ spa "Error en el borrado de '%-.192s' (Error: %d)"
+ swe "Kan inte radera filen '%-.192s' (Felkod: %d)"
+ ukr "Ðе можу видалити '%-.192s' (помилка: %d)"
+ER_CANT_FIND_SYSTEM_REC
+ cze "Nemohu -BÄíst záznam v systémové tabulce"
+ dan "Kan ikke læse posten i systemfolderen"
+ nla "Kan record niet lezen in de systeem tabel"
+ eng "Can't read record in system table"
+ jps "system table ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’読む事ãŒã§ãã¾ã›ã‚“ã§ã—ãŸ",
+ est "Ei suuda lugeda kirjet süsteemsest tabelist"
+ fre "Ne peut lire un enregistrement de la table 'system'"
+ ger "Datensatz in der Systemtabelle nicht lesbar"
+ greek "ΑδÏνατη η ανάγνωση εγγÏαφής από πίνακα του συστήματος"
+ hun "Nem olvashato rekord a rendszertablaban"
+ ita "Impossibile leggere il record dalla tabella di sistema"
+ jpn "system table ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’読む事ãŒã§ãã¾ã›ã‚“ã§ã—ãŸ"
+ kor "system í…Œì´ë¸”ì—ì„œ 레코드를 ì½ì„ 수 없습니다."
+ nor "Kan ikke lese posten i systemkatalogen"
+ norwegian-ny "Kan ikkje lese posten i systemkatalogen"
+ pol "Nie można odczytać rekordu z tabeli systemowej"
+ por "Não pode ler um registro numa tabela do sistema"
+ rum "Nu pot sa citesc cimpurile in tabla de system (system table)"
+ rus "Ðевозможно прочитать запиÑÑŒ в ÑиÑтемной таблице"
+ serbian "Ne mogu da proÄitam slog iz sistemske tabele"
+ slo "Nemôžem ÄítaÅ¥ záznam v systémovej tabuľke"
+ spa "No puedo leer el registro en la tabla del sistema"
+ swe "Hittar inte posten i systemregistret"
+ ukr "Ðе можу зчитати Ð·Ð°Ð¿Ð¸Ñ Ð· ÑиÑтемної таблиці"
+ER_CANT_GET_STAT
+ cze "Nemohu z-Bískat stav '%-.200s' (chybový kód: %d)"
+ dan "Kan ikke læse status af '%-.200s' (Fejlkode: %d)"
+ nla "Kan de status niet krijgen van '%-.200s' (Errcode: %d)"
+ eng "Can't get status of '%-.200s' (errno: %d)"
+ jps "'%-.200s' ã®ã‚¹ãƒ†ã‚¤ã‚¿ã‚¹ãŒå¾—られã¾ã›ã‚“. (errno: %d)",
+ est "Ei suuda lugeda '%-.200s' olekut (veakood: %d)"
+ fre "Ne peut obtenir le status de '%-.200s' (Errcode: %d)"
+ ger "Kann Status von '%-.200s' nicht ermitteln (Fehler: %d)"
+ greek "ΑδÏνατη η λήψη πληÏοφοÏιών για την κατάσταση του '%-.200s' (κωδικός λάθους: %d)"
+ hun "A(z) '%-.200s' statusza nem allapithato meg (hibakod: %d)"
+ ita "Impossibile leggere lo stato di '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ã®ã‚¹ãƒ†ã‚¤ã‚¿ã‚¹ãŒå¾—られã¾ã›ã‚“. (errno: %d)"
+ kor "'%-.200s'ì˜ ìƒíƒœë¥¼ 얻지 못했습니다. (ì—러번호: %d)"
+ nor "Kan ikke lese statusen til '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje lese statusen til '%-.200s' (Feilkode: %d)"
+ pol "Nie można otrzymać statusu '%-.200s' (Kod błędu: %d)"
+ por "Não pode obter o status de '%-.200s' (erro no. %d)"
+ rum "Nu pot sa obtin statusul lui '%-.200s' (Eroare: %d)"
+ rus "Ðевозможно получить ÑтатуÑную информацию о '%-.200s' (ошибка: %d)"
+ serbian "Ne mogu da dobijem stanje file-a '%-.200s' (errno: %d)"
+ slo "Nemôžem zistiť stav '%-.200s' (chybový kód: %d)"
+ spa "No puedo obtener el estado de '%-.200s' (Error: %d)"
+ swe "Kan inte läsa filinformationen (stat) från '%-.200s' (Felkod: %d)"
+ ukr "Ðе можу отримати ÑÑ‚Ð°Ñ‚ÑƒÑ '%-.200s' (помилка: %d)"
+ER_CANT_GET_WD
+ cze "Chyba p-Bři zjišťování pracovní adresář (chybový kód: %d)"
+ dan "Kan ikke læse aktive folder (Fejlkode: %d)"
+ nla "Kan de werkdirectory niet krijgen (Errcode: %d)"
+ eng "Can't get working directory (errno: %d)"
+ jps "working directory を得る事ãŒã§ãã¾ã›ã‚“ã§ã—㟠(errno: %d)",
+ est "Ei suuda identifitseerida jooksvat kataloogi (veakood: %d)"
+ fre "Ne peut obtenir le répertoire de travail (Errcode: %d)"
+ ger "Kann Arbeitsverzeichnis nicht ermitteln (Fehler: %d)"
+ greek "Ο φάκελλος εÏγασίας δεν βÏέθηκε (κωδικός λάθους: %d)"
+ hun "A munkakonyvtar nem allapithato meg (hibakod: %d)"
+ ita "Impossibile leggere la directory di lavoro (errno: %d)"
+ jpn "working directory を得る事ãŒã§ãã¾ã›ã‚“ã§ã—㟠(errno: %d)"
+ kor "수행 디렉토리를 찾지 못했습니다. (ì—러번호: %d)"
+ nor "Kan ikke lese aktiv katalog(Feilkode: %d)"
+ norwegian-ny "Kan ikkje lese aktiv katalog(Feilkode: %d)"
+ pol "Nie można rozpoznać aktualnego katalogu (Kod błędu: %d)"
+ por "Não pode obter o diretório corrente (erro no. %d)"
+ rum "Nu pot sa obtin directorul current (working directory) (Eroare: %d)"
+ rus "Ðевозможно определить рабочий каталог (ошибка: %d)"
+ serbian "Ne mogu da dobijem trenutni direktorijum (errno: %d)"
+ slo "Nemôžem zistiť pracovný adresár (chybový kód: %d)"
+ spa "No puedo acceder al directorio (Error: %d)"
+ swe "Kan inte inte läsa aktivt bibliotek. (Felkod: %d)"
+ ukr "Ðе можу визначити робочу теку (помилка: %d)"
+ER_CANT_LOCK
+ cze "Nemohu uzamknout soubor (chybov-Bý kód: %d)"
+ dan "Kan ikke låse fil (Fejlkode: %d)"
+ nla "Kan de file niet blokeren (Errcode: %d)"
+ eng "Can't lock file (errno: %d)"
+ jps "ファイルをロックã§ãã¾ã›ã‚“ (errno: %d)",
+ est "Ei suuda lukustada faili (veakood: %d)"
+ fre "Ne peut verrouiller le fichier (Errcode: %d)"
+ ger "Datei kann nicht gesperrt werden (Fehler: %d)"
+ greek "Το αÏχείο δεν μποÏεί να κλειδωθεί (κωδικός λάθους: %d)"
+ hun "A file nem zarolhato. (hibakod: %d)"
+ ita "Impossibile il locking il file (errno: %d)"
+ jpn "ファイルをロックã§ãã¾ã›ã‚“ (errno: %d)"
+ kor "í™”ì¼ì„ 잠그지(lock) 못했습니다. (ì—러번호: %d)"
+ nor "Kan ikke låse fila (Feilkode: %d)"
+ norwegian-ny "Kan ikkje låse fila (Feilkode: %d)"
+ pol "Nie można zablokować pliku (Kod błędu: %d)"
+ por "Não pode travar o arquivo (erro no. %d)"
+ rum "Nu pot sa lock fisierul (Eroare: %d)"
+ rus "Ðевозможно поÑтавить блокировку на файле (ошибка: %d)"
+ serbian "Ne mogu da zakljuÄam file (errno: %d)"
+ slo "Nemôžem zamknúť súbor (chybový kód: %d)"
+ spa "No puedo bloquear archivo: (Error: %d)"
+ swe "Kan inte låsa filen. (Felkod: %d)"
+ ukr "Ðе можу заблокувати файл (помилка: %d)"
+ER_CANT_OPEN_FILE
+ cze "Nemohu otev-Břít soubor '%-.200s' (chybový kód: %d)"
+ dan "Kan ikke åbne fil: '%-.200s' (Fejlkode: %d)"
+ nla "Kan de file '%-.200s' niet openen (Errcode: %d)"
+ eng "Can't open file: '%-.200s' (errno: %d)"
+ jps "'%-.200s' ファイルを開ã事ãŒã§ãã¾ã›ã‚“ (errno: %d)",
+ est "Ei suuda avada faili '%-.200s' (veakood: %d)"
+ fre "Ne peut ouvrir le fichier: '%-.200s' (Errcode: %d)"
+ ger "Kann Datei '%-.200s' nicht öffnen (Fehler: %d)"
+ greek "Δεν είναι δυνατό να ανοιχτεί το αÏχείο: '%-.200s' (κωδικός λάθους: %d)"
+ hun "A '%-.200s' file nem nyithato meg (hibakod: %d)"
+ ita "Impossibile aprire il file: '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ファイルを開ã事ãŒã§ãã¾ã›ã‚“ (errno: %d)"
+ kor "í™”ì¼ì„ 열지 못했습니다.: '%-.200s' (ì—러번호: %d)"
+ nor "Kan ikke åpne fila: '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje åpne fila: '%-.200s' (Feilkode: %d)"
+ pol "Nie można otworzyć pliku: '%-.200s' (Kod błędu: %d)"
+ por "Não pode abrir o arquivo '%-.200s' (erro no. %d)"
+ rum "Nu pot sa deschid fisierul: '%-.200s' (Eroare: %d)"
+ rus "Ðевозможно открыть файл: '%-.200s' (ошибка: %d)"
+ serbian "Ne mogu da otvorim file: '%-.200s' (errno: %d)"
+ slo "Nemôžem otvoriť súbor: '%-.200s' (chybový kód: %d)"
+ spa "No puedo abrir archivo: '%-.200s' (Error: %d)"
+ swe "Kan inte använda '%-.200s' (Felkod: %d)"
+ ukr "Ðе можу відкрити файл: '%-.200s' (помилка: %d)"
+ER_FILE_NOT_FOUND
+ cze "Nemohu naj-Bít soubor '%-.200s' (chybový kód: %d)"
+ dan "Kan ikke finde fila: '%-.200s' (Fejlkode: %d)"
+ nla "Kan de file: '%-.200s' niet vinden (Errcode: %d)"
+ eng "Can't find file: '%-.200s' (errno: %d)"
+ jps "'%-.200s' ファイルを見付ã‘る事ãŒã§ãã¾ã›ã‚“.(errno: %d)",
+ est "Ei suuda leida faili '%-.200s' (veakood: %d)"
+ fre "Ne peut trouver le fichier: '%-.200s' (Errcode: %d)"
+ ger "Kann Datei '%-.200s' nicht finden (Fehler: %d)"
+ greek "Δεν βÏέθηκε το αÏχείο: '%-.200s' (κωδικός λάθους: %d)"
+ hun "A(z) '%-.200s' file nem talalhato (hibakod: %d)"
+ ita "Impossibile trovare il file: '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ファイルを見付ã‘る事ãŒã§ãã¾ã›ã‚“.(errno: %d)"
+ kor "í™”ì¼ì„ 찾지 못했습니다.: '%-.200s' (ì—러번호: %d)"
+ nor "Kan ikke finne fila: '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje finne fila: '%-.200s' (Feilkode: %d)"
+ pol "Nie można znaleĽć pliku: '%-.200s' (Kod błędu: %d)"
+ por "Não pode encontrar o arquivo '%-.200s' (erro no. %d)"
+ rum "Nu pot sa gasesc fisierul: '%-.200s' (Eroare: %d)"
+ rus "Ðевозможно найти файл: '%-.200s' (ошибка: %d)"
+ serbian "Ne mogu da pronađem file: '%-.200s' (errno: %d)"
+ slo "Nemôžem nájsť súbor: '%-.200s' (chybový kód: %d)"
+ spa "No puedo encontrar archivo: '%-.200s' (Error: %d)"
+ swe "Hittar inte filen '%-.200s' (Felkod: %d)"
+ ukr "Ðе можу знайти файл: '%-.200s' (помилка: %d)"
+ER_CANT_READ_DIR
+ cze "Nemohu -BÄíst adresář '%-.192s' (chybový kód: %d)"
+ dan "Kan ikke læse folder '%-.192s' (Fejlkode: %d)"
+ nla "Kan de directory niet lezen van '%-.192s' (Errcode: %d)"
+ eng "Can't read dir of '%-.192s' (errno: %d)"
+ jps "'%-.192s' ディレクトリãŒèª­ã‚ã¾ã›ã‚“.(errno: %d)",
+ est "Ei suuda lugeda kataloogi '%-.192s' (veakood: %d)"
+ fre "Ne peut lire le répertoire de '%-.192s' (Errcode: %d)"
+ ger "Verzeichnis von '%-.192s' nicht lesbar (Fehler: %d)"
+ greek "Δεν είναι δυνατό να διαβαστεί ο φάκελλος του '%-.192s' (κωδικός λάθους: %d)"
+ hun "A(z) '%-.192s' konyvtar nem olvashato. (hibakod: %d)"
+ ita "Impossibile leggere la directory di '%-.192s' (errno: %d)"
+ jpn "'%-.192s' ディレクトリãŒèª­ã‚ã¾ã›ã‚“.(errno: %d)"
+ kor "'%-.192s'디렉토리를 ì½ì§€ 못했습니다. (ì—러번호: %d)"
+ nor "Kan ikke lese katalogen '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje lese katalogen '%-.192s' (Feilkode: %d)"
+ pol "Nie można odczytać katalogu '%-.192s' (Kod błędu: %d)"
+ por "Não pode ler o diretório de '%-.192s' (erro no. %d)"
+ rum "Nu pot sa citesc directorul '%-.192s' (Eroare: %d)"
+ rus "Ðевозможно прочитать каталог '%-.192s' (ошибка: %d)"
+ serbian "Ne mogu da proÄitam direktorijum '%-.192s' (errno: %d)"
+ slo "Nemôžem ÄítaÅ¥ adresár '%-.192s' (chybový kód: %d)"
+ spa "No puedo leer el directorio de '%-.192s' (Error: %d)"
+ swe "Kan inte läsa från bibliotek '%-.192s' (Felkod: %d)"
+ ukr "Ðе можу прочитати теку '%-.192s' (помилка: %d)"
+ER_CANT_SET_WD
+ cze "Nemohu zm-Běnit adresář na '%-.192s' (chybový kód: %d)"
+ dan "Kan ikke skifte folder til '%-.192s' (Fejlkode: %d)"
+ nla "Kan de directory niet veranderen naar '%-.192s' (Errcode: %d)"
+ eng "Can't change dir to '%-.192s' (errno: %d)"
+ jps "'%-.192s' ディレクトリ㫠chdir ã§ãã¾ã›ã‚“.(errno: %d)",
+ est "Ei suuda siseneda kataloogi '%-.192s' (veakood: %d)"
+ fre "Ne peut changer le répertoire pour '%-.192s' (Errcode: %d)"
+ ger "Kann nicht in das Verzeichnis '%-.192s' wechseln (Fehler: %d)"
+ greek "ΑδÏνατη η αλλαγή του Ï„Ïέχοντος καταλόγου σε '%-.192s' (κωδικός λάθους: %d)"
+ hun "Konyvtarvaltas nem lehetseges a(z) '%-.192s'-ba. (hibakod: %d)"
+ ita "Impossibile cambiare la directory in '%-.192s' (errno: %d)"
+ jpn "'%-.192s' ディレクトリ㫠chdir ã§ãã¾ã›ã‚“.(errno: %d)"
+ kor "'%-.192s'디렉토리로 ì´ë™í•  수 없었습니다. (ì—러번호: %d)"
+ nor "Kan ikke skifte katalog til '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje skifte katalog til '%-.192s' (Feilkode: %d)"
+ pol "Nie można zmienić katalogu na '%-.192s' (Kod błędu: %d)"
+ por "Não pode mudar para o diretório '%-.192s' (erro no. %d)"
+ rum "Nu pot sa schimb directorul '%-.192s' (Eroare: %d)"
+ rus "Ðевозможно перейти в каталог '%-.192s' (ошибка: %d)"
+ serbian "Ne mogu da promenim direktorijum na '%-.192s' (errno: %d)"
+ slo "Nemôžem vojsť do adresára '%-.192s' (chybový kód: %d)"
+ spa "No puedo cambiar al directorio de '%-.192s' (Error: %d)"
+ swe "Kan inte byta till '%-.192s' (Felkod: %d)"
+ ukr "Ðе можу перейти у теку '%-.192s' (помилка: %d)"
+ER_CHECKREAD
+ cze "Z-Báznam byl zmÄ›nÄ›n od posledního Ätení v tabulce '%-.192s'"
+ dan "Posten er ændret siden sidste læsning '%-.192s'"
+ nla "Record is veranderd sinds de laatste lees activiteit in de tabel '%-.192s'"
+ eng "Record has changed since last read in table '%-.192s'"
+ est "Kirje tabelis '%-.192s' on muutunud viimasest lugemisest saadik"
+ fre "Enregistrement modifié depuis sa dernière lecture dans la table '%-.192s'"
+ ger "Datensatz hat sich seit dem letzten Zugriff auf Tabelle '%-.192s' geändert"
+ greek "Η εγγÏαφή έχει αλλάξει από την τελευταία φοÏά που ανασÏÏθηκε από τον πίνακα '%-.192s'"
+ hun "A(z) '%-.192s' tablaban talalhato rekord megvaltozott az utolso olvasas ota"
+ ita "Il record e` cambiato dall'ultima lettura della tabella '%-.192s'"
+ kor "í…Œì´ë¸” '%-.192s'ì—ì„œ 마지막으로 ì½ì€ 후 Recordê°€ 변경ë˜ì—ˆìŠµë‹ˆë‹¤."
+ nor "Posten har blitt endret siden den ble lest '%-.192s'"
+ norwegian-ny "Posten har vorte endra sidan den sist vart lesen '%-.192s'"
+ pol "Rekord został zmieniony od ostaniego odczytania z tabeli '%-.192s'"
+ por "Registro alterado desde a última leitura da tabela '%-.192s'"
+ rum "Cimpul a fost schimbat de la ultima citire a tabelei '%-.192s'"
+ rus "ЗапиÑÑŒ изменилаÑÑŒ Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° поÑледней выборки в таблице '%-.192s'"
+ serbian "Slog je promenjen od zadnjeg Äitanja tabele '%-.192s'"
+ slo "Záznam bol zmenený od posledného Äítania v tabuľke '%-.192s'"
+ spa "El registro ha cambiado desde la ultima lectura de la tabla '%-.192s'"
+ swe "Posten har förändrats sedan den lästes i register '%-.192s'"
+ ukr "Ð—Ð°Ð¿Ð¸Ñ Ð±ÑƒÐ»Ð¾ змінено з чаÑу оÑтаннього Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð· таблиці '%-.192s'"
+ER_DISK_FULL
+ cze "Disk je pln-Bý (%s), Äekám na uvolnÄ›ní nÄ›jakého místa ..."
+ dan "Ikke mere diskplads (%s). Venter på at få frigjort plads..."
+ nla "Schijf vol (%s). Aan het wachten totdat er ruimte vrij wordt gemaakt..."
+ eng "Disk full (%s); waiting for someone to free some space..."
+ jps "Disk full (%s). 誰ã‹ãŒä½•ã‹ã‚’減らã™ã¾ã§ã¾ã£ã¦ãã ã•ã„...",
+ est "Ketas täis (%s). Ootame kuni tekib vaba ruumi..."
+ fre "Disque plein (%s). J'attend que quelqu'un libère de l'espace..."
+ ger "Festplatte voll (%s). Warte, bis jemand Platz schafft ..."
+ greek "Δεν υπάÏχει χώÏος στο δίσκο (%s). ΠαÏακαλώ, πεÏιμένετε να ελευθεÏωθεί χώÏος..."
+ hun "A lemez megtelt (%s)."
+ ita "Disco pieno (%s). In attesa che qualcuno liberi un po' di spazio..."
+ jpn "Disk full (%s). 誰ã‹ãŒä½•ã‹ã‚’減らã™ã¾ã§ã¾ã£ã¦ãã ã•ã„..."
+ kor "Disk full (%s). 다른 ì‚¬ëžŒì´ ì§€ìš¸ë•Œê¹Œì§€ 기다립니다..."
+ nor "Ikke mer diskplass (%s). Venter på å få frigjort plass..."
+ norwegian-ny "Ikkje meir diskplass (%s). Ventar på å få frigjort plass..."
+ pol "Dysk pełny (%s). Oczekiwanie na zwolnienie miejsca..."
+ por "Disco cheio (%s). Aguardando alguém liberar algum espaço..."
+ rum "Hard-disk-ul este plin (%s). Astept sa se elibereze ceva spatiu..."
+ rus "ДиÑк заполнен. (%s). Ожидаем, пока кто-то не уберет поÑле ÑÐµÐ±Ñ Ð¼ÑƒÑор..."
+ serbian "Disk je pun (%s). Čekam nekoga da dođe i oslobodi nešto mesta..."
+ slo "Disk je plný (%s), Äakám na uvoľnenie miesta..."
+ spa "Disco lleno (%s). Esperando para que se libere algo de espacio..."
+ swe "Disken är full (%s). Väntar tills det finns ledigt utrymme..."
+ ukr "ДиÑк заповнений (%s). Вичикую, доки звільнитьÑÑ Ñ‚Ñ€Ð¾Ñ…Ð¸ міÑцÑ..."
+ER_DUP_KEY 23000
+ cze "Nemohu zapsat, zdvojen-Bý klÃ­Ä v tabulce '%-.192s'"
+ dan "Kan ikke skrive, flere ens nøgler i tabellen '%-.192s'"
+ nla "Kan niet schrijven, dubbele zoeksleutel in tabel '%-.192s'"
+ eng "Can't write; duplicate key in table '%-.192s'"
+ jps "table '%-.192s' ã« key ãŒé‡è¤‡ã—ã¦ã„ã¦æ›¸ãã“ã‚ã¾ã›ã‚“",
+ est "Ei saa kirjutada, korduv võti tabelis '%-.192s'"
+ fre "Ecriture impossible, doublon dans une clé de la table '%-.192s'"
+ ger "Kann nicht speichern, Grund: doppelter Schlüssel in Tabelle '%-.192s'"
+ greek "Δεν είναι δυνατή η καταχώÏηση, η τιμή υπάÏχει ήδη στον πίνακα '%-.192s'"
+ hun "Irasi hiba, duplikalt kulcs a '%-.192s' tablaban."
+ ita "Scrittura impossibile: chiave duplicata nella tabella '%-.192s'"
+ jpn "table '%-.192s' ã« key ãŒé‡è¤‡ã—ã¦ã„ã¦æ›¸ãã“ã‚ã¾ã›ã‚“"
+ kor "기ë¡í•  수 ì—†ì니다., í…Œì´ë¸” '%-.192s'ì—ì„œ 중복 키"
+ nor "Kan ikke skrive, flere like nøkler i tabellen '%-.192s'"
+ norwegian-ny "Kan ikkje skrive, flere like nyklar i tabellen '%-.192s'"
+ pol "Nie można zapisać, powtórzone klucze w tabeli '%-.192s'"
+ por "Não pode gravar. Chave duplicada na tabela '%-.192s'"
+ rum "Nu pot sa scriu (can't write), cheie duplicata in tabela '%-.192s'"
+ rus "Ðевозможно произвеÑти запиÑÑŒ, дублирующийÑÑ ÐºÐ»ÑŽÑ‡ в таблице '%-.192s'"
+ serbian "Ne mogu da piÅ¡em poÅ¡to postoji duplirani kljuÄ u tabeli '%-.192s'"
+ slo "Nemôžem zapísaÅ¥, duplikát kľúÄa v tabuľke '%-.192s'"
+ spa "No puedo escribir, clave duplicada en la tabla '%-.192s'"
+ swe "Kan inte skriva, dubbel söknyckel i register '%-.192s'"
+ ukr "Ðе можу запиÑати, дублюючийÑÑ ÐºÐ»ÑŽÑ‡ в таблиці '%-.192s'"
+ER_ERROR_ON_CLOSE
+ cze "Chyba p-Bři zavírání '%-.192s' (chybový kód: %d)"
+ dan "Fejl ved lukning af '%-.192s' (Fejlkode: %d)"
+ nla "Fout bij het sluiten van '%-.192s' (Errcode: %d)"
+ eng "Error on close of '%-.192s' (errno: %d)"
+ est "Viga faili '%-.192s' sulgemisel (veakood: %d)"
+ fre "Erreur a la fermeture de '%-.192s' (Errcode: %d)"
+ ger "Fehler beim Schließen von '%-.192s' (Fehler: %d)"
+ greek "ΠαÏουσιάστηκε Ï€Ïόβλημα κλείνοντας το '%-.192s' (κωδικός λάθους: %d)"
+ hun "Hiba a(z) '%-.192s' zarasakor. (hibakod: %d)"
+ ita "Errore durante la chiusura di '%-.192s' (errno: %d)"
+ kor "'%-.192s'닫는 중 ì—러 (ì—러번호: %d)"
+ nor "Feil ved lukking av '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Feil ved lukking av '%-.192s' (Feilkode: %d)"
+ pol "Bł?d podczas zamykania '%-.192s' (Kod błędu: %d)"
+ por "Erro ao fechar '%-.192s' (erro no. %d)"
+ rum "Eroare inchizind '%-.192s' (errno: %d)"
+ rus "Ошибка при закрытии '%-.192s' (ошибка: %d)"
+ serbian "Greška pri zatvaranju '%-.192s' (errno: %d)"
+ slo "Chyba pri zatváraní '%-.192s' (chybový kód: %d)"
+ spa "Error en el cierre de '%-.192s' (Error: %d)"
+ swe "Fick fel vid stängning av '%-.192s' (Felkod: %d)"
+ ukr "Ðе можу закрити '%-.192s' (помилка: %d)"
+ER_ERROR_ON_READ
+ cze "Chyba p-BÅ™i Ätení souboru '%-.200s' (chybový kód: %d)"
+ dan "Fejl ved læsning af '%-.200s' (Fejlkode: %d)"
+ nla "Fout bij het lezen van file '%-.200s' (Errcode: %d)"
+ eng "Error reading file '%-.200s' (errno: %d)"
+ jps "'%-.200s' ファイルã®èª­ã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼ (errno: %d)",
+ est "Viga faili '%-.200s' lugemisel (veakood: %d)"
+ fre "Erreur en lecture du fichier '%-.200s' (Errcode: %d)"
+ ger "Fehler beim Lesen der Datei '%-.200s' (Fehler: %d)"
+ greek "ΠÏόβλημα κατά την ανάγνωση του αÏχείου '%-.200s' (κωδικός λάθους: %d)"
+ hun "Hiba a '%-.200s'file olvasasakor. (hibakod: %d)"
+ ita "Errore durante la lettura del file '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ファイルã®èª­ã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼ (errno: %d)"
+ kor "'%-.200s'í™”ì¼ ì½ê¸° ì—러 (ì—러번호: %d)"
+ nor "Feil ved lesing av '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Feil ved lesing av '%-.200s' (Feilkode: %d)"
+ pol "Bł?d podczas odczytu pliku '%-.200s' (Kod błędu: %d)"
+ por "Erro ao ler arquivo '%-.200s' (erro no. %d)"
+ rum "Eroare citind fisierul '%-.200s' (errno: %d)"
+ rus "Ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° '%-.200s' (ошибка: %d)"
+ serbian "GreÅ¡ka pri Äitanju file-a '%-.200s' (errno: %d)"
+ slo "Chyba pri Äítaní súboru '%-.200s' (chybový kód: %d)"
+ spa "Error leyendo el fichero '%-.200s' (Error: %d)"
+ swe "Fick fel vid läsning av '%-.200s' (Felkod %d)"
+ ukr "Ðе можу прочитати файл '%-.200s' (помилка: %d)"
+ER_ERROR_ON_RENAME
+ cze "Chyba p-Bři přejmenování '%-.210s' na '%-.210s' (chybový kód: %d)"
+ dan "Fejl ved omdøbning af '%-.210s' til '%-.210s' (Fejlkode: %d)"
+ nla "Fout bij het hernoemen van '%-.210s' naar '%-.210s' (Errcode: %d)"
+ eng "Error on rename of '%-.210s' to '%-.210s' (errno: %d)"
+ jps "'%-.210s' ã‚’ '%-.210s' ã« rename ã§ãã¾ã›ã‚“ (errno: %d)",
+ est "Viga faili '%-.210s' ümbernimetamisel '%-.210s'-ks (veakood: %d)"
+ fre "Erreur en renommant '%-.210s' en '%-.210s' (Errcode: %d)"
+ ger "Fehler beim Umbenennen von '%-.210s' in '%-.210s' (Fehler: %d)"
+ greek "ΠÏόβλημα κατά την μετονομασία του αÏχείου '%-.210s' to '%-.210s' (κωδικός λάθους: %d)"
+ hun "Hiba a '%-.210s' file atnevezesekor '%-.210s'. (hibakod: %d)"
+ ita "Errore durante la rinominazione da '%-.210s' a '%-.210s' (errno: %d)"
+ jpn "'%-.210s' ã‚’ '%-.210s' ã« rename ã§ãã¾ã›ã‚“ (errno: %d)"
+ kor "'%-.210s'를 '%-.210s'ë¡œ ì´ë¦„ 변경중 ì—러 (ì—러번호: %d)"
+ nor "Feil ved omdøping av '%-.210s' til '%-.210s' (Feilkode: %d)"
+ norwegian-ny "Feil ved omdøyping av '%-.210s' til '%-.210s' (Feilkode: %d)"
+ pol "Bł?d podczas zmieniania nazwy '%-.210s' na '%-.210s' (Kod błędu: %d)"
+ por "Erro ao renomear '%-.210s' para '%-.210s' (erro no. %d)"
+ rum "Eroare incercind sa renumesc '%-.210s' in '%-.210s' (errno: %d)"
+ rus "Ошибка при переименовании '%-.210s' в '%-.210s' (ошибка: %d)"
+ serbian "Greška pri promeni imena '%-.210s' na '%-.210s' (errno: %d)"
+ slo "Chyba pri premenovávaní '%-.210s' na '%-.210s' (chybový kód: %d)"
+ spa "Error en el renombrado de '%-.210s' a '%-.210s' (Error: %d)"
+ swe "Kan inte byta namn från '%-.210s' till '%-.210s' (Felkod: %d)"
+ ukr "Ðе можу перейменувати '%-.210s' у '%-.210s' (помилка: %d)"
+ER_ERROR_ON_WRITE
+ cze "Chyba p-Bři zápisu do souboru '%-.200s' (chybový kód: %d)"
+ dan "Fejl ved skriving av filen '%-.200s' (Fejlkode: %d)"
+ nla "Fout bij het wegschrijven van file '%-.200s' (Errcode: %d)"
+ eng "Error writing file '%-.200s' (errno: %d)"
+ jps "'%-.200s' ファイルを書ã事ãŒã§ãã¾ã›ã‚“ (errno: %d)",
+ est "Viga faili '%-.200s' kirjutamisel (veakood: %d)"
+ fre "Erreur d'écriture du fichier '%-.200s' (Errcode: %d)"
+ ger "Fehler beim Speichern der Datei '%-.200s' (Fehler: %d)"
+ greek "ΠÏόβλημα κατά την αποθήκευση του αÏχείου '%-.200s' (κωδικός λάθους: %d)"
+ hun "Hiba a '%-.200s' file irasakor. (hibakod: %d)"
+ ita "Errore durante la scrittura del file '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ファイルを書ã事ãŒã§ãã¾ã›ã‚“ (errno: %d)"
+ kor "'%-.200s'í™”ì¼ ê¸°ë¡ ì¤‘ ì—러 (ì—러번호: %d)"
+ nor "Feil ved skriving av fila '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Feil ved skriving av fila '%-.200s' (Feilkode: %d)"
+ pol "Bł?d podczas zapisywania pliku '%-.200s' (Kod błędu: %d)"
+ por "Erro ao gravar arquivo '%-.200s' (erro no. %d)"
+ rum "Eroare scriind fisierul '%-.200s' (errno: %d)"
+ rus "Ошибка запиÑи в файл '%-.200s' (ошибка: %d)"
+ serbian "Greška pri upisu '%-.200s' (errno: %d)"
+ slo "Chyba pri zápise do súboru '%-.200s' (chybový kód: %d)"
+ spa "Error escribiendo el archivo '%-.200s' (Error: %d)"
+ swe "Fick fel vid skrivning till '%-.200s' (Felkod %d)"
+ ukr "Ðе можу запиÑати файл '%-.200s' (помилка: %d)"
+ER_FILE_USED
+ cze "'%-.192s' je zam-BÄen proti zmÄ›nám"
+ dan "'%-.192s' er låst mod opdateringer"
+ nla "'%-.192s' is geblokeerd tegen veranderingen"
+ eng "'%-.192s' is locked against change"
+ jps "'%-.192s' ã¯ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™",
+ est "'%-.192s' on lukustatud muudatuste vastu"
+ fre "'%-.192s' est verrouillé contre les modifications"
+ ger "'%-.192s' ist für Änderungen gesperrt"
+ greek "'%-.192s' δεν επιτÏέπονται αλλαγές"
+ hun "'%-.192s' a valtoztatas ellen zarolva"
+ ita "'%-.192s' e` soggetto a lock contro i cambiamenti"
+ jpn "'%-.192s' ã¯ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™"
+ kor "'%-.192s'ê°€ 변경할 수 ì—†ë„ë¡ ìž ê²¨ìžˆì니다."
+ nor "'%-.192s' er låst mot oppdateringer"
+ norwegian-ny "'%-.192s' er låst mot oppdateringar"
+ pol "'%-.192s' jest zablokowany na wypadek zmian"
+ por "'%-.192s' está com travamento contra alterações"
+ rum "'%-.192s' este blocat pentry schimbari (loccked against change)"
+ rus "'%-.192s' заблокирован Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹"
+ serbian "'%-.192s' je zakljuÄan za upis"
+ slo "'%-.192s' je zamknutý proti zmenám"
+ spa "'%-.192s' esta bloqueado contra cambios"
+ swe "'%-.192s' är låst mot användning"
+ ukr "'%-.192s' заблокований на внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½"
+ER_FILSORT_ABORT
+ cze "T-Břídění přerušeno"
+ dan "Sortering afbrudt"
+ nla "Sorteren afgebroken"
+ eng "Sort aborted"
+ jps "Sort 中断",
+ est "Sorteerimine katkestatud"
+ fre "Tri alphabétique abandonné"
+ ger "Sortiervorgang abgebrochen"
+ greek "Η διαδικασία ταξινόμισης ακυÏώθηκε"
+ hun "Sikertelen rendezes"
+ ita "Operazione di ordinamento abbandonata"
+ jpn "Sort 中断"
+ kor "소트가 중단ë˜ì—ˆìŠµë‹ˆë‹¤."
+ nor "Sortering avbrutt"
+ norwegian-ny "Sortering avbrote"
+ pol "Sortowanie przerwane"
+ por "Ordenação abortada"
+ rum "Sortare intrerupta"
+ rus "Сортировка прервана"
+ serbian "Sortiranje je prekinuto"
+ slo "Triedenie prerušené"
+ spa "Ordeancion cancelada"
+ swe "Sorteringen avbruten"
+ ukr "Ð¡Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÑ€Ð²Ð°Ð½Ð¾"
+ER_FORM_NOT_FOUND
+ cze "Pohled '%-.192s' pro '%-.192s' neexistuje"
+ dan "View '%-.192s' eksisterer ikke for '%-.192s'"
+ nla "View '%-.192s' bestaat niet voor '%-.192s'"
+ eng "View '%-.192s' doesn't exist for '%-.192s'"
+ jps "View '%-.192s' ㌠'%-.192s' ã«å®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“",
+ est "Vaade '%-.192s' ei eksisteeri '%-.192s' jaoks"
+ fre "La vue (View) '%-.192s' n'existe pas pour '%-.192s'"
+ ger "View '%-.192s' existiert für '%-.192s' nicht"
+ greek "Το View '%-.192s' δεν υπάÏχει για '%-.192s'"
+ hun "A(z) '%-.192s' nezet nem letezik a(z) '%-.192s'-hoz"
+ ita "La view '%-.192s' non esiste per '%-.192s'"
+ jpn "View '%-.192s' ㌠'%-.192s' ã«å®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+ kor "ë·° '%-.192s'ê°€ '%-.192s'ì—서는 존재하지 ì•Šì니다."
+ nor "View '%-.192s' eksisterer ikke for '%-.192s'"
+ norwegian-ny "View '%-.192s' eksisterar ikkje for '%-.192s'"
+ pol "Widok '%-.192s' nie istnieje dla '%-.192s'"
+ por "Visão '%-.192s' não existe para '%-.192s'"
+ rum "View '%-.192s' nu exista pentru '%-.192s'"
+ rus "ПредÑтавление '%-.192s' не ÑущеÑтвует Ð´Ð»Ñ '%-.192s'"
+ serbian "View '%-.192s' ne postoji za '%-.192s'"
+ slo "Pohľad '%-.192s' neexistuje pre '%-.192s'"
+ spa "La vista '%-.192s' no existe para '%-.192s'"
+ swe "Formulär '%-.192s' finns inte i '%-.192s'"
+ ukr "ВиглÑд '%-.192s' не Ñ–Ñнує Ð´Ð»Ñ '%-.192s'"
+ER_GET_ERRNO
+ cze "Obsluha tabulky vr-Bátila chybu %d"
+ dan "Modtog fejl %d fra tabel håndteringen"
+ nla "Fout %d van tabel handler"
+ eng "Got error %d from storage engine"
+ est "Tabeli handler tagastas vea %d"
+ fre "Reçu l'erreur %d du handler de la table"
+ ger "Fehler %d (Speicher-Engine)"
+ greek "Ελήφθη μήνυμα λάθους %d από τον χειÏιστή πίνακα (table handler)"
+ hun "%d hibajelzes a tablakezelotol"
+ ita "Rilevato l'errore %d dal gestore delle tabelle"
+ jpn "Got error %d from table handler"
+ kor "í…Œì´ë¸” handlerì—ì„œ %d ì—러가 ë°œìƒ í•˜ì˜€ìŠµë‹ˆë‹¤."
+ nor "Mottok feil %d fra tabell håndterer"
+ norwegian-ny "Mottok feil %d fra tabell handterar"
+ pol "Otrzymano bł?d %d z obsługi tabeli"
+ por "Obteve erro %d no manipulador de tabelas"
+ rum "Eroarea %d obtinuta din handlerul tabelei"
+ rus "Получена ошибка %d от обработчика таблиц"
+ serbian "Handler tabela je vratio grešku %d"
+ slo "Obsluha tabuľky vrátila chybu %d"
+ spa "Error %d desde el manejador de la tabla"
+ swe "Fick felkod %d från databashanteraren"
+ ukr "Отримано помилку %d від деÑкриптора таблиці"
+ER_ILLEGAL_HA
+ cze "Obsluha tabulky '%-.192s' nem-Bá tento parametr"
+ dan "Denne mulighed eksisterer ikke for tabeltypen '%-.192s'"
+ nla "Tabel handler voor '%-.192s' heeft deze optie niet"
+ eng "Table storage engine for '%-.192s' doesn't have this option"
+ est "Tabeli '%-.192s' handler ei toeta antud operatsiooni"
+ fre "Le handler de la table '%-.192s' n'a pas cette option"
+ ger "Diese Option gibt es nicht (Speicher-Engine für '%-.192s')"
+ greek "Ο χειÏιστής πίνακα (table handler) για '%-.192s' δεν διαθέτει αυτή την επιλογή"
+ hun "A(z) '%-.192s' tablakezelonek nincs ilyen opcioja"
+ ita "Il gestore delle tabelle per '%-.192s' non ha questa opzione"
+ jpn "Table handler for '%-.192s' doesn't have this option"
+ kor "'%-.192s'ì˜ í…Œì´ë¸” handler는 ì´ëŸ¬í•œ ì˜µì…˜ì„ ì œê³µí•˜ì§€ ì•Šì니다."
+ nor "Tabell håndtereren for '%-.192s' har ikke denne muligheten"
+ norwegian-ny "Tabell håndteraren for '%-.192s' har ikkje denne moglegheita"
+ pol "Obsługa tabeli '%-.192s' nie posiada tej opcji"
+ por "Manipulador de tabela para '%-.192s' não tem esta opção"
+ rum "Handlerul tabelei pentru '%-.192s' nu are aceasta optiune"
+ rus "Обработчик таблицы '%-.192s' не поддерживает Ñту возможноÑÑ‚ÑŒ"
+ serbian "Handler tabela za '%-.192s' nema ovu opciju"
+ slo "Obsluha tabuľky '%-.192s' nemá tento parameter"
+ spa "El manejador de la tabla de '%-.192s' no tiene esta opcion"
+ swe "Tabellhanteraren for tabell '%-.192s' stödjer ej detta"
+ ukr "ДеÑкриптор таблиці '%-.192s' не має цієї влаÑтивоÑÑ‚Ñ–"
+ER_KEY_NOT_FOUND
+ cze "Nemohu naj-Bít záznam v '%-.192s'"
+ dan "Kan ikke finde posten i '%-.192s'"
+ nla "Kan record niet vinden in '%-.192s'"
+ eng "Can't find record in '%-.192s'"
+ jps "'%-.192s'ã®ãªã‹ã«ãƒ¬ã‚³ãƒ¼ãƒ‰ãŒè¦‹ä»˜ã‹ã‚Šã¾ã›ã‚“",
+ est "Ei suuda leida kirjet '%-.192s'-s"
+ fre "Ne peut trouver l'enregistrement dans '%-.192s'"
+ ger "Kann Datensatz in '%-.192s' nicht finden"
+ greek "ΑδÏνατη η ανεÏÏεση εγγÏαφής στο '%-.192s'"
+ hun "Nem talalhato a rekord '%-.192s'-ben"
+ ita "Impossibile trovare il record in '%-.192s'"
+ jpn "'%-.192s'ã®ãªã‹ã«ãƒ¬ã‚³ãƒ¼ãƒ‰ãŒè¦‹ä»˜ã‹ã‚Šã¾ã›ã‚“"
+ kor "'%-.192s'ì—ì„œ 레코드를 ì°¾ì„ ìˆ˜ ì—†ì니다."
+ nor "Kan ikke finne posten i '%-.192s'"
+ norwegian-ny "Kan ikkje finne posten i '%-.192s'"
+ pol "Nie można znaleĽć rekordu w '%-.192s'"
+ por "Não pode encontrar registro em '%-.192s'"
+ rum "Nu pot sa gasesc recordul in '%-.192s'"
+ rus "Ðевозможно найти запиÑÑŒ в '%-.192s'"
+ serbian "Ne mogu da pronađem slog u '%-.192s'"
+ slo "Nemôžem nájsť záznam v '%-.192s'"
+ spa "No puedo encontrar el registro en '%-.192s'"
+ swe "Hittar inte posten '%-.192s'"
+ ukr "Ðе можу запиÑати у '%-.192s'"
+ER_NOT_FORM_FILE
+ cze "Nespr-Bávná informace v souboru '%-.200s'"
+ dan "Forkert indhold i: '%-.200s'"
+ nla "Verkeerde info in file: '%-.200s'"
+ eng "Incorrect information in file: '%-.200s'"
+ jps "ファイル '%-.200s' ã® info ãŒé–“é•ã£ã¦ã„るよã†ã§ã™",
+ est "Vigane informatsioon failis '%-.200s'"
+ fre "Information erronnée dans le fichier: '%-.200s'"
+ ger "Falsche Information in Datei '%-.200s'"
+ greek "Λάθος πληÏοφοÏίες στο αÏχείο: '%-.200s'"
+ hun "Ervenytelen info a file-ban: '%-.200s'"
+ ita "Informazione errata nel file: '%-.200s'"
+ jpn "ファイル '%-.200s' ã® info ãŒé–“é•ã£ã¦ã„るよã†ã§ã™"
+ kor "í™”ì¼ì˜ 부정확한 ì •ë³´: '%-.200s'"
+ nor "Feil informasjon i filen: '%-.200s'"
+ norwegian-ny "Feil informasjon i fila: '%-.200s'"
+ pol "Niewła?ciwa informacja w pliku: '%-.200s'"
+ por "Informação incorreta no arquivo '%-.200s'"
+ rum "Informatie incorecta in fisierul: '%-.200s'"
+ rus "ÐÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð² файле '%-.200s'"
+ serbian "Pogrešna informacija u file-u: '%-.200s'"
+ slo "Nesprávna informácia v súbore: '%-.200s'"
+ spa "Informacion erronea en el archivo: '%-.200s'"
+ swe "Felaktig fil: '%-.200s'"
+ ukr "Хибна Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ñƒ файлі: '%-.200s'"
+ER_NOT_KEYFILE
+ cze "Nespr-Bávný klÃ­Ä pro tabulku '%-.200s'; pokuste se ho opravit"
+ dan "Fejl i indeksfilen til tabellen '%-.200s'; prøv at reparere den"
+ nla "Verkeerde zoeksleutel file voor tabel: '%-.200s'; probeer het te repareren"
+ eng "Incorrect key file for table '%-.200s'; try to repair it"
+ jps "'%-.200s' テーブル㮠key file ãŒé–“é•ã£ã¦ã„るよã†ã§ã™. 修復をã—ã¦ãã ã•ã„",
+ est "Tabeli '%-.200s' võtmefail on vigane; proovi seda parandada"
+ fre "Index corrompu dans la table: '%-.200s'; essayez de le réparer"
+ ger "Fehlerhafte Index-Datei für Tabelle '%-.200s'; versuche zu reparieren"
+ greek "Λάθος αÏχείο ταξινόμισης (key file) για τον πίνακα: '%-.200s'; ΠαÏακαλώ, διοÏθώστε το!"
+ hun "Ervenytelen kulcsfile a tablahoz: '%-.200s'; probalja kijavitani!"
+ ita "File chiave errato per la tabella : '%-.200s'; prova a riparalo"
+ jpn "'%-.200s' テーブル㮠key file ãŒé–“é•ã£ã¦ã„るよã†ã§ã™. 修復をã—ã¦ãã ã•ã„"
+ kor "'%-.200s' í…Œì´ë¸”ì˜ ë¶€ì •í™•í•œ 키 존재. 수정하시오!"
+ nor "Tabellen '%-.200s' har feil i nøkkelfilen; forsøk å reparer den"
+ norwegian-ny "Tabellen '%-.200s' har feil i nykkelfila; prøv å reparere den"
+ pol "Niewła?ciwy plik kluczy dla tabeli: '%-.200s'; spróbuj go naprawić"
+ por "Arquivo de índice incorreto para tabela '%-.200s'; tente repará-lo"
+ rum "Cheia fisierului incorecta pentru tabela: '%-.200s'; incearca s-o repari"
+ rus "Ðекорректный индекÑный файл Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹: '%-.200s'. Попробуйте воÑÑтановить его"
+ serbian "Pogrešan key file za tabelu: '%-.200s'; probajte da ga ispravite"
+ slo "Nesprávny kÄ¾ÃºÄ pre tabuľku '%-.200s'; pokúste sa ho opraviÅ¥"
+ spa "Clave de archivo erronea para la tabla: '%-.200s'; intente repararlo"
+ swe "Fatalt fel vid hantering av register '%-.200s'; kör en reparation"
+ ukr "Хибний файл ключей Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ–: '%-.200s'; Спробуйте його відновити"
+ER_OLD_KEYFILE
+ cze "Star-Bý klíÄový soubor pro '%-.192s'; opravte ho."
+ dan "Gammel indeksfil for tabellen '%-.192s'; reparer den"
+ nla "Oude zoeksleutel file voor tabel '%-.192s'; repareer het!"
+ eng "Old key file for table '%-.192s'; repair it!"
+ jps "'%-.192s' テーブルã¯å¤ã„å½¢å¼ã® key file ã®ã‚ˆã†ã§ã™; 修復をã—ã¦ãã ã•ã„",
+ est "Tabeli '%-.192s' võtmefail on aegunud; paranda see!"
+ fre "Vieux fichier d'index pour la table '%-.192s'; réparez le!"
+ ger "Alte Index-Datei für Tabelle '%-.192s'. Bitte reparieren"
+ greek "Παλαιό αÏχείο ταξινόμισης (key file) για τον πίνακα '%-.192s'; ΠαÏακαλώ, διοÏθώστε το!"
+ hun "Regi kulcsfile a '%-.192s'tablahoz; probalja kijavitani!"
+ ita "File chiave vecchio per la tabella '%-.192s'; riparalo!"
+ jpn "'%-.192s' テーブルã¯å¤ã„å½¢å¼ã® key file ã®ã‚ˆã†ã§ã™; 修復をã—ã¦ãã ã•ã„"
+ kor "'%-.192s' í…Œì´ë¸”ì˜ ì´ì „ë²„ì ¼ì˜ í‚¤ 존재. 수정하시오!"
+ nor "Gammel nøkkelfil for tabellen '%-.192s'; reparer den!"
+ norwegian-ny "Gammel nykkelfil for tabellen '%-.192s'; reparer den!"
+ pol "Plik kluczy dla tabeli '%-.192s' jest starego typu; napraw go!"
+ por "Arquivo de índice desatualizado para tabela '%-.192s'; repare-o!"
+ rum "Cheia fisierului e veche pentru tabela '%-.192s'; repar-o!"
+ rus "Старый индекÑный файл Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ '%-.192s'; отремонтируйте его!"
+ serbian "Zastareo key file za tabelu '%-.192s'; ispravite ga"
+ slo "Starý kľúÄový súbor pre '%-.192s'; opravte ho!"
+ spa "Clave de archivo antigua para la tabla '%-.192s'; reparelo!"
+ swe "Gammal nyckelfil '%-.192s'; reparera registret"
+ ukr "Старий файл ключей Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– '%-.192s'; Відновіть його!"
+ER_OPEN_AS_READONLY
+ cze "'%-.192s' je jen pro -BÄtení"
+ dan "'%-.192s' er skrivebeskyttet"
+ nla "'%-.192s' is alleen leesbaar"
+ eng "Table '%-.192s' is read only"
+ jps "'%-.192s' ã¯èª­ã¿è¾¼ã¿å°‚用ã§ã™",
+ est "Tabel '%-.192s' on ainult lugemiseks"
+ fre "'%-.192s' est en lecture seulement"
+ ger "Tabelle '%-.192s' ist nur lesbar"
+ greek "'%-.192s' επιτÏέπεται μόνο η ανάγνωση"
+ hun "'%-.192s' irasvedett"
+ ita "'%-.192s' e` di sola lettura"
+ jpn "'%-.192s' ã¯èª­ã¿è¾¼ã¿å°‚用ã§ã™"
+ kor "í…Œì´ë¸” '%-.192s'는 ì½ê¸°ì „ìš© 입니다."
+ nor "'%-.192s' er skrivebeskyttet"
+ norwegian-ny "'%-.192s' er skrivetryggja"
+ pol "'%-.192s' jest tylko do odczytu"
+ por "Tabela '%-.192s' é somente para leitura"
+ rum "Tabela '%-.192s' e read-only"
+ rus "Таблица '%-.192s' предназначена только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ"
+ serbian "Tabelu '%-.192s' je dozvoljeno samo Äitati"
+ slo "'%-.192s' is ÄítaÅ¥ only"
+ spa "'%-.192s' es de solo lectura"
+ swe "'%-.192s' är skyddad mot förändring"
+ ukr "Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ '%-.192s' тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ"
+ER_OUTOFMEMORY HY001 S1001
+ cze "M-Bálo paměti. Přestartujte daemona a zkuste znovu (je potřeba %d bytů)"
+ dan "Ikke mere hukommelse. Genstart serveren og prøv igen (mangler %d bytes)"
+ nla "Geen geheugen meer. Herstart server en probeer opnieuw (%d bytes nodig)"
+ eng "Out of memory; restart server and try again (needed %d bytes)"
+ jps "Out of memory. デーモンをリスタートã—ã¦ã¿ã¦ãã ã•ã„ (%d bytes å¿…è¦)",
+ est "Mälu sai otsa. Proovi MySQL uuesti käivitada (puudu jäi %d baiti)"
+ fre "Manque de mémoire. Redémarrez le démon et ré-essayez (%d octets nécessaires)"
+ ger "Kein Speicher vorhanden (%d Bytes benötigt). Bitte Server neu starten"
+ greek "Δεν υπάÏχει διαθέσιμη μνήμη. ΠÏοσπαθήστε πάλι, επανεκινώντας τη διαδικασία (demon) (χÏειάζονται %d bytes)"
+ hun "Nincs eleg memoria. Inditsa ujra a demont, es probalja ismet. (%d byte szukseges.)"
+ ita "Memoria esaurita. Fai ripartire il demone e riprova (richiesti %d bytes)"
+ jpn "Out of memory. デーモンをリスタートã—ã¦ã¿ã¦ãã ã•ã„ (%d bytes å¿…è¦)"
+ kor "Out of memory. ë°ëª¬ì„ 재 실행 후 다시 시작하시오 (needed %d bytes)"
+ nor "Ikke mer minne. Star på nytt tjenesten og prøv igjen (trengte %d byter)"
+ norwegian-ny "Ikkje meir minne. Start på nytt tenesten og prøv igjen (trengte %d bytar)"
+ pol "Zbyt mało pamięci. Uruchom ponownie demona i spróbuj ponownie (potrzeba %d bajtów)"
+ por "Sem memória. Reinicie o programa e tente novamente (necessita de %d bytes)"
+ rum "Out of memory. Porneste daemon-ul din nou si incearca inca o data (e nevoie de %d bytes)"
+ rus "ÐедоÑтаточно памÑти. ПерезапуÑтите Ñервер и попробуйте еще раз (нужно %d байт)"
+ serbian "Nema memorije. Restartujte MySQL server i probajte ponovo (potrebno je %d byte-ova)"
+ slo "Málo pamäti. Reštartujte daemona a skúste znova (je potrebných %d bytov)"
+ spa "Memoria insuficiente. Reinicie el demonio e intentelo otra vez (necesita %d bytes)"
+ swe "Oväntat slut på minnet, starta om programmet och försök på nytt (Behövde %d bytes)"
+ ukr "Брак пам'ÑÑ‚Ñ–. РеÑтартуйте Ñервер та Ñпробуйте знову (потрібно %d байтів)"
+ER_OUT_OF_SORTMEMORY HY001 S1001
+ cze "M-Bálo paměti pro třídění. Zvyšte velikost třídícího bufferu"
+ dan "Ikke mere sorteringshukommelse. Øg sorteringshukommelse (sort buffer size) for serveren"
+ nla "Geen geheugen om te sorteren. Verhoog de server sort buffer size"
+ eng "Out of sort memory; increase server sort buffer size"
+ jps "Out of sort memory. sort buffer size ãŒè¶³ã‚Šãªã„よã†ã§ã™.",
+ est "Mälu sai sorteerimisel otsa. Suurenda MySQL-i sorteerimispuhvrit"
+ fre "Manque de mémoire pour le tri. Augmentez-la."
+ ger "Kein Speicher zum Sortieren vorhanden. sort_buffer_size sollte im Server erhöht werden"
+ greek "Δεν υπάÏχει διαθέσιμη μνήμη για ταξινόμιση. Αυξήστε το sort buffer size για τη διαδικασία (demon)"
+ hun "Nincs eleg memoria a rendezeshez. Novelje a rendezo demon puffermeretet"
+ ita "Memoria per gli ordinamenti esaurita. Incrementare il 'sort_buffer' al demone"
+ jpn "Out of sort memory. sort buffer size ãŒè¶³ã‚Šãªã„よã†ã§ã™."
+ kor "Out of sort memory. daemon sort bufferì˜ í¬ê¸°ë¥¼ ì¦ê°€ì‹œí‚¤ì„¸ìš”"
+ nor "Ikke mer sorteringsminne. Øk sorteringsminnet (sort buffer size) for tjenesten"
+ norwegian-ny "Ikkje meir sorteringsminne. Auk sorteringsminnet (sorteringsbffer storleik) for tenesten"
+ pol "Zbyt mało pamięci dla sortowania. Zwiększ wielko?ć bufora demona dla sortowania"
+ por "Sem memória para ordenação. Aumente tamanho do 'buffer' de ordenação"
+ rum "Out of memory pentru sortare. Largeste marimea buffer-ului pentru sortare in daemon (sort buffer size)"
+ rus "ÐедоÑтаточно памÑти Ð´Ð»Ñ Ñортировки. Увеличьте размер буфера Ñортировки на Ñервере"
+ serbian "Nema memorije za sortiranje. Povećajte veliÄinu sort buffer-a MySQL server-u"
+ slo "Málo pamäti pre triedenie, zvýšte veľkosť triediaceho bufferu"
+ spa "Memoria de ordenacion insuficiente. Incremente el tamano del buffer de ordenacion"
+ swe "Sorteringsbufferten räcker inte till. Kontrollera startparametrarna"
+ ukr "Брак пам'ÑÑ‚Ñ– Ð´Ð»Ñ ÑортуваннÑ. Треба збільшити розмір буфера ÑÐ¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñƒ Ñервера"
+ER_UNEXPECTED_EOF
+ cze "Neo-BÄekávaný konec souboru pÅ™i Ätení '%-.192s' (chybový kód: %d)"
+ dan "Uventet afslutning på fil (eof) ved læsning af filen '%-.192s' (Fejlkode: %d)"
+ nla "Onverwachte eof gevonden tijdens het lezen van file '%-.192s' (Errcode: %d)"
+ eng "Unexpected EOF found when reading file '%-.192s' (errno: %d)"
+ jps "'%-.192s' ファイルを読ã¿è¾¼ã¿ä¸­ã« EOF ãŒäºˆæœŸã›ã¬æ‰€ã§ç¾ã‚Œã¾ã—ãŸ. (errno: %d)",
+ est "Ootamatu faililõpumärgend faili '%-.192s' lugemisel (veakood: %d)"
+ fre "Fin de fichier inattendue en lisant '%-.192s' (Errcode: %d)"
+ ger "Unerwartetes Ende beim Lesen der Datei '%-.192s' (Fehler: %d)"
+ greek "Κατά τη διάÏκεια της ανάγνωσης, βÏέθηκε απÏοσδόκητα το τέλος του αÏχείου '%-.192s' (κωδικός λάθους: %d)"
+ hun "Varatlan filevege-jel a '%-.192s'olvasasakor. (hibakod: %d)"
+ ita "Fine del file inaspettata durante la lettura del file '%-.192s' (errno: %d)"
+ jpn "'%-.192s' ファイルを読ã¿è¾¼ã¿ä¸­ã« EOF ãŒäºˆæœŸã›ã¬æ‰€ã§ç¾ã‚Œã¾ã—ãŸ. (errno: %d)"
+ kor "'%-.192s' í™”ì¼ì„ ì½ëŠ” ë„중 ìž˜ëª»ëœ eofì„ ë°œê²¬ (ì—러번호: %d)"
+ nor "Uventet slutt på fil (eof) ved lesing av filen '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Uventa slutt på fil (eof) ved lesing av fila '%-.192s' (Feilkode: %d)"
+ pol "Nieoczekiwany 'eof' napotkany podczas czytania z pliku '%-.192s' (Kod błędu: %d)"
+ por "Encontrado fim de arquivo inesperado ao ler arquivo '%-.192s' (erro no. %d)"
+ rum "Sfirsit de fisier neasteptat in citirea fisierului '%-.192s' (errno: %d)"
+ rus "Ðеожиданный конец файла '%-.192s' (ошибка: %d)"
+ serbian "NeoÄekivani kraj pri Äitanju file-a '%-.192s' (errno: %d)"
+ slo "NeoÄakávaný koniec súboru pri Äítaní '%-.192s' (chybový kód: %d)"
+ spa "Inesperado fin de ficheroU mientras leiamos el archivo '%-.192s' (Error: %d)"
+ swe "Oväntat filslut vid läsning från '%-.192s' (Felkod: %d)"
+ ukr "Хибний кінець файлу '%-.192s' (помилка: %d)"
+ER_CON_COUNT_ERROR 08004
+ cze "P-Bříliš mnoho spojení"
+ dan "For mange forbindelser (connections)"
+ nla "Te veel verbindingen"
+ eng "Too many connections"
+ jps "接続ãŒå¤šã™ãŽã¾ã™",
+ est "Liiga palju samaaegseid ühendusi"
+ fre "Trop de connexions"
+ ger "Zu viele Verbindungen"
+ greek "ΥπάÏχουν πολλές συνδέσεις..."
+ hun "Tul sok kapcsolat"
+ ita "Troppe connessioni"
+ jpn "接続ãŒå¤šã™ãŽã¾ã™"
+ kor "너무 ë§Žì€ ì—°ê²°... max_connectionì„ ì¦ê°€ 시키시오..."
+ nor "For mange tilkoblinger (connections)"
+ norwegian-ny "For mange tilkoplingar (connections)"
+ pol "Zbyt wiele poł?czeń"
+ por "Excesso de conexões"
+ rum "Prea multe conectiuni"
+ rus "Слишком много Ñоединений"
+ serbian "Previše konekcija"
+ slo "Príliš mnoho spojení"
+ spa "Demasiadas conexiones"
+ swe "För många anslutningar"
+ ukr "Забагато з'єднань"
+ER_OUT_OF_RESOURCES
+ cze "M-Bálo prostoru/paměti pro thread"
+ dan "Udgået for tråde/hukommelse"
+ nla "Geen thread geheugen meer; controleer of mysqld of andere processen al het beschikbare geheugen gebruikt. Zo niet, dan moet u wellicht 'ulimit' gebruiken om mysqld toe te laten meer geheugen te benutten, of u kunt extra swap ruimte toevoegen"
+ eng "Out of memory; check if mysqld or some other process uses all available memory; if not, you may have to use 'ulimit' to allow mysqld to use more memory or you can add more swap space"
+ jps "Out of memory; mysqld ã‹ãã®ä»–ã®ãƒ—ロセスãŒãƒ¡ãƒ¢ãƒªãƒ¼ã‚’å…¨ã¦ä½¿ã£ã¦ã„ã‚‹ã‹ç¢ºèªã—ã¦ãã ã•ã„. メモリーを使ã„切ã£ã¦ã„ãªã„å ´åˆã€'ulimit' を設定ã—㦠mysqld ã®ãƒ¡ãƒ¢ãƒªãƒ¼ä½¿ç”¨é™ç•Œé‡ã‚’多ãã™ã‚‹ã‹ã€swap space を増やã—ã¦ã¿ã¦ãã ã•ã„",
+ est "Mälu sai otsa. Võimalik, et aitab swap-i lisamine või käsu 'ulimit' abil MySQL-le rohkema mälu kasutamise lubamine"
+ fre "Manque de 'threads'/mémoire"
+ ger "Kein Speicher mehr vorhanden. Prüfen Sie, ob mysqld oder ein anderer Prozess den gesamten Speicher verbraucht. Wenn nicht, sollten Sie mit 'ulimit' dafür sorgen, dass mysqld mehr Speicher benutzen darf, oder mehr Swap-Speicher einrichten"
+ greek "ΠÏόβλημα με τη διαθέσιμη μνήμη (Out of thread space/memory)"
+ hun "Elfogyott a thread-memoria"
+ ita "Fine dello spazio/memoria per i thread"
+ jpn "Out of memory; mysqld ã‹ãã®ä»–ã®ãƒ—ロセスãŒãƒ¡ãƒ¢ãƒªãƒ¼ã‚’å…¨ã¦ä½¿ã£ã¦ã„ã‚‹ã‹ç¢ºèªã—ã¦ãã ã•ã„. メモリーを使ã„切ã£ã¦ã„ãªã„å ´åˆã€'ulimit' を設定ã—㦠mysqld ã®ãƒ¡ãƒ¢ãƒªãƒ¼ä½¿ç”¨é™ç•Œé‡ã‚’多ãã™ã‚‹ã‹ã€swap space を増やã—ã¦ã¿ã¦ãã ã•ã„"
+# This message failed to convert from euc-kr, skipped
+ nor "Tomt for tråd plass/minne"
+ norwegian-ny "Tomt for tråd plass/minne"
+ pol "Zbyt mało miejsca/pamięci dla w?tku"
+ por "Sem memória. Verifique se o mysqld ou algum outro processo está usando toda memória disponível. Se não, você pode ter que usar 'ulimit' para permitir ao mysqld usar mais memória ou você pode adicionar mais área de 'swap'"
+ rum "Out of memory; Verifica daca mysqld sau vreun alt proces foloseste toate memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui mysqld sa foloseasca mai multa memorie ori adauga mai mult spatiu pentru swap (swap space)"
+ rus "ÐедоÑтаточно памÑти; удоÑтоверьтеÑÑŒ, что mysqld или какой-либо другой процеÑÑ Ð½Ðµ занимает вÑÑŽ доÑтупную памÑÑ‚ÑŒ. ЕÑли нет, то вы можете иÑпользовать ulimit, чтобы выделить Ð´Ð»Ñ mysqld больше памÑти, или увеличить объем файла подкачки"
+ serbian "Nema memorije; Proverite da li MySQL server ili neki drugi proces koristi svu slobodnu memoriju. (UNIX: Ako ne, probajte da upotrebite 'ulimit' komandu da biste dozvolili daemon-u da koristi više memorije ili probajte da dodate više swap memorije)"
+ slo "Málo miesta-pamäti pre vlákno"
+ spa "Memoria/espacio de tranpaso insuficiente"
+ swe "Fick slut på minnet. Kontrollera om mysqld eller någon annan process använder allt tillgängligt minne. Om inte, försök använda 'ulimit' eller allokera mera swap"
+ ukr "Брак пам'ÑÑ‚Ñ–; Перевірте чи mysqld або ÑкіÑÑŒ інші процеÑи викориÑтовують уÑÑŽ доÑтупну пам'ÑÑ‚ÑŒ. Як ні, то ви можете ÑкориÑтатиÑÑ 'ulimit', аби дозволити mysqld викориÑтовувати більше пам'ÑÑ‚Ñ– або ви можете додати більше міÑÑ†Ñ Ð¿Ñ–Ð´ Ñвап"
+ER_BAD_HOST_ERROR 08S01
+ cze "Nemohu zjistit jm-Béno stroje pro Vaši adresu"
+ dan "Kan ikke få værtsnavn for din adresse"
+ nla "Kan de hostname niet krijgen van uw adres"
+ eng "Can't get hostname for your address"
+ jps "ãã® address ã® hostname ãŒå¼•ã‘ã¾ã›ã‚“.",
+ est "Ei suuda lahendada IP aadressi masina nimeks"
+ fre "Ne peut obtenir de hostname pour votre adresse"
+ ger "Kann Hostnamen für diese Adresse nicht erhalten"
+ greek "Δεν έγινε γνωστό το hostname για την address σας"
+ hun "A gepnev nem allapithato meg a cimbol"
+ ita "Impossibile risalire al nome dell'host dall'indirizzo (risoluzione inversa)"
+ jpn "ãã® address ã® hostname ãŒå¼•ã‘ã¾ã›ã‚“."
+ kor "ë‹¹ì‹ ì˜ ì»´í“¨í„°ì˜ í˜¸ìŠ¤íŠ¸ì´ë¦„ì„ ì–»ì„ ìˆ˜ ì—†ì니다."
+ nor "Kan ikke få tak i vertsnavn for din adresse"
+ norwegian-ny "Kan ikkje få tak i vertsnavn for di adresse"
+ pol "Nie można otrzymać nazwy hosta dla twojego adresu"
+ por "Não pode obter nome do 'host' para seu endereço"
+ rum "Nu pot sa obtin hostname-ul adresei tale"
+ rus "Ðевозможно получить Ð¸Ð¼Ñ Ñ…Ð¾Ñта Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ адреÑа"
+ serbian "Ne mogu da dobijem ime host-a za vašu IP adresu"
+ slo "Nemôžem zistiť meno hostiteľa pre vašu adresu"
+ spa "No puedo obtener el nombre de maquina de tu direccion"
+ swe "Kan inte hitta 'hostname' för din adress"
+ ukr "Ðе можу визначити ім'Ñ Ñ…Ð¾Ñту Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ñ— адреÑи"
+ER_HANDSHAKE_ERROR 08S01
+ cze "Chyba p-Bři ustavování spojení"
+ dan "Forkert håndtryk (handshake)"
+ nla "Verkeerde handshake"
+ eng "Bad handshake"
+ est "Väär handshake"
+ fre "Mauvais 'handshake'"
+ ger "Ungültiger Handshake"
+ greek "Η αναγνώÏιση (handshake) δεν έγινε σωστά"
+ hun "A kapcsolatfelvetel nem sikerult (Bad handshake)"
+ ita "Negoziazione impossibile"
+ nor "Feil håndtrykk (handshake)"
+ norwegian-ny "Feil handtrykk (handshake)"
+ pol "ZÅ‚y uchwyt(handshake)"
+ por "Negociação de acesso falhou"
+ rum "Prost inceput de conectie (bad handshake)"
+ rus "Ðекорректное приветÑтвие"
+ serbian "LoÅ¡ poÄetak komunikacije (handshake)"
+ slo "Chyba pri nadväzovaní spojenia"
+ spa "Protocolo erroneo"
+ swe "Fel vid initiering av kommunikationen med klienten"
+ ukr "Ðевірна уÑтановка зв'Ñзку"
+ER_DBACCESS_DENIED_ERROR 42000
+ cze "P-Břístup pro uživatele '%-.48s'@'%-.64s' k databázi '%-.192s' není povolen"
+ dan "Adgang nægtet bruger: '%-.48s'@'%-.64s' til databasen '%-.192s'"
+ nla "Toegang geweigerd voor gebruiker: '%-.48s'@'%-.64s' naar database '%-.192s'"
+ eng "Access denied for user '%-.48s'@'%-.64s' to database '%-.192s'"
+ jps "ユーザー '%-.48s'@'%-.64s' ã® '%-.192s' データベースã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’æ‹’å¦ã—ã¾ã™",
+ est "Ligipääs keelatud kasutajale '%-.48s'@'%-.64s' andmebaasile '%-.192s'"
+ fre "Accès refusé pour l'utilisateur: '%-.48s'@'@%-.64s'. Base '%-.192s'"
+ ger "Benutzer '%-.48s'@'%-.64s' hat keine Zugriffsberechtigung für Datenbank '%-.192s'"
+ greek "Δεν επιτέÏεται η Ï€Ïόσβαση στο χÏήστη: '%-.48s'@'%-.64s' στη βάση δεδομένων '%-.192s'"
+ hun "A(z) '%-.48s'@'%-.64s' felhasznalo szamara tiltott eleres az '%-.192s' adabazishoz."
+ ita "Accesso non consentito per l'utente: '%-.48s'@'%-.64s' al database '%-.192s'"
+ jpn "ユーザー '%-.48s'@'%-.64s' ã® '%-.192s' データベースã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’æ‹’å¦ã—ã¾ã™"
+ kor "'%-.48s'@'%-.64s' 사용ìžëŠ” '%-.192s' ë°ì´íƒ€ë² ì´ìŠ¤ì— ì ‘ê·¼ì´ ê±°ë¶€ ë˜ì—ˆìŠµë‹ˆë‹¤."
+ nor "Tilgang nektet for bruker: '%-.48s'@'%-.64s' til databasen '%-.192s' nektet"
+ norwegian-ny "Tilgang ikkje tillate for brukar: '%-.48s'@'%-.64s' til databasen '%-.192s' nekta"
+ por "Acesso negado para o usuário '%-.48s'@'%-.64s' ao banco de dados '%-.192s'"
+ rum "Acces interzis pentru utilizatorul: '%-.48s'@'%-.64s' la baza de date '%-.192s'"
+ rus "Ð”Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ '%-.48s'@'%-.64s' доÑтуп к базе данных '%-.192s' закрыт"
+ serbian "Pristup je zabranjen korisniku '%-.48s'@'%-.64s' za bazu '%-.192s'"
+ slo "Zakázaný prístup pre užívateľa: '%-.48s'@'%-.64s' k databázi '%-.192s'"
+ spa "Acceso negado para usuario: '%-.48s'@'%-.64s' para la base de datos '%-.192s'"
+ swe "Användare '%-.48s'@'%-.64s' är ej berättigad att använda databasen %-.192s"
+ ukr "ДоÑтуп заборонено Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача: '%-.48s'@'%-.64s' до бази данних '%-.192s'"
+ER_ACCESS_DENIED_ERROR 28000
+ cze "P-Břístup pro uživatele '%-.48s'@'%-.64s' (s heslem %s)"
+ dan "Adgang nægtet bruger: '%-.48s'@'%-.64s' (Bruger adgangskode: %s)"
+ nla "Toegang geweigerd voor gebruiker: '%-.48s'@'%-.64s' (Wachtwoord gebruikt: %s)"
+ eng "Access denied for user '%-.48s'@'%-.64s' (using password: %s)"
+ jps "ユーザー '%-.48s'@'%-.64s' ã‚’æ‹’å¦ã—ã¾ã™.uUsing password: %s)",
+ est "Ligipääs keelatud kasutajale '%-.48s'@'%-.64s' (kasutab parooli: %s)"
+ fre "Accès refusé pour l'utilisateur: '%-.48s'@'@%-.64s' (mot de passe: %s)"
+ ger "Benutzer '%-.48s'@'%-.64s' hat keine Zugriffsberechtigung (verwendetes Passwort: %s)"
+ greek "Δεν επιτέÏεται η Ï€Ïόσβαση στο χÏήστη: '%-.48s'@'%-.64s' (χÏήση password: %s)"
+ hun "A(z) '%-.48s'@'%-.64s' felhasznalo szamara tiltott eleres. (Hasznalja a jelszot: %s)"
+ ita "Accesso non consentito per l'utente: '%-.48s'@'%-.64s' (Password: %s)"
+ jpn "ユーザー '%-.48s'@'%-.64s' ã‚’æ‹’å¦ã—ã¾ã™.uUsing password: %s)"
+ kor "'%-.48s'@'%-.64s' 사용ìžëŠ” ì ‘ê·¼ì´ ê±°ë¶€ ë˜ì—ˆìŠµë‹ˆë‹¤. (using password: %s)"
+ nor "Tilgang nektet for bruker: '%-.48s'@'%-.64s' (Bruker passord: %s)"
+ norwegian-ny "Tilgang ikke tillate for brukar: '%-.48s'@'%-.64s' (Brukar passord: %s)"
+ por "Acesso negado para o usuário '%-.48s'@'%-.64s' (senha usada: %s)"
+ rum "Acces interzis pentru utilizatorul: '%-.48s'@'%-.64s' (Folosind parola: %s)"
+ rus "ДоÑтуп закрыт Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ '%-.48s'@'%-.64s' (был иÑпользован пароль: %s)"
+ serbian "Pristup je zabranjen korisniku '%-.48s'@'%-.64s' (koristi lozinku: '%s')"
+ slo "Zakázaný prístup pre užívateľa: '%-.48s'@'%-.64s' (použitie hesla: %s)"
+ spa "Acceso negado para usuario: '%-.48s'@'%-.64s' (Usando clave: %s)"
+ swe "Användare '%-.48s'@'%-.64s' är ej berättigad att logga in (Använder lösen: %s)"
+ ukr "ДоÑтуп заборонено Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача: '%-.48s'@'%-.64s' (ВикориÑтано пароль: %s)"
+ER_NO_DB_ERROR 3D000
+ cze "Nebyla vybr-Bána žádná databáze"
+ dan "Ingen database valgt"
+ nla "Geen database geselecteerd"
+ eng "No database selected"
+ jps "データベースãŒé¸æŠžã•ã‚Œã¦ã„ã¾ã›ã‚“.",
+ est "Andmebaasi ei ole valitud"
+ fre "Aucune base n'a été sélectionnée"
+ ger "Keine Datenbank ausgewählt"
+ greek "Δεν επιλέχθηκε βάση δεδομένων"
+ hun "Nincs kivalasztott adatbazis"
+ ita "Nessun database selezionato"
+ jpn "データベースãŒé¸æŠžã•ã‚Œã¦ã„ã¾ã›ã‚“."
+ kor "ì„ íƒëœ ë°ì´íƒ€ë² ì´ìŠ¤ê°€ 없습니다."
+ nor "Ingen database valgt"
+ norwegian-ny "Ingen database vald"
+ pol "Nie wybrano żadnej bazy danych"
+ por "Nenhum banco de dados foi selecionado"
+ rum "Nici o baza de data nu a fost selectata inca"
+ rus "База данных не выбрана"
+ serbian "Ni jedna baza nije selektovana"
+ slo "Nebola vybraná databáza"
+ spa "Base de datos no seleccionada"
+ swe "Ingen databas i användning"
+ ukr "Базу данних не вибрано"
+ER_UNKNOWN_COM_ERROR 08S01
+ cze "Nezn-Bámý příkaz"
+ dan "Ukendt kommando"
+ nla "Onbekend commando"
+ eng "Unknown command"
+ jps "ãã®ã‚³ãƒžãƒ³ãƒ‰ã¯ä½•ï¼Ÿ",
+ est "Tundmatu käsk"
+ fre "Commande inconnue"
+ ger "Unbekannter Befehl"
+ greek "Αγνωστη εντολή"
+ hun "Ervenytelen parancs"
+ ita "Comando sconosciuto"
+ jpn "ãã®ã‚³ãƒžãƒ³ãƒ‰ã¯ä½•ï¼Ÿ"
+ kor "명령어가 뭔지 모르겠어요..."
+ nor "Ukjent kommando"
+ norwegian-ny "Ukjent kommando"
+ pol "Nieznana komenda"
+ por "Comando desconhecido"
+ rum "Comanda invalida"
+ rus "ÐеизвеÑÑ‚Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° коммуникационного протокола"
+ serbian "Nepoznata komanda"
+ slo "Neznámy príkaz"
+ spa "Comando desconocido"
+ swe "Okänt commando"
+ ukr "Ðевідома команда"
+ER_BAD_NULL_ERROR 23000
+ cze "Sloupec '%-.192s' nem-Bůže být null"
+ dan "Kolonne '%-.192s' kan ikke være NULL"
+ nla "Kolom '%-.192s' kan niet null zijn"
+ eng "Column '%-.192s' cannot be null"
+ jps "Column '%-.192s' 㯠null ã«ã¯ã§ããªã„ã®ã§ã™",
+ est "Tulp '%-.192s' ei saa omada nullväärtust"
+ fre "Le champ '%-.192s' ne peut être vide (null)"
+ ger "Feld '%-.192s' darf nicht NULL sein"
+ greek "Το πεδίο '%-.192s' δεν μποÏεί να είναι κενό (null)"
+ hun "A(z) '%-.192s' oszlop erteke nem lehet nulla"
+ ita "La colonna '%-.192s' non puo` essere nulla"
+ jpn "Column '%-.192s' 㯠null ã«ã¯ã§ããªã„ã®ã§ã™"
+ kor "칼럼 '%-.192s'는 ë„(Null)ì´ ë˜ë©´ 안ë©ë‹ˆë‹¤. "
+ nor "Kolonne '%-.192s' kan ikke vere null"
+ norwegian-ny "Kolonne '%-.192s' kan ikkje vere null"
+ pol "Kolumna '%-.192s' nie może być null"
+ por "Coluna '%-.192s' não pode ser vazia"
+ rum "Coloana '%-.192s' nu poate sa fie null"
+ rus "Столбец '%-.192s' не может принимать величину NULL"
+ serbian "Kolona '%-.192s' ne može biti NULL"
+ slo "Pole '%-.192s' nemôže byť null"
+ spa "La columna '%-.192s' no puede ser nula"
+ swe "Kolumn '%-.192s' får inte vara NULL"
+ ukr "Стовбець '%-.192s' не може бути нульовим"
+ER_BAD_DB_ERROR 42000
+ cze "Nezn-Bámá databáze '%-.192s'"
+ dan "Ukendt database '%-.192s'"
+ nla "Onbekende database '%-.192s'"
+ eng "Unknown database '%-.192s'"
+ jps "'%-.192s' ãªã‚“ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¯çŸ¥ã‚Šã¾ã›ã‚“.",
+ est "Tundmatu andmebaas '%-.192s'"
+ fre "Base '%-.192s' inconnue"
+ ger "Unbekannte Datenbank '%-.192s'"
+ greek "Αγνωστη βάση δεδομένων '%-.192s'"
+ hun "Ervenytelen adatbazis: '%-.192s'"
+ ita "Database '%-.192s' sconosciuto"
+ jpn "'%-.192s' ãªã‚“ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¯çŸ¥ã‚Šã¾ã›ã‚“."
+ kor "ë°ì´íƒ€ë² ì´ìŠ¤ '%-.192s'는 알수 ì—†ìŒ"
+ nor "Ukjent database '%-.192s'"
+ norwegian-ny "Ukjent database '%-.192s'"
+ pol "Nieznana baza danych '%-.192s'"
+ por "Banco de dados '%-.192s' desconhecido"
+ rum "Baza de data invalida '%-.192s'"
+ rus "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð±Ð°Ð·Ð° данных '%-.192s'"
+ serbian "Nepoznata baza '%-.192s'"
+ slo "Neznáma databáza '%-.192s'"
+ spa "Base de datos desconocida '%-.192s'"
+ swe "Okänd databas: '%-.192s'"
+ ukr "Ðевідома база данних '%-.192s'"
+ER_TABLE_EXISTS_ERROR 42S01
+ cze "Tabulka '%-.192s' ji-Bž existuje"
+ dan "Tabellen '%-.192s' findes allerede"
+ nla "Tabel '%-.192s' bestaat al"
+ eng "Table '%-.192s' already exists"
+ jps "Table '%-.192s' ã¯æ—¢ã«ã‚ã‚Šã¾ã™",
+ est "Tabel '%-.192s' juba eksisteerib"
+ fre "La table '%-.192s' existe déjà"
+ ger "Tabelle '%-.192s' bereits vorhanden"
+ greek "Ο πίνακας '%-.192s' υπάÏχει ήδη"
+ hun "A(z) '%-.192s' tabla mar letezik"
+ ita "La tabella '%-.192s' esiste gia`"
+ jpn "Table '%-.192s' ã¯æ—¢ã«ã‚ã‚Šã¾ã™"
+ kor "í…Œì´ë¸” '%-.192s'는 ì´ë¯¸ 존재함"
+ nor "Tabellen '%-.192s' eksisterer allerede"
+ norwegian-ny "Tabellen '%-.192s' eksisterar allereide"
+ pol "Tabela '%-.192s' już istnieje"
+ por "Tabela '%-.192s' já existe"
+ rum "Tabela '%-.192s' exista deja"
+ rus "Таблица '%-.192s' уже ÑущеÑтвует"
+ serbian "Tabela '%-.192s' već postoji"
+ slo "Tabuľka '%-.192s' už existuje"
+ spa "La tabla '%-.192s' ya existe"
+ swe "Tabellen '%-.192s' finns redan"
+ ukr "Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ '%-.192s' вже Ñ–Ñнує"
+ER_BAD_TABLE_ERROR 42S02
+ cze "Nezn-Bámá tabulka '%-.100s'"
+ dan "Ukendt tabel '%-.100s'"
+ nla "Onbekende tabel '%-.100s'"
+ eng "Unknown table '%-.100s'"
+ jps "table '%-.100s' ã¯ã‚ã‚Šã¾ã›ã‚“.",
+ est "Tundmatu tabel '%-.100s'"
+ fre "Table '%-.100s' inconnue"
+ ger "Unbekannte Tabelle '%-.100s'"
+ greek "Αγνωστος πίνακας '%-.100s'"
+ hun "Ervenytelen tabla: '%-.100s'"
+ ita "Tabella '%-.100s' sconosciuta"
+ jpn "table '%-.100s' ã¯ã‚ã‚Šã¾ã›ã‚“."
+ kor "í…Œì´ë¸” '%-.100s'는 알수 ì—†ìŒ"
+ nor "Ukjent tabell '%-.100s'"
+ norwegian-ny "Ukjent tabell '%-.100s'"
+ pol "Nieznana tabela '%-.100s'"
+ por "Tabela '%-.100s' desconhecida"
+ rum "Tabela '%-.100s' este invalida"
+ rus "ÐеизвеÑÑ‚Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° '%-.100s'"
+ serbian "Nepoznata tabela '%-.100s'"
+ slo "Neznáma tabuľka '%-.100s'"
+ spa "Tabla '%-.100s' desconocida"
+ swe "Okänd tabell '%-.100s'"
+ ukr "Ðевідома Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ '%-.100s'"
+ER_NON_UNIQ_ERROR 23000
+ cze "Sloupec '%-.192s' v %-.192s nen-Bí zcela jasný"
+ dan "Felt: '%-.192s' i tabel %-.192s er ikke entydigt"
+ nla "Kolom: '%-.192s' in %-.192s is niet eenduidig"
+ eng "Column '%-.192s' in %-.192s is ambiguous"
+ est "Väli '%-.192s' %-.192s-s ei ole ühene"
+ fre "Champ: '%-.192s' dans %-.192s est ambigu"
+ ger "Feld '%-.192s' in %-.192s ist nicht eindeutig"
+ greek "Το πεδίο: '%-.192s' σε %-.192s δεν έχει καθοÏιστεί"
+ hun "A(z) '%-.192s' oszlop %-.192s-ben ketertelmu"
+ ita "Colonna: '%-.192s' di %-.192s e` ambigua"
+ jpn "Column: '%-.192s' in %-.192s is ambiguous"
+ kor "칼럼: '%-.192s' in '%-.192s' ì´ ëª¨í˜¸í•¨"
+ nor "Felt: '%-.192s' i tabell %-.192s er ikke entydig"
+ norwegian-ny "Kolonne: '%-.192s' i tabell %-.192s er ikkje eintydig"
+ pol "Kolumna: '%-.192s' w %-.192s jest dwuznaczna"
+ por "Coluna '%-.192s' em '%-.192s' é ambígua"
+ rum "Coloana: '%-.192s' in %-.192s este ambigua"
+ rus "Столбец '%-.192s' в %-.192s задан неоднозначно"
+ serbian "Kolona '%-.192s' u %-.192s nije jedinstvena u kontekstu"
+ slo "Pole: '%-.192s' v %-.192s je nejasné"
+ spa "La columna: '%-.192s' en %-.192s es ambigua"
+ swe "Kolumn '%-.192s' i %-.192s är inte unik"
+ ukr "Стовбець '%-.192s' у %-.192s визначений неоднозначно"
+ER_SERVER_SHUTDOWN 08S01
+ cze "Prob-Bíhá ukonÄování práce serveru"
+ dan "Database nedlukning er i gang"
+ nla "Bezig met het stoppen van de server"
+ eng "Server shutdown in progress"
+ jps "Server を shutdown 中...",
+ est "Serveri seiskamine käib"
+ fre "Arrêt du serveur en cours"
+ ger "Der Server wird heruntergefahren"
+ greek "ΕναÏξη διαδικασίας αποσÏνδεσης του εξυπηÏετητή (server shutdown)"
+ hun "A szerver leallitasa folyamatban"
+ ita "Shutdown del server in corso"
+ jpn "Server を shutdown 中..."
+ kor "Server가 셧다운 중입니다."
+ nor "Database nedkobling er i gang"
+ norwegian-ny "Tenar nedkopling er i gang"
+ pol "Trwa kończenie działania serwera"
+ por "'Shutdown' do servidor em andamento"
+ rum "Terminarea serverului este in desfasurare"
+ rus "Сервер находитÑÑ Ð² процеÑÑе оÑтановки"
+ serbian "Gašenje servera je u toku"
+ slo "Prebieha ukonÄovanie práce servera"
+ spa "Desconexion de servidor en proceso"
+ swe "Servern går nu ned"
+ ukr "ЗавершуєтьÑÑ Ñ€Ð°Ð±Ð¾Ñ‚Ð° Ñервера"
+ER_BAD_FIELD_ERROR 42S22 S0022
+ cze "Nezn-Bámý sloupec '%-.192s' v %-.192s"
+ dan "Ukendt kolonne '%-.192s' i tabel %-.192s"
+ nla "Onbekende kolom '%-.192s' in %-.192s"
+ eng "Unknown column '%-.192s' in '%-.192s'"
+ jps "'%-.192s' column 㯠'%-.192s' ã«ã¯ã‚ã‚Šã¾ã›ã‚“.",
+ est "Tundmatu tulp '%-.192s' '%-.192s'-s"
+ fre "Champ '%-.192s' inconnu dans %-.192s"
+ ger "Unbekanntes Tabellenfeld '%-.192s' in %-.192s"
+ greek "Αγνωστο πεδίο '%-.192s' σε '%-.192s'"
+ hun "A(z) '%-.192s' oszlop ervenytelen '%-.192s'-ben"
+ ita "Colonna sconosciuta '%-.192s' in '%-.192s'"
+ jpn "'%-.192s' column 㯠'%-.192s' ã«ã¯ã‚ã‚Šã¾ã›ã‚“."
+ kor "Unknown 칼럼 '%-.192s' in '%-.192s'"
+ nor "Ukjent kolonne '%-.192s' i tabell %-.192s"
+ norwegian-ny "Ukjent felt '%-.192s' i tabell %-.192s"
+ pol "Nieznana kolumna '%-.192s' w %-.192s"
+ por "Coluna '%-.192s' desconhecida em '%-.192s'"
+ rum "Coloana invalida '%-.192s' in '%-.192s'"
+ rus "ÐеизвеÑтный Ñтолбец '%-.192s' в '%-.192s'"
+ serbian "Nepoznata kolona '%-.192s' u '%-.192s'"
+ slo "Neznáme pole '%-.192s' v '%-.192s'"
+ spa "La columna '%-.192s' en %-.192s es desconocida"
+ swe "Okänd kolumn '%-.192s' i %-.192s"
+ ukr "Ðевідомий Ñтовбець '%-.192s' у '%-.192s'"
+ER_WRONG_FIELD_WITH_GROUP 42000 S1009
+ cze "Pou-Bžité '%-.192s' nebylo v group by"
+ dan "Brugte '%-.192s' som ikke var i group by"
+ nla "Opdracht gebruikt '%-.192s' dat niet in de GROUP BY voorkomt"
+ eng "'%-.192s' isn't in GROUP BY"
+ jps "'%-.192s' isn't in GROUP BY",
+ est "'%-.192s' puudub GROUP BY klauslis"
+ fre "'%-.192s' n'est pas dans 'group by'"
+ ger "'%-.192s' ist nicht in GROUP BY vorhanden"
+ greek "ΧÏησιμοποιήθηκε '%-.192s' που δεν υπήÏχε στο group by"
+ hun "Used '%-.192s' with wasn't in group by"
+ ita "Usato '%-.192s' che non e` nel GROUP BY"
+ kor "'%-.192s'ì€ GROUP BYì†ì— ì—†ìŒ"
+ nor "Brukte '%-.192s' som ikke var i group by"
+ norwegian-ny "Brukte '%-.192s' som ikkje var i group by"
+ pol "Użyto '%-.192s' bez umieszczenia w group by"
+ por "'%-.192s' não está em 'GROUP BY'"
+ rum "'%-.192s' nu exista in clauza GROUP BY"
+ rus "'%-.192s' не приÑутÑтвует в GROUP BY"
+ serbian "Entitet '%-.192s' nije naveden u komandi 'GROUP BY'"
+ slo "Použité '%-.192s' nebolo v 'group by'"
+ spa "Usado '%-.192s' el cual no esta group by"
+ swe "'%-.192s' finns inte i GROUP BY"
+ ukr "'%-.192s' не є у GROUP BY"
+ER_WRONG_GROUP_FIELD 42000 S1009
+ cze "Nemohu pou-Bžít group na '%-.192s'"
+ dan "Kan ikke gruppere på '%-.192s'"
+ nla "Kan '%-.192s' niet groeperen"
+ eng "Can't group on '%-.192s'"
+ est "Ei saa grupeerida '%-.192s' järgi"
+ fre "Ne peut regrouper '%-.192s'"
+ ger "Gruppierung über '%-.192s' nicht möglich"
+ greek "ΑδÏνατη η ομαδοποίηση (group on) '%-.192s'"
+ hun "A group nem hasznalhato: '%-.192s'"
+ ita "Impossibile raggruppare per '%-.192s'"
+ kor "'%-.192s'를 그룹할 수 ì—†ìŒ"
+ nor "Kan ikke gruppere på '%-.192s'"
+ norwegian-ny "Kan ikkje gruppere på '%-.192s'"
+ pol "Nie można grupować po '%-.192s'"
+ por "Não pode agrupar em '%-.192s'"
+ rum "Nu pot sa grupez pe (group on) '%-.192s'"
+ rus "Ðевозможно произвеÑти группировку по '%-.192s'"
+ serbian "Ne mogu da grupišem po '%-.192s'"
+ slo "Nemôžem použiť 'group' na '%-.192s'"
+ spa "No puedo agrupar por '%-.192s'"
+ swe "Kan inte använda GROUP BY med '%-.192s'"
+ ukr "Ðе можу групувати по '%-.192s'"
+ER_WRONG_SUM_SELECT 42000 S1009
+ cze "P-Bříkaz obsahuje zároveň funkci sum a sloupce"
+ dan "Udtrykket har summer (sum) funktioner og kolonner i samme udtryk"
+ nla "Opdracht heeft totaliseer functies en kolommen in dezelfde opdracht"
+ eng "Statement has sum functions and columns in same statement"
+ est "Lauses on korraga nii tulbad kui summeerimisfunktsioonid"
+ fre "Vous demandez la fonction sum() et des champs dans la même commande"
+ ger "Die Verwendung von Summierungsfunktionen und Spalten im selben Befehl ist nicht erlaubt"
+ greek "Η διατÏπωση πεÏιέχει sum functions και columns στην ίδια διατÏπωση"
+ ita "Il comando ha una funzione SUM e una colonna non specificata nella GROUP BY"
+ kor "Statement ê°€ sumê¸°ëŠ¥ì„ ë™ìž‘중ì´ê³  ì¹¼ëŸ¼ë„ ë™ì¼í•œ statement입니다."
+ nor "Uttrykket har summer (sum) funksjoner og kolonner i samme uttrykk"
+ norwegian-ny "Uttrykket har summer (sum) funksjoner og kolonner i same uttrykk"
+ pol "Zapytanie ma funkcje sumuj?ce i kolumny w tym samym zapytaniu"
+ por "Cláusula contém funções de soma e colunas juntas"
+ rum "Comanda are functii suma si coloane in aceeasi comanda"
+ rus "Выражение Ñодержит групповые функции и Ñтолбцы, но не включает GROUP BY. Ркак вы умудрилиÑÑŒ получить Ñто Ñообщение об ошибке?"
+ serbian "Izraz ima 'SUM' agregatnu funkciju i kolone u isto vreme"
+ slo "Príkaz obsahuje zároveň funkciu 'sum' a poľa"
+ spa "El estamento tiene funciones de suma y columnas en el mismo estamento"
+ swe "Kommandot har både sum functions och enkla funktioner"
+ ukr "У виразі викориÑтано підÑумовуючі функції порÑд з іменами Ñтовбців"
+ER_WRONG_VALUE_COUNT 21S01
+ cze "Po-BÄet sloupců neodpovídá zadané hodnotÄ›"
+ dan "Kolonne tæller stemmer ikke med antallet af værdier"
+ nla "Het aantal kolommen komt niet overeen met het aantal opgegeven waardes"
+ eng "Column count doesn't match value count"
+ est "Tulpade arv erineb väärtuste arvust"
+ ger "Die Anzahl der Spalten entspricht nicht der Anzahl der Werte"
+ greek "Το Column count δεν ταιÏιάζει με το value count"
+ hun "Az oszlopban levo ertek nem egyezik meg a szamitott ertekkel"
+ ita "Il numero delle colonne non e` uguale al numero dei valori"
+ kor "ì¹¼ëŸ¼ì˜ ì¹´ìš´íŠ¸ê°€ ê°’ì˜ ì¹´ìš´íŠ¸ì™€ ì¼ì¹˜í•˜ì§€ 않습니다."
+ nor "Felt telling stemmer verdi telling"
+ norwegian-ny "Kolonne telling stemmer verdi telling"
+ pol "Liczba kolumn nie odpowiada liczbie warto?ci"
+ por "Contagem de colunas não confere com a contagem de valores"
+ rum "Numarul de coloane nu este acelasi cu numarul valoarei"
+ rus "КоличеÑтво Ñтолбцов не Ñовпадает Ñ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтвом значений"
+ serbian "Broj kolona ne odgovara broju vrednosti"
+ slo "PoÄet polí nezodpovedá zadanej hodnote"
+ spa "La columna con count no tiene valores para contar"
+ swe "Antalet kolumner motsvarar inte antalet värden"
+ ukr "КількіÑÑ‚ÑŒ Ñтовбців не Ñпівпадає з кількіÑÑ‚ÑŽ значень"
+ER_TOO_LONG_IDENT 42000 S1009
+ cze "Jm-Béno identifikátoru '%-.100s' je příliš dlouhé"
+ dan "Navnet '%-.100s' er for langt"
+ nla "Naam voor herkenning '%-.100s' is te lang"
+ eng "Identifier name '%-.100s' is too long"
+ jps "Identifier name '%-.100s' ã¯é•·ã™ãŽã¾ã™",
+ est "Identifikaatori '%-.100s' nimi on liiga pikk"
+ fre "Le nom de l'identificateur '%-.100s' est trop long"
+ ger "Name des Bezeichners '%-.100s' ist zu lang"
+ greek "Το identifier name '%-.100s' είναι Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿"
+ hun "A(z) '%-.100s' azonositonev tul hosszu."
+ ita "Il nome dell'identificatore '%-.100s' e` troppo lungo"
+ jpn "Identifier name '%-.100s' ã¯é•·ã™ãŽã¾ã™"
+ kor "Identifier '%-.100s'는 너무 길군요."
+ nor "Identifikator '%-.100s' er for lang"
+ norwegian-ny "Identifikator '%-.100s' er for lang"
+ pol "Nazwa identyfikatora '%-.100s' jest zbyt długa"
+ por "Nome identificador '%-.100s' é longo demais"
+ rum "Numele indentificatorului '%-.100s' este prea lung"
+ rus "Слишком длинный идентификатор '%-.100s'"
+ serbian "Ime '%-.100s' je predugaÄko"
+ slo "Meno identifikátora '%-.100s' je príliš dlhé"
+ spa "El nombre del identificador '%-.100s' es demasiado grande"
+ swe "Kolumnnamn '%-.100s' är för långt"
+ ukr "Ім'Ñ Ñ–Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ‚Ð¾Ñ€Ð° '%-.100s' задовге"
+ER_DUP_FIELDNAME 42S21 S1009
+ cze "Zdvojen-Bé jméno sloupce '%-.192s'"
+ dan "Feltnavnet '%-.192s' findes allerede"
+ nla "Dubbele kolom naam '%-.192s'"
+ eng "Duplicate column name '%-.192s'"
+ jps "'%-.192s' ã¨ã„ㆠcolumn åã¯é‡è¤‡ã—ã¦ã¾ã™",
+ est "Kattuv tulba nimi '%-.192s'"
+ fre "Nom du champ '%-.192s' déjà utilisé"
+ ger "Doppelter Spaltenname: '%-.192s'"
+ greek "Επανάληψη column name '%-.192s'"
+ hun "Duplikalt oszlopazonosito: '%-.192s'"
+ ita "Nome colonna duplicato '%-.192s'"
+ jpn "'%-.192s' ã¨ã„ㆠcolumn åã¯é‡è¤‡ã—ã¦ã¾ã™"
+ kor "ì¤‘ë³µëœ ì¹¼ëŸ¼ ì´ë¦„: '%-.192s'"
+ nor "Feltnavnet '%-.192s' eksisterte fra før"
+ norwegian-ny "Feltnamnet '%-.192s' eksisterte frå før"
+ pol "Powtórzona nazwa kolumny '%-.192s'"
+ por "Nome da coluna '%-.192s' duplicado"
+ rum "Numele coloanei '%-.192s' e duplicat"
+ rus "ДублирующееÑÑ Ð¸Ð¼Ñ Ñтолбца '%-.192s'"
+ serbian "Duplirano ime kolone '%-.192s'"
+ slo "Opakované meno poľa '%-.192s'"
+ spa "Nombre de columna duplicado '%-.192s'"
+ swe "Kolumnnamn '%-.192s finns flera gånger"
+ ukr "Дублююче ім'Ñ ÑÑ‚Ð¾Ð²Ð±Ñ†Ñ '%-.192s'"
+ER_DUP_KEYNAME 42000 S1009
+ cze "Zdvojen-Bé jméno klíÄe '%-.192s'"
+ dan "Indeksnavnet '%-.192s' findes allerede"
+ nla "Dubbele zoeksleutel naam '%-.192s'"
+ eng "Duplicate key name '%-.192s'"
+ jps "'%-.192s' ã¨ã„ㆠkey ã®åå‰ã¯é‡è¤‡ã—ã¦ã„ã¾ã™",
+ est "Kattuv võtme nimi '%-.192s'"
+ fre "Nom de clef '%-.192s' déjà utilisé"
+ ger "Doppelter Name für Schlüssel vorhanden: '%-.192s'"
+ greek "Επανάληψη key name '%-.192s'"
+ hun "Duplikalt kulcsazonosito: '%-.192s'"
+ ita "Nome chiave duplicato '%-.192s'"
+ jpn "'%-.192s' ã¨ã„ㆠkey ã®åå‰ã¯é‡è¤‡ã—ã¦ã„ã¾ã™"
+ kor "ì¤‘ë³µëœ í‚¤ ì´ë¦„ : '%-.192s'"
+ nor "Nøkkelnavnet '%-.192s' eksisterte fra før"
+ norwegian-ny "Nøkkelnamnet '%-.192s' eksisterte frå før"
+ pol "Powtórzony nazwa klucza '%-.192s'"
+ por "Nome da chave '%-.192s' duplicado"
+ rum "Numele cheiei '%-.192s' e duplicat"
+ rus "ДублирующееÑÑ Ð¸Ð¼Ñ ÐºÐ»ÑŽÑ‡Ð° '%-.192s'"
+ serbian "Duplirano ime kljuÄa '%-.192s'"
+ slo "Opakované meno kľúÄa '%-.192s'"
+ spa "Nombre de clave duplicado '%-.192s'"
+ swe "Nyckelnamn '%-.192s' finns flera gånger"
+ ukr "Дублююче ім'Ñ ÐºÐ»ÑŽÑ‡Ð° '%-.192s'"
+# When using this error code, please use ER(ER_DUP_ENTRY_WITH_KEY_NAME)
+# for the message string. See, for example, code in handler.cc.
+ER_DUP_ENTRY 23000 S1009
+ cze "Zdvojen-Bý klÃ­Ä '%-.192s' (Äíslo klíÄe %d)"
+ dan "Ens værdier '%-.192s' for indeks %d"
+ nla "Dubbele ingang '%-.192s' voor zoeksleutel %d"
+ eng "Duplicate entry '%-.192s' for key %d"
+ jps "'%-.192s' 㯠key %d ã«ãŠã„ã¦é‡è¤‡ã—ã¦ã„ã¾ã™",
+ est "Kattuv väärtus '%-.192s' võtmele %d"
+ fre "Duplicata du champ '%-.192s' pour la clef %d"
+ ger "Doppelter Eintrag '%-.192s' für Schlüssel %d"
+ greek "Διπλή εγγÏαφή '%-.192s' για το κλειδί %d"
+ hun "Duplikalt bejegyzes '%-.192s' a %d kulcs szerint."
+ ita "Valore duplicato '%-.192s' per la chiave %d"
+ jpn "'%-.192s' 㯠key %d ã«ãŠã„ã¦é‡è¤‡ã—ã¦ã„ã¾ã™"
+ kor "ì¤‘ë³µëœ ìž…ë ¥ ê°’ '%-.192s': key %d"
+ nor "Like verdier '%-.192s' for nøkkel %d"
+ norwegian-ny "Like verdiar '%-.192s' for nykkel %d"
+ pol "Powtórzone wyst?pienie '%-.192s' dla klucza %d"
+ por "Entrada '%-.192s' duplicada para a chave %d"
+ rum "Cimpul '%-.192s' e duplicat pentru cheia %d"
+ rus "ДублирующаÑÑÑ Ð·Ð°Ð¿Ð¸ÑÑŒ '%-.192s' по ключу %d"
+ serbian "Dupliran unos '%-.192s' za kljuÄ '%d'"
+ slo "Opakovaný kÄ¾ÃºÄ '%-.192s' (Äíslo kľúÄa %d)"
+ spa "Entrada duplicada '%-.192s' para la clave %d"
+ swe "Dubbel nyckel '%-.192s' för nyckel %d"
+ ukr "Дублюючий Ð·Ð°Ð¿Ð¸Ñ '%-.192s' Ð´Ð»Ñ ÐºÐ»ÑŽÑ‡Ð° %d"
+ER_WRONG_FIELD_SPEC 42000 S1009
+ cze "Chybn-Bá specifikace sloupce '%-.192s'"
+ dan "Forkert kolonnespecifikaton for felt '%-.192s'"
+ nla "Verkeerde kolom specificatie voor kolom '%-.192s'"
+ eng "Incorrect column specifier for column '%-.192s'"
+ est "Vigane tulba kirjeldus tulbale '%-.192s'"
+ fre "Mauvais paramètre de champ pour le champ '%-.192s'"
+ ger "Falsche Spezifikation für Feld '%-.192s'"
+ greek "Εσφαλμένο column specifier για το πεδίο '%-.192s'"
+ hun "Rossz oszlopazonosito: '%-.192s'"
+ ita "Specifica errata per la colonna '%-.192s'"
+ kor "칼럼 '%-.192s'ì˜ ë¶€ì •í™•í•œ 칼럼 ì •ì˜ìž"
+ nor "Feil kolonne spesifikator for felt '%-.192s'"
+ norwegian-ny "Feil kolonne spesifikator for kolonne '%-.192s'"
+ pol "Błędna specyfikacja kolumny dla kolumny '%-.192s'"
+ por "Especificador de coluna incorreto para a coluna '%-.192s'"
+ rum "Specificandul coloanei '%-.192s' este incorect"
+ rus "Ðекорректный определитель Ñтолбца Ð´Ð»Ñ Ñтолбца '%-.192s'"
+ serbian "Pogrešan naziv kolone za kolonu '%-.192s'"
+ slo "Chyba v špecifikácii poľa '%-.192s'"
+ spa "Especificador de columna erroneo para la columna '%-.192s'"
+ swe "Felaktigt kolumntyp för kolumn '%-.192s'"
+ ukr "Ðевірний Ñпецифікатор ÑÑ‚Ð¾Ð²Ð±Ñ†Ñ '%-.192s'"
+ER_PARSE_ERROR 42000 s1009
+ cze "%s bl-Bízko '%-.80s' na řádku %d"
+ dan "%s nær '%-.80s' på linje %d"
+ nla "%s bij '%-.80s' in regel %d"
+ eng "%s near '%-.80s' at line %d"
+ jps "%s : '%-.80s' 付近 : %d 行目",
+ est "%s '%-.80s' ligidal real %d"
+ fre "%s près de '%-.80s' à la ligne %d"
+ ger "%s bei '%-.80s' in Zeile %d"
+ greek "%s πλησίον '%-.80s' στη γÏαμμή %d"
+ hun "A %s a '%-.80s'-hez kozeli a %d sorban"
+ ita "%s vicino a '%-.80s' linea %d"
+ jpn "%s : '%-.80s' 付近 : %d 行目"
+ kor "'%s' ì—러 ê°™ì니다. ('%-.80s' 명령어 ë¼ì¸ %d)"
+ nor "%s nær '%-.80s' på linje %d"
+ norwegian-ny "%s attmed '%-.80s' på line %d"
+ pol "%s obok '%-.80s' w linii %d"
+ por "%s próximo a '%-.80s' na linha %d"
+ rum "%s linga '%-.80s' pe linia %d"
+ rus "%s около '%-.80s' на Ñтроке %d"
+ serbian "'%s' u iskazu '%-.80s' na liniji %d"
+ slo "%s blízko '%-.80s' na riadku %d"
+ spa "%s cerca '%-.80s' en la linea %d"
+ swe "%s nära '%-.80s' på rad %d"
+ ukr "%s Ð±Ñ–Ð»Ñ '%-.80s' в Ñтроці %d"
+ER_EMPTY_QUERY 42000
+ cze "V-Býsledek dotazu je prázdný"
+ dan "Forespørgsel var tom"
+ nla "Query was leeg"
+ eng "Query was empty"
+ jps "Query ãŒç©ºã§ã™.",
+ est "Tühi päring"
+ fre "Query est vide"
+ ger "Leere Abfrage"
+ greek "Το εÏώτημα (query) που θέσατε ήταν κενό"
+ hun "Ures lekerdezes."
+ ita "La query e` vuota"
+ jpn "Query ãŒç©ºã§ã™."
+ kor "쿼리결과가 없습니다."
+ nor "Forespørsel var tom"
+ norwegian-ny "Førespurnad var tom"
+ pol "Zapytanie było puste"
+ por "Consulta (query) estava vazia"
+ rum "Query-ul a fost gol"
+ rus "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð¾ÐºÐ°Ð·Ð°Ð»ÑÑ Ð¿ÑƒÑтым"
+ serbian "Upit je bio prazan"
+ slo "Výsledok požiadavky bol prázdny"
+ spa "La query estaba vacia"
+ swe "Frågan var tom"
+ ukr "ПуÑтий запит"
+ER_NONUNIQ_TABLE 42000 S1009
+ cze "Nejednozna-BÄná tabulka/alias: '%-.192s'"
+ dan "Tabellen/aliaset: '%-.192s' er ikke unikt"
+ nla "Niet unieke waarde tabel/alias: '%-.192s'"
+ eng "Not unique table/alias: '%-.192s'"
+ jps "'%-.192s' ã¯ä¸€æ„ã® table/alias åã§ã¯ã‚ã‚Šã¾ã›ã‚“",
+ est "Ei ole unikaalne tabel/alias '%-.192s'"
+ fre "Table/alias: '%-.192s' non unique"
+ ger "Tabellenname/Alias '%-.192s' nicht eindeutig"
+ greek "ΑδÏνατη η ανεÏÏεση unique table/alias: '%-.192s'"
+ hun "Nem egyedi tabla/alias: '%-.192s'"
+ ita "Tabella/alias non unico: '%-.192s'"
+ jpn "'%-.192s' ã¯ä¸€æ„ã® table/alias åã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+ kor "Unique 하지 ì•Šì€ í…Œì´ë¸”/alias: '%-.192s'"
+ nor "Ikke unikt tabell/alias: '%-.192s'"
+ norwegian-ny "Ikkje unikt tabell/alias: '%-.192s'"
+ pol "Tabela/alias nie s? unikalne: '%-.192s'"
+ por "Tabela/alias '%-.192s' não única"
+ rum "Tabela/alias: '%-.192s' nu este unic"
+ rus "ПовторÑющаÑÑÑ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð°/пÑевдоним '%-.192s'"
+ serbian "Tabela ili alias nisu bili jedinstveni: '%-.192s'"
+ slo "Nie jednoznaÄná tabuľka/alias: '%-.192s'"
+ spa "Tabla/alias: '%-.192s' es no unica"
+ swe "Icke unikt tabell/alias: '%-.192s'"
+ ukr "Ðеунікальна таблицÑ/пÑевдонім: '%-.192s'"
+ER_INVALID_DEFAULT 42000 S1009
+ cze "Chybn-Bá defaultní hodnota pro '%-.192s'"
+ dan "Ugyldig standardværdi for '%-.192s'"
+ nla "Foutieve standaard waarde voor '%-.192s'"
+ eng "Invalid default value for '%-.192s'"
+ est "Vigane vaikeväärtus '%-.192s' jaoks"
+ fre "Valeur par défaut invalide pour '%-.192s'"
+ ger "Fehlerhafter Vorgabewert (DEFAULT) für '%-.192s'"
+ greek "Εσφαλμένη Ï€ÏοκαθοÏισμένη τιμή (default value) για '%-.192s'"
+ hun "Ervenytelen ertek: '%-.192s'"
+ ita "Valore di default non valido per '%-.192s'"
+ kor "'%-.192s'ì˜ ìœ íš¨í•˜ì§€ 못한 ë””í´íŠ¸ ê°’ì„ ì‚¬ìš©í•˜ì…¨ìŠµë‹ˆë‹¤."
+ nor "Ugyldig standardverdi for '%-.192s'"
+ norwegian-ny "Ugyldig standardverdi for '%-.192s'"
+ pol "Niewła?ciwa warto?ć domy?lna dla '%-.192s'"
+ por "Valor padrão (default) inválido para '%-.192s'"
+ rum "Valoarea de default este invalida pentru '%-.192s'"
+ rus "Ðекорректное значение по умолчанию Ð´Ð»Ñ '%-.192s'"
+ serbian "Loša default vrednost za '%-.192s'"
+ slo "Chybná implicitná hodnota pre '%-.192s'"
+ spa "Valor por defecto invalido para '%-.192s'"
+ swe "Ogiltigt DEFAULT värde för '%-.192s'"
+ ukr "Ðевірне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð¾ замовчуванню Ð´Ð»Ñ '%-.192s'"
+ER_MULTIPLE_PRI_KEY 42000 S1009
+ cze "Definov-Báno více primárních klíÄů"
+ dan "Flere primærnøgler specificeret"
+ nla "Meerdere primaire zoeksleutels gedefinieerd"
+ eng "Multiple primary key defined"
+ jps "複数㮠primary key ãŒå®šç¾©ã•ã‚Œã¾ã—ãŸ",
+ est "Mitut primaarset võtit ei saa olla"
+ fre "Plusieurs clefs primaires définies"
+ ger "Mehrere Primärschlüssel (PRIMARY KEY) definiert"
+ greek "ΠεÏισσότεÏα από ένα primary key οÏίστηκαν"
+ hun "Tobbszoros elsodleges kulcs definialas."
+ ita "Definite piu` chiave primarie"
+ jpn "複数㮠primary key ãŒå®šç¾©ã•ã‚Œã¾ã—ãŸ"
+ kor "Multiple primary keyê°€ ì •ì˜ë˜ì–´ 있슴"
+ nor "Fleire primærnøkle spesifisert"
+ norwegian-ny "Fleire primærnyklar spesifisert"
+ pol "Zdefiniowano wiele kluczy podstawowych"
+ por "Definida mais de uma chave primária"
+ rum "Chei primare definite de mai multe ori"
+ rus "Указано неÑколько первичных ключей"
+ serbian "Definisani viÅ¡estruki primarni kljuÄevi"
+ slo "Zadefinovaných viac primárnych kľúÄov"
+ spa "Multiples claves primarias definidas"
+ swe "Flera PRIMARY KEY använda"
+ ukr "Первинного ключа визначено неодноразово"
+ER_TOO_MANY_KEYS 42000 S1009
+ cze "Zad-Báno příliÅ¡ mnoho klíÄů, je povoleno nejvíce %d klíÄů"
+ dan "For mange nøgler specificeret. Kun %d nøgler må bruges"
+ nla "Teveel zoeksleutels gedefinieerd. Maximaal zijn %d zoeksleutels toegestaan"
+ eng "Too many keys specified; max %d keys allowed"
+ jps "key ã®æŒ‡å®šãŒå¤šã™ãŽã¾ã™. key ã¯æœ€å¤§ %d ã¾ã§ã§ã™",
+ est "Liiga palju võtmeid. Maksimaalselt võib olla %d võtit"
+ fre "Trop de clefs sont définies. Maximum de %d clefs alloué"
+ ger "Zu viele Schlüssel definiert. Maximal %d Schlüssel erlaubt"
+ greek "ΠάÏα πολλά key οÏίσθηκαν. Το Ï€Î¿Î»Ï %d επιτÏέπονται"
+ hun "Tul sok kulcs. Maximum %d kulcs engedelyezett."
+ ita "Troppe chiavi. Sono ammesse max %d chiavi"
+ jpn "key ã®æŒ‡å®šãŒå¤šã™ãŽã¾ã™. key ã¯æœ€å¤§ %d ã¾ã§ã§ã™"
+ kor "너무 ë§Žì€ í‚¤ê°€ ì •ì˜ë˜ì–´ 있ì니다.. 최대 %dì˜ í‚¤ê°€ 가능함"
+ nor "For mange nøkler spesifisert. Maks %d nøkler tillatt"
+ norwegian-ny "For mange nykler spesifisert. Maks %d nyklar tillatt"
+ pol "Okre?lono zbyt wiele kluczy. Dostępnych jest maksymalnie %d kluczy"
+ por "Especificadas chaves demais. O máximo permitido são %d chaves"
+ rum "Prea multe chei. Numarul de chei maxim este %d"
+ rus "Указано Ñлишком много ключей. РазрешаетÑÑ ÑƒÐºÐ°Ð·Ñ‹Ð²Ð°Ñ‚ÑŒ не более %d ключей"
+ serbian "Navedeno je previÅ¡e kljuÄeva. Maksimum %d kljuÄeva je dozvoljeno"
+ slo "Zadaných ríliÅ¡ veľa kľúÄov. Najviac %d kľúÄov je povolených"
+ spa "Demasiadas claves primarias declaradas. Un maximo de %d claves son permitidas"
+ swe "För många nycklar använda. Man får ha högst %d nycklar"
+ ukr "Забагато ключів зазначено. Дозволено не більше %d ключів"
+ER_TOO_MANY_KEY_PARTS 42000 S1009
+ cze "Zad-Báno příliÅ¡ mnoho Äást klíÄů, je povoleno nejvíce %d Äástí"
+ dan "For mange nøgledele specificeret. Kun %d dele må bruges"
+ nla "Teveel zoeksleutel onderdelen gespecificeerd. Maximaal %d onderdelen toegestaan"
+ eng "Too many key parts specified; max %d parts allowed"
+ est "Võti koosneb liiga paljudest osadest. Maksimaalselt võib olla %d osa"
+ fre "Trop de parties specifiées dans la clef. Maximum de %d parties"
+ ger "Zu viele Teilschlüssel definiert. Maximal %d Teilschlüssel erlaubt"
+ greek "ΠάÏα πολλά key parts οÏίσθηκαν. Το Ï€Î¿Î»Ï %d επιτÏέπονται"
+ hun "Tul sok kulcsdarabot definialt. Maximum %d resz engedelyezett"
+ ita "Troppe parti di chiave specificate. Sono ammesse max %d parti"
+ kor "너무 ë§Žì€ í‚¤ 부분(parts)ë“¤ì´ ì •ì˜ë˜ì–´ 있ì니다.. 최대 %d ë¶€ë¶„ì´ ê°€ëŠ¥í•¨"
+ nor "For mange nøkkeldeler spesifisert. Maks %d deler tillatt"
+ norwegian-ny "For mange nykkeldelar spesifisert. Maks %d delar tillatt"
+ pol "Okre?lono zbyt wiele czę?ci klucza. Dostępnych jest maksymalnie %d czę?ci"
+ por "Especificadas partes de chave demais. O máximo permitido são %d partes"
+ rum "Prea multe chei. Numarul de chei maxim este %d"
+ rus "Указано Ñлишком много чаÑтей ÑоÑтавного ключа. РазрешаетÑÑ ÑƒÐºÐ°Ð·Ñ‹Ð²Ð°Ñ‚ÑŒ не более %d чаÑтей"
+ serbian "Navedeno je previÅ¡e delova kljuÄa. Maksimum %d delova je dozvoljeno"
+ slo "Zadaných ríliÅ¡ veľa Äastí kľúÄov. Je povolených najviac %d Äastí"
+ spa "Demasiadas partes de clave declaradas. Un maximo de %d partes son permitidas"
+ swe "För många nyckeldelar använda. Man får ha högst %d nyckeldelar"
+ ukr "Забагато чаÑтин ключа зазначено. Дозволено не більше %d чаÑтин"
+ER_TOO_LONG_KEY 42000 S1009
+ cze "Zadan-Bý klÃ­Ä byl příliÅ¡ dlouhý, nejvÄ›tší délka klíÄe je %d"
+ dan "Specificeret nøgle var for lang. Maksimal nøglelængde er %d"
+ nla "Gespecificeerde zoeksleutel was te lang. De maximale lengte is %d"
+ eng "Specified key was too long; max key length is %d bytes"
+ jps "key ãŒé•·ã™ãŽã¾ã™. key ã®é•·ã•ã¯æœ€å¤§ %d ã§ã™",
+ est "Võti on liiga pikk. Maksimaalne võtmepikkus on %d"
+ fre "La clé est trop longue. Longueur maximale: %d"
+ ger "Schlüssel ist zu lang. Die maximale Schlüssellänge beträgt %d"
+ greek "Το κλειδί που οÏίσθηκε είναι Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿. Το μέγιστο μήκος είναι %d"
+ hun "A megadott kulcs tul hosszu. Maximalis kulcshosszusag: %d"
+ ita "La chiave specificata e` troppo lunga. La max lunghezza della chiave e` %d"
+ jpn "key ãŒé•·ã™ãŽã¾ã™. key ã®é•·ã•ã¯æœ€å¤§ %d ã§ã™"
+ kor "ì •ì˜ëœ 키가 너무 ê¹ë‹ˆë‹¤. 최대 í‚¤ì˜ ê¸¸ì´ëŠ” %d입니다."
+ nor "Spesifisert nøkkel var for lang. Maks nøkkellengde er is %d"
+ norwegian-ny "Spesifisert nykkel var for lang. Maks nykkellengde er %d"
+ pol "Zdefinowany klucz jest zbyt długi. Maksymaln? długo?ci? klucza jest %d"
+ por "Chave especificada longa demais. O comprimento de chave máximo permitido é %d"
+ rum "Cheia specificata este prea lunga. Marimea maxima a unei chei este de %d"
+ rus "Указан Ñлишком длинный ключ. МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð´Ð»Ð¸Ð½Ð° ключа ÑоÑтавлÑет %d байт"
+ serbian "Navedeni kljuÄ je predug. Maksimalna dužina kljuÄa je %d"
+ slo "Zadaný kÄ¾ÃºÄ je príliÅ¡ dlhý, najväÄÅ¡ia dĺžka kľúÄa je %d"
+ spa "Declaracion de clave demasiado larga. La maxima longitud de clave es %d"
+ swe "För lång nyckel. Högsta tillåtna nyckellängd är %d"
+ ukr "Зазначений ключ задовгий. Ðайбільша довжина ключа %d байтів"
+ER_KEY_COLUMN_DOES_NOT_EXITS 42000 S1009
+ cze "Kl-BíÄový sloupec '%-.192s' v tabulce neexistuje"
+ dan "Nøglefeltet '%-.192s' eksisterer ikke i tabellen"
+ nla "Zoeksleutel kolom '%-.192s' bestaat niet in tabel"
+ eng "Key column '%-.192s' doesn't exist in table"
+ jps "Key column '%-.192s' ãŒãƒ†ãƒ¼ãƒ–ルã«ã‚ã‚Šã¾ã›ã‚“.",
+ est "Võtme tulp '%-.192s' puudub tabelis"
+ fre "La clé '%-.192s' n'existe pas dans la table"
+ ger "In der Tabelle gibt es kein Schlüsselfeld '%-.192s'"
+ greek "Το πεδίο κλειδί '%-.192s' δεν υπάÏχει στον πίνακα"
+ hun "A(z) '%-.192s'kulcsoszlop nem letezik a tablaban"
+ ita "La colonna chiave '%-.192s' non esiste nella tabella"
+ jpn "Key column '%-.192s' ãŒãƒ†ãƒ¼ãƒ–ルã«ã‚ã‚Šã¾ã›ã‚“."
+ kor "Key 칼럼 '%-.192s'는 í…Œì´ë¸”ì— ì¡´ìž¬í•˜ì§€ 않습니다."
+ nor "Nøkkel felt '%-.192s' eksiterer ikke i tabellen"
+ norwegian-ny "Nykkel kolonne '%-.192s' eksiterar ikkje i tabellen"
+ pol "Kolumna '%-.192s' zdefiniowana w kluczu nie istnieje w tabeli"
+ por "Coluna chave '%-.192s' não existe na tabela"
+ rum "Coloana cheie '%-.192s' nu exista in tabela"
+ rus "Ключевой Ñтолбец '%-.192s' в таблице не ÑущеÑтвует"
+ serbian "KljuÄna kolona '%-.192s' ne postoji u tabeli"
+ slo "KľúÄový stĺpec '%-.192s' v tabuľke neexistuje"
+ spa "La columna clave '%-.192s' no existe en la tabla"
+ swe "Nyckelkolumn '%-.192s' finns inte"
+ ukr "Ключовий Ñтовбець '%-.192s' не Ñ–Ñнує у таблиці"
+ER_BLOB_USED_AS_KEY 42000 S1009
+ cze "Blob sloupec '%-.192s' nem-Bůže být použit jako klíÄ"
+ dan "BLOB feltet '%-.192s' kan ikke bruges ved specifikation af indeks"
+ nla "BLOB kolom '%-.192s' kan niet gebruikt worden bij zoeksleutel specificatie"
+ eng "BLOB column '%-.192s' can't be used in key specification with the used table type"
+ est "BLOB-tüüpi tulpa '%-.192s' ei saa kasutada võtmena"
+ fre "Champ BLOB '%-.192s' ne peut être utilisé dans une clé"
+ ger "BLOB-Feld '%-.192s' kann beim verwendeten Tabellentyp nicht als Schlüssel verwendet werden"
+ greek "Πεδίο Ï„Ïπου Blob '%-.192s' δεν μποÏεί να χÏησιμοποιηθεί στον οÏισμό ενός ÎºÎ»ÎµÎ¹Î´Î¹Î¿Ï (key specification)"
+ hun "Blob objektum '%-.192s' nem hasznalhato kulcskent"
+ ita "La colonna BLOB '%-.192s' non puo` essere usata nella specifica della chiave"
+ kor "BLOB 칼럼 '%-.192s'는 키 ì •ì˜ì—ì„œ ì‚¬ìš©ë  ìˆ˜ 없습니다."
+ nor "Blob felt '%-.192s' kan ikke brukes ved spesifikasjon av nøkler"
+ norwegian-ny "Blob kolonne '%-.192s' kan ikkje brukast ved spesifikasjon av nyklar"
+ pol "Kolumna typu Blob '%-.192s' nie może być użyta w specyfikacji klucza"
+ por "Coluna BLOB '%-.192s' não pode ser utilizada na especificação de chave para o tipo de tabela usado"
+ rum "Coloana de tip BLOB '%-.192s' nu poate fi folosita in specificarea cheii cu tipul de tabla folosit"
+ rus "Столбец типа BLOB '%-.192s' не может быть иÑпользован как значение ключа в таблице такого типа"
+ serbian "BLOB kolona '%-.192s' ne može biti upotrebljena za navoÄ‘enje kljuÄa sa tipom tabele koji se trenutno koristi"
+ slo "Blob pole '%-.192s' nemôže byÅ¥ použité ako kľúÄ"
+ spa "La columna Blob '%-.192s' no puede ser usada en una declaracion de clave"
+ swe "En BLOB '%-.192s' kan inte vara nyckel med den använda tabelltypen"
+ ukr "BLOB Ñтовбець '%-.192s' не може бути викориÑтаний у визначенні ключа в цьому типі таблиці"
+ER_TOO_BIG_FIELDLENGTH 42000 S1009
+ cze "P-Bříliš velká délka sloupce '%-.192s' (nejvíce %lu). Použijte BLOB"
+ dan "For stor feltlængde for kolonne '%-.192s' (maks = %lu). Brug BLOB i stedet"
+ nla "Te grote kolomlengte voor '%-.192s' (max = %lu). Maak hiervoor gebruik van het type BLOB"
+ eng "Column length too big for column '%-.192s' (max = %lu); use BLOB or TEXT instead"
+ jps "column '%-.192s' ã¯,確ä¿ã™ã‚‹ column ã®å¤§ãã•ãŒå¤šã™ãŽã¾ã™. (最大 %lu ã¾ã§). BLOB ã‚’ã‹ã‚ã‚Šã«ä½¿ç”¨ã—ã¦ãã ã•ã„."
+ est "Tulba '%-.192s' pikkus on liiga pikk (maksimaalne pikkus: %lu). Kasuta BLOB väljatüüpi"
+ fre "Champ '%-.192s' trop long (max = %lu). Utilisez un BLOB"
+ ger "Feldlänge für Feld '%-.192s' zu groß (maximal %lu). BLOB- oder TEXT-Spaltentyp verwenden!"
+ greek "Î Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿ μήκος για το πεδίο '%-.192s' (max = %lu). ΠαÏακαλώ χÏησιμοποιείστε τον Ï„Ïπο BLOB"
+ hun "A(z) '%-.192s' oszlop tul hosszu. (maximum = %lu). Hasznaljon BLOB tipust inkabb."
+ ita "La colonna '%-.192s' e` troppo grande (max=%lu). Utilizza un BLOB."
+ jpn "column '%-.192s' ã¯,確ä¿ã™ã‚‹ column ã®å¤§ãã•ãŒå¤šã™ãŽã¾ã™. (最大 %lu ã¾ã§). BLOB ã‚’ã‹ã‚ã‚Šã«ä½¿ç”¨ã—ã¦ãã ã•ã„."
+ kor "칼럼 '%-.192s'ì˜ ì¹¼ëŸ¼ 길ì´ê°€ 너무 ê¹ë‹ˆë‹¤ (최대 = %lu). ëŒ€ì‹ ì— BLOB를 사용하세요."
+ nor "For stor nøkkellengde for kolonne '%-.192s' (maks = %lu). Bruk BLOB istedenfor"
+ norwegian-ny "For stor nykkellengde for felt '%-.192s' (maks = %lu). Bruk BLOB istadenfor"
+ pol "Zbyt duża długo?ć kolumny '%-.192s' (maks. = %lu). W zamian użyj typu BLOB"
+ por "Comprimento da coluna '%-.192s' grande demais (max = %lu); use BLOB em seu lugar"
+ rum "Lungimea coloanei '%-.192s' este prea lunga (maximum = %lu). Foloseste BLOB mai bine"
+ rus "Слишком Ð±Ð¾Ð»ÑŒÑˆÐ°Ñ Ð´Ð»Ð¸Ð½Ð° Ñтолбца '%-.192s' (макÑимум = %lu). ИÑпользуйте тип BLOB или TEXT вмеÑто текущего"
+ serbian "Previše podataka za kolonu '%-.192s' (maksimum je %lu). Upotrebite BLOB polje"
+ slo "Príliš veľká dĺžka pre pole '%-.192s' (maximum = %lu). Použite BLOB"
+ spa "Longitud de columna demasiado grande para la columna '%-.192s' (maximo = %lu).Usar BLOB en su lugar"
+ swe "För stor kolumnlängd angiven för '%-.192s' (max= %lu). Använd en BLOB instället"
+ ukr "Задовга довжина ÑÑ‚Ð¾Ð²Ð±Ñ†Ñ '%-.192s' (max = %lu). ВикориÑтайте тип BLOB"
+ER_WRONG_AUTO_KEY 42000 S1009
+ cze "M-Bůžete mít pouze jedno AUTO pole a to musí být definováno jako klíÄ"
+ dan "Der kan kun specificeres eet AUTO_INCREMENT-felt, og det skal være indekseret"
+ nla "Er kan slechts 1 autofield zijn en deze moet als zoeksleutel worden gedefinieerd."
+ eng "Incorrect table definition; there can be only one auto column and it must be defined as a key"
+ jps "テーブルã®å®šç¾©ãŒé•ã„ã¾ã™; there can be only one auto column and it must be defined as a key",
+ est "Vigane tabelikirjeldus; Tabelis tohib olla üks auto_increment tüüpi tulp ning see peab olema defineeritud võtmena"
+ fre "Un seul champ automatique est permis et il doit être indexé"
+ ger "Falsche Tabellendefinition. Es darf nur eine AUTO_INCREMENT-Spalte geben, und diese muss als Schlüssel definiert werden"
+ greek "ΜποÏεί να υπάÏχει μόνο ένα auto field και Ï€Ïέπει να έχει οÏισθεί σαν key"
+ hun "Csak egy auto mezo lehetseges, es azt kulcskent kell definialni."
+ ita "Puo` esserci solo un campo AUTO e deve essere definito come chiave"
+ jpn "テーブルã®å®šç¾©ãŒé•ã„ã¾ã™; there can be only one auto column and it must be defined as a key"
+ kor "부정확한 í…Œì´ë¸” ì •ì˜; í…Œì´ë¸”ì€ í•˜ë‚˜ì˜ auto ì¹¼ëŸ¼ì´ ì¡´ìž¬í•˜ê³  키로 ì •ì˜ë˜ì–´ì ¸ì•¼ 합니다."
+ nor "Bare ett auto felt kan være definert som nøkkel."
+ norwegian-ny "Bare eitt auto felt kan være definert som nøkkel."
+ pol "W tabeli może być tylko jedno pole auto i musi ono być zdefiniowane jako klucz"
+ por "Definição incorreta de tabela. Somente é permitido um único campo auto-incrementado e ele tem que ser definido como chave"
+ rum "Definitia tabelei este incorecta; Nu pot fi mai mult de o singura coloana de tip auto si aceasta trebuie definita ca cheie"
+ rus "Ðекорректное определение таблицы: может ÑущеÑтвовать только один автоинкрементный Ñтолбец, и он должен быть определен как ключ"
+ serbian "PogreÅ¡na definicija tabele; U tabeli može postojati samo jedna 'AUTO' kolona i ona mora biti istovremeno definisana kao kolona kljuÄa"
+ slo "Môžete maÅ¥ iba jedno AUTO pole a to musí byÅ¥ definované ako kľúÄ"
+ spa "Puede ser solamente un campo automatico y este debe ser definido como una clave"
+ swe "Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel"
+ ukr "Ðевірне Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ–; Може бути лише один автоматичний Ñтовбець, що повинен бути визначений Ñк ключ"
+ER_READY
+ cze "%s: p-Břipraven na spojení\nVersion: '%s' socket: '%s' port: %d""
+ dan "%s: klar til tilslutninger\nVersion: '%s' socket: '%s' port: %d""
+ nla "%s: klaar voor verbindingen\nVersion: '%s' socket: '%s' port: %d""
+ eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d"
+ jps "%s: 準備完了¥nVersion: '%s' socket: '%s' port: %d"",
+ est "%s: ootab ühendusi\nVersion: '%s' socket: '%s' port: %d""
+ fre "%s: Prêt pour des connexions\nVersion: '%s' socket: '%s' port: %d""
+ ger "%s: Bereit für Verbindungen.\nVersion: '%s' Socket: '%s' Port: %d"
+ greek "%s: σε αναμονή συνδέσεων\nVersion: '%s' socket: '%s' port: %d""
+ hun "%s: kapcsolatra kesz\nVersion: '%s' socket: '%s' port: %d""
+ ita "%s: Pronto per le connessioni\nVersion: '%s' socket: '%s' port: %d""
+ jpn "%s: 準備完了\nVersion: '%s' socket: '%s' port: %d""
+ kor "%s: 연결 준비중입니다\nVersion: '%s' socket: '%s' port: %d""
+ nor "%s: klar for tilkoblinger\nVersion: '%s' socket: '%s' port: %d""
+ norwegian-ny "%s: klar for tilkoblingar\nVersion: '%s' socket: '%s' port: %d""
+ pol "%s: gotowe do poł?czenia\nVersion: '%s' socket: '%s' port: %d""
+ por "%s: Pronto para conexões\nVersion: '%s' socket: '%s' port: %d""
+ rum "%s: sint gata pentru conectii\nVersion: '%s' socket: '%s' port: %d""
+ rus "%s: Готов принимать ÑоединениÑ.\nВерÑиÑ: '%s' Ñокет: '%s' порт: %d"
+ serbian "%s: Spreman za konekcije\nVersion: '%s' socket: '%s' port: %d""
+ slo "%s: pripravený na spojenie\nVersion: '%s' socket: '%s' port: %d""
+ spa "%s: preparado para conexiones\nVersion: '%s' socket: '%s' port: %d""
+ swe "%s: klar att ta emot klienter\nVersion: '%s' socket: '%s' port: %d""
+ ukr "%s: Готовий Ð´Ð»Ñ Ð·'єднань!\nVersion: '%s' socket: '%s' port: %d""
+ER_NORMAL_SHUTDOWN
+ cze "%s: norm-Bální ukonÄení\n"
+ dan "%s: Normal nedlukning\n"
+ nla "%s: Normaal afgesloten \n"
+ eng "%s: Normal shutdown\n"
+ est "%s: MySQL lõpetas\n"
+ fre "%s: Arrêt normal du serveur\n"
+ ger "%s: Normal heruntergefahren\n"
+ greek "%s: Φυσιολογική διαδικασία shutdown\n"
+ hun "%s: Normal leallitas\n"
+ ita "%s: Shutdown normale\n"
+ kor "%s: ì •ìƒì ì¸ shutdown\n"
+ nor "%s: Normal avslutning\n"
+ norwegian-ny "%s: Normal nedkopling\n"
+ pol "%s: Standardowe zakończenie działania\n"
+ por "%s: 'Shutdown' normal\n"
+ rum "%s: Terminare normala\n"
+ rus "%s: ÐšÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ð°Ñ Ð¾Ñтановка\n"
+ serbian "%s: Normalno gašenje\n"
+ slo "%s: normálne ukonÄenie\n"
+ spa "%s: Apagado normal\n"
+ swe "%s: Normal avslutning\n"
+ ukr "%s: Ðормальне завершеннÑ\n"
+ER_GOT_SIGNAL
+ cze "%s: p-BÅ™ijat signal %d, konÄím\n"
+ dan "%s: Fangede signal %d. Afslutter!!\n"
+ nla "%s: Signaal %d. Systeem breekt af!\n"
+ eng "%s: Got signal %d. Aborting!\n"
+ jps "%s: Got signal %d. 中断!¥n",
+ est "%s: sain signaali %d. Lõpetan!\n"
+ fre "%s: Reçu le signal %d. Abandonne!\n"
+ ger "%s: Signal %d erhalten. Abbruch!\n"
+ greek "%s: Ελήφθη το μήνυμα %d. Η διαδικασία εγκαταλείπεται!\n"
+ hun "%s: %d jelzes. Megszakitva!\n"
+ ita "%s: Ricevuto segnale %d. Interruzione!\n"
+ jpn "%s: Got signal %d. 中断!\n"
+ kor "%s: %d 신호가 들어왔ìŒ. 중지!\n"
+ nor "%s: Oppdaget signal %d. Avslutter!\n"
+ norwegian-ny "%s: Oppdaga signal %d. Avsluttar!\n"
+ pol "%s: Otrzymano sygnał %d. Kończenie działania!\n"
+ por "%s: Obteve sinal %d. Abortando!\n"
+ rum "%s: Semnal %d obtinut. Aborting!\n"
+ rus "%s: Получен Ñигнал %d. Прекращаем!\n"
+ serbian "%s: Dobio signal %d. Prekidam!\n"
+ slo "%s: prijatý signál %d, ukonÄenie (Abort)!\n"
+ spa "%s: Recibiendo signal %d. Abortando!\n"
+ swe "%s: Fick signal %d. Avslutar!\n"
+ ukr "%s: Отримано Ñигнал %d. ПерериваюÑÑŒ!\n"
+ER_SHUTDOWN_COMPLETE
+ cze "%s: ukon-BÄení práce hotovo\n"
+ dan "%s: Server lukket\n"
+ nla "%s: Afsluiten afgerond\n"
+ eng "%s: Shutdown complete\n"
+ jps "%s: Shutdown 完了¥n",
+ est "%s: Lõpp\n"
+ fre "%s: Arrêt du serveur terminé\n"
+ ger "%s: Herunterfahren beendet\n"
+ greek "%s: Η διαδικασία Shutdown ολοκληÏώθηκε\n"
+ hun "%s: A leallitas kesz\n"
+ ita "%s: Shutdown completato\n"
+ jpn "%s: Shutdown 完了\n"
+ kor "%s: Shutdown ì´ ì™„ë£Œë¨!\n"
+ nor "%s: Avslutning komplett\n"
+ norwegian-ny "%s: Nedkopling komplett\n"
+ pol "%s: Zakończenie działania wykonane\n"
+ por "%s: 'Shutdown' completo\n"
+ rum "%s: Terminare completa\n"
+ rus "%s: ОÑтановка завершена\n"
+ serbian "%s: Gašenje završeno\n"
+ slo "%s: práca ukonÄená\n"
+ spa "%s: Apagado completado\n"
+ swe "%s: Avslutning klar\n"
+ ukr "%s: Роботу завершено\n"
+ER_FORCING_CLOSE 08S01
+ cze "%s: n-Básilné uzavření threadu %ld uživatele '%-.48s'\n"
+ dan "%s: Forceret nedlukning af tråd: %ld bruger: '%-.48s'\n"
+ nla "%s: Afsluiten afgedwongen van thread %ld gebruiker: '%-.48s'\n"
+ eng "%s: Forcing close of thread %ld user: '%-.48s'\n"
+ jps "%s: スレッド %ld 強制終了 user: '%-.48s'¥n",
+ est "%s: Sulgen jõuga lõime %ld kasutaja: '%-.48s'\n"
+ fre "%s: Arrêt forcé de la tâche (thread) %ld utilisateur: '%-.48s'\n"
+ ger "%s: Thread %ld zwangsweise beendet. Benutzer: '%-.48s'\n"
+ greek "%s: Το thread θα κλείσει %ld user: '%-.48s'\n"
+ hun "%s: A(z) %ld thread kenyszeritett zarasa. Felhasznalo: '%-.48s'\n"
+ ita "%s: Forzata la chiusura del thread %ld utente: '%-.48s'\n"
+ jpn "%s: スレッド %ld 強制終了 user: '%-.48s'\n"
+ kor "%s: thread %ldì˜ ê°•ì œ 종료 user: '%-.48s'\n"
+ nor "%s: Påtvinget avslutning av tråd %ld bruker: '%-.48s'\n"
+ norwegian-ny "%s: Påtvinga avslutning av tråd %ld brukar: '%-.48s'\n"
+ pol "%s: Wymuszenie zamknięcia w?tku %ld użytkownik: '%-.48s'\n"
+ por "%s: Forçando finalização da 'thread' %ld - usuário '%-.48s'\n"
+ rum "%s: Terminare fortata a thread-ului %ld utilizatorului: '%-.48s'\n"
+ rus "%s: Принудительно закрываем поток %ld пользователÑ: '%-.48s'\n"
+ serbian "%s: Usiljeno gašenje thread-a %ld koji pripada korisniku: '%-.48s'\n"
+ slo "%s: násilné ukonÄenie vlákna %ld užívateľa '%-.48s'\n"
+ spa "%s: Forzando a cerrar el thread %ld usuario: '%-.48s'\n"
+ swe "%s: Stänger av tråd %ld; användare: '%-.48s'\n"
+ ukr "%s: ПриÑкорюю Ð·Ð°ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð³Ñ–Ð»ÐºÐ¸ %ld кориÑтувача: '%-.48s'\n"
+ER_IPSOCK_ERROR 08S01
+ cze "Nemohu vytvo-Břit IP socket"
+ dan "Kan ikke oprette IP socket"
+ nla "Kan IP-socket niet openen"
+ eng "Can't create IP socket"
+ jps "IP socket ãŒä½œã‚Œã¾ã›ã‚“",
+ est "Ei suuda luua IP socketit"
+ fre "Ne peut créer la connexion IP (socket)"
+ ger "Kann IP-Socket nicht erzeugen"
+ greek "Δεν είναι δυνατή η δημιουÏγία IP socket"
+ hun "Az IP socket nem hozhato letre"
+ ita "Impossibile creare il socket IP"
+ jpn "IP socket ãŒä½œã‚Œã¾ã›ã‚“"
+ kor "IP ì†Œì¼“ì„ ë§Œë“¤ì§€ 못했습니다."
+ nor "Kan ikke opprette IP socket"
+ norwegian-ny "Kan ikkje opprette IP socket"
+ pol "Nie można stworzyć socket'u IP"
+ por "Não pode criar o soquete IP"
+ rum "Nu pot crea IP socket"
+ rus "Ðевозможно Ñоздать IP-Ñокет"
+ serbian "Ne mogu da kreiram IP socket"
+ slo "Nemôžem vytvoriť IP socket"
+ spa "No puedo crear IP socket"
+ swe "Kan inte skapa IP-socket"
+ ukr "Ðе можу Ñтворити IP роз'єм"
+ER_NO_SUCH_INDEX 42S12 S1009
+ cze "Tabulka '%-.192s' nem-Bá index odpovídající CREATE INDEX. Vytvořte tabulku znovu"
+ dan "Tabellen '%-.192s' har ikke den nøgle, som blev brugt i CREATE INDEX. Genopret tabellen"
+ nla "Tabel '%-.192s' heeft geen INDEX zoals deze gemaakt worden met CREATE INDEX. Maak de tabel opnieuw"
+ eng "Table '%-.192s' has no index like the one used in CREATE INDEX; recreate the table"
+ jps "Table '%-.192s' ã¯ãã®ã‚ˆã†ãª index ã‚’æŒã£ã¦ã„ã¾ã›ã‚“(CREATE INDEX 実行時ã«æŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“). テーブルを作り直ã—ã¦ãã ã•ã„",
+ est "Tabelil '%-.192s' puuduvad võtmed. Loo tabel uuesti"
+ fre "La table '%-.192s' n'a pas d'index comme celle utilisée dans CREATE INDEX. Recréez la table"
+ ger "Tabelle '%-.192s' besitzt keinen wie den in CREATE INDEX verwendeten Index. Tabelle neu anlegen"
+ greek "Ο πίνακας '%-.192s' δεν έχει ευÏετήÏιο (index) σαν αυτό που χÏησιμοποιείτε στην CREATE INDEX. ΠαÏακαλώ, ξαναδημιουÏγήστε τον πίνακα"
+ hun "A(z) '%-.192s' tablahoz nincs meg a CREATE INDEX altal hasznalt index. Alakitsa at a tablat"
+ ita "La tabella '%-.192s' non ha nessun indice come quello specificatato dalla CREATE INDEX. Ricrea la tabella"
+ jpn "Table '%-.192s' ã¯ãã®ã‚ˆã†ãª index ã‚’æŒã£ã¦ã„ã¾ã›ã‚“(CREATE INDEX 実行時ã«æŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“). テーブルを作り直ã—ã¦ãã ã•ã„"
+ kor "í…Œì´ë¸” '%-.192s'는 ì¸ë±ìŠ¤ë¥¼ 만들지 않았습니다. alter í…Œì´ë¸”ëª…ë ¹ì„ ì´ìš©í•˜ì—¬ í…Œì´ë¸”ì„ ìˆ˜ì •í•˜ì„¸ìš”..."
+ nor "Tabellen '%-.192s' har ingen index som den som er brukt i CREATE INDEX. Gjenopprett tabellen"
+ norwegian-ny "Tabellen '%-.192s' har ingen index som den som er brukt i CREATE INDEX. Oprett tabellen på nytt"
+ pol "Tabela '%-.192s' nie ma indeksu takiego jak w CREATE INDEX. Stwórz tabelę"
+ por "Tabela '%-.192s' não possui um índice como o usado em CREATE INDEX. Recrie a tabela"
+ rum "Tabela '%-.192s' nu are un index ca acela folosit in CREATE INDEX. Re-creeaza tabela"
+ rus "Ð’ таблице '%-.192s' нет такого индекÑа, как в CREATE INDEX. Создайте таблицу заново"
+ serbian "Tabela '%-.192s' nema isti indeks kao onaj upotrebljen pri komandi 'CREATE INDEX'. Napravite tabelu ponovo"
+ slo "Tabuľka '%-.192s' nemá index zodpovedajúci CREATE INDEX. Vytvorte tabulku znova"
+ spa "La tabla '%-.192s' no tiene indice como el usado en CREATE INDEX. Crea de nuevo la tabla"
+ swe "Tabellen '%-.192s' har inget index som motsvarar det angivna i CREATE INDEX. Skapa om tabellen"
+ ukr "Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ '%-.192s' має індекÑ, що не Ñпівпадає з вказанним у CREATE INDEX. Створіть таблицю знову"
+ER_WRONG_FIELD_TERMINATORS 42000 S1009
+ cze "Argument separ-Bátoru položek nebyl oÄekáván. PÅ™eÄtÄ›te si manuál"
+ dan "Felt adskiller er ikke som forventet, se dokumentationen"
+ nla "De argumenten om velden te scheiden zijn anders dan verwacht. Raadpleeg de handleiding"
+ eng "Field separator argument is not what is expected; check the manual"
+ est "Väljade eraldaja erineb oodatust. Tutvu kasutajajuhendiga"
+ fre "Séparateur de champs inconnu. Vérifiez dans le manuel"
+ ger "Feldbegrenzer-Argument ist nicht in der erwarteten Form. Bitte im Handbuch nachlesen"
+ greek "Ο διαχωÏιστής πεδίων δεν είναι αυτός που αναμενόταν. ΠαÏακαλώ ανατÏέξτε στο manual"
+ hun "A mezoelvalaszto argumentumok nem egyeznek meg a varttal. Nezze meg a kezikonyvben!"
+ ita "L'argomento 'Field separator' non e` quello atteso. Controlla il manuale"
+ kor "í•„ë“œ êµ¬ë¶„ìž ì¸ìˆ˜ë“¤ì´ 완전하지 않습니다. ë©”ë‰´ì–¼ì„ ì°¾ì•„ 보세요."
+ nor "Felt skiller argumentene er ikke som forventet, se dokumentasjonen"
+ norwegian-ny "Felt skiljer argumenta er ikkje som venta, sjå dokumentasjonen"
+ pol "Nie oczekiwano separatora. SprawdĽ podręcznik"
+ por "Argumento separador de campos não é o esperado. Cheque o manual"
+ rum "Argumentul pentru separatorul de cimpuri este diferit de ce ma asteptam. Verifica manualul"
+ rus "Ðргумент Ñ€Ð°Ð·Ð´ÐµÐ»Ð¸Ñ‚ÐµÐ»Ñ Ð¿Ð¾Ð»ÐµÐ¹ - не тот, который ожидалÑÑ. ОбращайтеÑÑŒ к документации"
+ serbian "Argument separatora polja nije ono Å¡to se oÄekivalo. Proverite uputstvo MySQL server-a"
+ slo "Argument oddeľovaÄ polí nezodpovedá požiadavkám. Skontrolujte v manuáli"
+ spa "Los separadores de argumentos del campo no son los especificados. Comprueba el manual"
+ swe "Fältseparatorerna är vad som förväntades. Kontrollera mot manualen"
+ ukr "Хибний розділювач полів. Почитайте документацію"
+ER_BLOBS_AND_NO_TERMINATED 42000 S1009
+ cze "Nen-Bí možné použít pevný rowlength s BLOBem. Použijte 'fields terminated by'."
+ dan "Man kan ikke bruge faste feltlængder med BLOB. Brug i stedet 'fields terminated by'."
+ nla "Bij het gebruik van BLOBs is het niet mogelijk om vaste rijlengte te gebruiken. Maak s.v.p. gebruik van 'fields terminated by'."
+ eng "You can't use fixed rowlength with BLOBs; please use 'fields terminated by'"
+ est "BLOB-tüüpi väljade olemasolul ei saa kasutada fikseeritud väljapikkust. Vajalik 'fields terminated by' määrang."
+ fre "Vous ne pouvez utiliser des lignes de longueur fixe avec des BLOBs. Utiliser 'fields terminated by'."
+ ger "Eine feste Zeilenlänge kann für BLOB-Felder nicht verwendet werden. Bitte 'fields terminated by' verwenden"
+ greek "Δεν μποÏείτε να χÏησιμοποιήσετε fixed rowlength σε BLOBs. ΠαÏακαλώ χÏησιμοποιείστε 'fields terminated by'."
+ hun "Fix hosszusagu BLOB-ok nem hasznalhatok. Hasznalja a 'mezoelvalaszto jelet' ."
+ ita "Non possono essere usate righe a lunghezza fissa con i BLOB. Usa 'FIELDS TERMINATED BY'."
+ jpn "You can't use fixed rowlength with BLOBs; please use 'fields terminated by'."
+ kor "BLOB로는 고정길ì´ì˜ lowlength를 사용할 수 없습니다. 'fields terminated by'를 사용하세요."
+ nor "En kan ikke bruke faste feltlengder med BLOB. Vennlisgt bruk 'fields terminated by'."
+ norwegian-ny "Ein kan ikkje bruke faste feltlengder med BLOB. Vennlisgt bruk 'fields terminated by'."
+ pol "Nie można użyć stałej długo?ci wiersza z polami typu BLOB. Użyj 'fields terminated by'."
+ por "Você não pode usar comprimento de linha fixo com BLOBs. Por favor, use campos com comprimento limitado."
+ rum "Nu poti folosi lungime de cimp fix pentru BLOB-uri. Foloseste 'fields terminated by'."
+ rus "ФикÑированный размер запиÑи Ñ Ð¿Ð¾Ð»Ñми типа BLOB иÑпользовать нельзÑ, применÑйте 'fields terminated by'"
+ serbian "Ne možete koristiti fiksnu veliÄinu sloga kada imate BLOB polja. Molim koristite 'fields terminated by' opciju."
+ slo "Nie je možné použiť fixnú dĺžku s BLOBom. Použite 'fields terminated by'."
+ spa "No puedes usar longitudes de filas fijos con BLOBs. Por favor usa 'campos terminados por '."
+ swe "Man kan inte använda fast radlängd med blobs. Använd 'fields terminated by'"
+ ukr "Ðе можна викориÑтовувати Ñталу довжину Ñтроки з BLOB. ЗкориÑтайтеÑÑ 'fields terminated by'"
+ER_TEXTFILE_NOT_READABLE
+ cze "Soubor '%-.128s' mus-Bí být v adresáři databáze nebo Äitelný pro vÅ¡echny"
+ dan "Filen '%-.128s' skal være i database-folderen og kunne læses af alle"
+ nla "Het bestand '%-.128s' dient in de database directory voor the komen of leesbaar voor iedereen te zijn."
+ eng "The file '%-.128s' must be in the database directory or be readable by all"
+ jps "ファイル '%-.128s' 㯠databse ã® directory ã«ã‚ã‚‹ã‹å…¨ã¦ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒèª­ã‚るよã†ã«è¨±å¯ã•ã‚Œã¦ã„ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“.",
+ est "Fail '%-.128s' peab asuma andmebaasi kataloogis või olema kõigile loetav"
+ fre "Le fichier '%-.128s' doit être dans le répertoire de la base et lisible par tous"
+ ger "Datei '%-.128s' muss im Datenbank-Verzeichnis vorhanden oder lesbar für alle sein"
+ greek "Το αÏχείο '%-.128s' Ï€Ïέπει να υπάÏχει στο database directory ή να μποÏεί να διαβαστεί από όλους"
+ hun "A(z) '%-.128s'-nak az adatbazis konyvtarban kell lennie, vagy mindenki szamara olvashatonak"
+ ita "Il file '%-.128s' deve essere nella directory del database e deve essere leggibile da tutti"
+ jpn "ファイル '%-.128s' 㯠databse ã® directory ã«ã‚ã‚‹ã‹å…¨ã¦ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒèª­ã‚るよã†ã«è¨±å¯ã•ã‚Œã¦ã„ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“."
+ kor "'%-.128s' í™”ì¼ëŠ” ë°ì´íƒ€ë² ì´ìŠ¤ ë””ë ‰í† ë¦¬ì— ì¡´ìž¬í•˜ê±°ë‚˜ 모ë‘ì—게 ì½ê¸° 가능하여야 합니다."
+ nor "Filen '%-.128s' må være i database-katalogen for å være lesbar for alle"
+ norwegian-ny "Filen '%-.128s' må være i database-katalogen for å være lesbar for alle"
+ pol "Plik '%-.128s' musi znajdować sie w katalogu bazy danych lub mieć prawa czytania przez wszystkich"
+ por "Arquivo '%-.128s' tem que estar no diretório do banco de dados ou ter leitura possível para todos"
+ rum "Fisierul '%-.128s' trebuie sa fie in directorul bazei de data sau trebuie sa poata sa fie citit de catre toata lumea (verifica permisiile)"
+ rus "Файл '%-.128s' должен находитьÑÑ Ð² том же каталоге, что и база данных, или быть общедоÑтупным Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ"
+ serbian "File '%-.128s' mora biti u direktorijumu gde su file-ovi baze i mora imati odgovarajuća prava pristupa"
+ slo "Súbor '%-.128s' musí byÅ¥ v adresári databázy, alebo Äitateľný pre vÅ¡etkých"
+ spa "El archivo '%-.128s' debe estar en el directorio de la base de datos o ser de lectura por todos"
+ swe "Textfilen '%-.128s' måste finnas i databasbiblioteket eller vara läsbar för alla"
+ ukr "Файл '%-.128s' повинен бути у теці бази данних або мати вÑтановлене право на Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð´Ð»Ñ ÑƒÑÑ–Ñ…"
+ER_FILE_EXISTS_ERROR
+ cze "Soubor '%-.200s' ji-Bž existuje"
+ dan "Filen '%-.200s' eksisterer allerede"
+ nla "Het bestand '%-.200s' bestaat reeds"
+ eng "File '%-.200s' already exists"
+ jps "File '%-.200s' ã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™",
+ est "Fail '%-.200s' juba eksisteerib"
+ fre "Le fichier '%-.200s' existe déjà"
+ ger "Datei '%-.200s' bereits vorhanden"
+ greek "Το αÏχείο '%-.200s' υπάÏχει ήδη"
+ hun "A '%-.200s' file mar letezik."
+ ita "Il file '%-.200s' esiste gia`"
+ jpn "File '%-.200s' ã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™"
+ kor "'%-.200s' í™”ì¼ì€ ì´ë¯¸ 존재합니다."
+ nor "Filen '%-.200s' eksisterte allerede"
+ norwegian-ny "Filen '%-.200s' eksisterte allereide"
+ pol "Plik '%-.200s' już istnieje"
+ por "Arquivo '%-.200s' já existe"
+ rum "Fisierul '%-.200s' exista deja"
+ rus "Файл '%-.200s' уже ÑущеÑтвует"
+ serbian "File '%-.200s' već postoji"
+ slo "Súbor '%-.200s' už existuje"
+ spa "El archivo '%-.200s' ya existe"
+ swe "Filen '%-.200s' existerar redan"
+ ukr "Файл '%-.200s' вже Ñ–Ñнує"
+ER_LOAD_INFO
+ cze "Z-Báznamů: %ld Vymazáno: %ld PÅ™eskoÄeno: %ld Varování: %ld"
+ dan "Poster: %ld Fjernet: %ld Sprunget over: %ld Advarsler: %ld"
+ nla "Records: %ld Verwijderd: %ld Overgeslagen: %ld Waarschuwingen: %ld"
+ eng "Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld"
+ jps "レコード数: %ld 削除: %ld Skipped: %ld Warnings: %ld",
+ est "Kirjeid: %ld Kustutatud: %ld Vahele jäetud: %ld Hoiatusi: %ld"
+ fre "Enregistrements: %ld Effacés: %ld Non traités: %ld Avertissements: %ld"
+ ger "Datensätze: %ld Gelöscht: %ld Ausgelassen: %ld Warnungen: %ld"
+ greek "ΕγγÏαφές: %ld ΔιαγÏαφές: %ld ΠαÏεκάμφθησαν: %ld ΠÏοειδοποιήσεις: %ld"
+ hun "Rekordok: %ld Torolve: %ld Skipped: %ld Warnings: %ld"
+ ita "Records: %ld Cancellati: %ld Saltati: %ld Avvertimenti: %ld"
+ jpn "レコード数: %ld 削除: %ld Skipped: %ld Warnings: %ld"
+ kor "레코드: %ld개 삭제: %ld개 스킵: %ld개 경고: %ld개"
+ nor "Poster: %ld Fjernet: %ld Hoppet over: %ld Advarsler: %ld"
+ norwegian-ny "Poster: %ld Fjerna: %ld Hoppa over: %ld Ã…tvaringar: %ld"
+ pol "Recordów: %ld Usuniętych: %ld Pominiętych: %ld Ostrzeżeń: %ld"
+ por "Registros: %ld - Deletados: %ld - Ignorados: %ld - Avisos: %ld"
+ rum "Recorduri: %ld Sterse: %ld Sarite (skipped): %ld Atentionari (warnings): %ld"
+ rus "ЗапиÑей: %ld Удалено: %ld Пропущено: %ld Предупреждений: %ld"
+ serbian "Slogova: %ld Izbrisano: %ld PreskoÄeno: %ld Upozorenja: %ld"
+ slo "Záznamov: %ld Zmazaných: %ld PreskoÄených: %ld Varovania: %ld"
+ spa "Registros: %ld Borrados: %ld Saltados: %ld Peligros: %ld"
+ swe "Rader: %ld Bortagna: %ld Dubletter: %ld Varningar: %ld"
+ ukr "ЗапиÑів: %ld Видалено: %ld Пропущено: %ld ЗаÑтережень: %ld"
+ER_ALTER_INFO
+ cze "Z-Báznamů: %ld Zdvojených: %ld"
+ dan "Poster: %ld Ens: %ld"
+ nla "Records: %ld Dubbel: %ld"
+ eng "Records: %ld Duplicates: %ld"
+ jps "レコード数: %ld é‡è¤‡: %ld",
+ est "Kirjeid: %ld Kattuvaid: %ld"
+ fre "Enregistrements: %ld Doublons: %ld"
+ ger "Datensätze: %ld Duplikate: %ld"
+ greek "ΕγγÏαφές: %ld Επαναλήψεις: %ld"
+ hun "Rekordok: %ld Duplikalva: %ld"
+ ita "Records: %ld Duplicati: %ld"
+ jpn "レコード数: %ld é‡è¤‡: %ld"
+ kor "레코드: %ld개 중복: %ld개"
+ nor "Poster: %ld Like: %ld"
+ norwegian-ny "Poster: %ld Like: %ld"
+ pol "Rekordów: %ld Duplikatów: %ld"
+ por "Registros: %ld - Duplicados: %ld"
+ rum "Recorduri: %ld Duplicate: %ld"
+ rus "ЗапиÑей: %ld Дубликатов: %ld"
+ serbian "Slogova: %ld Duplikata: %ld"
+ slo "Záznamov: %ld Opakovaných: %ld"
+ spa "Registros: %ld Duplicados: %ld"
+ swe "Rader: %ld Dubletter: %ld"
+ ukr "ЗапиÑів: %ld Дублікатів: %ld"
+ER_WRONG_SUB_KEY
+ cze "Chybn-Bá podÄást klíÄe -- není to Å™etÄ›zec nebo je delší než délka Äásti klíÄe"
+ dan "Forkert indeksdel. Den anvendte nøgledel er ikke en streng eller længden er større end nøglelængden"
+ nla "Foutief sub-gedeelte van de zoeksleutel. De gebruikte zoeksleutel is geen onderdeel van een string of of de gebruikte lengte is langer dan de zoeksleutel"
+ eng "Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys"
+ est "Vigane võtme osa. Kasutatud võtmeosa ei ole string tüüpi, määratud pikkus on pikem kui võtmeosa või tabelihandler ei toeta seda tüüpi võtmeid"
+ fre "Mauvaise sous-clef. Ce n'est pas un 'string' ou la longueur dépasse celle définie dans la clef"
+ ger "Falscher Unterteilschlüssel. Der verwendete Schlüsselteil ist entweder kein String, die verwendete Länge ist länger als der Teilschlüssel oder die Speicher-Engine unterstützt keine Unterteilschlüssel"
+ greek "Εσφαλμένο sub part key. Το χÏησιμοποιοÏμενο key part δεν είναι string ή το μήκος του είναι μεγαλÏτεÏο"
+ hun "Rossz alkulcs. A hasznalt kulcsresz nem karaktersorozat vagy hosszabb, mint a kulcsresz"
+ ita "Sotto-parte della chiave errata. La parte di chiave utilizzata non e` una stringa o la lunghezza e` maggiore della parte di chiave."
+ jpn "Incorrect prefix key; the used key part isn't a string or the used length is longer than the key part"
+ kor "부정확한 서버 파트 키. ì‚¬ìš©ëœ í‚¤ 파트가 스트ë§ì´ 아니거나 키 íŒŒíŠ¸ì˜ ê¸¸ì´ê°€ 너무 ê¹ë‹ˆë‹¤."
+ nor "Feil delnøkkel. Den brukte delnøkkelen er ikke en streng eller den oppgitte lengde er lengre enn nøkkel lengden"
+ norwegian-ny "Feil delnykkel. Den brukte delnykkelen er ikkje ein streng eller den oppgitte lengda er lengre enn nykkellengden"
+ pol "Błędna podczę?ć klucza. Użyta czę?ć klucza nie jest łańcuchem lub użyta długo?ć jest większa niż czę?ć klucza"
+ por "Sub parte da chave incorreta. A parte da chave usada não é uma 'string' ou o comprimento usado é maior que parte da chave ou o manipulador de tabelas não suporta sub chaves únicas"
+ rum "Componentul cheii este incorrect. Componentul folosit al cheii nu este un sir sau lungimea folosita este mai lunga decit lungimea cheii"
+ rus "ÐÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ð°Ñ Ñ‡Ð°ÑÑ‚ÑŒ ключа. ИÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÐµÐ¼Ð°Ñ Ñ‡Ð°ÑÑ‚ÑŒ ключа не ÑвлÑетÑÑ Ñтрокой, ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ð°Ñ Ð´Ð»Ð¸Ð½Ð° больше, чем длина чаÑти ключа, или обработчик таблицы не поддерживает уникальные чаÑти ключа"
+ serbian "PogreÅ¡an pod-kljuÄ dela kljuÄa. Upotrebljeni deo kljuÄa nije string, upotrebljena dužina je veća od dela kljuÄa ili handler tabela ne podržava jedinstvene pod-kljuÄeve"
+ slo "Incorrect prefix key; the used key part isn't a string or the used length is longer than the key part"
+ spa "Parte de la clave es erronea. Una parte de la clave no es una cadena o la longitud usada es tan grande como la parte de la clave"
+ swe "Felaktig delnyckel. Nyckeldelen är inte en sträng eller den angivna längden är längre än kolumnlängden"
+ ukr "Ðевірна чаÑтина ключа. ВикориÑтана чаÑтина ключа не Ñ” Ñтрокою, задовга або вказівник таблиці не підтримує унікальних чаÑтин ключей"
+ER_CANT_REMOVE_ALL_FIELDS 42000
+ cze "Nen-Bí možné vymazat všechny položky s ALTER TABLE. Použijte DROP TABLE"
+ dan "Man kan ikke slette alle felter med ALTER TABLE. Brug DROP TABLE i stedet."
+ nla "Het is niet mogelijk alle velden te verwijderen met ALTER TABLE. Gebruik a.u.b. DROP TABLE hiervoor!"
+ eng "You can't delete all columns with ALTER TABLE; use DROP TABLE instead"
+ jps "ALTER TABLE ã§å…¨ã¦ã® column ã¯å‰Šé™¤ã§ãã¾ã›ã‚“. DROP TABLE を使用ã—ã¦ãã ã•ã„",
+ est "ALTER TABLE kasutades ei saa kustutada kõiki tulpasid. Kustuta tabel DROP TABLE abil"
+ fre "Vous ne pouvez effacer tous les champs avec ALTER TABLE. Utilisez DROP TABLE"
+ ger "Mit ALTER TABLE können nicht alle Felder auf einmal gelöscht werden. Dafür DROP TABLE verwenden"
+ greek "Δεν είναι δυνατή η διαγÏαφή όλων των πεδίων με ALTER TABLE. ΠαÏακαλώ χÏησιμοποιείστε DROP TABLE"
+ hun "Az osszes mezo nem torolheto az ALTER TABLE-lel. Hasznalja a DROP TABLE-t helyette"
+ ita "Non si possono cancellare tutti i campi con una ALTER TABLE. Utilizzare DROP TABLE"
+ jpn "ALTER TABLE ã§å…¨ã¦ã® column ã¯å‰Šé™¤ã§ãã¾ã›ã‚“. DROP TABLE を使用ã—ã¦ãã ã•ã„"
+ kor "ALTER TABLE 명령으로는 모든 ì¹¼ëŸ¼ì„ ì§€ìš¸ 수 없습니다. DROP TABLE ëª…ë ¹ì„ ì´ìš©í•˜ì„¸ìš”."
+ nor "En kan ikke slette alle felt med ALTER TABLE. Bruk DROP TABLE isteden."
+ norwegian-ny "Ein kan ikkje slette alle felt med ALTER TABLE. Bruk DROP TABLE istadenfor."
+ pol "Nie można usun?ć wszystkich pól wykorzystuj?c ALTER TABLE. W zamian użyj DROP TABLE"
+ por "Você não pode deletar todas as colunas com ALTER TABLE; use DROP TABLE em seu lugar"
+ rum "Nu poti sterge toate coloanele cu ALTER TABLE. Foloseste DROP TABLE in schimb"
+ rus "ÐÐµÐ»ÑŒÐ·Ñ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ вÑе Ñтолбцы Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ ALTER TABLE. ИÑпользуйте DROP TABLE"
+ serbian "Ne možete da izbrišete sve kolone pomoću komande 'ALTER TABLE'. Upotrebite komandu 'DROP TABLE' ako želite to da uradite"
+ slo "One nemôžem zmazať all fields with ALTER TABLE; use DROP TABLE instead"
+ spa "No puede borrar todos los campos con ALTER TABLE. Usa DROP TABLE para hacerlo"
+ swe "Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället"
+ ukr "Ðе можливо видалити вÑÑ– Ñтовбці за допомогою ALTER TABLE. Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ ÑкориÑтайтеÑÑ DROP TABLE"
+ER_CANT_DROP_FIELD_OR_KEY 42000
+ cze "Nemohu zru-BÅ¡it '%-.192s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíÄe"
+ dan "Kan ikke udføre DROP '%-.192s'. Undersøg om feltet/nøglen eksisterer."
+ nla "Kan '%-.192s' niet weggooien. Controleer of het veld of de zoeksleutel daadwerkelijk bestaat."
+ eng "Can't DROP '%-.192s'; check that column/key exists"
+ jps "'%-.192s' を破棄ã§ãã¾ã›ã‚“ã§ã—ãŸ; check that column/key exists",
+ est "Ei suuda kustutada '%-.192s'. Kontrolli kas tulp/võti eksisteerib"
+ fre "Ne peut effacer (DROP) '%-.192s'. Vérifiez s'il existe"
+ ger "Kann '%-.192s' nicht löschen. Existiert die Spalte oder der Schlüssel?"
+ greek "ΑδÏνατη η διαγÏαφή (DROP) '%-.192s'. ΠαÏακαλώ ελέγξτε αν το πεδίο/κλειδί υπάÏχει"
+ hun "A DROP '%-.192s' nem lehetseges. Ellenorizze, hogy a mezo/kulcs letezik-e"
+ ita "Impossibile cancellare '%-.192s'. Controllare che il campo chiave esista"
+ jpn "'%-.192s' を破棄ã§ãã¾ã›ã‚“ã§ã—ãŸ; check that column/key exists"
+ kor "'%-.192s'를 DROPí•  수 없습니다. 칼럼ì´ë‚˜ 키가 존재하는지 채í¬í•˜ì„¸ìš”."
+ nor "Kan ikke DROP '%-.192s'. Undersøk om felt/nøkkel eksisterer."
+ norwegian-ny "Kan ikkje DROP '%-.192s'. Undersøk om felt/nøkkel eksisterar."
+ pol "Nie można wykonać operacji DROP '%-.192s'. SprawdĽ, czy to pole/klucz istnieje"
+ por "Não se pode fazer DROP '%-.192s'. Confira se esta coluna/chave existe"
+ rum "Nu pot sa DROP '%-.192s'. Verifica daca coloana/cheia exista"
+ rus "Ðевозможно удалить (DROP) '%-.192s'. УбедитеÑÑŒ что Ñтолбец/ключ дейÑтвительно ÑущеÑтвует"
+ serbian "Ne mogu da izvrÅ¡im komandu drop 'DROP' na '%-.192s'. Proverite da li ta kolona (odnosno kljuÄ) postoji"
+ slo "Nemôžem zruÅ¡iÅ¥ (DROP) '%-.192s'. Skontrolujte, Äi neexistujú záznamy/kľúÄe"
+ spa "No puedo ELIMINAR '%-.192s'. compuebe que el campo/clave existe"
+ swe "Kan inte ta bort '%-.192s'. Kontrollera att fältet/nyckel finns"
+ ukr "Ðе можу DROP '%-.192s'. Перевірте, чи цей Ñтовбець/ключ Ñ–Ñнує"
+ER_INSERT_INFO
+ cze "Z-Báznamů: %ld Zdvojených: %ld Varování: %ld"
+ dan "Poster: %ld Ens: %ld Advarsler: %ld"
+ nla "Records: %ld Dubbel: %ld Waarschuwing: %ld"
+ eng "Records: %ld Duplicates: %ld Warnings: %ld"
+ jps "レコード数: %ld é‡è¤‡æ•°: %ld Warnings: %ld",
+ est "Kirjeid: %ld Kattuvaid: %ld Hoiatusi: %ld"
+ fre "Enregistrements: %ld Doublons: %ld Avertissements: %ld"
+ ger "Datensätze: %ld Duplikate: %ld Warnungen: %ld"
+ greek "ΕγγÏαφές: %ld Επαναλήψεις: %ld ΠÏοειδοποιήσεις: %ld"
+ hun "Rekordok: %ld Duplikalva: %ld Warnings: %ld"
+ ita "Records: %ld Duplicati: %ld Avvertimenti: %ld"
+ jpn "レコード数: %ld é‡è¤‡æ•°: %ld Warnings: %ld"
+ kor "레코드: %ld개 중복: %ld개 경고: %ld개"
+ nor "Poster: %ld Like: %ld Advarsler: %ld"
+ norwegian-ny "Postar: %ld Like: %ld Ã…tvaringar: %ld"
+ pol "Rekordów: %ld Duplikatów: %ld Ostrzeżeń: %ld"
+ por "Registros: %ld - Duplicados: %ld - Avisos: %ld"
+ rum "Recorduri: %ld Duplicate: %ld Atentionari (warnings): %ld"
+ rus "ЗапиÑей: %ld Дубликатов: %ld Предупреждений: %ld"
+ serbian "Slogova: %ld Duplikata: %ld Upozorenja: %ld"
+ slo "Záznamov: %ld Opakovaných: %ld Varovania: %ld"
+ spa "Registros: %ld Duplicados: %ld Peligros: %ld"
+ swe "Rader: %ld Dubletter: %ld Varningar: %ld"
+ ukr "ЗапиÑів: %ld Дублікатів: %ld ЗаÑтережень: %ld"
+ER_UPDATE_TABLE_USED
+ eng "You can't specify target table '%-.192s' for update in FROM clause"
+ ger "Die Verwendung der zu aktualisierenden Zieltabelle '%-.192s' ist in der FROM-Klausel nicht zulässig."
+ rus "Ðе допуÑкаетÑÑ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ðµ таблицы '%-.192s' в ÑпиÑке таблиц FROM Ð´Ð»Ñ Ð²Ð½ÐµÑÐµÐ½Ð¸Ñ Ð² нее изменений"
+ swe "INSERT-table '%-.192s' får inte finnas i FROM tabell-listan"
+ ukr "Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ '%-.192s' що змінюєтьÑÑ Ð½Ðµ дозволена у переліку таблиць FROM"
+ER_NO_SUCH_THREAD
+ cze "Nezn-Bámá identifikace threadu: %lu"
+ dan "Ukendt tråd id: %lu"
+ nla "Onbekend thread id: %lu"
+ eng "Unknown thread id: %lu"
+ jps "thread id: %lu ã¯ã‚ã‚Šã¾ã›ã‚“",
+ est "Tundmatu lõim: %lu"
+ fre "Numéro de tâche inconnu: %lu"
+ ger "Unbekannte Thread-ID: %lu"
+ greek "Αγνωστο thread id: %lu"
+ hun "Ervenytelen szal (thread) id: %lu"
+ ita "Thread id: %lu sconosciuto"
+ jpn "thread id: %lu ã¯ã‚ã‚Šã¾ã›ã‚“"
+ kor "알수 없는 쓰레드 id: %lu"
+ nor "Ukjent tråd id: %lu"
+ norwegian-ny "Ukjent tråd id: %lu"
+ pol "Nieznany identyfikator w?tku: %lu"
+ por "'Id' de 'thread' %lu desconhecido"
+ rum "Id-ul: %lu thread-ului este necunoscut"
+ rus "ÐеизвеÑтный номер потока: %lu"
+ serbian "Nepoznat thread identifikator: %lu"
+ slo "Neznáma identifikácia vlákna: %lu"
+ spa "Identificador del thread: %lu desconocido"
+ swe "Finns ingen tråd med id %lu"
+ ukr "Ðевідомий ідентифікатор гілки: %lu"
+ER_KILL_DENIED_ERROR
+ cze "Nejste vlastn-Bíkem threadu %lu"
+ dan "Du er ikke ejer af tråden %lu"
+ nla "U bent geen bezitter van thread %lu"
+ eng "You are not owner of thread %lu"
+ jps "thread %lu ã®ã‚ªãƒ¼ãƒŠãƒ¼ã§ã¯ã‚ã‚Šã¾ã›ã‚“",
+ est "Ei ole lõime %lu omanik"
+ fre "Vous n'êtes pas propriétaire de la tâche no: %lu"
+ ger "Sie sind nicht Eigentümer von Thread %lu"
+ greek "Δεν είσθε owner του thread %lu"
+ hun "A %lu thread-nek mas a tulajdonosa"
+ ita "Utente non proprietario del thread %lu"
+ jpn "thread %lu ã®ã‚ªãƒ¼ãƒŠãƒ¼ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+ kor "쓰레드(Thread) %luì˜ ì†Œìœ ìžê°€ 아닙니다."
+ nor "Du er ikke eier av tråden %lu"
+ norwegian-ny "Du er ikkje eigar av tråd %lu"
+ pol "Nie jeste? wła?cicielem w?tku %lu"
+ por "Você não é proprietário da 'thread' %lu"
+ rum "Nu sinteti proprietarul threadului %lu"
+ rus "Ð’Ñ‹ не ÑвлÑетеÑÑŒ владельцем потока %lu"
+ serbian "Vi niste vlasnik thread-a %lu"
+ slo "Nie ste vlastníkom vlákna %lu"
+ spa "Tu no eres el propietario del thread%lu"
+ swe "Du är inte ägare till tråd %lu"
+ ukr "Ви не володар гілки %lu"
+ER_NO_TABLES_USED
+ cze "Nejsou pou-Bžity žádné tabulky"
+ dan "Ingen tabeller i brug"
+ nla "Geen tabellen gebruikt."
+ eng "No tables used"
+ est "Ãœhtegi tabelit pole kasutusel"
+ fre "Aucune table utilisée"
+ ger "Keine Tabellen verwendet"
+ greek "Δεν χÏησιμοποιήθηκαν πίνακες"
+ hun "Nincs hasznalt tabla"
+ ita "Nessuna tabella usata"
+ kor "ì–´ë–¤ í…Œì´ë¸”ë„ ì‚¬ìš©ë˜ì§€ 않았습니다."
+ nor "Ingen tabeller i bruk"
+ norwegian-ny "Ingen tabellar i bruk"
+ pol "Nie ma żadej użytej tabeli"
+ por "Nenhuma tabela usada"
+ rum "Nici o tabela folosita"
+ rus "Ðикакие таблицы не иÑпользованы"
+ serbian "Nema upotrebljenih tabela"
+ slo "Nie je použitá žiadna tabuľka"
+ spa "No ha tablas usadas"
+ swe "Inga tabeller angivna"
+ ukr "Ðе викориÑтано таблиць"
+ER_TOO_BIG_SET
+ cze "P-Bříliš mnoho řetězců pro sloupec %-.192s a SET"
+ dan "For mange tekststrenge til specifikationen af SET i kolonne %-.192s"
+ nla "Teveel strings voor kolom %-.192s en SET"
+ eng "Too many strings for column %-.192s and SET"
+ est "Liiga palju string tulbale %-.192s tüübile SET"
+ fre "Trop de chaînes dans la colonne %-.192s avec SET"
+ ger "Zu viele Strings für Feld %-.192s und SET angegeben"
+ greek "ΠάÏα πολλά strings για το πεδίο %-.192s και SET"
+ hun "Tul sok karakter: %-.192s es SET"
+ ita "Troppe stringhe per la colonna %-.192s e la SET"
+ kor "칼럼 %-.192s와 SETì—ì„œ 스트ë§ì´ 너무 많습니다."
+ nor "For mange tekststrenger kolonne %-.192s og SET"
+ norwegian-ny "For mange tekststrengar felt %-.192s og SET"
+ pol "Zbyt wiele łańcuchów dla kolumny %-.192s i polecenia SET"
+ por "'Strings' demais para coluna '%-.192s' e SET"
+ rum "Prea multe siruri pentru coloana %-.192s si SET"
+ rus "Слишком много значений Ð´Ð»Ñ Ñтолбца %-.192s в SET"
+ serbian "Previše string-ova za kolonu '%-.192s' i komandu 'SET'"
+ slo "Príliš mnoho reťazcov pre pole %-.192s a SET"
+ spa "Muchas strings para columna %-.192s y SET"
+ swe "För många alternativ till kolumn %-.192s för SET"
+ ukr "Забагато Ñтрок Ð´Ð»Ñ ÑÑ‚Ð¾Ð²Ð±Ñ†Ñ %-.192s та SET"
+ER_NO_UNIQUE_LOGFILE
+ cze "Nemohu vytvo-BÅ™it jednoznaÄné jméno logovacího souboru %-.200s.(1-999)\n"
+ dan "Kan ikke lave unikt log-filnavn %-.200s.(1-999)\n"
+ nla "Het is niet mogelijk een unieke naam te maken voor de logfile %-.200s.(1-999)\n"
+ eng "Can't generate a unique log-filename %-.200s.(1-999)\n"
+ est "Ei suuda luua unikaalset logifaili nime %-.200s.(1-999)\n"
+ fre "Ne peut générer un unique nom de journal %-.200s.(1-999)\n"
+ ger "Kann keinen eindeutigen Dateinamen für die Logdatei %-.200s(1-999) erzeugen\n"
+ greek "ΑδÏνατη η δημιουÏγία unique log-filename %-.200s.(1-999)\n"
+ hun "Egyedi log-filenev nem generalhato: %-.200s.(1-999)\n"
+ ita "Impossibile generare un nome del file log unico %-.200s.(1-999)\n"
+ kor "Unique ë¡œê·¸í™”ì¼ '%-.200s'를 만들수 없습니다.(1-999)\n"
+ nor "Kan ikke lage unikt loggfilnavn %-.200s.(1-999)\n"
+ norwegian-ny "Kan ikkje lage unikt loggfilnavn %-.200s.(1-999)\n"
+ pol "Nie można stworzyć unikalnej nazwy pliku z logiem %-.200s.(1-999)\n"
+ por "Não pode gerar um nome de arquivo de 'log' único '%-.200s'.(1-999)\n"
+ rum "Nu pot sa generez un nume de log unic %-.200s.(1-999)\n"
+ rus "Ðевозможно Ñоздать уникальное Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° журнала %-.200s.(1-999)\n"
+ serbian "Ne mogu da generišem jedinstveno ime log-file-a: '%-.200s.(1-999)'\n"
+ slo "Nemôžem vytvoriť unikátne meno log-súboru %-.200s.(1-999)\n"
+ spa "No puede crear un unico archivo log %-.200s.(1-999)\n"
+ swe "Kan inte generera ett unikt filnamn %-.200s.(1-999)\n"
+ ukr "Ðе можу згенерувати унікальне ім'Ñ log-файлу %-.200s.(1-999)\n"
+ER_TABLE_NOT_LOCKED_FOR_WRITE
+ cze "Tabulka '%-.192s' byla zam-BÄena s READ a nemůže být zmÄ›nÄ›na"
+ dan "Tabellen '%-.192s' var låst med READ lås og kan ikke opdateres"
+ nla "Tabel '%-.192s' was gelocked met een lock om te lezen. Derhalve kunnen geen wijzigingen worden opgeslagen."
+ eng "Table '%-.192s' was locked with a READ lock and can't be updated"
+ jps "Table '%-.192s' 㯠READ lock ã«ãªã£ã¦ã„ã¦ã€æ›´æ–°ã¯ã§ãã¾ã›ã‚“",
+ est "Tabel '%-.192s' on lukustatud READ lukuga ning ei ole muudetav"
+ fre "Table '%-.192s' verrouillée lecture (READ): modification impossible"
+ ger "Tabelle '%-.192s' ist mit Lesesperre versehen und kann nicht aktualisiert werden"
+ greek "Ο πίνακας '%-.192s' έχει κλειδωθεί με READ lock και δεν επιτÏέπονται αλλαγές"
+ hun "A(z) '%-.192s' tabla zarolva lett (READ lock) es nem lehet frissiteni"
+ ita "La tabella '%-.192s' e` soggetta a lock in lettura e non puo` essere aggiornata"
+ jpn "Table '%-.192s' 㯠READ lock ã«ãªã£ã¦ã„ã¦ã€æ›´æ–°ã¯ã§ãã¾ã›ã‚“"
+ kor "í…Œì´ë¸” '%-.192s'는 READ ë½ì´ 잠겨있어서 갱신할 수 없습니다."
+ nor "Tabellen '%-.192s' var låst med READ lås og kan ikke oppdateres"
+ norwegian-ny "Tabellen '%-.192s' var låst med READ lås og kan ikkje oppdaterast"
+ pol "Tabela '%-.192s' została zablokowana przez READ i nie może zostać zaktualizowana"
+ por "Tabela '%-.192s' foi travada com trava de leitura e não pode ser atualizada"
+ rum "Tabela '%-.192s' a fost locked cu un READ lock si nu poate fi actualizata"
+ rus "Таблица '%-.192s' заблокирована уровнем READ lock и не может быть изменена"
+ serbian "Tabela '%-.192s' je zakljuÄana READ lock-om; iz nje se može samo Äitati ali u nju se ne može pisati"
+ slo "Tabuľka '%-.192s' bola zamknutá s READ a nemôže byť zmenená"
+ spa "Tabla '%-.192s' fue trabada con un READ lock y no puede ser actualizada"
+ swe "Tabell '%-.192s' kan inte uppdateras emedan den är låst för läsning"
+ ukr "Таблицю '%-.192s' заблоковано тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ, тому Ñ—Ñ— не можна оновити"
+ER_TABLE_NOT_LOCKED
+ cze "Tabulka '%-.192s' nebyla zam-BÄena s LOCK TABLES"
+ dan "Tabellen '%-.192s' var ikke låst med LOCK TABLES"
+ nla "Tabel '%-.192s' was niet gelocked met LOCK TABLES"
+ eng "Table '%-.192s' was not locked with LOCK TABLES"
+ jps "Table '%-.192s' 㯠LOCK TABLES ã«ã‚ˆã£ã¦ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã›ã‚“",
+ est "Tabel '%-.192s' ei ole lukustatud käsuga LOCK TABLES"
+ fre "Table '%-.192s' non verrouillée: utilisez LOCK TABLES"
+ ger "Tabelle '%-.192s' wurde nicht mit LOCK TABLES gesperrt"
+ greek "Ο πίνακας '%-.192s' δεν έχει κλειδωθεί με LOCK TABLES"
+ hun "A(z) '%-.192s' tabla nincs zarolva a LOCK TABLES-szel"
+ ita "Non e` stato impostato il lock per la tabella '%-.192s' con LOCK TABLES"
+ jpn "Table '%-.192s' 㯠LOCK TABLES ã«ã‚ˆã£ã¦ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+ kor "í…Œì´ë¸” '%-.192s'는 LOCK TABLES 명령으로 잠기지 않았습니다."
+ nor "Tabellen '%-.192s' var ikke låst med LOCK TABLES"
+ norwegian-ny "Tabellen '%-.192s' var ikkje låst med LOCK TABLES"
+ pol "Tabela '%-.192s' nie została zablokowana poleceniem LOCK TABLES"
+ por "Tabela '%-.192s' não foi travada com LOCK TABLES"
+ rum "Tabela '%-.192s' nu a fost locked cu LOCK TABLES"
+ rus "Таблица '%-.192s' не была заблокирована Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ LOCK TABLES"
+ serbian "Tabela '%-.192s' nije bila zakljuÄana komandom 'LOCK TABLES'"
+ slo "Tabuľka '%-.192s' nebola zamknutá s LOCK TABLES"
+ spa "Tabla '%-.192s' no fue trabada con LOCK TABLES"
+ swe "Tabell '%-.192s' är inte låst med LOCK TABLES"
+ ukr "Таблицю '%-.192s' не було блоковано з LOCK TABLES"
+ER_BLOB_CANT_HAVE_DEFAULT 42000
+ cze "Blob polo-Bžka '%-.192s' nemůže mít defaultní hodnotu"
+ dan "BLOB feltet '%-.192s' kan ikke have en standard værdi"
+ nla "Blob veld '%-.192s' can geen standaardwaarde bevatten"
+ eng "BLOB/TEXT column '%-.192s' can't have a default value"
+ est "BLOB-tüüpi tulp '%-.192s' ei saa omada vaikeväärtust"
+ fre "BLOB '%-.192s' ne peut avoir de valeur par défaut"
+ ger "BLOB/TEXT-Feld '%-.192s' darf keinen Vorgabewert (DEFAULT) haben"
+ greek "Τα Blob πεδία '%-.192s' δεν μποÏοÏν να έχουν Ï€ÏοκαθοÏισμένες τιμές (default value)"
+ hun "A(z) '%-.192s' blob objektumnak nem lehet alapertelmezett erteke"
+ ita "Il campo BLOB '%-.192s' non puo` avere un valore di default"
+ jpn "BLOB column '%-.192s' can't have a default value"
+ kor "BLOB 칼럼 '%-.192s' 는 ë””í´íŠ¸ ê°’ì„ ê°€ì§ˆ 수 없습니다."
+ nor "Blob feltet '%-.192s' kan ikke ha en standard verdi"
+ norwegian-ny "Blob feltet '%-.192s' kan ikkje ha ein standard verdi"
+ pol "Pole typu blob '%-.192s' nie może mieć domy?lnej warto?ci"
+ por "Coluna BLOB '%-.192s' não pode ter um valor padrão (default)"
+ rum "Coloana BLOB '%-.192s' nu poate avea o valoare default"
+ rus "Ðевозможно указывать значение по умолчанию Ð´Ð»Ñ Ñтолбца BLOB '%-.192s'"
+ serbian "BLOB kolona '%-.192s' ne može imati default vrednost"
+ slo "Pole BLOB '%-.192s' nemôže mať implicitnú hodnotu"
+ spa "Campo Blob '%-.192s' no puede tener valores patron"
+ swe "BLOB fält '%-.192s' kan inte ha ett DEFAULT-värde"
+ ukr "Стовбець BLOB '%-.192s' не може мати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð¾ замовчуванню"
+ER_WRONG_DB_NAME 42000
+ cze "Nep-Břípustné jméno databáze '%-.100s'"
+ dan "Ugyldigt database navn '%-.100s'"
+ nla "Databasenaam '%-.100s' is niet getoegestaan"
+ eng "Incorrect database name '%-.100s'"
+ jps "指定ã—㟠database å '%-.100s' ãŒé–“é•ã£ã¦ã„ã¾ã™",
+ est "Vigane andmebaasi nimi '%-.100s'"
+ fre "Nom de base de donnée illégal: '%-.100s'"
+ ger "Unerlaubter Datenbankname '%-.100s'"
+ greek "Λάθος όνομα βάσης δεδομένων '%-.100s'"
+ hun "Hibas adatbazisnev: '%-.100s'"
+ ita "Nome database errato '%-.100s'"
+ jpn "指定ã—㟠database å '%-.100s' ãŒé–“é•ã£ã¦ã„ã¾ã™"
+ kor "'%-.100s' ë°ì´íƒ€ë² ì´ìŠ¤ì˜ ì´ë¦„ì´ ë¶€ì •í™•í•©ë‹ˆë‹¤."
+ nor "Ugyldig database navn '%-.100s'"
+ norwegian-ny "Ugyldig database namn '%-.100s'"
+ pol "Niedozwolona nazwa bazy danych '%-.100s'"
+ por "Nome de banco de dados '%-.100s' incorreto"
+ rum "Numele bazei de date este incorect '%-.100s'"
+ rus "Ðекорректное Ð¸Ð¼Ñ Ð±Ð°Ð·Ñ‹ данных '%-.100s'"
+ serbian "Pogrešno ime baze '%-.100s'"
+ slo "Neprípustné meno databázy '%-.100s'"
+ spa "Nombre de base de datos ilegal '%-.100s'"
+ swe "Felaktigt databasnamn '%-.100s'"
+ ukr "Ðевірне ім'Ñ Ð±Ð°Ð·Ð¸ данних '%-.100s'"
+ER_WRONG_TABLE_NAME 42000
+ cze "Nep-Břípustné jméno tabulky '%-.100s'"
+ dan "Ugyldigt tabel navn '%-.100s'"
+ nla "Niet toegestane tabelnaam '%-.100s'"
+ eng "Incorrect table name '%-.100s'"
+ jps "指定ã—㟠table å '%-.100s' ã¯ã¾ã¡ãŒã£ã¦ã„ã¾ã™",
+ est "Vigane tabeli nimi '%-.100s'"
+ fre "Nom de table illégal: '%-.100s'"
+ ger "Unerlaubter Tabellenname '%-.100s'"
+ greek "Λάθος όνομα πίνακα '%-.100s'"
+ hun "Hibas tablanev: '%-.100s'"
+ ita "Nome tabella errato '%-.100s'"
+ jpn "指定ã—㟠table å '%-.100s' ã¯ã¾ã¡ãŒã£ã¦ã„ã¾ã™"
+ kor "'%-.100s' í…Œì´ë¸” ì´ë¦„ì´ ë¶€ì •í™•í•©ë‹ˆë‹¤."
+ nor "Ugyldig tabell navn '%-.100s'"
+ norwegian-ny "Ugyldig tabell namn '%-.100s'"
+ pol "Niedozwolona nazwa tabeli '%-.100s'..."
+ por "Nome de tabela '%-.100s' incorreto"
+ rum "Numele tabelei este incorect '%-.100s'"
+ rus "Ðекорректное Ð¸Ð¼Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ '%-.100s'"
+ serbian "Pogrešno ime tabele '%-.100s'"
+ slo "Neprípustné meno tabuľky '%-.100s'"
+ spa "Nombre de tabla ilegal '%-.100s'"
+ swe "Felaktigt tabellnamn '%-.100s'"
+ ukr "Ðевірне ім'Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– '%-.100s'"
+ER_TOO_BIG_SELECT 42000
+ cze "Zadan-Bý SELECT by procházel příliš mnoho záznamů a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v pořádku, použijte SET SQL_BIG_SELECTS=1"
+ dan "SELECT ville undersøge for mange poster og ville sandsynligvis tage meget lang tid. Undersøg WHERE delen og brug SET SQL_BIG_SELECTS=1 hvis udtrykket er korrekt"
+ nla "Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET SQL_BIG_SELECTS=1 als het stament in orde is."
+ eng "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay"
+ est "SELECT lause peab läbi vaatama suure hulga kirjeid ja võtaks tõenäoliselt liiga kaua aega. Tasub kontrollida WHERE klauslit ja vajadusel kasutada käsku SET SQL_BIG_SELECTS=1"
+ fre "SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vérifiez la clause WHERE et utilisez SET SQL_BIG_SELECTS=1 si SELECT se passe bien"
+ ger "Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange dauern. Bitte WHERE-Klausel überprüfen und gegebenenfalls SET SQL_BIG_SELECTS=1 oder SET SQL_MAX_JOIN_SIZE=# verwenden"
+ greek "Το SELECT θα εξετάσει μεγάλο αÏιθμό εγγÏαφών και πιθανώς θα καθυστεÏήσει. ΠαÏακαλώ εξετάστε τις παÏαμέτÏους του WHERE και χÏησιμοποιείστε SET SQL_BIG_SELECTS=1 αν το SELECT είναι σωστό"
+ hun "A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET SQL_BIG_SELECTS=1 beallitast, ha a SELECT okay"
+ ita "La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET SQL_BIG_SELECTS=1 se e` tutto a posto."
+ kor "SELECT 명령ì—ì„œ 너무 ë§Žì€ ë ˆì½”ë“œë¥¼ 찾기 ë•Œë¬¸ì— ë§Žì€ ì‹œê°„ì´ ì†Œìš”ë©ë‹ˆë‹¤. ë”°ë¼ì„œ WHERE ë¬¸ì„ ì ê²€í•˜ê±°ë‚˜, 만약 SELECTê°€ okë˜ë©´ SET SQL_BIG_SELECTS=1 ì˜µì…˜ì„ ì‚¬ìš©í•˜ì„¸ìš”."
+ nor "SELECT ville undersøke for mange poster og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt"
+ norwegian-ny "SELECT ville undersøkje for mange postar og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt"
+ pol "Operacja SELECT będzie dotyczyła zbyt wielu rekordów i prawdopodobnie zajmie bardzo dużo czasu. SprawdĽ warunek WHERE i użyj SQL_OPTION BIG_SELECTS=1 je?li operacja SELECT jest poprawna"
+ por "O SELECT examinaria registros demais e provavelmente levaria muito tempo. Cheque sua cláusula WHERE e use SET SQL_BIG_SELECTS=1, se o SELECT estiver correto"
+ rum "SELECT-ul ar examina prea multe cimpuri si probabil ar lua prea mult timp; verifica clauza WHERE si foloseste SET SQL_BIG_SELECTS=1 daca SELECT-ul e okay"
+ rus "Ð”Ð»Ñ Ñ‚Ð°ÐºÐ¾Ð¹ выборки SELECT должен будет проÑмотреть Ñлишком много запиÑей и, видимо, Ñто займет очень много времени. Проверьте ваше указание WHERE, и, еÑли в нем вÑе в порÑдке, укажите SET SQL_BIG_SELECTS=1"
+ serbian "Komanda 'SELECT' će ispitati previše slogova i potrošiti previše vremena. Proverite vaš 'WHERE' filter i upotrebite 'SET OPTION SQL_BIG_SELECTS=1' ako želite baš ovakvu komandu"
+ slo "Zadaná požiadavka SELECT by prechádzala príliš mnoho záznamov a trvala by príliš dlho. Skontrolujte tvar WHERE a ak je v poriadku, použite SET SQL_BIG_SELECTS=1"
+ spa "El SELECT puede examinar muchos registros y probablemente con mucho tiempo. Verifique tu WHERE y usa SET SQL_BIG_SELECTS=1 si el SELECT esta correcto"
+ swe "Den angivna frågan skulle läsa mer än MAX_JOIN_SIZE rader. Kontrollera din WHERE och använd SET SQL_BIG_SELECTS=1 eller SET MAX_JOIN_SIZE=# ifall du vill hantera stora joins"
+ ukr "Запиту SELECT потрібно обробити багато запиÑів, що, певне, займе дуже багато чаÑу. Перевірте ваше WHERE та викориÑтовуйте SET SQL_BIG_SELECTS=1, Ñкщо цей запит SELECT Ñ” вірним"
+ER_UNKNOWN_ERROR
+ cze "Nezn-Bámá chyba"
+ dan "Ukendt fejl"
+ nla "Onbekende Fout"
+ eng "Unknown error"
+ est "Tundmatu viga"
+ fre "Erreur inconnue"
+ ger "Unbekannter Fehler"
+ greek "ΠÏοέκυψε άγνωστο λάθος"
+ hun "Ismeretlen hiba"
+ ita "Errore sconosciuto"
+ kor "알수 없는 ì—러입니다."
+ nor "Ukjent feil"
+ norwegian-ny "Ukjend feil"
+ por "Erro desconhecido"
+ rum "Eroare unknown"
+ rus "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°"
+ serbian "Nepoznata greška"
+ slo "Neznámá chyba"
+ spa "Error desconocido"
+ swe "Oidentifierat fel"
+ ukr "Ðевідома помилка"
+ER_UNKNOWN_PROCEDURE 42000
+ cze "Nezn-Bámá procedura %-.192s"
+ dan "Ukendt procedure %-.192s"
+ nla "Onbekende procedure %-.192s"
+ eng "Unknown procedure '%-.192s'"
+ est "Tundmatu protseduur '%-.192s'"
+ fre "Procédure %-.192s inconnue"
+ ger "Unbekannte Prozedur '%-.192s'"
+ greek "Αγνωστη διαδικασία '%-.192s'"
+ hun "Ismeretlen eljaras: '%-.192s'"
+ ita "Procedura '%-.192s' sconosciuta"
+ kor "알수 없는 수행문 : '%-.192s'"
+ nor "Ukjent prosedyre %-.192s"
+ norwegian-ny "Ukjend prosedyre %-.192s"
+ pol "Unkown procedure %-.192s"
+ por "'Procedure' '%-.192s' desconhecida"
+ rum "Procedura unknown '%-.192s'"
+ rus "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¿Ñ€Ð¾Ñ†ÐµÐ´ÑƒÑ€Ð° '%-.192s'"
+ serbian "Nepoznata procedura '%-.192s'"
+ slo "Neznámá procedúra '%-.192s'"
+ spa "Procedimiento desconocido %-.192s"
+ swe "Okänd procedur: %-.192s"
+ ukr "Ðевідома процедура '%-.192s'"
+ER_WRONG_PARAMCOUNT_TO_PROCEDURE 42000
+ cze "Chybn-Bý poÄet parametrů procedury %-.192s"
+ dan "Forkert antal parametre til proceduren %-.192s"
+ nla "Foutief aantal parameters doorgegeven aan procedure %-.192s"
+ eng "Incorrect parameter count to procedure '%-.192s'"
+ est "Vale parameetrite hulk protseduurile '%-.192s'"
+ fre "Mauvais nombre de paramètres pour la procedure %-.192s"
+ ger "Falsche Parameterzahl für Prozedur '%-.192s'"
+ greek "Λάθος αÏιθμός παÏαμέτÏων στη διαδικασία '%-.192s'"
+ hun "Rossz parameter a(z) '%-.192s'eljaras szamitasanal"
+ ita "Numero di parametri errato per la procedura '%-.192s'"
+ kor "'%-.192s' ìˆ˜í–‰ë¬¸ì— ëŒ€í•œ 부정확한 파ë¼ë©”í„°"
+ nor "Feil parameter antall til prosedyren %-.192s"
+ norwegian-ny "Feil parameter tal til prosedyra %-.192s"
+ pol "Incorrect parameter count to procedure %-.192s"
+ por "Número de parâmetros incorreto para a 'procedure' '%-.192s'"
+ rum "Procedura '%-.192s' are un numar incorect de parametri"
+ rus "Ðекорректное количеÑтво параметров Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ†ÐµÐ´ÑƒÑ€Ñ‹ '%-.192s'"
+ serbian "Pogrešan broj parametara za proceduru '%-.192s'"
+ slo "Chybný poÄet parametrov procedúry '%-.192s'"
+ spa "Equivocado parametro count para procedimiento %-.192s"
+ swe "Felaktigt antal parametrar till procedur %-.192s"
+ ukr "Хибна кількіÑÑ‚ÑŒ параметрів процедури '%-.192s'"
+ER_WRONG_PARAMETERS_TO_PROCEDURE
+ cze "Chybn-Bé parametry procedury %-.192s"
+ dan "Forkert(e) parametre til proceduren %-.192s"
+ nla "Foutieve parameters voor procedure %-.192s"
+ eng "Incorrect parameters to procedure '%-.192s'"
+ est "Vigased parameetrid protseduurile '%-.192s'"
+ fre "Paramètre erroné pour la procedure %-.192s"
+ ger "Falsche Parameter für Prozedur '%-.192s'"
+ greek "Λάθος παÏάμετÏοι στην διαδικασία '%-.192s'"
+ hun "Rossz parameter a(z) '%-.192s' eljarasban"
+ ita "Parametri errati per la procedura '%-.192s'"
+ kor "'%-.192s' ìˆ˜í–‰ë¬¸ì— ëŒ€í•œ 부정확한 파ë¼ë©”í„°"
+ nor "Feil parametre til prosedyren %-.192s"
+ norwegian-ny "Feil parameter til prosedyra %-.192s"
+ pol "Incorrect parameters to procedure %-.192s"
+ por "Parâmetros incorretos para a 'procedure' '%-.192s'"
+ rum "Procedura '%-.192s' are parametrii incorecti"
+ rus "Ðекорректные параметры Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ†ÐµÐ´ÑƒÑ€Ñ‹ '%-.192s'"
+ serbian "Pogrešni parametri prosleđeni proceduri '%-.192s'"
+ slo "Chybné parametre procedúry '%-.192s'"
+ spa "Equivocados parametros para procedimiento %-.192s"
+ swe "Felaktiga parametrar till procedur %-.192s"
+ ukr "Хибний параметер процедури '%-.192s'"
+ER_UNKNOWN_TABLE 42S02
+ cze "Nezn-Bámá tabulka '%-.192s' v %-.32s"
+ dan "Ukendt tabel '%-.192s' i %-.32s"
+ nla "Onbekende tabel '%-.192s' in %-.32s"
+ eng "Unknown table '%-.192s' in %-.32s"
+ est "Tundmatu tabel '%-.192s' %-.32s-s"
+ fre "Table inconnue '%-.192s' dans %-.32s"
+ ger "Unbekannte Tabelle '%-.192s' in '%-.32s'"
+ greek "Αγνωστος πίνακας '%-.192s' σε %-.32s"
+ hun "Ismeretlen tabla: '%-.192s' %-.32s-ban"
+ ita "Tabella '%-.192s' sconosciuta in %-.32s"
+ jpn "Unknown table '%-.192s' in %-.32s"
+ kor "알수 없는 í…Œì´ë¸” '%-.192s' (ë°ì´íƒ€ë² ì´ìŠ¤ %-.32s)"
+ nor "Ukjent tabell '%-.192s' i %-.32s"
+ norwegian-ny "Ukjend tabell '%-.192s' i %-.32s"
+ pol "Unknown table '%-.192s' in %-.32s"
+ por "Tabela '%-.192s' desconhecida em '%-.32s'"
+ rum "Tabla '%-.192s' invalida in %-.32s"
+ rus "ÐеизвеÑÑ‚Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° '%-.192s' в %-.32s"
+ serbian "Nepoznata tabela '%-.192s' u '%-.32s'"
+ slo "Neznáma tabuľka '%-.192s' v %-.32s"
+ spa "Tabla desconocida '%-.192s' in %-.32s"
+ swe "Okänd tabell '%-.192s' i '%-.32s'"
+ ukr "Ðевідома Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ '%-.192s' у %-.32s"
+ER_FIELD_SPECIFIED_TWICE 42000
+ cze "Polo-Bžka '%-.192s' je zadána dvakrát"
+ dan "Feltet '%-.192s' er anvendt to gange"
+ nla "Veld '%-.192s' is dubbel gespecificeerd"
+ eng "Column '%-.192s' specified twice"
+ est "Tulp '%-.192s' on määratletud topelt"
+ fre "Champ '%-.192s' spécifié deux fois"
+ ger "Feld '%-.192s' wurde zweimal angegeben"
+ greek "Το πεδίο '%-.192s' έχει οÏισθεί δÏο φοÏές"
+ hun "A(z) '%-.192s' mezot ketszer definialta"
+ ita "Campo '%-.192s' specificato 2 volte"
+ kor "칼럼 '%-.192s'는 ë‘번 ì •ì˜ë˜ì–´ 있ì니다."
+ nor "Feltet '%-.192s' er spesifisert to ganger"
+ norwegian-ny "Feltet '%-.192s' er spesifisert to gangar"
+ pol "Field '%-.192s' specified twice"
+ por "Coluna '%-.192s' especificada duas vezes"
+ rum "Coloana '%-.192s' specificata de doua ori"
+ rus "Столбец '%-.192s' указан дважды"
+ serbian "Kolona '%-.192s' je navedena dva puta"
+ slo "Pole '%-.192s' je zadané dvakrát"
+ spa "Campo '%-.192s' especificado dos veces"
+ swe "Fält '%-.192s' är redan använt"
+ ukr "Стовбець '%-.192s' зазначено двічі"
+ER_INVALID_GROUP_FUNC_USE
+ cze "Nespr-Bávné použití funkce group"
+ dan "Forkert brug af grupperings-funktion"
+ nla "Ongeldig gebruik van GROUP-functie"
+ eng "Invalid use of group function"
+ est "Vigane grupeerimisfunktsiooni kasutus"
+ fre "Utilisation invalide de la clause GROUP"
+ ger "Falsche Verwendung einer Gruppierungsfunktion"
+ greek "Εσφαλμένη χÏήση της group function"
+ hun "A group funkcio ervenytelen hasznalata"
+ ita "Uso non valido di una funzione di raggruppamento"
+ kor "ìž˜ëª»ëœ ê·¸ë£¹ 함수를 사용하였습니다."
+ por "Uso inválido de função de agrupamento (GROUP)"
+ rum "Folosire incorecta a functiei group"
+ rus "Ðеправильное иÑпользование групповых функций"
+ serbian "Pogrešna upotreba 'GROUP' funkcije"
+ slo "Nesprávne použitie funkcie GROUP"
+ spa "Invalido uso de función en grupo"
+ swe "Felaktig användning av SQL grupp function"
+ ukr "Хибне викориÑÑ‚Ð°Ð½Ð½Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ— групуваннÑ"
+ER_UNSUPPORTED_EXTENSION 42000
+ cze "Tabulka '%-.192s' pou-Bžívá rozšíření, které v této verzi MySQL není"
+ dan "Tabellen '%-.192s' bruger et filtypenavn som ikke findes i denne MySQL version"
+ nla "Tabel '%-.192s' gebruikt een extensie, die niet in deze MySQL-versie voorkomt."
+ eng "Table '%-.192s' uses an extension that doesn't exist in this MySQL version"
+ est "Tabel '%-.192s' kasutab laiendust, mis ei eksisteeri antud MySQL versioonis"
+ fre "Table '%-.192s' : utilise une extension invalide pour cette version de MySQL"
+ ger "Tabelle '%-.192s' verwendet eine Erweiterung, die in dieser MySQL-Version nicht verfügbar ist"
+ greek "Ο πίνακς '%-.192s' χÏησιμοποιεί κάποιο extension που δεν υπάÏχει στην έκδοση αυτή της MySQL"
+ hun "A(z) '%-.192s' tabla olyan bovitest hasznal, amely nem letezik ebben a MySQL versioban."
+ ita "La tabella '%-.192s' usa un'estensione che non esiste in questa versione di MySQL"
+ kor "í…Œì´ë¸” '%-.192s'는 í™•ìž¥ëª…ë ¹ì„ ì´ìš©í•˜ì§€ë§Œ í˜„ìž¬ì˜ MySQL 버젼ì—서는 존재하지 않습니다."
+ nor "Table '%-.192s' uses a extension that doesn't exist in this MySQL version"
+ norwegian-ny "Table '%-.192s' uses a extension that doesn't exist in this MySQL version"
+ pol "Table '%-.192s' uses a extension that doesn't exist in this MySQL version"
+ por "Tabela '%-.192s' usa uma extensão que não existe nesta versão do MySQL"
+ rum "Tabela '%-.192s' foloseste o extensire inexistenta in versiunea curenta de MySQL"
+ rus "Ð’ таблице '%-.192s' иÑпользуютÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñти, не поддерживаемые в Ñтой верÑии MySQL"
+ serbian "Tabela '%-.192s' koristi ekstenziju koje ne postoji u ovoj verziji MySQL-a"
+ slo "Tabuľka '%-.192s' používa rozšírenie, ktoré v tejto verzii MySQL nie je"
+ spa "Tabla '%-.192s' usa una extensión que no existe en esta MySQL versión"
+ swe "Tabell '%-.192s' har en extension som inte finns i denna version av MySQL"
+ ukr "Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ '%-.192s' викориÑтовує розширеннÑ, що не Ñ–Ñнує у цій верÑÑ–Ñ— MySQL"
+ER_TABLE_MUST_HAVE_COLUMNS 42000
+ cze "Tabulka mus-Bí mít alespoň jeden sloupec"
+ dan "En tabel skal have mindst een kolonne"
+ nla "Een tabel moet minstens 1 kolom bevatten"
+ eng "A table must have at least 1 column"
+ jps "テーブルã¯æœ€ä½Ž 1 個㮠column ãŒå¿…è¦ã§ã™",
+ est "Tabelis peab olema vähemalt üks tulp"
+ fre "Une table doit comporter au moins une colonne"
+ ger "Eine Tabelle muss mindestens eine Spalte besitzen"
+ greek "Ενας πίνακας Ï€Ïέπει να έχει τουλάχιστον ένα πεδίο"
+ hun "A tablanak legalabb egy oszlopot tartalmazni kell"
+ ita "Una tabella deve avere almeno 1 colonna"
+ jpn "テーブルã¯æœ€ä½Ž 1 個㮠column ãŒå¿…è¦ã§ã™"
+ kor "í•˜ë‚˜ì˜ í…Œì´ë¸”ì—서는 ì ì–´ë„ í•˜ë‚˜ì˜ ì¹¼ëŸ¼ì´ ì¡´ìž¬í•˜ì—¬ì•¼ 합니다."
+ por "Uma tabela tem que ter pelo menos uma (1) coluna"
+ rum "O tabela trebuie sa aiba cel putin o coloana"
+ rus "Ð’ таблице должен быть как минимум один Ñтолбец"
+ serbian "Tabela mora imati najmanje jednu kolonu"
+ slo "Tabuľka musí mať aspoň 1 pole"
+ spa "Una tabla debe tener al menos 1 columna"
+ swe "Tabeller måste ha minst 1 kolumn"
+ ukr "Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ Ð¿Ð¾Ð²Ð¸Ð½Ð½Ð° мати хочаб один Ñтовбець"
+ER_RECORD_FILE_FULL
+ cze "Tabulka '%-.192s' je pln-Bá"
+ dan "Tabellen '%-.192s' er fuld"
+ nla "De tabel '%-.192s' is vol"
+ eng "The table '%-.192s' is full"
+ jps "table '%-.192s' ã¯ã„ã£ã±ã„ã§ã™",
+ est "Tabel '%-.192s' on täis"
+ fre "La table '%-.192s' est pleine"
+ ger "Tabelle '%-.192s' ist voll"
+ greek "Ο πίνακας '%-.192s' είναι γεμάτος"
+ hun "A '%-.192s' tabla megtelt"
+ ita "La tabella '%-.192s' e` piena"
+ jpn "table '%-.192s' ã¯ã„ã£ã±ã„ã§ã™"
+ kor "í…Œì´ë¸” '%-.192s'ê°€ full났습니다. "
+ por "Tabela '%-.192s' está cheia"
+ rum "Tabela '%-.192s' e plina"
+ rus "Таблица '%-.192s' переполнена"
+ serbian "Tabela '%-.192s' je popunjena do kraja"
+ slo "Tabuľka '%-.192s' je plná"
+ spa "La tabla '%-.192s' está llena"
+ swe "Tabellen '%-.192s' är full"
+ ukr "Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ '%-.192s' заповнена"
+ER_UNKNOWN_CHARACTER_SET 42000
+ cze "Nezn-Bámá znaková sada: '%-.64s'"
+ dan "Ukendt tegnsæt: '%-.64s'"
+ nla "Onbekende character set: '%-.64s'"
+ eng "Unknown character set: '%-.64s'"
+ jps "character set '%-.64s' ã¯ã‚µãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“",
+ est "Vigane kooditabel '%-.64s'"
+ fre "Jeu de caractères inconnu: '%-.64s'"
+ ger "Unbekannter Zeichensatz: '%-.64s'"
+ greek "Αγνωστο character set: '%-.64s'"
+ hun "Ervenytelen karakterkeszlet: '%-.64s'"
+ ita "Set di caratteri '%-.64s' sconosciuto"
+ jpn "character set '%-.64s' ã¯ã‚µãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“"
+ kor "알수없는 언어 Set: '%-.64s'"
+ por "Conjunto de caracteres '%-.64s' desconhecido"
+ rum "Set de caractere invalid: '%-.64s'"
+ rus "ÐеизвеÑÑ‚Ð½Ð°Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²ÐºÐ° '%-.64s'"
+ serbian "Nepoznati karakter-set: '%-.64s'"
+ slo "Neznáma znaková sada: '%-.64s'"
+ spa "Juego de caracteres desconocido: '%-.64s'"
+ swe "Okänd teckenuppsättning: '%-.64s'"
+ ukr "Ðевідома кодова таблицÑ: '%-.64s'"
+ER_TOO_MANY_TABLES
+ cze "P-Bříliš mnoho tabulek, MySQL jich může mít v joinu jen %d"
+ dan "For mange tabeller. MySQL kan kun bruge %d tabeller i et join"
+ nla "Teveel tabellen. MySQL kan slechts %d tabellen in een join bevatten"
+ eng "Too many tables; MySQL can only use %d tables in a join"
+ jps "テーブルãŒå¤šã™ãŽã¾ã™; MySQL can only use %d tables in a join",
+ est "Liiga palju tabeleid. MySQL suudab JOINiga ühendada kuni %d tabelit"
+ fre "Trop de tables. MySQL ne peut utiliser que %d tables dans un JOIN"
+ ger "Zu viele Tabellen. MySQL kann in einem Join maximal %d Tabellen verwenden"
+ greek "Î Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿Ï‚ αÏιθμός πινάκων. Η MySQL μποÏεί να χÏησιμοποιήσει %d πίνακες σε διαδικασία join"
+ hun "Tul sok tabla. A MySQL csak %d tablat tud kezelni osszefuzeskor"
+ ita "Troppe tabelle. MySQL puo` usare solo %d tabelle in una join"
+ jpn "テーブルãŒå¤šã™ãŽã¾ã™; MySQL can only use %d tables in a join"
+ kor "너무 ë§Žì€ í…Œì´ë¸”ì´ Joinë˜ì—ˆìŠµë‹ˆë‹¤. MySQLì—서는 JOINì‹œ %dê°œì˜ í…Œì´ë¸”만 사용할 수 있습니다."
+ por "Tabelas demais. O MySQL pode usar somente %d tabelas em uma junção (JOIN)"
+ rum "Prea multe tabele. MySQL nu poate folosi mai mult de %d tabele intr-un join"
+ rus "Слишком много таблиц. MySQL может иÑпользовать только %d таблиц в Ñоединении"
+ serbian "Previše tabela. MySQL može upotrebiti maksimum %d tabela pri 'JOIN' operaciji"
+ slo "Príliš mnoho tabuliek. MySQL môže použiť len %d v JOIN-e"
+ spa "Muchas tablas. MySQL solamente puede usar %d tablas en un join"
+ swe "För många tabeller. MySQL can ha högst %d tabeller i en och samma join"
+ ukr "Забагато таблиць. MySQL може викориÑтовувати лише %d таблиць у об'єднанні"
+ER_TOO_MANY_FIELDS
+ cze "P-Bříliš mnoho položek"
+ dan "For mange felter"
+ nla "Te veel velden"
+ eng "Too many columns"
+ jps "column ãŒå¤šã™ãŽã¾ã™",
+ est "Liiga palju tulpasid"
+ fre "Trop de champs"
+ ger "Zu viele Felder"
+ greek "Î Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿Ï‚ αÏιθμός πεδίων"
+ hun "Tul sok mezo"
+ ita "Troppi campi"
+ jpn "column ãŒå¤šã™ãŽã¾ã™"
+ kor "ì¹¼ëŸ¼ì´ ë„ˆë¬´ 많습니다."
+ por "Colunas demais"
+ rum "Prea multe coloane"
+ rus "Слишком много Ñтолбцов"
+ serbian "Previše kolona"
+ slo "Príliš mnoho polí"
+ spa "Muchos campos"
+ swe "För många fält"
+ ukr "Забагато Ñтовбців"
+ER_TOO_BIG_ROWSIZE 42000
+ cze "-BŘádek je příliÅ¡ velký. Maximální velikost řádku, nepoÄítaje položky blob, je %ld. Musíte zmÄ›nit nÄ›které položky na blob"
+ dan "For store poster. Max post størrelse, uden BLOB's, er %ld. Du må lave nogle felter til BLOB's"
+ nla "Rij-grootte is groter dan toegestaan. Maximale rij grootte, blobs niet meegeteld, is %ld. U dient sommige velden in blobs te veranderen."
+ eng "Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some columns to TEXT or BLOBs"
+ jps "row size ãŒå¤§ãã™ãŽã¾ã™. BLOB ã‚’å«ã¾ãªã„å ´åˆã® row size ã®æœ€å¤§ã¯ %ld ã§ã™. ã„ãã¤ã‹ã® field ã‚’ BLOB ã«å¤‰ãˆã¦ãã ã•ã„.",
+ est "Liiga pikk kirje. Kirje maksimumpikkus arvestamata BLOB-tüüpi välju on %ld. Muuda mõned väljad BLOB-tüüpi väljadeks"
+ fre "Ligne trop grande. Le taille maximale d'une ligne, sauf les BLOBs, est %ld. Changez le type de quelques colonnes en BLOB"
+ ger "Zeilenlänge zu groß. Die maximale Zeilenlänge für den verwendeten Tabellentyp (ohne BLOB-Felder) beträgt %ld. Einige Felder müssen in BLOB oder TEXT umgewandelt werden"
+ greek "Î Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿ μέγεθος εγγÏαφής. Το μέγιστο μέγεθος εγγÏαφής, χωÏίς να υπολογίζονται τα blobs, είναι %ld. ΠÏέπει να οÏίσετε κάποια πεδία σαν blobs"
+ hun "Tul nagy sormeret. A maximalis sormeret (nem szamolva a blob objektumokat) %ld. Nehany mezot meg kell valtoztatnia"
+ ita "Riga troppo grande. La massima grandezza di una riga, non contando i BLOB, e` %ld. Devi cambiare alcuni campi in BLOB"
+ jpn "row size ãŒå¤§ãã™ãŽã¾ã™. BLOB ã‚’å«ã¾ãªã„å ´åˆã® row size ã®æœ€å¤§ã¯ %ld ã§ã™. ã„ãã¤ã‹ã® field ã‚’ BLOB ã«å¤‰ãˆã¦ãã ã•ã„."
+ kor "너무 í° row 사ì´ì¦ˆìž…니다. BLOB를 계산하지 ì•Šê³  최대 row 사ì´ì¦ˆëŠ” %ld입니다. ì–¼ë§ˆê°„ì˜ í•„ë“œë“¤ì„ BLOBë¡œ 바꾸셔야 ê² êµ°ìš”.."
+ por "Tamanho de linha grande demais. O máximo tamanho de linha, não contando BLOBs, é %ld. Você tem que mudar alguns campos para BLOBs"
+ rum "Marimea liniei (row) prea mare. Marimea maxima a liniei, excluzind BLOB-urile este de %ld. Trebuie sa schimbati unele cimpuri in BLOB-uri"
+ rus "Слишком большой размер запиÑи. МакÑимальный размер Ñтроки, иÑÐºÐ»ÑŽÑ‡Ð°Ñ Ð¿Ð¾Ð»Ñ BLOB, - %ld. Возможно, вам Ñледует изменить тип некоторых полей на BLOB"
+ serbian "Prevelik slog. Maksimalna veliÄina sloga, ne raÄunajući BLOB polja, je %ld. Trebali bi da promenite tip nekih polja u BLOB"
+ slo "Riadok je príliš veľký. Maximálna veľkosť riadku, okrem 'BLOB', je %ld. Musíte zmeniť niektoré položky na BLOB"
+ spa "Tamaño de línea muy grande. Máximo tamaño de línea, no contando blob, es %ld. Tu tienes que cambiar algunos campos para blob"
+ swe "För stor total radlängd. Den högst tillåtna radlängden, förutom BLOBs, är %ld. Ändra några av dina fält till BLOB"
+ ukr "Задовга Ñтрока. Ðайбільшою довжиною Ñтроки, не рахуючи BLOB, Ñ” %ld. Вам потрібно привеÑти деÑкі Ñтовбці до типу BLOB"
+ER_STACK_OVERRUN
+ cze "P-BÅ™eteÄení zásobníku threadu: použito %ld z %ld. Použijte 'mysqld --thread_stack=#' k zadání vÄ›tšího zásobníku"
+ dan "Thread stack brugt: Brugt: %ld af en %ld stak. Brug 'mysqld --thread_stack=#' for at allokere en større stak om nødvendigt"
+ nla "Thread stapel overrun: Gebruikte: %ld van een %ld stack. Gebruik 'mysqld --thread_stack=#' om een grotere stapel te definieren (indien noodzakelijk)."
+ eng "Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld --thread_stack=#' to specify a bigger stack if needed"
+ jps "Thread stack overrun: Used: %ld of a %ld stack. スタック領域を多ãã¨ã‚ŠãŸã„å ´åˆã€'mysqld --thread_stack=#' ã¨æŒ‡å®šã—ã¦ãã ã•ã„",
+ fre "Débordement de la pile des tâches (Thread stack). Utilisées: %ld pour une pile de %ld. Essayez 'mysqld --thread_stack=#' pour indiquer une plus grande valeur"
+ ger "Thread-Stack-Überlauf. Benutzt: %ld von %ld Stack. 'mysqld --thread_stack=#' verwenden, um bei Bedarf einen größeren Stack anzulegen"
+ greek "Stack overrun στο thread: Used: %ld of a %ld stack. ΠαÏακαλώ χÏησιμοποιείστε 'mysqld --thread_stack=#' για να οÏίσετε ένα μεγαλÏτεÏο stack αν χÏειάζεται"
+ hun "Thread verem tullepes: Used: %ld of a %ld stack. Hasznalja a 'mysqld --thread_stack=#' nagyobb verem definialasahoz"
+ ita "Thread stack overrun: Usati: %ld di uno stack di %ld. Usa 'mysqld --thread_stack=#' per specificare uno stack piu` grande."
+ jpn "Thread stack overrun: Used: %ld of a %ld stack. スタック領域を多ãã¨ã‚ŠãŸã„å ´åˆã€'mysqld --thread_stack=#' ã¨æŒ‡å®šã—ã¦ãã ã•ã„"
+ kor "쓰레드 스íƒì´ 넘쳤습니다. 사용: %ldê°œ 스íƒ: %ldê°œ. 만약 필요시 ë”í° ìŠ¤íƒì„ ì›í• ë•Œì—는 'mysqld --thread_stack=#' 를 ì •ì˜í•˜ì„¸ìš”"
+ por "Estouro da pilha do 'thread'. Usados %ld de uma pilha de %ld. Use 'mysqld --thread_stack=#' para especificar uma pilha maior, se necessário"
+ rum "Stack-ul thread-ului a fost depasit (prea mic): Folositi: %ld intr-un stack de %ld. Folositi 'mysqld --thread_stack=#' ca sa specifici un stack mai mare"
+ rus "Стек потоков переполнен: иÑпользовано: %ld из %ld Ñтека. ПрименÑйте 'mysqld --thread_stack=#' Ð´Ð»Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐµÐ³Ð¾ размера Ñтека, еÑли необходимо"
+ serbian "Prepisivanje thread stack-a: Upotrebljeno: %ld od %ld stack memorije. Upotrebite 'mysqld --thread_stack=#' da navedete veći stack ako je potrebno"
+ slo "PreteÄenie zásobníku vlákna: použité: %ld z %ld. Použite 'mysqld --thread_stack=#' k zadaniu väÄÅ¡ieho zásobníka"
+ spa "Sobrecarga de la pila de thread: Usada: %ld de una %ld pila. Use 'mysqld --thread_stack=#' para especificar una mayor pila si necesario"
+ swe "Trådstacken tog slut: Har använt %ld av %ld bytes. Använd 'mysqld --thread_stack=#' ifall du behöver en större stack"
+ ukr "Стек гілок переповнено: ВикориÑтано: %ld з %ld. ВикориÑтовуйте 'mysqld --thread_stack=#' аби зазначити більший Ñтек, Ñкщо необхідно"
+ER_WRONG_OUTER_JOIN 42000
+ cze "V OUTER JOIN byl nalezen k-Břížový odkaz. Prověřte ON podmínky"
+ dan "Krydsreferencer fundet i OUTER JOIN; check dine ON conditions"
+ nla "Gekruiste afhankelijkheid gevonden in OUTER JOIN. Controleer uw ON-conditions"
+ eng "Cross dependency found in OUTER JOIN; examine your ON conditions"
+ est "Ristsõltuvus OUTER JOIN klauslis. Kontrolli oma ON tingimusi"
+ fre "Dépendance croisée dans une clause OUTER JOIN. Vérifiez la condition ON"
+ ger "OUTER JOIN enthält fehlerhafte Abhängigkeiten. In ON verwendete Bedingungen überprüfen"
+ greek "Cross dependency βÏέθηκε σε OUTER JOIN. ΠαÏακαλώ εξετάστε τις συνθήκες που θέσατε στο ON"
+ hun "Keresztfuggoseg van az OUTER JOIN-ban. Ellenorizze az ON felteteleket"
+ ita "Trovata una dipendenza incrociata nella OUTER JOIN. Controlla le condizioni ON"
+ por "Dependência cruzada encontrada em junção externa (OUTER JOIN); examine as condições utilizadas nas cláusulas 'ON'"
+ rum "Dependinta incrucisata (cross dependency) gasita in OUTER JOIN. Examinati conditiile ON"
+ rus "Ð’ OUTER JOIN обнаружена перекреÑÑ‚Ð½Ð°Ñ Ð·Ð°Ð²Ð¸ÑимоÑÑ‚ÑŒ. Внимательно проанализируйте Ñвои уÑÐ»Ð¾Ð²Ð¸Ñ ON"
+ serbian "Unakrsna zavisnost pronađena u komandi 'OUTER JOIN'. Istražite vaše 'ON' uslove"
+ slo "V OUTER JOIN bol nájdený krížový odkaz. Skontrolujte podmienky ON"
+ spa "Dependencia cruzada encontrada en OUTER JOIN. Examine su condición ON"
+ swe "Felaktigt referens i OUTER JOIN. Kontrollera ON-uttrycket"
+ ukr "ПерехреÑна залежніÑÑ‚ÑŒ у OUTER JOIN. Перевірте умову ON"
+ER_NULL_COLUMN_IN_INDEX 42000
+ eng "Table handler doesn't support NULL in given index. Please change column '%-.192s' to be NOT NULL or use another handler"
+ swe "Tabell hanteraren kan inte indexera NULL kolumner för den givna index typen. Ändra '%-.192s' till NOT NULL eller använd en annan hanterare"
+ER_CANT_FIND_UDF
+ cze "Nemohu na-BÄíst funkci '%-.192s'"
+ dan "Kan ikke læse funktionen '%-.192s'"
+ nla "Kan functie '%-.192s' niet laden"
+ eng "Can't load function '%-.192s'"
+ jps "function '%-.192s' ã‚’ ロードã§ãã¾ã›ã‚“",
+ est "Ei suuda avada funktsiooni '%-.192s'"
+ fre "Imposible de charger la fonction '%-.192s'"
+ ger "Kann Funktion '%-.192s' nicht laden"
+ greek "Δεν είναι δυνατή η διαδικασία load για τη συνάÏτηση '%-.192s'"
+ hun "A(z) '%-.192s' fuggveny nem toltheto be"
+ ita "Impossibile caricare la funzione '%-.192s'"
+ jpn "function '%-.192s' ã‚’ ロードã§ãã¾ã›ã‚“"
+ kor "'%-.192s' 함수를 로드하지 못했습니다."
+ por "Não pode carregar a função '%-.192s'"
+ rum "Nu pot incarca functia '%-.192s'"
+ rus "Ðевозможно загрузить функцию '%-.192s'"
+ serbian "Ne mogu da uÄitam funkciju '%-.192s'"
+ slo "Nemôžem naÄítaÅ¥ funkciu '%-.192s'"
+ spa "No puedo cargar función '%-.192s'"
+ swe "Kan inte ladda funktionen '%-.192s'"
+ ukr "Ðе можу завантажити функцію '%-.192s'"
+ER_CANT_INITIALIZE_UDF
+ cze "Nemohu inicializovat funkci '%-.192s'; %-.80s"
+ dan "Kan ikke starte funktionen '%-.192s'; %-.80s"
+ nla "Kan functie '%-.192s' niet initialiseren; %-.80s"
+ eng "Can't initialize function '%-.192s'; %-.80s"
+ jps "function '%-.192s' ã‚’åˆæœŸåŒ–ã§ãã¾ã›ã‚“; %-.80s",
+ est "Ei suuda algväärtustada funktsiooni '%-.192s'; %-.80s"
+ fre "Impossible d'initialiser la fonction '%-.192s'; %-.80s"
+ ger "Kann Funktion '%-.192s' nicht initialisieren: %-.80s"
+ greek "Δεν είναι δυνατή η έναÏξη της συνάÏτησης '%-.192s'; %-.80s"
+ hun "A(z) '%-.192s' fuggveny nem inicializalhato; %-.80s"
+ ita "Impossibile inizializzare la funzione '%-.192s'; %-.80s"
+ jpn "function '%-.192s' ã‚’åˆæœŸåŒ–ã§ãã¾ã›ã‚“; %-.80s"
+ kor "'%-.192s' 함수를 초기화 하지 못했습니다.; %-.80s"
+ por "Não pode inicializar a função '%-.192s' - '%-.80s'"
+ rum "Nu pot initializa functia '%-.192s'; %-.80s"
+ rus "Ðевозможно инициализировать функцию '%-.192s'; %-.80s"
+ serbian "Ne mogu da inicijalizujem funkciju '%-.192s'; %-.80s"
+ slo "Nemôžem inicializovať funkciu '%-.192s'; %-.80s"
+ spa "No puedo inicializar función '%-.192s'; %-.80s"
+ swe "Kan inte initialisera funktionen '%-.192s'; '%-.80s'"
+ ukr "Ðе можу ініціалізувати функцію '%-.192s'; %-.80s"
+ER_UDF_NO_PATHS
+ cze "Pro sd-Bílenou knihovnu nejsou povoleny cesty"
+ dan "Angivelse af sti ikke tilladt for delt bibliotek"
+ nla "Geen pad toegestaan voor shared library"
+ eng "No paths allowed for shared library"
+ jps "shared library ã¸ã®ãƒ‘スãŒé€šã£ã¦ã„ã¾ã›ã‚“",
+ est "Teegi nimes ei tohi olla kataloogi"
+ fre "Chemin interdit pour les bibliothèques partagées"
+ ger "Keine Pfade gestattet für Shared Library"
+ greek "Δεν βÏέθηκαν paths για την shared library"
+ hun "Nincs ut a megosztott konyvtarakhoz (shared library)"
+ ita "Non sono ammessi path per le librerie condivisa"
+ jpn "shared library ã¸ã®ãƒ‘スãŒé€šã£ã¦ã„ã¾ã›ã‚“"
+ kor "공유 ë¼ì´ë²„러리를 위한 패스가 ì •ì˜ë˜ì–´ 있지 않습니다."
+ por "Não há caminhos (paths) permitidos para biblioteca compartilhada"
+ rum "Nici un paths nu e permis pentru o librarie shared"
+ rus "ÐедопуÑтимо указывать пути Ð´Ð»Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸Ñ‡ÐµÑких библиотек"
+ serbian "Ne postoje dozvoljene putanje do share-ovane biblioteke"
+ slo "Neprípustné žiadne cesty k zdieľanej knižnici"
+ spa "No pasos permitidos para librarias conjugadas"
+ swe "Man får inte ange sökväg för dynamiska bibliotek"
+ ukr "Ðе дозволено викориÑтовувати путі Ð´Ð»Ñ Ñ€Ð¾Ð·Ð´Ñ–Ð»ÑŽÐ²Ð°Ð½Ð¸Ñ… бібліотек"
+ER_UDF_EXISTS
+ cze "Funkce '%-.192s' ji-Bž existuje"
+ dan "Funktionen '%-.192s' findes allerede"
+ nla "Functie '%-.192s' bestaat reeds"
+ eng "Function '%-.192s' already exists"
+ jps "Function '%-.192s' ã¯æ—¢ã«å®šç¾©ã•ã‚Œã¦ã„ã¾ã™",
+ est "Funktsioon '%-.192s' juba eksisteerib"
+ fre "La fonction '%-.192s' existe déjà"
+ ger "Funktion '%-.192s' existiert schon"
+ greek "Η συνάÏτηση '%-.192s' υπάÏχει ήδη"
+ hun "A '%-.192s' fuggveny mar letezik"
+ ita "La funzione '%-.192s' esiste gia`"
+ jpn "Function '%-.192s' ã¯æ—¢ã«å®šç¾©ã•ã‚Œã¦ã„ã¾ã™"
+ kor "'%-.192s' 함수는 ì´ë¯¸ 존재합니다."
+ por "Função '%-.192s' já existe"
+ rum "Functia '%-.192s' exista deja"
+ rus "Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ '%-.192s' уже ÑущеÑтвует"
+ serbian "Funkcija '%-.192s' već postoji"
+ slo "Funkcia '%-.192s' už existuje"
+ spa "Función '%-.192s' ya existe"
+ swe "Funktionen '%-.192s' finns redan"
+ ukr "Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ '%-.192s' вже Ñ–Ñнує"
+ER_CANT_OPEN_LIBRARY
+ cze "Nemohu otev-Břít sdílenou knihovnu '%-.192s' (errno: %d %-.128s)"
+ dan "Kan ikke åbne delt bibliotek '%-.192s' (errno: %d %-.128s)"
+ nla "Kan shared library '%-.192s' niet openen (Errcode: %d %-.128s)"
+ eng "Can't open shared library '%-.192s' (errno: %d %-.128s)"
+ jps "shared library '%-.192s' ã‚’é–‹ã事ãŒã§ãã¾ã›ã‚“ (errno: %d %-.128s)",
+ est "Ei suuda avada jagatud teeki '%-.192s' (veakood: %d %-.128s)"
+ fre "Impossible d'ouvrir la bibliothèque partagée '%-.192s' (errno: %d %-.128s)"
+ ger "Kann Shared Library '%-.192s' nicht öffnen (Fehler: %d %-.128s)"
+ greek "Δεν είναι δυνατή η ανάγνωση της shared library '%-.192s' (κωδικός λάθους: %d %-.128s)"
+ hun "A(z) '%-.192s' megosztott konyvtar nem hasznalhato (hibakod: %d %-.128s)"
+ ita "Impossibile aprire la libreria condivisa '%-.192s' (errno: %d %-.128s)"
+ jpn "shared library '%-.192s' ã‚’é–‹ã事ãŒã§ãã¾ã›ã‚“ (errno: %d %-.128s)"
+ kor "'%-.192s' 공유 ë¼ì´ë²„러리를 열수 없습니다.(ì—러번호: %d %-.128s)"
+ nor "Can't open shared library '%-.192s' (errno: %d %-.128s)"
+ norwegian-ny "Can't open shared library '%-.192s' (errno: %d %-.128s)"
+ pol "Can't open shared library '%-.192s' (errno: %d %-.128s)"
+ por "Não pode abrir biblioteca compartilhada '%-.192s' (erro no. %d '%-.128s')"
+ rum "Nu pot deschide libraria shared '%-.192s' (Eroare: %d %-.128s)"
+ rus "Ðевозможно открыть динамичеÑкую библиотеку '%-.192s' (ошибка: %d %-.128s)"
+ serbian "Ne mogu da otvorim share-ovanu biblioteku '%-.192s' (errno: %d %-.128s)"
+ slo "Nemôžem otvoriť zdieľanú knižnicu '%-.192s' (chybový kód: %d %-.128s)"
+ spa "No puedo abrir libraria conjugada '%-.192s' (errno: %d %-.128s)"
+ swe "Kan inte öppna det dynamiska biblioteket '%-.192s' (Felkod: %d %-.128s)"
+ ukr "Ðе можу відкрити розділювану бібліотеку '%-.192s' (помилка: %d %-.128s)"
+ER_CANT_FIND_DL_ENTRY
+ cze "Nemohu naj-Bít funkci '%-.128s' v knihovně"
+ dan "Kan ikke finde funktionen '%-.128s' i bibliotek"
+ nla "Kan functie '%-.128s' niet in library vinden"
+ eng "Can't find symbol '%-.128s' in library"
+ jps "function '%-.128s' をライブラリー中ã«è¦‹ä»˜ã‘る事ãŒã§ãã¾ã›ã‚“",
+ est "Ei leia funktsiooni '%-.128s' antud teegis"
+ fre "Impossible de trouver la fonction '%-.128s' dans la bibliothèque"
+ ger "Kann Funktion '%-.128s' in der Library nicht finden"
+ greek "Δεν είναι δυνατή η ανεÏÏεση της συνάÏτησης '%-.128s' στην βιβλιοθήκη"
+ hun "A(z) '%-.128s' fuggveny nem talalhato a konyvtarban"
+ ita "Impossibile trovare la funzione '%-.128s' nella libreria"
+ jpn "function '%-.128s' をライブラリー中ã«è¦‹ä»˜ã‘る事ãŒã§ãã¾ã›ã‚“"
+ kor "ë¼ì´ë²„러리ì—ì„œ '%-.128s' 함수를 ì°¾ì„ ìˆ˜ 없습니다."
+ por "Não pode encontrar a função '%-.128s' na biblioteca"
+ rum "Nu pot gasi functia '%-.128s' in libraria"
+ rus "Ðевозможно отыÑкать Ñимвол '%-.128s' в библиотеке"
+ serbian "Ne mogu da pronadjem funkciju '%-.128s' u biblioteci"
+ slo "Nemôžem nájsť funkciu '%-.128s' v knižnici"
+ spa "No puedo encontrar función '%-.128s' en libraria"
+ swe "Hittar inte funktionen '%-.128s' in det dynamiska biblioteket"
+ ukr "Ðе можу знайти функцію '%-.128s' у бібліотеці"
+ER_FUNCTION_NOT_DEFINED
+ cze "Funkce '%-.192s' nen-Bí definována"
+ dan "Funktionen '%-.192s' er ikke defineret"
+ nla "Functie '%-.192s' is niet gedefinieerd"
+ eng "Function '%-.192s' is not defined"
+ jps "Function '%-.192s' ã¯å®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“",
+ est "Funktsioon '%-.192s' ei ole defineeritud"
+ fre "La fonction '%-.192s' n'est pas définie"
+ ger "Funktion '%-.192s' ist nicht definiert"
+ greek "Η συνάÏτηση '%-.192s' δεν έχει οÏισθεί"
+ hun "A '%-.192s' fuggveny nem definialt"
+ ita "La funzione '%-.192s' non e` definita"
+ jpn "Function '%-.192s' ã¯å®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+ kor "'%-.192s' 함수가 ì •ì˜ë˜ì–´ 있지 않습니다."
+ por "Função '%-.192s' não está definida"
+ rum "Functia '%-.192s' nu e definita"
+ rus "Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ '%-.192s' не определена"
+ serbian "Funkcija '%-.192s' nije definisana"
+ slo "Funkcia '%-.192s' nie je definovaná"
+ spa "Función '%-.192s' no está definida"
+ swe "Funktionen '%-.192s' är inte definierad"
+ ukr "Функцію '%-.192s' не визначено"
+ER_HOST_IS_BLOCKED
+ cze "Stroj '%-.64s' je zablokov-Bán kvůli mnoha chybám při připojování. Odblokujete použitím 'mysqladmin flush-hosts'"
+ dan "Værten '%-.64s' er blokeret på grund af mange fejlforespørgsler. Lås op med 'mysqladmin flush-hosts'"
+ nla "Host '%-.64s' is geblokkeeerd vanwege te veel verbindings fouten. Deblokkeer met 'mysqladmin flush-hosts'"
+ eng "Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'"
+ jps "Host '%-.64s' 㯠many connection error ã®ãŸã‚ã€æ‹’å¦ã•ã‚Œã¾ã—ãŸ. 'mysqladmin flush-hosts' ã§è§£é™¤ã—ã¦ãã ã•ã„",
+ est "Masin '%-.64s' on blokeeritud hulgaliste ühendusvigade tõttu. Blokeeringu saab tühistada 'mysqladmin flush-hosts' käsuga"
+ fre "L'hôte '%-.64s' est bloqué à cause d'un trop grand nombre d'erreur de connexion. Débloquer le par 'mysqladmin flush-hosts'"
+ ger "Host '%-.64s' blockiert wegen zu vieler Verbindungsfehler. Aufheben der Blockierung mit 'mysqladmin flush-hosts'"
+ greek "Ο υπολογιστής '%-.64s' έχει αποκλεισθεί λόγω πολλαπλών λαθών σÏνδεσης. ΠÏοσπαθήστε να διοÏώσετε με 'mysqladmin flush-hosts'"
+ hun "A '%-.64s' host blokkolodott, tul sok kapcsolodasi hiba miatt. Hasznalja a 'mysqladmin flush-hosts' parancsot"
+ ita "Sistema '%-.64s' bloccato a causa di troppi errori di connessione. Per sbloccarlo: 'mysqladmin flush-hosts'"
+ jpn "Host '%-.64s' 㯠many connection error ã®ãŸã‚ã€æ‹’å¦ã•ã‚Œã¾ã—ãŸ. 'mysqladmin flush-hosts' ã§è§£é™¤ã—ã¦ãã ã•ã„"
+ kor "너무 ë§Žì€ ì—°ê²°ì˜¤ë¥˜ë¡œ ì¸í•˜ì—¬ 호스트 '%-.64s'는 블ë½ë˜ì—ˆìŠµë‹ˆë‹¤. 'mysqladmin flush-hosts'를 ì´ìš©í•˜ì—¬ 블ë½ì„ 해제하세요"
+ por "'Host' '%-.64s' está bloqueado devido a muitos erros de conexão. Desbloqueie com 'mysqladmin flush-hosts'"
+ rum "Host-ul '%-.64s' e blocat din cauza multelor erori de conectie. Poti deploca folosind 'mysqladmin flush-hosts'"
+ rus "ХоÑÑ‚ '%-.64s' заблокирован из-за Ñлишком большого количеÑтва ошибок ÑоединениÑ. Разблокировать его можно Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ 'mysqladmin flush-hosts'"
+ serbian "Host '%-.64s' je blokiran zbog previše grešaka u konekciji. Možete ga odblokirati pomoću komande 'mysqladmin flush-hosts'"
+ spa "Servidor '%-.64s' está bloqueado por muchos errores de conexión. Desbloquear con 'mysqladmin flush-hosts'"
+ swe "Denna dator, '%-.64s', är blockerad pga många felaktig paket. Gör 'mysqladmin flush-hosts' för att ta bort alla blockeringarna"
+ ukr "ХоÑÑ‚ '%-.64s' заблоковано з причини великої кількоÑÑ‚Ñ– помилок з'єднаннÑ. Ð”Ð»Ñ Ñ€Ð¾Ð·Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸Ñтовуйте 'mysqladmin flush-hosts'"
+ER_HOST_NOT_PRIVILEGED
+ cze "Stroj '%-.64s' nem-Bá povoleno se k tomuto MySQL serveru připojit"
+ dan "Værten '%-.64s' kan ikke tilkoble denne MySQL-server"
+ nla "Het is host '%-.64s' is niet toegestaan verbinding te maken met deze MySQL server"
+ eng "Host '%-.64s' is not allowed to connect to this MySQL server"
+ jps "Host '%-.64s' 㯠MySQL server ã«æŽ¥ç¶šã‚’許å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“",
+ est "Masinal '%-.64s' puudub ligipääs sellele MySQL serverile"
+ fre "Le hôte '%-.64s' n'est pas authorisé à se connecter à ce serveur MySQL"
+ ger "Host '%-.64s' hat keine Berechtigung, sich mit diesem MySQL-Server zu verbinden"
+ greek "Ο υπολογιστής '%-.64s' δεν έχει δικαίωμα σÏνδεσης με τον MySQL server"
+ hun "A '%-.64s' host szamara nem engedelyezett a kapcsolodas ehhez a MySQL szerverhez"
+ ita "Al sistema '%-.64s' non e` consentita la connessione a questo server MySQL"
+ jpn "Host '%-.64s' 㯠MySQL server ã«æŽ¥ç¶šã‚’許å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+ kor "'%-.64s' 호스트는 ì´ MySQLì„œë²„ì— ì ‘ì†í•  허가를 받지 못했습니다."
+ por "'Host' '%-.64s' não tem permissão para se conectar com este servidor MySQL"
+ rum "Host-ul '%-.64s' nu este permis a se conecta la aceste server MySQL"
+ rus "ХоÑту '%-.64s' не разрешаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð°Ñ‚ÑŒÑÑ Ðº Ñтому Ñерверу MySQL"
+ serbian "Host-u '%-.64s' nije dozvoljeno da se konektuje na ovaj MySQL server"
+ spa "Servidor '%-.64s' no está permitido para conectar con este servidor MySQL"
+ swe "Denna dator, '%-.64s', har inte privileger att använda denna MySQL server"
+ ukr "ХоÑту '%-.64s' не доволено зв'ÑзуватиÑÑŒ з цим Ñервером MySQL"
+ER_PASSWORD_ANONYMOUS_USER 42000
+ cze "Pou-Bžíváte MySQL jako anonymní uživatel a anonymní uživatelé nemají povoleno měnit hesla"
+ dan "Du bruger MySQL som anonym bruger. Anonyme brugere må ikke ændre adgangskoder"
+ nla "U gebruikt MySQL als anonieme gebruiker en deze mogen geen wachtwoorden wijzigen"
+ eng "You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords"
+ jps "MySQL ã‚’ anonymous users ã§ä½¿ç”¨ã—ã¦ã„る状態ã§ã¯ã€ãƒ‘スワードã®å¤‰æ›´ã¯ã§ãã¾ã›ã‚“",
+ est "Te kasutate MySQL-i anonüümse kasutajana, kelledel pole parooli muutmise õigust"
+ fre "Vous utilisez un utilisateur anonyme et les utilisateurs anonymes ne sont pas autorisés à changer les mots de passe"
+ ger "Sie benutzen MySQL als anonymer Benutzer und dürfen daher keine Passwörter ändern"
+ greek "ΧÏησιμοποιείτε την MySQL σαν anonymous user και έτσι δεν μποÏείτε να αλλάξετε τα passwords άλλων χÏηστών"
+ hun "Nevtelen (anonymous) felhasznalokent nem negedelyezett a jelszovaltoztatas"
+ ita "Impossibile cambiare la password usando MySQL come utente anonimo"
+ jpn "MySQL ã‚’ anonymous users ã§ä½¿ç”¨ã—ã¦ã„る状態ã§ã¯ã€ãƒ‘スワードã®å¤‰æ›´ã¯ã§ãã¾ã›ã‚“"
+ kor "ë‹¹ì‹ ì€ MySQLì„œë²„ì— ìµëª…ì˜ ì‚¬ìš©ìžë¡œ ì ‘ì†ì„ 하셨습니다.ìµëª…ì˜ ì‚¬ìš©ìžëŠ” 암호를 변경할 수 없습니다."
+ por "Você está usando o MySQL como usuário anônimo e usuários anônimos não têm permissão para mudar senhas"
+ rum "Dumneavoastra folositi MySQL ca un utilizator anonim si utilizatorii anonimi nu au voie sa schime parolele"
+ rus "Ð’Ñ‹ иÑпользуете MySQL от имени анонимного пользователÑ, а анонимным пользователÑм не разрешаетÑÑ Ð¼ÐµÐ½ÑÑ‚ÑŒ пароли"
+ serbian "Vi koristite MySQL kao anonimni korisnik a anonimnim korisnicima nije dozvoljeno da menjaju lozinke"
+ spa "Tu estás usando MySQL como un usuario anonimo y usuarios anonimos no tienen permiso para cambiar las claves"
+ swe "Du använder MySQL som en anonym användare och som sådan får du inte ändra ditt lösenord"
+ ukr "Ви викориÑтовуєте MySQL Ñк анонімний кориÑтувач, тому вам не дозволено змінювати паролі"
+ER_PASSWORD_NOT_ALLOWED 42000
+ cze "Na zm-Běnu hesel ostatním musíte mít právo provést update tabulek v databázi mysql"
+ dan "Du skal have tilladelse til at opdatere tabeller i MySQL databasen for at ændre andres adgangskoder"
+ nla "U moet tabel update priveleges hebben in de mysql database om wachtwoorden voor anderen te mogen wijzigen"
+ eng "You must have privileges to update tables in the mysql database to be able to change passwords for others"
+ jps "ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ‘スワードを変更ã™ã‚‹ãŸã‚ã«ã¯, mysql データベースã«å¯¾ã—㦠update ã®è¨±å¯ãŒãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“.",
+ est "Teiste paroolide muutmiseks on nõutav tabelite muutmisõigus 'mysql' andmebaasis"
+ fre "Vous devez avoir le privilège update sur les tables de la base de donnée mysql pour pouvoir changer les mots de passe des autres"
+ ger "Sie benötigen die Berechtigung zum Aktualisieren von Tabellen in der Datenbank 'mysql', um die Passwörter anderer Benutzer ändern zu können"
+ greek "ΠÏέπει να έχετε δικαίωμα διόÏθωσης πινάκων (update) στη βάση δεδομένων mysql για να μποÏείτε να αλλάξετε τα passwords άλλων χÏηστών"
+ hun "Onnek tabla-update joggal kell rendelkeznie a mysql adatbazisban masok jelszavanak megvaltoztatasahoz"
+ ita "E` necessario il privilegio di update sulle tabelle del database mysql per cambiare le password per gli altri utenti"
+ jpn "ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ‘スワードを変更ã™ã‚‹ãŸã‚ã«ã¯, mysql データベースã«å¯¾ã—㦠update ã®è¨±å¯ãŒãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“."
+ kor "ë‹¹ì‹ ì€ ë‹¤ë¥¸ì‚¬ìš©ìžë“¤ì˜ 암호를 변경할 수 있ë„ë¡ ë°ì´íƒ€ë² ì´ìŠ¤ ë³€ê²½ê¶Œí•œì„ ê°€ì ¸ì•¼ 합니다."
+ por "Você deve ter privilégios para atualizar tabelas no banco de dados mysql para ser capaz de mudar a senha de outros"
+ rum "Trebuie sa aveti privilegii sa actualizati tabelele in bazele de date mysql ca sa puteti sa schimati parolele altora"
+ rus "Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾ чтобы изменÑÑ‚ÑŒ пароли других пользователей, у Ð²Ð°Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ‹ быть привилегии на изменение таблиц в базе данных mysql"
+ serbian "Morate imati privilegije da možete da update-ujete određene tabele ako želite da menjate lozinke za druge korisnike"
+ spa "Tu debes de tener permiso para actualizar tablas en la base de datos mysql para cambiar las claves para otros"
+ swe "För att ändra lösenord för andra måste du ha rättigheter att uppdatera mysql-databasen"
+ ukr "Ви повині мати право на Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†ÑŒ у базі данних mysql, аби мати можливіÑÑ‚ÑŒ змінювати пароль іншим"
+ER_PASSWORD_NO_MATCH 42000
+ cze "V tabulce user nen-Bí žádný odpovídající řádek"
+ dan "Kan ikke finde nogen tilsvarende poster i bruger tabellen"
+ nla "Kan geen enkele passende rij vinden in de gebruikers tabel"
+ eng "Can't find any matching row in the user table"
+ est "Ei leia vastavat kirjet kasutajate tabelis"
+ fre "Impossible de trouver un enregistrement correspondant dans la table user"
+ ger "Kann keinen passenden Datensatz in Tabelle 'user' finden"
+ greek "Δεν είναι δυνατή η ανεÏÏεση της αντίστοιχης εγγÏαφής στον πίνακα των χÏηστών"
+ hun "Nincs megegyezo sor a user tablaban"
+ ita "Impossibile trovare la riga corrispondente nella tabella user"
+ kor "ì‚¬ìš©ìž í…Œì´ë¸”ì—ì„œ ì¼ì¹˜í•˜ëŠ” ê²ƒì„ ì°¾ì„ ìˆ˜ ì—†ì니다."
+ por "Não pode encontrar nenhuma linha que combine na tabela usuário (user table)"
+ rum "Nu pot gasi nici o linie corespunzatoare in tabela utilizatorului"
+ rus "Ðевозможно отыÑкать подходÑщую запиÑÑŒ в таблице пользователей"
+ serbian "Ne mogu da pronađem odgovarajući slog u 'user' tabeli"
+ spa "No puedo encontrar una línea correponsdiente en la tabla user"
+ swe "Hittade inte användaren i 'user'-tabellen"
+ ukr "Ðе можу знайти відповідних запиÑів у таблиці кориÑтувача"
+ER_UPDATE_INFO
+ cze "Nalezen-Bých řádků: %ld Změněno: %ld Varování: %ld"
+ dan "Poster fundet: %ld Ændret: %ld Advarsler: %ld"
+ nla "Passende rijen: %ld Gewijzigd: %ld Waarschuwingen: %ld"
+ eng "Rows matched: %ld Changed: %ld Warnings: %ld"
+ jps "一致数(Rows matched): %ld 変更: %ld Warnings: %ld",
+ est "Sobinud kirjeid: %ld Muudetud: %ld Hoiatusi: %ld"
+ fre "Enregistrements correspondants: %ld Modifiés: %ld Warnings: %ld"
+ ger "Datensätze gefunden: %ld Geändert: %ld Warnungen: %ld"
+ hun "Megegyezo sorok szama: %ld Valtozott: %ld Warnings: %ld"
+ ita "Rows riconosciute: %ld Cambiate: %ld Warnings: %ld"
+ jpn "一致数(Rows matched): %ld 変更: %ld Warnings: %ld"
+ kor "ì¼ì¹˜í•˜ëŠ” Rows : %ldê°œ 변경ë¨: %ldê°œ 경고: %ldê°œ"
+ por "Linhas que combinaram: %ld - Alteradas: %ld - Avisos: %ld"
+ rum "Linii identificate (matched): %ld Schimbate: %ld Atentionari (warnings): %ld"
+ rus "Совпало запиÑей: %ld Изменено: %ld Предупреждений: %ld"
+ serbian "Odgovarajućih slogova: %ld Promenjeno: %ld Upozorenja: %ld"
+ spa "Líneas correspondientes: %ld Cambiadas: %ld Avisos: %ld"
+ swe "Rader: %ld Uppdaterade: %ld Varningar: %ld"
+ ukr "ЗапиÑів відповідає: %ld Змінено: %ld ЗаÑтережень: %ld"
+ER_CANT_CREATE_THREAD
+ cze "Nemohu vytvo-BÅ™it nový thread (errno %d). Pokud je jeÅ¡tÄ› nÄ›jaká volná paměť, podívejte se do manuálu na Äást o chybách specifických pro jednotlivé operaÄní systémy"
+ dan "Kan ikke danne en ny tråd (fejl nr. %d). Hvis computeren ikke er løbet tør for hukommelse, kan du se i brugervejledningen for en mulig operativ-system - afhængig fejl"
+ nla "Kan geen nieuwe thread aanmaken (Errcode: %d). Indien er geen tekort aan geheugen is kunt u de handleiding consulteren over een mogelijke OS afhankelijke fout"
+ eng "Can't create a new thread (errno %d); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug"
+ jps "æ–°è¦ã«ã‚¹ãƒ¬ãƒƒãƒ‰ãŒä½œã‚Œã¾ã›ã‚“ã§ã—㟠(errno %d). ã‚‚ã—最大使用許å¯ãƒ¡ãƒ¢ãƒªãƒ¼æ•°ã‚’越ãˆã¦ã„ãªã„ã®ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¦ã„ã‚‹ãªã‚‰, マニュアルã®ä¸­ã‹ã‚‰ 'possible OS-dependent bug' ã¨ã„ã†æ–‡å­—を探ã—ã¦ãã¿ã¦ã ã•ã„.",
+ est "Ei suuda luua uut lõime (veakood %d). Kui mälu ei ole otsas, on tõenäoliselt tegemist operatsioonisüsteemispetsiifilise veaga"
+ fre "Impossible de créer une nouvelle tâche (errno %d). S'il reste de la mémoire libre, consultez le manual pour trouver un éventuel bug dépendant de l'OS"
+ ger "Kann keinen neuen Thread erzeugen (Fehler: %d). Sollte noch Speicher verfügbar sein, bitte im Handbuch wegen möglicher Fehler im Betriebssystem nachschlagen"
+ hun "Uj thread letrehozasa nem lehetseges (Hibakod: %d). Amenyiben van meg szabad memoria, olvassa el a kezikonyv operacios rendszerfuggo hibalehetosegekrol szolo reszet"
+ ita "Impossibile creare un nuovo thread (errno %d). Se non ci sono problemi di memoria disponibile puoi consultare il manuale per controllare possibili problemi dipendenti dal SO"
+ jpn "æ–°è¦ã«ã‚¹ãƒ¬ãƒƒãƒ‰ãŒä½œã‚Œã¾ã›ã‚“ã§ã—㟠(errno %d). ã‚‚ã—最大使用許å¯ãƒ¡ãƒ¢ãƒªãƒ¼æ•°ã‚’越ãˆã¦ã„ãªã„ã®ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¦ã„ã‚‹ãªã‚‰, マニュアルã®ä¸­ã‹ã‚‰ 'possible OS-dependent bug' ã¨ã„ã†æ–‡å­—を探ã—ã¦ãã¿ã¦ã ã•ã„."
+ kor "새로운 쓰레드를 만들 수 없습니다.(ì—러번호 %d). 만약 여유메모리가 있다면 OS-dependent버그 ì˜ ë©”ë‰´ì–¼ ë¶€ë¶„ì„ ì°¾ì•„ë³´ì‹œì˜¤."
+ nor "Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug"
+ norwegian-ny "Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug"
+ pol "Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug"
+ por "Não pode criar uma nova 'thread' (erro no. %d). Se você não estiver sem memória disponível, você pode consultar o manual sobre um possível 'bug' dependente do sistema operacional"
+ rum "Nu pot crea un thread nou (Eroare %d). Daca mai aveti memorie disponibila in sistem, puteti consulta manualul - ar putea exista un potential bug in legatura cu sistemul de operare"
+ rus "Ðевозможно Ñоздать новый поток (ошибка %d). ЕÑли Ñто не ÑитуациÑ, ÑвÑÐ·Ð°Ð½Ð½Ð°Ñ Ñ Ð½ÐµÑ…Ð²Ð°Ñ‚ÐºÐ¾Ð¹ памÑти, то вам Ñледует изучить документацию на предмет опиÑÐ°Ð½Ð¸Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ð¹ ошибки работы в конкретной ОС"
+ serbian "Ne mogu da kreiram novi thread (errno %d). Ako imate joÅ¡ slobodne memorije, trebali biste da pogledate u priruÄniku da li je ovo specifiÄna greÅ¡ka vaÅ¡eg operativnog sistema"
+ spa "No puedo crear un nuevo thread (errno %d). Si tu está con falta de memoria disponible, tu puedes consultar el Manual para posibles problemas con SO"
+ swe "Kan inte skapa en ny tråd (errno %d)"
+ ukr "Ðе можу Ñтворити нову гілку (помилка %d). Якщо ви не викориÑтали уÑÑŽ пам'ÑÑ‚ÑŒ, то прочитайте документацію до вашої ОС - можливо це помилка ОС"
+ER_WRONG_VALUE_COUNT_ON_ROW 21S01
+ cze "Po-BÄet sloupců neodpovídá poÄtu hodnot na řádku %ld"
+ dan "Kolonne antallet stemmer ikke overens med antallet af værdier i post %ld"
+ nla "Kolom aantal komt niet overeen met waarde aantal in rij %ld"
+ eng "Column count doesn't match value count at row %ld"
+ est "Tulpade hulk erineb väärtuste hulgast real %ld"
+ ger "Anzahl der Felder stimmt nicht mit der Anzahl der Werte in Zeile %ld überein"
+ hun "Az oszlopban talalhato ertek nem egyezik meg a %ld sorban szamitott ertekkel"
+ ita "Il numero delle colonne non corrisponde al conteggio alla riga %ld"
+ kor "Row %ldì—ì„œ 칼럼 카운트와 value 카운터와 ì¼ì¹˜í•˜ì§€ 않습니다."
+ por "Contagem de colunas não confere com a contagem de valores na linha %ld"
+ rum "Numarul de coloane nu corespunde cu numarul de valori la linia %ld"
+ rus "КоличеÑтво Ñтолбцов не Ñовпадает Ñ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтвом значений в запиÑи %ld"
+ serbian "Broj kolona ne odgovara broju vrednosti u slogu %ld"
+ spa "El número de columnas no corresponde al número en la línea %ld"
+ swe "Antalet kolumner motsvarar inte antalet värden på rad: %ld"
+ ukr "КількіÑÑ‚ÑŒ Ñтовбців не Ñпівпадає з кількіÑÑ‚ÑŽ значень у Ñтроці %ld"
+ER_CANT_REOPEN_TABLE
+ cze "Nemohu znovuotev-Břít tabulku: '%-.192s"
+ dan "Kan ikke genåbne tabel '%-.192s"
+ nla "Kan tabel niet opnieuw openen: '%-.192s"
+ eng "Can't reopen table: '%-.192s'"
+ est "Ei suuda taasavada tabelit '%-.192s'"
+ fre "Impossible de réouvrir la table: '%-.192s"
+ ger "Kann Tabelle'%-.192s' nicht erneut öffnen"
+ hun "Nem lehet ujra-megnyitni a tablat: '%-.192s"
+ ita "Impossibile riaprire la tabella: '%-.192s'"
+ kor "í…Œì´ë¸”ì„ ë‹¤ì‹œ 열수 없군요: '%-.192s"
+ nor "Can't reopen table: '%-.192s"
+ norwegian-ny "Can't reopen table: '%-.192s"
+ pol "Can't reopen table: '%-.192s"
+ por "Não pode reabrir a tabela '%-.192s"
+ rum "Nu pot redeschide tabela: '%-.192s'"
+ rus "Ðевозможно заново открыть таблицу '%-.192s'"
+ serbian "Ne mogu da ponovo otvorim tabelu '%-.192s'"
+ slo "Can't reopen table: '%-.192s"
+ spa "No puedo reabrir tabla: '%-.192s"
+ swe "Kunde inte stänga och öppna tabell '%-.192s"
+ ukr "Ðе можу перевідкрити таблицю: '%-.192s'"
+ER_INVALID_USE_OF_NULL 22004
+ cze "Neplatn-Bé užití hodnoty NULL"
+ dan "Forkert brug af nulværdi (NULL)"
+ nla "Foutief gebruik van de NULL waarde"
+ eng "Invalid use of NULL value"
+ jps "NULL 値ã®ä½¿ç”¨æ–¹æ³•ãŒä¸é©åˆ‡ã§ã™",
+ est "NULL väärtuse väärkasutus"
+ fre "Utilisation incorrecte de la valeur NULL"
+ ger "Unerlaubte Verwendung eines NULL-Werts"
+ hun "A NULL ervenytelen hasznalata"
+ ita "Uso scorretto del valore NULL"
+ jpn "NULL 値ã®ä½¿ç”¨æ–¹æ³•ãŒä¸é©åˆ‡ã§ã™"
+ kor "NULL ê°’ì„ ìž˜ëª» 사용하셨군요..."
+ por "Uso inválido do valor NULL"
+ rum "Folosirea unei value NULL e invalida"
+ rus "Ðеправильное иÑпользование величины NULL"
+ serbian "Pogrešna upotreba vrednosti NULL"
+ spa "Invalido uso de valor NULL"
+ swe "Felaktig använding av NULL"
+ ukr "Хибне викориÑÑ‚Ð°Ð½Ð½Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ NULL"
+ER_REGEXP_ERROR 42000
+ cze "Regul-Bární výraz vrátil chybu '%-.64s'"
+ dan "Fik fejl '%-.64s' fra regexp"
+ nla "Fout '%-.64s' ontvangen van regexp"
+ eng "Got error '%-.64s' from regexp"
+ est "regexp tagastas vea '%-.64s'"
+ fre "Erreur '%-.64s' provenant de regexp"
+ ger "regexp lieferte Fehler '%-.64s'"
+ hun "'%-.64s' hiba a regularis kifejezes hasznalata soran (regexp)"
+ ita "Errore '%-.64s' da regexp"
+ kor "regexpì—ì„œ '%-.64s'ê°€ 났습니다."
+ por "Obteve erro '%-.64s' em regexp"
+ rum "Eroarea '%-.64s' obtinuta din expresia regulara (regexp)"
+ rus "Получена ошибка '%-.64s' от регулÑрного выражениÑ"
+ serbian "Funkcija regexp je vratila grešku '%-.64s'"
+ spa "Obtenido error '%-.64s' de regexp"
+ swe "Fick fel '%-.64s' från REGEXP"
+ ukr "Отримано помилку '%-.64s' від регулÑрного виразу"
+ER_MIX_OF_GROUP_FUNC_AND_FIELDS 42000
+ cze "Pokud nen-Bí žádná GROUP BY klauzule, není dovoleno souÄasné použití GROUP položek (MIN(),MAX(),COUNT()...) s ne GROUP položkami"
+ dan "Sammenblanding af GROUP kolonner (MIN(),MAX(),COUNT()...) uden GROUP kolonner er ikke tilladt, hvis der ikke er noget GROUP BY prædikat"
+ nla "Het mixen van GROUP kolommen (MIN(),MAX(),COUNT()...) met no-GROUP kolommen is foutief indien er geen GROUP BY clausule is"
+ eng "Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause"
+ est "GROUP tulpade (MIN(),MAX(),COUNT()...) kooskasutamine tavaliste tulpadega ilma GROUP BY klauslita ei ole lubatud"
+ fre "Mélanger les colonnes GROUP (MIN(),MAX(),COUNT()...) avec des colonnes normales est interdit s'il n'y a pas de clause GROUP BY"
+ ger "Das Vermischen von GROUP-Feldern (MIN(),MAX(),COUNT()...) mit Nicht-GROUP-Feldern ist nicht zulässig, wenn keine GROUP-BY-Klausel vorhanden ist"
+ hun "A GROUP mezok (MIN(),MAX(),COUNT()...) kevert hasznalata nem lehetseges GROUP BY hivatkozas nelkul"
+ ita "Il mescolare funzioni di aggregazione (MIN(),MAX(),COUNT()...) e non e` illegale se non c'e` una clausula GROUP BY"
+ kor "Mixing of GROUP 칼럼s (MIN(),MAX(),COUNT(),...) with no GROUP 칼럼s is illegal if there is no GROUP BY clause"
+ por "Mistura de colunas agrupadas (com MIN(), MAX(), COUNT(), ...) com colunas não agrupadas é ilegal, se não existir uma cláusula de agrupamento (cláusula GROUP BY)"
+ rum "Amestecarea de coloane GROUP (MIN(),MAX(),COUNT()...) fara coloane GROUP este ilegala daca nu exista o clauza GROUP BY"
+ rus "Одновременное иÑпользование Ñгруппированных (GROUP) Ñтолбцов (MIN(),MAX(),COUNT(),...) Ñ Ð½ÐµÑгруппированными Ñтолбцами ÑвлÑетÑÑ Ð½ÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ñ‹Ð¼, еÑли в выражении еÑÑ‚ÑŒ GROUP BY"
+ serbian "Upotreba agregatnih funkcija (MIN(),MAX(),COUNT()...) bez 'GROUP' kolona je pogrešna ako ne postoji 'GROUP BY' iskaz"
+ spa "Mezcla de columnas GROUP (MIN(),MAX(),COUNT()...) con no GROUP columnas es ilegal si no hat la clausula GROUP BY"
+ swe "Man får ha både GROUP-kolumner (MIN(),MAX(),COUNT()...) och fält i en fråga om man inte har en GROUP BY-del"
+ ukr "Ð—Ð¼Ñ–ÑˆÑƒÐ²Ð°Ð½Ð½Ñ GROUP Ñтовбців (MIN(),MAX(),COUNT()...) з не GROUP ÑтовбцÑми Ñ” забороненим, Ñкщо не має GROUP BY"
+ER_NONEXISTING_GRANT 42000
+ cze "Neexistuje odpov-Bídající grant pro uživatele '%-.48s' na stroji '%-.64s'"
+ dan "Denne tilladelse findes ikke for brugeren '%-.48s' på vært '%-.64s'"
+ nla "Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.48s' op host '%-.64s'"
+ eng "There is no such grant defined for user '%-.48s' on host '%-.64s'"
+ jps "ユーザー '%-.48s' (ホスト '%-.64s' ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼) ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“",
+ est "Sellist õigust ei ole defineeritud kasutajale '%-.48s' masinast '%-.64s'"
+ fre "Un tel droit n'est pas défini pour l'utilisateur '%-.48s' sur l'hôte '%-.64s'"
+ ger "Für Benutzer '%-.48s' auf Host '%-.64s' gibt es keine solche Berechtigung"
+ hun "A '%-.48s' felhasznalonak nincs ilyen joga a '%-.64s' host-on"
+ ita "GRANT non definita per l'utente '%-.48s' dalla macchina '%-.64s'"
+ jpn "ユーザー '%-.48s' (ホスト '%-.64s' ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼) ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+ kor "ì‚¬ìš©ìž '%-.48s' (호스트 '%-.64s')를 위하여 ì •ì˜ëœ 그런 승ì¸ì€ 없습니다."
+ por "Não existe tal permissão (grant) definida para o usuário '%-.48s' no 'host' '%-.64s'"
+ rum "Nu exista un astfel de grant definit pentru utilzatorul '%-.48s' de pe host-ul '%-.64s'"
+ rus "Такие права не определены Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ '%-.48s' на хоÑте '%-.64s'"
+ serbian "Ne postoji odobrenje za pristup korisniku '%-.48s' na host-u '%-.64s'"
+ spa "No existe permiso definido para usuario '%-.48s' en el servidor '%-.64s'"
+ swe "Det finns inget privilegium definierat för användare '%-.48s' på '%-.64s'"
+ ukr "Повноважень не визначено Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача '%-.48s' з хоÑту '%-.64s'"
+ER_TABLEACCESS_DENIED_ERROR 42000
+ cze "%-.16s p-Bříkaz nepřístupný pro uživatele: '%-.48s'@'%-.64s' pro tabulku '%-.192s'"
+ dan "%-.16s-kommandoen er ikke tilladt for brugeren '%-.48s'@'%-.64s' for tabellen '%-.192s'"
+ nla "%-.16s commando geweigerd voor gebruiker: '%-.48s'@'%-.64s' voor tabel '%-.192s'"
+ eng "%-.16s command denied to user '%-.48s'@'%-.64s' for table '%-.192s'"
+ jps "コマンド %-.16s 㯠ユーザー '%-.48s'@'%-.64s' ,テーブル '%-.192s' ã«å¯¾ã—ã¦è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“",
+ est "%-.16s käsk ei ole lubatud kasutajale '%-.48s'@'%-.64s' tabelis '%-.192s'"
+ fre "La commande '%-.16s' est interdite à l'utilisateur: '%-.48s'@'@%-.64s' sur la table '%-.192s'"
+ ger "%-.16s Befehl nicht erlaubt für Benutzer '%-.48s'@'%-.64s' auf Tabelle '%-.192s'"
+ hun "%-.16s parancs a '%-.48s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.192s' tablaban"
+ ita "Comando %-.16s negato per l'utente: '%-.48s'@'%-.64s' sulla tabella '%-.192s'"
+ jpn "コマンド %-.16s 㯠ユーザー '%-.48s'@'%-.64s' ,テーブル '%-.192s' ã«å¯¾ã—ã¦è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+ kor "'%-.16s' ëª…ë ¹ì€ ë‹¤ìŒ ì‚¬ìš©ìžì—게 거부ë˜ì—ˆìŠµë‹ˆë‹¤. : '%-.48s'@'%-.64s' for í…Œì´ë¸” '%-.192s'"
+ por "Comando '%-.16s' negado para o usuário '%-.48s'@'%-.64s' na tabela '%-.192s'"
+ rum "Comanda %-.16s interzisa utilizatorului: '%-.48s'@'%-.64s' pentru tabela '%-.192s'"
+ rus "Команда %-.16s запрещена пользователю '%-.48s'@'%-.64s' Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ '%-.192s'"
+ serbian "%-.16s komanda zabranjena za korisnika '%-.48s'@'%-.64s' za tabelu '%-.192s'"
+ spa "%-.16s comando negado para usuario: '%-.48s'@'%-.64s' para tabla '%-.192s'"
+ swe "%-.16s ej tillåtet för '%-.48s'@'%-.64s' för tabell '%-.192s'"
+ ukr "%-.16s команда заборонена кориÑтувачу: '%-.48s'@'%-.64s' у таблиці '%-.192s'"
+ER_COLUMNACCESS_DENIED_ERROR 42000
+ cze "%-.16s p-Bříkaz nepřístupný pro uživatele: '%-.48s'@'%-.64s' pro sloupec '%-.192s' v tabulce '%-.192s'"
+ dan "%-.16s-kommandoen er ikke tilladt for brugeren '%-.48s'@'%-.64s' for kolonne '%-.192s' in tabellen '%-.192s'"
+ nla "%-.16s commando geweigerd voor gebruiker: '%-.48s'@'%-.64s' voor kolom '%-.192s' in tabel '%-.192s'"
+ eng "%-.16s command denied to user '%-.48s'@'%-.64s' for column '%-.192s' in table '%-.192s'"
+ jps "コマンド %-.16s 㯠ユーザー '%-.48s'@'%-.64s'Â¥n カラム '%-.192s' テーブル '%-.192s' ã«å¯¾ã—ã¦è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“",
+ est "%-.16s käsk ei ole lubatud kasutajale '%-.48s'@'%-.64s' tulbale '%-.192s' tabelis '%-.192s'"
+ fre "La commande '%-.16s' est interdite à l'utilisateur: '%-.48s'@'@%-.64s' sur la colonne '%-.192s' de la table '%-.192s'"
+ ger "%-.16s Befehl nicht erlaubt für Benutzer '%-.48s'@'%-.64s' und Feld '%-.192s' in Tabelle '%-.192s'"
+ hun "%-.16s parancs a '%-.48s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.192s' mezo eseten a '%-.192s' tablaban"
+ ita "Comando %-.16s negato per l'utente: '%-.48s'@'%-.64s' sulla colonna '%-.192s' della tabella '%-.192s'"
+ jpn "コマンド %-.16s 㯠ユーザー '%-.48s'@'%-.64s'\n カラム '%-.192s' テーブル '%-.192s' ã«å¯¾ã—ã¦è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+ kor "'%-.16s' ëª…ë ¹ì€ ë‹¤ìŒ ì‚¬ìš©ìžì—게 거부ë˜ì—ˆìŠµë‹ˆë‹¤. : '%-.48s'@'%-.64s' for 칼럼 '%-.192s' in í…Œì´ë¸” '%-.192s'"
+ por "Comando '%-.16s' negado para o usuário '%-.48s'@'%-.64s' na coluna '%-.192s', na tabela '%-.192s'"
+ rum "Comanda %-.16s interzisa utilizatorului: '%-.48s'@'%-.64s' pentru coloana '%-.192s' in tabela '%-.192s'"
+ rus "Команда %-.16s запрещена пользователю '%-.48s'@'%-.64s' Ð´Ð»Ñ Ñтолбца '%-.192s' в таблице '%-.192s'"
+ serbian "%-.16s komanda zabranjena za korisnika '%-.48s'@'%-.64s' za kolonu '%-.192s' iz tabele '%-.192s'"
+ spa "%-.16s comando negado para usuario: '%-.48s'@'%-.64s' para columna '%-.192s' en la tabla '%-.192s'"
+ swe "%-.16s ej tillåtet för '%-.48s'@'%-.64s' för kolumn '%-.192s' i tabell '%-.192s'"
+ ukr "%-.16s команда заборонена кориÑтувачу: '%-.48s'@'%-.64s' Ð´Ð»Ñ ÑÑ‚Ð¾Ð²Ð±Ñ†Ñ '%-.192s' у таблиці '%-.192s'"
+ER_ILLEGAL_GRANT_FOR_TABLE 42000
+ cze "Neplatn-Bý příkaz GRANT/REVOKE. Prosím, pÅ™eÄtÄ›te si v manuálu, jaká privilegia je možné použít."
+ dan "Forkert GRANT/REVOKE kommando. Se i brugervejledningen hvilke privilegier der kan specificeres."
+ nla "Foutief GRANT/REVOKE commando. Raadpleeg de handleiding welke priveleges gebruikt kunnen worden."
+ eng "Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used"
+ est "Vigane GRANT/REVOKE käsk. Tutvu kasutajajuhendiga"
+ fre "Commande GRANT/REVOKE incorrecte. Consultez le manuel."
+ ger "Unzulässiger GRANT- oder REVOKE-Befehl. Verfügbare Berechtigungen sind im Handbuch aufgeführt"
+ greek "Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used."
+ hun "Ervenytelen GRANT/REVOKE parancs. Kerem, nezze meg a kezikonyvben, milyen jogok lehetsegesek"
+ ita "Comando GRANT/REVOKE illegale. Prego consultare il manuale per sapere quali privilegi possono essere usati."
+ jpn "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
+ kor "ìž˜ëª»ëœ GRANT/REVOKE 명령. ì–´ë–¤ 권리와 승ì¸ì´ 사용ë˜ì–´ 질 수 있는지 ë©”ë‰´ì–¼ì„ ë³´ì‹œì˜¤."
+ nor "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
+ norwegian-ny "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
+ pol "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
+ por "Comando GRANT/REVOKE ilegal. Por favor consulte no manual quais privilégios podem ser usados."
+ rum "Comanda GRANT/REVOKE ilegala. Consultati manualul in privinta privilegiilor ce pot fi folosite."
+ rus "ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° GRANT или REVOKE. ОбратитеÑÑŒ к документации, чтобы выÑÑнить, какие привилегии можно иÑпользовать"
+ serbian "PogreÅ¡na 'GRANT' odnosno 'REVOKE' komanda. Molim Vas pogledajte u priruÄniku koje vrednosti mogu biti upotrebljene."
+ slo "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
+ spa "Ilegal comando GRANT/REVOKE. Por favor consulte el manual para cuales permisos pueden ser usados."
+ swe "Felaktigt GRANT-privilegium använt"
+ ukr "Хибна GRANT/REVOKE команда; прочитайте документацію ÑтоÑовно того, Ñкі права можна викориÑтовувати"
+ER_GRANT_WRONG_HOST_OR_USER 42000
+ cze "Argument p-Bříkazu GRANT uživatel nebo stroj je příliš dlouhý"
+ dan "Værts- eller brugernavn for langt til GRANT"
+ nla "De host of gebruiker parameter voor GRANT is te lang"
+ eng "The host or user argument to GRANT is too long"
+ est "Masina või kasutaja nimi GRANT lauses on liiga pikk"
+ fre "L'hôte ou l'utilisateur donné en argument à GRANT est trop long"
+ ger "Das Host- oder User-Argument für GRANT ist zu lang"
+ hun "A host vagy felhasznalo argumentuma tul hosszu a GRANT parancsban"
+ ita "L'argomento host o utente per la GRANT e` troppo lungo"
+ kor "승ì¸(GRANT)ì„ ìœ„í•˜ì—¬ 사용한 사용ìžë‚˜ í˜¸ìŠ¤íŠ¸ì˜ ê°’ë“¤ì´ ë„ˆë¬´ ê¹ë‹ˆë‹¤."
+ por "Argumento de 'host' ou de usuário para o GRANT é longo demais"
+ rum "Argumentul host-ului sau utilizatorului pentru GRANT e prea lung"
+ rus "Слишком длинное Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ/хоÑта Ð´Ð»Ñ GRANT"
+ serbian "Argument 'host' ili 'korisnik' prosleÄ‘en komandi 'GRANT' je predugaÄak"
+ spa "El argumento para servidor o usuario para GRANT es demasiado grande"
+ swe "Felaktigt maskinnamn eller användarnamn använt med GRANT"
+ ukr "Ðргумент host або user Ð´Ð»Ñ GRANT задовгий"
+ER_NO_SUCH_TABLE 42S02
+ cze "Tabulka '%-.192s.%-.192s' neexistuje"
+ dan "Tabellen '%-.192s.%-.192s' eksisterer ikke"
+ nla "Tabel '%-.192s.%-.192s' bestaat niet"
+ eng "Table '%-.192s.%-.192s' doesn't exist"
+ est "Tabelit '%-.192s.%-.192s' ei eksisteeri"
+ fre "La table '%-.192s.%-.192s' n'existe pas"
+ ger "Tabelle '%-.192s.%-.192s' existiert nicht"
+ hun "A '%-.192s.%-.192s' tabla nem letezik"
+ ita "La tabella '%-.192s.%-.192s' non esiste"
+ jpn "Table '%-.192s.%-.192s' doesn't exist"
+ kor "í…Œì´ë¸” '%-.192s.%-.192s' 는 존재하지 않습니다."
+ nor "Table '%-.192s.%-.192s' doesn't exist"
+ norwegian-ny "Table '%-.192s.%-.192s' doesn't exist"
+ pol "Table '%-.192s.%-.192s' doesn't exist"
+ por "Tabela '%-.192s.%-.192s' não existe"
+ rum "Tabela '%-.192s.%-.192s' nu exista"
+ rus "Таблица '%-.192s.%-.192s' не ÑущеÑтвует"
+ serbian "Tabela '%-.192s.%-.192s' ne postoji"
+ slo "Table '%-.192s.%-.192s' doesn't exist"
+ spa "Tabla '%-.192s.%-.192s' no existe"
+ swe "Det finns ingen tabell som heter '%-.192s.%-.192s'"
+ ukr "Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ '%-.192s.%-.192s' не Ñ–Ñнує"
+ER_NONEXISTING_TABLE_GRANT 42000
+ cze "Neexistuje odpov-Bídající grant pro uživatele '%-.48s' na stroji '%-.64s' pro tabulku '%-.192s'"
+ dan "Denne tilladelse eksisterer ikke for brugeren '%-.48s' på vært '%-.64s' for tabellen '%-.192s'"
+ nla "Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.48s' op host '%-.64s' op tabel '%-.192s'"
+ eng "There is no such grant defined for user '%-.48s' on host '%-.64s' on table '%-.192s'"
+ est "Sellist õigust ei ole defineeritud kasutajale '%-.48s' masinast '%-.64s' tabelile '%-.192s'"
+ fre "Un tel droit n'est pas défini pour l'utilisateur '%-.48s' sur l'hôte '%-.64s' sur la table '%-.192s'"
+ ger "Eine solche Berechtigung ist für User '%-.48s' auf Host '%-.64s' an Tabelle '%-.192s' nicht definiert"
+ hun "A '%-.48s' felhasznalo szamara a '%-.64s' host '%-.192s' tablajaban ez a parancs nem engedelyezett"
+ ita "GRANT non definita per l'utente '%-.48s' dalla macchina '%-.64s' sulla tabella '%-.192s'"
+ kor "ì‚¬ìš©ìž '%-.48s'(호스트 '%-.64s')는 í…Œì´ë¸” '%-.192s'를 사용하기 위하여 ì •ì˜ëœ 승ì¸ì€ 없습니다. "
+ por "Não existe tal permissão (grant) definido para o usuário '%-.48s' no 'host' '%-.64s', na tabela '%-.192s'"
+ rum "Nu exista un astfel de privilegiu (grant) definit pentru utilizatorul '%-.48s' de pe host-ul '%-.64s' pentru tabela '%-.192s'"
+ rus "Такие права не определены Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ '%-.48s' на компьютере '%-.64s' Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ '%-.192s'"
+ serbian "Ne postoji odobrenje za pristup korisniku '%-.48s' na host-u '%-.64s' tabeli '%-.192s'"
+ spa "No existe tal permiso definido para usuario '%-.48s' en el servidor '%-.64s' en la tabla '%-.192s'"
+ swe "Det finns inget privilegium definierat för användare '%-.48s' på '%-.64s' för tabell '%-.192s'"
+ ukr "Повноважень не визначено Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача '%-.48s' з хоÑту '%-.64s' Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– '%-.192s'"
+ER_NOT_ALLOWED_COMMAND 42000
+ cze "Pou-Bžitý příkaz není v této verzi MySQL povolen"
+ dan "Den brugte kommando er ikke tilladt med denne udgave af MySQL"
+ nla "Het used commando is niet toegestaan in deze MySQL versie"
+ eng "The used command is not allowed with this MySQL version"
+ est "Antud käsk ei ole lubatud käesolevas MySQL versioonis"
+ fre "Cette commande n'existe pas dans cette version de MySQL"
+ ger "Der verwendete Befehl ist in dieser MySQL-Version nicht zulässig"
+ hun "A hasznalt parancs nem engedelyezett ebben a MySQL verzioban"
+ ita "Il comando utilizzato non e` supportato in questa versione di MySQL"
+ kor "ì‚¬ìš©ëœ ëª…ë ¹ì€ í˜„ìž¬ì˜ MySQL 버젼ì—서는 ì´ìš©ë˜ì§€ 않습니다."
+ por "Comando usado não é permitido para esta versão do MySQL"
+ rum "Comanda folosita nu este permisa pentru aceasta versiune de MySQL"
+ rus "Эта команда не допуÑкаетÑÑ Ð² данной верÑии MySQL"
+ serbian "Upotrebljena komanda nije dozvoljena sa ovom verzijom MySQL servera"
+ spa "El comando usado no es permitido con esta versión de MySQL"
+ swe "Du kan inte använda detta kommando med denna MySQL version"
+ ukr "ВикориÑтовувана команда не дозволена у цій верÑÑ–Ñ— MySQL"
+ER_SYNTAX_ERROR 42000
+ cze "Va-Bše syntaxe je nějaká divná"
+ dan "Der er en fejl i SQL syntaksen"
+ nla "Er is iets fout in de gebruikte syntax"
+ eng "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use"
+ est "Viga SQL süntaksis"
+ fre "Erreur de syntaxe"
+ ger "Fehler in der SQL-Syntax. Bitte die korrekte Syntax im Handbuch nachschlagen"
+ greek "You have an error in your SQL syntax"
+ hun "Szintaktikai hiba"
+ ita "Errore di sintassi nella query SQL"
+ jpn "Something is wrong in your syntax"
+ kor "SQL êµ¬ë¬¸ì— ì˜¤ë¥˜ê°€ 있습니다."
+ nor "Something is wrong in your syntax"
+ norwegian-ny "Something is wrong in your syntax"
+ pol "Something is wrong in your syntax"
+ por "Você tem um erro de sintaxe no seu SQL"
+ rum "Aveti o eroare in sintaxa RSQL"
+ rus "У Ð²Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° в запроÑе. Изучите документацию по иÑпользуемой верÑии MySQL на предмет корректного ÑинтакÑиÑа"
+ serbian "Imate grešku u vašoj SQL sintaksi"
+ slo "Something is wrong in your syntax"
+ spa "Algo está equivocado en su sintax"
+ swe "Du har något fel i din syntax"
+ ukr "У Ð²Ð°Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° у ÑинтакÑиÑÑ– SQL"
+ER_DELAYED_CANT_CHANGE_LOCK
+ cze "Zpo-Bžděný insert threadu nebyl schopen získat požadovaný zámek pro tabulku %-.192s"
+ dan "Forsinket indsættelse tråden (delayed insert thread) kunne ikke opnå lås på tabellen %-.192s"
+ nla "'Delayed insert' thread kon de aangevraagde 'lock' niet krijgen voor tabel %-.192s"
+ eng "Delayed insert thread couldn't get requested lock for table %-.192s"
+ est "INSERT DELAYED lõim ei suutnud saada soovitud lukku tabelile %-.192s"
+ fre "La tâche 'delayed insert' n'a pas pu obtenir le verrou démandé sur la table %-.192s"
+ ger "Verzögerter (DELAYED) Einfüge-Thread konnte die angeforderte Sperre für Tabelle '%-.192s' nicht erhalten"
+ hun "A kesleltetett beillesztes (delayed insert) thread nem kapott zatolast a %-.192s tablahoz"
+ ita "Il thread di inserimento ritardato non riesce ad ottenere il lock per la tabella %-.192s"
+ kor "ì§€ì—°ëœ insert 쓰레드가 í…Œì´ë¸” %-.192sì˜ ìš”êµ¬ëœ ë½í‚¹ì„ 처리할 수 없었습니다."
+ por "'Thread' de inserção retardada (atrasada) pois não conseguiu obter a trava solicitada para tabela '%-.192s'"
+ rum "Thread-ul pentru inserarea aminata nu a putut obtine lacatul (lock) pentru tabela %-.192s"
+ rus "Поток, обÑлуживающий отложенную вÑтавку (delayed insert), не Ñмог получить запрашиваемую блокировку на таблицу %-.192s"
+ serbian "Prolongirani 'INSERT' thread nije mogao da dobije traženo zakljuÄavanje tabele '%-.192s'"
+ spa "Thread de inserción retarda no pudiendo bloquear para la tabla %-.192s"
+ swe "DELAYED INSERT-tråden kunde inte låsa tabell '%-.192s'"
+ ukr "Гілка Ð´Ð»Ñ INSERT DELAYED не може отримати Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– %-.192s"
+ER_TOO_MANY_DELAYED_THREADS
+ cze "P-Bříliš mnoho zpožděných threadů"
+ dan "For mange slettede tråde (threads) i brug"
+ nla "Te veel 'delayed' threads in gebruik"
+ eng "Too many delayed threads in use"
+ est "Liiga palju DELAYED lõimesid kasutusel"
+ fre "Trop de tâche 'delayed' en cours"
+ ger "Zu viele verzögerte (DELAYED) Threads in Verwendung"
+ hun "Tul sok kesletetett thread (delayed)"
+ ita "Troppi threads ritardati in uso"
+ kor "너무 ë§Žì€ ì§€ì—° 쓰레드를 사용하고 있습니다."
+ por "Excesso de 'threads' retardadas (atrasadas) em uso"
+ rum "Prea multe threaduri aminate care sint in uz"
+ rus "Слишком много потоков, обÑлуживающих отложенную вÑтавку (delayed insert)"
+ serbian "Previše prolongiranih thread-ova je u upotrebi"
+ spa "Muchos threads retardados en uso"
+ swe "Det finns redan 'max_delayed_threads' trådar i använding"
+ ukr "Забагато затриманих гілок викориÑтовуєтьÑÑ"
+ER_ABORTING_CONNECTION 08S01
+ cze "Zru-Bšeno spojení %ld do databáze: '%-.192s' uživatel: '%-.48s' (%-.64s)"
+ dan "Afbrudt forbindelse %ld til database: '%-.192s' bruger: '%-.48s' (%-.64s)"
+ nla "Afgebroken verbinding %ld naar db: '%-.192s' gebruiker: '%-.48s' (%-.64s)"
+ eng "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ est "Ãœhendus katkestatud %ld andmebaasile: '%-.192s' kasutajale: '%-.48s' (%-.64s)"
+ fre "Connection %ld avortée vers la bd: '%-.192s' utilisateur: '%-.48s' (%-.64s)"
+ ger "Abbruch der Verbindung %ld zur Datenbank '%-.192s'. Benutzer: '%-.48s' (%-.64s)"
+ hun "Megszakitott kapcsolat %ld db: '%-.192s' adatbazishoz, felhasznalo: '%-.48s' (%-.64s)"
+ ita "Interrotta la connessione %ld al db: '%-.192s' utente: '%-.48s' (%-.64s)"
+ jpn "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ kor "ë°ì´íƒ€ë² ì´ìŠ¤ ì ‘ì†ì„ 위한 ì—°ê²° %ldê°€ ì¤‘ë‹¨ë¨ : '%-.192s' 사용ìž: '%-.48s' (%-.64s)"
+ nor "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ norwegian-ny "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ pol "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ por "Conexão %ld abortou para o banco de dados '%-.192s' - usuário '%-.48s' (%-.64s)"
+ rum "Conectie terminata %ld la baza de date: '%-.192s' utilizator: '%-.48s' (%-.64s)"
+ rus "Прервано Ñоединение %ld к базе данных '%-.192s' Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ '%-.48s' (%-.64s)"
+ serbian "Prekinuta konekcija broj %ld ka bazi: '%-.192s' korisnik je bio: '%-.48s' (%-.64s)"
+ slo "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ spa "Conexión abortada %ld para db: '%-.192s' usuario: '%-.48s' (%-.64s)"
+ swe "Avbröt länken för tråd %ld till db '%-.192s', användare '%-.48s' (%-.64s)"
+ ukr "Перервано з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ %ld до бази данних: '%-.192s' кориÑтувача: '%-.48s' (%-.64s)"
+ER_NET_PACKET_TOO_LARGE 08S01
+ cze "Zji-Bštěn příchozí packet delší než 'max_allowed_packet'"
+ dan "Modtog en datapakke som var større end 'max_allowed_packet'"
+ nla "Groter pakket ontvangen dan 'max_allowed_packet'"
+ eng "Got a packet bigger than 'max_allowed_packet' bytes"
+ est "Saabus suurem pakett kui lubatud 'max_allowed_packet' muutujaga"
+ fre "Paquet plus grand que 'max_allowed_packet' reçu"
+ ger "Empfangenes Paket ist größer als 'max_allowed_packet' Bytes"
+ hun "A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'max_allowed_packet'"
+ ita "Ricevuto un pacchetto piu` grande di 'max_allowed_packet'"
+ kor "'max_allowed_packet'보다 ë”í° íŒ¨í‚·ì„ ë°›ì•˜ìŠµë‹ˆë‹¤."
+ por "Obteve um pacote maior do que a taxa máxima de pacotes definida (max_allowed_packet)"
+ rum "Un packet mai mare decit 'max_allowed_packet' a fost primit"
+ rus "Полученный пакет больше, чем 'max_allowed_packet'"
+ serbian "Primio sam mrežni paket veći od definisane vrednosti 'max_allowed_packet'"
+ spa "Obtenido un paquete mayor que 'max_allowed_packet'"
+ swe "Kommunkationspaketet är större än 'max_allowed_packet'"
+ ukr "Отримано пакет більший ніж max_allowed_packet"
+ER_NET_READ_ERROR_FROM_PIPE 08S01
+ cze "Zji-BÅ¡tÄ›na chyba pÅ™i Ätení z roury spojení"
+ dan "Fik læsefejl fra forbindelse (connection pipe)"
+ nla "Kreeg leesfout van de verbindings pipe"
+ eng "Got a read error from the connection pipe"
+ est "Viga ühendustoru lugemisel"
+ fre "Erreur de lecture reçue du pipe de connexion"
+ ger "Lese-Fehler bei einer Verbindungs-Pipe"
+ hun "Olvasasi hiba a kapcsolat soran"
+ ita "Rilevato un errore di lettura dalla pipe di connessione"
+ kor "ì—°ê²° 파ì´í”„로부터 ì—러가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤."
+ por "Obteve um erro de leitura no 'pipe' da conexão"
+ rum "Eroare la citire din cauza lui 'connection pipe'"
+ rus "Получена ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ð¾Ñ‚ потока ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ (connection pipe)"
+ serbian "GreÅ¡ka pri Äitanju podataka sa pipe-a"
+ spa "Obtenido un error de lectura de la conexión pipe"
+ swe "Fick läsfel från klienten vid läsning från 'PIPE'"
+ ukr "Отримано помилку Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð· комунікаційного каналу"
+ER_NET_FCNTL_ERROR 08S01
+ cze "Zji-Bštěna chyba fcntl()"
+ dan "Fik fejlmeddelelse fra fcntl()"
+ nla "Kreeg fout van fcntl()"
+ eng "Got an error from fcntl()"
+ est "fcntl() tagastas vea"
+ fre "Erreur reçue de fcntl() "
+ ger "fcntl() lieferte einen Fehler"
+ hun "Hiba a fcntl() fuggvenyben"
+ ita "Rilevato un errore da fcntl()"
+ kor "fcntl() 함수로부터 ì—러가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤."
+ por "Obteve um erro em fcntl()"
+ rum "Eroare obtinuta de la fcntl()"
+ rus "Получена ошибка от fcntl()"
+ serbian "Greška pri izvršavanju funkcije fcntl()"
+ spa "Obtenido un error de fcntl()"
+ swe "Fick fatalt fel från 'fcntl()'"
+ ukr "Отримано помилкку від fcntl()"
+ER_NET_PACKETS_OUT_OF_ORDER 08S01
+ cze "P-Bříchozí packety v chybném pořadí"
+ dan "Modtog ikke datapakker i korrekt rækkefølge"
+ nla "Pakketten in verkeerde volgorde ontvangen"
+ eng "Got packets out of order"
+ est "Paketid saabusid vales järjekorras"
+ fre "Paquets reçus dans le désordre"
+ ger "Pakete nicht in der richtigen Reihenfolge empfangen"
+ hun "Helytelen sorrendben erkezett adatcsomagok"
+ ita "Ricevuti pacchetti non in ordine"
+ kor "순서가 맞지않는 íŒ¨í‚·ì„ ë°›ì•˜ìŠµë‹ˆë‹¤."
+ por "Obteve pacotes fora de ordem"
+ rum "Packets care nu sint ordonati au fost gasiti"
+ rus "Пакеты получены в неверном порÑдке"
+ serbian "Primio sam mrežne pakete van reda"
+ spa "Obtenido paquetes desordenados"
+ swe "Kommunikationspaketen kom i fel ordning"
+ ukr "Отримано пакети у неналежному порÑдку"
+ER_NET_UNCOMPRESS_ERROR 08S01
+ cze "Nemohu rozkomprimovat komunika-BÄní packet"
+ dan "Kunne ikke dekomprimere kommunikations-pakke (communication packet)"
+ nla "Communicatiepakket kon niet worden gedecomprimeerd"
+ eng "Couldn't uncompress communication packet"
+ est "Viga andmepaketi lahtipakkimisel"
+ fre "Impossible de décompresser le paquet reçu"
+ ger "Kommunikationspaket lässt sich nicht entpacken"
+ hun "A kommunikacios adatcsomagok nem tomorithetok ki"
+ ita "Impossibile scompattare i pacchetti di comunicazione"
+ kor "통신 íŒ¨í‚·ì˜ ì••ì¶•í•´ì œë¥¼ í•  수 없었습니다."
+ por "Não conseguiu descomprimir pacote de comunicação"
+ rum "Nu s-a putut decompresa pachetul de comunicatie (communication packet)"
+ rus "Ðевозможно раÑпаковать пакет, полученный через коммуникационный протокол"
+ serbian "Ne mogu da dekompresujem mrežne pakete"
+ spa "No puedo descomprimir paquetes de comunicación"
+ swe "Kunde inte packa up kommunikationspaketet"
+ ukr "Ðе можу декомпреÑувати комунікаційний пакет"
+ER_NET_READ_ERROR 08S01
+ cze "Zji-BÅ¡tÄ›na chyba pÅ™i Ätení komunikaÄního packetu"
+ dan "Fik fejlmeddelelse ved læsning af kommunikations-pakker (communication packets)"
+ nla "Fout bij het lezen van communicatiepakketten"
+ eng "Got an error reading communication packets"
+ est "Viga andmepaketi lugemisel"
+ fre "Erreur de lecture des paquets reçus"
+ ger "Fehler beim Lesen eines Kommunikationspakets"
+ hun "HIba a kommunikacios adatcsomagok olvasasa soran"
+ ita "Rilevato un errore ricevendo i pacchetti di comunicazione"
+ kor "통신 íŒ¨í‚·ì„ ì½ëŠ” 중 오류가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤."
+ por "Obteve um erro na leitura de pacotes de comunicação"
+ rum "Eroare obtinuta citind pachetele de comunicatie (communication packets)"
+ rus "Получена ошибка в процеÑÑе Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¿Ð°ÐºÐµÑ‚Ð° через коммуникационный протокол "
+ serbian "Greška pri primanju mrežnih paketa"
+ spa "Obtenido un error leyendo paquetes de comunicación"
+ swe "Fick ett fel vid läsning från klienten"
+ ukr "Отримано помилку Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼ÑƒÐ½Ñ–ÐºÐ°Ñ†Ñ–Ð¹Ð½Ð¸Ñ… пакетів"
+ER_NET_READ_INTERRUPTED 08S01
+ cze "Zji-BÅ¡tÄ›n timeout pÅ™i Ätení komunikaÄního packetu"
+ dan "Timeout-fejl ved læsning af kommunukations-pakker (communication packets)"
+ nla "Timeout bij het lezen van communicatiepakketten"
+ eng "Got timeout reading communication packets"
+ est "Kontrollaja ületamine andmepakettide lugemisel"
+ fre "Timeout en lecture des paquets reçus"
+ ger "Zeitüberschreitung beim Lesen eines Kommunikationspakets"
+ hun "Idotullepes a kommunikacios adatcsomagok olvasasa soran"
+ ita "Rilevato un timeout ricevendo i pacchetti di comunicazione"
+ kor "통신 íŒ¨í‚·ì„ ì½ëŠ” 중 timeoutì´ ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤."
+ por "Obteve expiração de tempo (timeout) na leitura de pacotes de comunicação"
+ rum "Timeout obtinut citind pachetele de comunicatie (communication packets)"
+ rus "Получен таймаут Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð¿Ð°ÐºÐµÑ‚Ð° через коммуникационный протокол "
+ serbian "Vremenski limit za Äitanje mrežnih paketa je istekao"
+ spa "Obtenido timeout leyendo paquetes de comunicación"
+ swe "Fick 'timeout' vid läsning från klienten"
+ ukr "Отримано затримку Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼ÑƒÐ½Ñ–ÐºÐ°Ñ†Ñ–Ð¹Ð½Ð¸Ñ… пакетів"
+ER_NET_ERROR_ON_WRITE 08S01
+ cze "Zji-BÅ¡tÄ›na chyba pÅ™i zápisu komunikaÄního packetu"
+ dan "Fik fejlmeddelelse ved skrivning af kommunukations-pakker (communication packets)"
+ nla "Fout bij het schrijven van communicatiepakketten"
+ eng "Got an error writing communication packets"
+ est "Viga andmepaketi kirjutamisel"
+ fre "Erreur d'écriture des paquets envoyés"
+ ger "Fehler beim Schreiben eines Kommunikationspakets"
+ hun "Hiba a kommunikacios csomagok irasa soran"
+ ita "Rilevato un errore inviando i pacchetti di comunicazione"
+ kor "통신 íŒ¨í‚·ì„ ê¸°ë¡í•˜ëŠ” 중 오류가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤."
+ por "Obteve um erro na escrita de pacotes de comunicação"
+ rum "Eroare in scrierea pachetelor de comunicatie (communication packets)"
+ rus "Получена ошибка при передаче пакета через коммуникационный протокол "
+ serbian "Greška pri slanju mrežnih paketa"
+ spa "Obtenido un error de escribiendo paquetes de comunicación"
+ swe "Fick ett fel vid skrivning till klienten"
+ ukr "Отримано помилку запиÑу комунікаційних пакетів"
+ER_NET_WRITE_INTERRUPTED 08S01
+ cze "Zji-BÅ¡tÄ›n timeout pÅ™i zápisu komunikaÄního packetu"
+ dan "Timeout-fejl ved skrivning af kommunukations-pakker (communication packets)"
+ nla "Timeout bij het schrijven van communicatiepakketten"
+ eng "Got timeout writing communication packets"
+ est "Kontrollaja ületamine andmepakettide kirjutamisel"
+ fre "Timeout d'écriture des paquets envoyés"
+ ger "Zeitüberschreitung beim Schreiben eines Kommunikationspakets"
+ hun "Idotullepes a kommunikacios csomagok irasa soran"
+ ita "Rilevato un timeout inviando i pacchetti di comunicazione"
+ kor "통신 íŒ¨íŒƒì„ ê¸°ë¡í•˜ëŠ” 중 timeoutì´ ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤."
+ por "Obteve expiração de tempo ('timeout') na escrita de pacotes de comunicação"
+ rum "Timeout obtinut scriind pachetele de comunicatie (communication packets)"
+ rus "Получен таймаут в процеÑÑе передачи пакета через коммуникационный протокол "
+ serbian "Vremenski limit za slanje mrežnih paketa je istekao"
+ spa "Obtenido timeout escribiendo paquetes de comunicación"
+ swe "Fick 'timeout' vid skrivning till klienten"
+ ukr "Отримано затримку запиÑу комунікаційних пакетів"
+ER_TOO_LONG_STRING 42000
+ cze "V-Býsledný řetězec je delší než 'max_allowed_packet'"
+ dan "Strengen med resultater er større end 'max_allowed_packet'"
+ nla "Resultaat string is langer dan 'max_allowed_packet'"
+ eng "Result string is longer than 'max_allowed_packet' bytes"
+ est "Tulemus on pikem kui lubatud 'max_allowed_packet' muutujaga"
+ fre "La chaîne résultat est plus grande que 'max_allowed_packet'"
+ ger "Ergebnis-String ist länger als 'max_allowed_packet' Bytes"
+ hun "Ez eredmeny sztring nagyobb, mint a lehetseges maximum: 'max_allowed_packet'"
+ ita "La stringa di risposta e` piu` lunga di 'max_allowed_packet'"
+ por "'String' resultante é mais longa do que 'max_allowed_packet'"
+ rum "Sirul rezultat este mai lung decit 'max_allowed_packet'"
+ rus "Ð ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð¸Ñ€ÑƒÑŽÑ‰Ð°Ñ Ñтрока больше, чем 'max_allowed_packet'"
+ serbian "RezultujuÄi string je duži nego Å¡to to dozvoljava parametar servera 'max_allowed_packet'"
+ spa "La string resultante es mayor que max_allowed_packet"
+ swe "Resultatsträngen är längre än max_allowed_packet"
+ ukr "Строка результату довша ніж max_allowed_packet"
+ER_TABLE_CANT_HANDLE_BLOB 42000
+ cze "Typ pou-Bžité tabulky nepodporuje BLOB/TEXT sloupce"
+ dan "Denne tabeltype understøtter ikke brug af BLOB og TEXT kolonner"
+ nla "Het gebruikte tabel type ondersteunt geen BLOB/TEXT kolommen"
+ eng "The used table type doesn't support BLOB/TEXT columns"
+ est "Valitud tabelitüüp ei toeta BLOB/TEXT tüüpi välju"
+ fre "Ce type de table ne supporte pas les colonnes BLOB/TEXT"
+ ger "Der verwendete Tabellentyp unterstützt keine BLOB- und TEXT-Felder"
+ hun "A hasznalt tabla tipus nem tamogatja a BLOB/TEXT mezoket"
+ ita "Il tipo di tabella usata non supporta colonne di tipo BLOB/TEXT"
+ por "Tipo de tabela usado não permite colunas BLOB/TEXT"
+ rum "Tipul de tabela folosit nu suporta coloane de tip BLOB/TEXT"
+ rus "ИÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÐµÐ¼Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° не поддерживает типы BLOB/TEXT"
+ serbian "Iskorišteni tip tabele ne podržava kolone tipa 'BLOB' odnosno 'TEXT'"
+ spa "El tipo de tabla usada no permite soporte para columnas BLOB/TEXT"
+ swe "Den använda tabelltypen kan inte hantera BLOB/TEXT-kolumner"
+ ukr "ВикориÑтаний тип таблиці не підтримує BLOB/TEXT Ñтовбці"
+ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 42000
+ cze "Typ pou-Bžité tabulky nepodporuje AUTO_INCREMENT sloupce"
+ dan "Denne tabeltype understøtter ikke brug af AUTO_INCREMENT kolonner"
+ nla "Het gebruikte tabel type ondersteunt geen AUTO_INCREMENT kolommen"
+ eng "The used table type doesn't support AUTO_INCREMENT columns"
+ est "Valitud tabelitüüp ei toeta AUTO_INCREMENT tüüpi välju"
+ fre "Ce type de table ne supporte pas les colonnes AUTO_INCREMENT"
+ ger "Der verwendete Tabellentyp unterstützt keine AUTO_INCREMENT-Felder"
+ hun "A hasznalt tabla tipus nem tamogatja az AUTO_INCREMENT tipusu mezoket"
+ ita "Il tipo di tabella usata non supporta colonne di tipo AUTO_INCREMENT"
+ por "Tipo de tabela usado não permite colunas AUTO_INCREMENT"
+ rum "Tipul de tabela folosit nu suporta coloane de tip AUTO_INCREMENT"
+ rus "ИÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÐµÐ¼Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° не поддерживает автоинкрементные Ñтолбцы"
+ serbian "Iskorišteni tip tabele ne podržava kolone tipa 'AUTO_INCREMENT'"
+ spa "El tipo de tabla usada no permite soporte para columnas AUTO_INCREMENT"
+ swe "Den använda tabelltypen kan inte hantera AUTO_INCREMENT-kolumner"
+ ukr "ВикориÑтаний тип таблиці не підтримує AUTO_INCREMENT Ñтовбці"
+ER_DELAYED_INSERT_TABLE_LOCKED
+ cze "INSERT DELAYED nen-Bí možno s tabulkou '%-.192s' použít, protože je zamÄená pomocí LOCK TABLES"
+ dan "INSERT DELAYED kan ikke bruges med tabellen '%-.192s', fordi tabellen er låst med LOCK TABLES"
+ nla "INSERT DELAYED kan niet worden gebruikt bij table '%-.192s', vanwege een 'lock met LOCK TABLES"
+ eng "INSERT DELAYED can't be used with table '%-.192s' because it is locked with LOCK TABLES"
+ est "INSERT DELAYED ei saa kasutada tabeli '%-.192s' peal, kuna see on lukustatud LOCK TABLES käsuga"
+ fre "INSERT DELAYED ne peut être utilisé avec la table '%-.192s', car elle est verrouée avec LOCK TABLES"
+ ger "INSERT DELAYED kann für Tabelle '%-.192s' nicht verwendet werden, da sie mit LOCK TABLES gesperrt ist"
+ greek "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ hun "Az INSERT DELAYED nem hasznalhato a '%-.192s' tablahoz, mert a tabla zarolt (LOCK TABLES)"
+ ita "L'inserimento ritardato (INSERT DELAYED) non puo` essere usato con la tabella '%-.192s', perche` soggetta a lock da 'LOCK TABLES'"
+ jpn "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ kor "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ nor "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ norwegian-ny "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ pol "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ por "INSERT DELAYED não pode ser usado com a tabela '%-.192s', porque ela está travada com LOCK TABLES"
+ rum "INSERT DELAYED nu poate fi folosit cu tabela '%-.192s', deoarece este locked folosing LOCK TABLES"
+ rus "ÐÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать INSERT DELAYED Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ '%-.192s', потому что она заблокирована Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ LOCK TABLES"
+ serbian "Komanda 'INSERT DELAYED' ne može biti iskoriÅ¡tena u tabeli '%-.192s', zbog toga Å¡to je zakljuÄana komandom 'LOCK TABLES'"
+ slo "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ spa "INSERT DELAYED no puede ser usado con tablas '%-.192s', porque esta bloqueada con LOCK TABLES"
+ swe "INSERT DELAYED kan inte användas med tabell '%-.192s', emedan den är låst med LOCK TABLES"
+ ukr "INSERT DELAYED не може бути викориÑтано з таблицею '%-.192s', тому що Ñ—Ñ— заблоковано з LOCK TABLES"
+ER_WRONG_COLUMN_NAME 42000
+ cze "Nespr-Bávné jméno sloupce '%-.100s'"
+ dan "Forkert kolonnenavn '%-.100s'"
+ nla "Incorrecte kolom naam '%-.100s'"
+ eng "Incorrect column name '%-.100s'"
+ est "Vigane tulba nimi '%-.100s'"
+ fre "Nom de colonne '%-.100s' incorrect"
+ ger "Falscher Spaltenname '%-.100s'"
+ hun "Ervenytelen mezonev: '%-.100s'"
+ ita "Nome colonna '%-.100s' non corretto"
+ por "Nome de coluna '%-.100s' incorreto"
+ rum "Nume increct de coloana '%-.100s'"
+ rus "Ðеверное Ð¸Ð¼Ñ Ñтолбца '%-.100s'"
+ serbian "Pogrešno ime kolone '%-.100s'"
+ spa "Incorrecto nombre de columna '%-.100s'"
+ swe "Felaktigt kolumnnamn '%-.100s'"
+ ukr "Ðевірне ім'Ñ ÑÑ‚Ð¾Ð²Ð±Ñ†Ñ '%-.100s'"
+ER_WRONG_KEY_COLUMN 42000
+ cze "Handler pou-Bžité tabulky neumí indexovat sloupce '%-.192s'"
+ dan "Den brugte tabeltype kan ikke indeksere kolonnen '%-.192s'"
+ nla "De gebruikte tabel 'handler' kan kolom '%-.192s' niet indexeren"
+ eng "The used storage engine can't index column '%-.192s'"
+ est "Tabelihandler ei oska indekseerida tulpa '%-.192s'"
+ fre "Le handler de la table ne peut indexé la colonne '%-.192s'"
+ ger "Die verwendete Speicher-Engine kann die Spalte '%-.192s' nicht indizieren"
+ greek "The used table handler can't index column '%-.192s'"
+ hun "A hasznalt tablakezelo nem tudja a '%-.192s' mezot indexelni"
+ ita "Il gestore delle tabelle non puo` indicizzare la colonna '%-.192s'"
+ jpn "The used table handler can't index column '%-.192s'"
+ kor "The used table handler can't index column '%-.192s'"
+ nor "The used table handler can't index column '%-.192s'"
+ norwegian-ny "The used table handler can't index column '%-.192s'"
+ pol "The used table handler can't index column '%-.192s'"
+ por "O manipulador de tabela usado não pode indexar a coluna '%-.192s'"
+ rum "Handler-ul tabelei folosite nu poate indexa coloana '%-.192s'"
+ rus "ИÑпользованный обработчик таблицы не может проиндекÑировать Ñтолбец '%-.192s'"
+ serbian "Handler tabele ne može da indeksira kolonu '%-.192s'"
+ slo "The used table handler can't index column '%-.192s'"
+ spa "El manipulador de tabla usado no puede indexar columna '%-.192s'"
+ swe "Den använda tabelltypen kan inte indexera kolumn '%-.192s'"
+ ukr "ВикориÑтаний вказівник таблиці не може індекÑувати Ñтовбець '%-.192s'"
+ER_WRONG_MRG_TABLE
+ cze "V-Bšechny tabulky v MERGE tabulce nejsou definovány stejně"
+ dan "Tabellerne i MERGE er ikke defineret ens"
+ nla "Niet alle tabellen in de MERGE tabel hebben identieke gedefinities"
+ eng "Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist"
+ est "Kõik tabelid MERGE tabeli määratluses ei ole identsed"
+ fre "Toutes les tables de la table de type MERGE n'ont pas la même définition"
+ ger "Nicht alle Tabellen in der MERGE-Tabelle sind gleich definiert"
+ hun "A MERGE tablaban talalhato tablak definicioja nem azonos"
+ ita "Non tutte le tabelle nella tabella di MERGE sono definite in maniera identica"
+ jpn "All tables in the MERGE table are not defined identically"
+ kor "All tables in the MERGE table are not defined identically"
+ nor "All tables in the MERGE table are not defined identically"
+ norwegian-ny "All tables in the MERGE table are not defined identically"
+ pol "All tables in the MERGE table are not defined identically"
+ por "Todas as tabelas contidas na tabela fundida (MERGE) não estão definidas identicamente"
+ rum "Toate tabelele din tabela MERGE nu sint definite identic"
+ rus "Ðе вÑе таблицы в MERGE определены одинаково"
+ serbian "Tabele iskoriÅ¡tene u 'MERGE' tabeli nisu definisane na isti naÄin"
+ slo "All tables in the MERGE table are not defined identically"
+ spa "Todas las tablas en la MERGE tabla no estan definidas identicamente"
+ swe "Tabellerna i MERGE-tabellen är inte identiskt definierade"
+ ukr "Таблиці у MERGE TABLE мають різну Ñтруктуру"
+ER_DUP_UNIQUE 23000
+ cze "Kv-Bůli unique constraintu nemozu zapsat do tabulky '%-.192s'"
+ dan "Kan ikke skrive til tabellen '%-.192s' fordi det vil bryde CONSTRAINT regler"
+ nla "Kan niet opslaan naar table '%-.192s' vanwege 'unique' beperking"
+ eng "Can't write, because of unique constraint, to table '%-.192s'"
+ est "Ei suuda kirjutada tabelisse '%-.192s', kuna see rikub ühesuse kitsendust"
+ fre "Écriture impossible à cause d'un index UNIQUE sur la table '%-.192s'"
+ ger "Schreiben in Tabelle '%-.192s' nicht möglich wegen einer Eindeutigkeitsbeschränkung (unique constraint)"
+ hun "A '%-.192s' nem irhato, az egyedi mezok miatt"
+ ita "Impossibile scrivere nella tabella '%-.192s' per limitazione di unicita`"
+ por "Não pode gravar, devido à restrição UNIQUE, na tabela '%-.192s'"
+ rum "Nu pot scrie pe hard-drive, din cauza constraintului unic (unique constraint) pentru tabela '%-.192s'"
+ rus "Ðевозможно запиÑать в таблицу '%-.192s' из-за ограничений уникального ключа"
+ serbian "Zbog provere jedinstvenosti ne mogu da upišem podatke u tabelu '%-.192s'"
+ spa "No puedo escribir, debido al único constraint, para tabla '%-.192s'"
+ swe "Kan inte skriva till tabell '%-.192s'; UNIQUE-test"
+ ukr "Ðе можу запиÑати до таблиці '%-.192s', з причини вимог унікальноÑÑ‚Ñ–"
+ER_BLOB_KEY_WITHOUT_LENGTH 42000
+ cze "BLOB sloupec '%-.192s' je pou-Bžit ve specifikaci klíÄe bez délky"
+ dan "BLOB kolonnen '%-.192s' brugt i nøglespecifikation uden nøglelængde"
+ nla "BLOB kolom '%-.192s' gebruikt in zoeksleutel specificatie zonder zoeksleutel lengte"
+ eng "BLOB/TEXT column '%-.192s' used in key specification without a key length"
+ est "BLOB-tüüpi tulp '%-.192s' on kasutusel võtmes ilma pikkust määratlemata"
+ fre "La colonne '%-.192s' de type BLOB est utilisée dans une définition d'index sans longueur d'index"
+ ger "BLOB- oder TEXT-Spalte '%-.192s' wird in der Schlüsseldefinition ohne Schlüssellängenangabe verwendet"
+ greek "BLOB column '%-.192s' used in key specification without a key length"
+ hun "BLOB mezo '%-.192s' hasznalt a mezo specifikacioban, a mezohossz megadasa nelkul"
+ ita "La colonna '%-.192s' di tipo BLOB e` usata in una chiave senza specificarne la lunghezza"
+ jpn "BLOB column '%-.192s' used in key specification without a key length"
+ kor "BLOB column '%-.192s' used in key specification without a key length"
+ nor "BLOB column '%-.192s' used in key specification without a key length"
+ norwegian-ny "BLOB column '%-.192s' used in key specification without a key length"
+ pol "BLOB column '%-.192s' used in key specification without a key length"
+ por "Coluna BLOB '%-.192s' usada na especificação de chave sem o comprimento da chave"
+ rum "Coloana BLOB '%-.192s' este folosita in specificarea unei chei fara ca o lungime de cheie sa fie folosita"
+ rus "Столбец типа BLOB '%-.192s' был указан в определении ключа без ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð´Ð»Ð¸Ð½Ñ‹ ключа"
+ serbian "BLOB kolona '%-.192s' je upotrebljena u specifikaciji kljuÄa bez navoÄ‘enja dužine kljuÄa"
+ slo "BLOB column '%-.192s' used in key specification without a key length"
+ spa "Columna BLOB column '%-.192s' usada en especificación de clave sin tamaño de la clave"
+ swe "Du har inte angett någon nyckellängd för BLOB '%-.192s'"
+ ukr "Стовбець BLOB '%-.192s' викориÑтано у визначенні ключа без Ð²ÐºÐ°Ð·Ð°Ð½Ð½Ñ Ð´Ð¾Ð²Ð¶Ð¸Ð½Ð¸ ключа"
+ER_PRIMARY_CANT_HAVE_NULL 42000
+ cze "V-BÅ¡echny Äásti primárního klíÄe musejí být NOT NULL; pokud potÅ™ebujete NULL, použijte UNIQUE"
+ dan "Alle dele af en PRIMARY KEY skal være NOT NULL; Hvis du skal bruge NULL i nøglen, brug UNIQUE istedet"
+ nla "Alle delen van een PRIMARY KEY moeten NOT NULL zijn; Indien u NULL in een zoeksleutel nodig heeft kunt u UNIQUE gebruiken"
+ eng "All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead"
+ est "Kõik PRIMARY KEY peavad olema määratletud NOT NULL piiranguga; vajadusel kasuta UNIQUE tüüpi võtit"
+ fre "Toutes les parties d'un index PRIMARY KEY doivent être NOT NULL; Si vous avez besoin d'un NULL dans l'index, utilisez un index UNIQUE"
+ ger "Alle Teile eines PRIMARY KEY müssen als NOT NULL definiert sein. Wenn NULL in einem Schlüssel benötigt wird, muss ein UNIQUE-Schlüssel verwendet werden"
+ hun "Az elsodleges kulcs teljes egeszeben csak NOT NULL tipusu lehet; Ha NULL mezot szeretne a kulcskent, hasznalja inkabb a UNIQUE-ot"
+ ita "Tutte le parti di una chiave primaria devono essere dichiarate NOT NULL; se necessitano valori NULL nelle chiavi utilizzare UNIQUE"
+ por "Todas as partes de uma chave primária devem ser não-nulas. Se você precisou usar um valor nulo (NULL) em uma chave, use a cláusula UNIQUE em seu lugar"
+ rum "Toate partile unei chei primare (PRIMARY KEY) trebuie sa fie NOT NULL; Daca aveti nevoie de NULL in vreo cheie, folositi UNIQUE in schimb"
+ rus "Ð’Ñе чаÑти первичного ключа (PRIMARY KEY) должны быть определены как NOT NULL; ЕÑли вам нужна поддержка величин NULL в ключе, воÑпользуйтеÑÑŒ индекÑом UNIQUE"
+ serbian "Svi delovi primarnog kljuÄa moraju biti razliÄiti od NULL; Ako Vam ipak treba NULL vrednost u kljuÄu, upotrebite 'UNIQUE'"
+ spa "Todas las partes de un PRIMARY KEY deben ser NOT NULL; Si necesitas NULL en una clave, use UNIQUE"
+ swe "Alla delar av en PRIMARY KEY måste vara NOT NULL; Om du vill ha en nyckel med NULL, använd UNIQUE istället"
+ ukr "УÑÑ– чаÑтини PRIMARY KEY повинні бути NOT NULL; Якщо ви потребуєте NULL у ключі, ÑкориÑтайтеÑÑ UNIQUE"
+ER_TOO_MANY_ROWS 42000
+ cze "V-Býsledek obsahuje více než jeden řádek"
+ dan "Resultatet bestod af mere end een række"
+ nla "Resultaat bevatte meer dan een rij"
+ eng "Result consisted of more than one row"
+ est "Tulemis oli rohkem kui üks kirje"
+ fre "Le résultat contient plus d'un enregistrement"
+ ger "Ergebnis besteht aus mehr als einer Zeile"
+ hun "Az eredmeny tobb, mint egy sort tartalmaz"
+ ita "Il risultato consiste di piu` di una riga"
+ por "O resultado consistiu em mais do que uma linha"
+ rum "Resultatul constista din mai multe linii"
+ rus "Ð’ результате возвращена более чем одна Ñтрока"
+ serbian "Rezultat je saÄinjen od viÅ¡e slogova"
+ spa "Resultado compuesto de mas que una línea"
+ swe "Resultet bestod av mera än en rad"
+ ukr "Результат знаходитьÑÑ Ñƒ більше ніж одній Ñтроці"
+ER_REQUIRES_PRIMARY_KEY 42000
+ cze "Tento typ tabulky vy-Bžaduje primární klíÄ"
+ dan "Denne tabeltype kræver en primærnøgle"
+ nla "Dit tabel type heeft een primaire zoeksleutel nodig"
+ eng "This table type requires a primary key"
+ est "Antud tabelitüüp nõuab primaarset võtit"
+ fre "Ce type de table nécessite une clé primaire (PRIMARY KEY)"
+ ger "Dieser Tabellentyp benötigt einen Primärschlüssel (PRIMARY KEY)"
+ hun "Az adott tablatipushoz elsodleges kulcs hasznalata kotelezo"
+ ita "Questo tipo di tabella richiede una chiave primaria"
+ por "Este tipo de tabela requer uma chave primária"
+ rum "Aceast tip de tabela are nevoie de o cheie primara"
+ rus "Этот тип таблицы требует Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿ÐµÑ€Ð²Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ ключа"
+ serbian "Ovaj tip tabele zahteva da imate definisan primarni kljuÄ"
+ spa "Este tipo de tabla necesita de una primary key"
+ swe "Denna tabelltyp kräver en PRIMARY KEY"
+ ukr "Цей тип таблиці потребує первинного ключа"
+ER_NO_RAID_COMPILED
+ cze "Tato verze MySQL nen-Bí zkompilována s podporou RAID"
+ dan "Denne udgave af MySQL er ikke oversat med understøttelse af RAID"
+ nla "Deze versie van MySQL is niet gecompileerd met RAID ondersteuning"
+ eng "This version of MySQL is not compiled with RAID support"
+ est "Antud MySQL versioon on kompileeritud ilma RAID toeta"
+ fre "Cette version de MySQL n'est pas compilée avec le support RAID"
+ ger "Diese MySQL-Version ist nicht mit RAID-Unterstützung kompiliert"
+ hun "Ezen leforditott MySQL verzio nem tartalmaz RAID support-ot"
+ ita "Questa versione di MYSQL non e` compilata con il supporto RAID"
+ por "Esta versão do MySQL não foi compilada com suporte a RAID"
+ rum "Aceasta versiune de MySQL, nu a fost compilata cu suport pentru RAID"
+ rus "Эта верÑÐ¸Ñ MySQL Ñкомпилирована без поддержки RAID"
+ serbian "Ova verzija MySQL servera nije kompajlirana sa podrškom za RAID uređaje"
+ spa "Esta versión de MySQL no es compilada con soporte RAID"
+ swe "Denna version av MySQL är inte kompilerad med RAID"
+ ukr "Ð¦Ñ Ð²ÐµÑ€ÑÑ–Ñ MySQL не зкомпільована з підтримкою RAID"
+ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE
+ cze "Update tabulky bez WHERE s kl-BíÄem není v módu bezpeÄných update dovoleno"
+ dan "Du bruger sikker opdaterings modus ('safe update mode') og du forsøgte at opdatere en tabel uden en WHERE klausul, der gør brug af et KEY felt"
+ nla "U gebruikt 'safe update mode' en u probeerde een tabel te updaten zonder een WHERE met een KEY kolom"
+ eng "You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column"
+ est "Katse muuta tabelit turvalises rezhiimis ilma WHERE klauslita"
+ fre "Vous êtes en mode 'safe update' et vous essayez de faire un UPDATE sans clause WHERE utilisant un index"
+ ger "MySQL läuft im sicheren Aktualisierungsmodus (safe update mode). Sie haben versucht, eine Tabelle zu aktualisieren, ohne in der WHERE-Klausel ein KEY-Feld anzugeben"
+ hun "On a biztonsagos update modot hasznalja, es WHERE that uses a KEY column"
+ ita "In modalita` 'safe update' si e` cercato di aggiornare una tabella senza clausola WHERE su una chiave"
+ por "Você está usando modo de atualização seguro e tentou atualizar uma tabela sem uma cláusula WHERE que use uma coluna chave"
+ rus "Ð’Ñ‹ работаете в режиме безопаÑных обновлений (safe update mode) и попробовали изменить таблицу без иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ð¾Ð³Ð¾ Ñтолбца в чаÑти WHERE"
+ serbian "Vi koristite safe update mod servera, a probali ste da promenite podatke bez 'WHERE' komande koja koristi kolonu kljuÄa"
+ spa "Tu estás usando modo de actualización segura y tentado actualizar una tabla sin un WHERE que usa una KEY columna"
+ swe "Du använder 'säker uppdateringsmod' och försökte uppdatera en tabell utan en WHERE-sats som använder sig av en nyckel"
+ ukr "Ви у режимі безпечного Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð° намагаєтеÑÑŒ оновити таблицю без оператора WHERE, що викориÑтовує KEY Ñтовбець"
+ER_KEY_DOES_NOT_EXITS 42000 S1009
+ cze "Kl-BÃ­Ä '%-.192s' v tabulce '%-.192s' neexistuje"
+ dan "Nøglen '%-.192s' eksisterer ikke i tabellen '%-.192s'"
+ nla "Zoeksleutel '%-.192s' bestaat niet in tabel '%-.192s'"
+ eng "Key '%-.192s' doesn't exist in table '%-.192s'"
+ est "Võti '%-.192s' ei eksisteeri tabelis '%-.192s'"
+ fre "L'index '%-.192s' n'existe pas sur la table '%-.192s'"
+ ger "Schlüssel '%-.192s' existiert in der Tabelle '%-.192s' nicht"
+ hun "A '%-.192s' kulcs nem letezik a '%-.192s' tablaban"
+ ita "La chiave '%-.192s' non esiste nella tabella '%-.192s'"
+ por "Chave '%-.192s' não existe na tabela '%-.192s'"
+ rus "Ключ '%-.192s' не ÑущеÑтвует в таблице '%-.192s'"
+ serbian "KljuÄ '%-.192s' ne postoji u tabeli '%-.192s'"
+ spa "Clave '%-.192s' no existe en la tabla '%-.192s'"
+ swe "Nyckel '%-.192s' finns inte in tabell '%-.192s'"
+ ukr "Ключ '%-.192s' не Ñ–Ñнує в таблиці '%-.192s'"
+ER_CHECK_NO_SUCH_TABLE 42000
+ cze "Nemohu otev-Břít tabulku"
+ dan "Kan ikke åbne tabellen"
+ nla "Kan tabel niet openen"
+ eng "Can't open table"
+ est "Ei suuda avada tabelit"
+ fre "Impossible d'ouvrir la table"
+ ger "Kann Tabelle nicht öffnen"
+ hun "Nem tudom megnyitni a tablat"
+ ita "Impossibile aprire la tabella"
+ por "Não pode abrir a tabela"
+ rus "Ðевозможно открыть таблицу"
+ serbian "Ne mogu da otvorim tabelu"
+ spa "No puedo abrir tabla"
+ swe "Kan inte öppna tabellen"
+ ukr "Ðе можу відкрити таблицю"
+ER_CHECK_NOT_IMPLEMENTED 42000
+ cze "Handler tabulky nepodporuje %s"
+ dan "Denne tabeltype understøtter ikke %s"
+ nla "De 'handler' voor de tabel ondersteund geen %s"
+ eng "The storage engine for the table doesn't support %s"
+ est "Antud tabelitüüp ei toeta %s käske"
+ fre "Ce type de table ne supporte pas les %s"
+ ger "Die Speicher-Engine für diese Tabelle unterstützt kein %s"
+ greek "The handler for the table doesn't support %s"
+ hun "A tabla kezeloje (handler) nem tamogatja az %s"
+ ita "Il gestore per la tabella non supporta il %s"
+ jpn "The handler for the table doesn't support %s"
+ kor "The handler for the table doesn't support %s"
+ nor "The handler for the table doesn't support %s"
+ norwegian-ny "The handler for the table doesn't support %s"
+ pol "The handler for the table doesn't support %s"
+ por "O manipulador de tabela não suporta %s"
+ rum "The handler for the table doesn't support %s"
+ rus "Обработчик таблицы не поддерживает Ñтого: %s"
+ serbian "Handler za ovu tabelu ne dozvoljava %s komande"
+ slo "The handler for the table doesn't support %s"
+ spa "El manipulador de la tabla no permite soporte para %s"
+ swe "Tabellhanteraren för denna tabell kan inte göra %s"
+ ukr "Вказівник таблиці не підтримуе %s"
+ER_CANT_DO_THIS_DURING_AN_TRANSACTION 25000
+ cze "Proveden-Bí tohoto příkazu není v transakci dovoleno"
+ dan "Du må ikke bruge denne kommando i en transaktion"
+ nla "Het is u niet toegestaan dit commando uit te voeren binnen een transactie"
+ eng "You are not allowed to execute this command in a transaction"
+ est "Seda käsku ei saa kasutada transaktsiooni sees"
+ fre "Vous n'êtes pas autorisé à exécute cette commande dans une transaction"
+ ger "Sie dürfen diesen Befehl nicht in einer Transaktion ausführen"
+ hun "Az On szamara nem engedelyezett a parancs vegrehajtasa a tranzakcioban"
+ ita "Non puoi eseguire questo comando in una transazione"
+ por "Não lhe é permitido executar este comando em uma transação"
+ rus "Вам не разрешено выполнÑÑ‚ÑŒ Ñту команду в транзакции"
+ serbian "Nije Vam dozvoljeno da izvršite ovu komandu u transakciji"
+ spa "No tienes el permiso para ejecutar este comando en una transición"
+ swe "Du får inte utföra detta kommando i en transaktion"
+ ukr "Вам не дозволено виконувати цю команду в транзакції"
+ER_ERROR_DURING_COMMIT
+ cze "Chyba %d p-Bři COMMIT"
+ dan "Modtog fejl %d mens kommandoen COMMIT blev udført"
+ nla "Kreeg fout %d tijdens COMMIT"
+ eng "Got error %d during COMMIT"
+ est "Viga %d käsu COMMIT täitmisel"
+ fre "Erreur %d lors du COMMIT"
+ ger "Fehler %d beim COMMIT"
+ hun "%d hiba a COMMIT vegrehajtasa soran"
+ ita "Rilevato l'errore %d durante il COMMIT"
+ por "Obteve erro %d durante COMMIT"
+ rus "Получена ошибка %d в процеÑÑе COMMIT"
+ serbian "Greška %d za vreme izvršavanja komande 'COMMIT'"
+ spa "Obtenido error %d durante COMMIT"
+ swe "Fick fel %d vid COMMIT"
+ ukr "Отримано помилку %d під Ñ‡Ð°Ñ COMMIT"
+ER_ERROR_DURING_ROLLBACK
+ cze "Chyba %d p-Bři ROLLBACK"
+ dan "Modtog fejl %d mens kommandoen ROLLBACK blev udført"
+ nla "Kreeg fout %d tijdens ROLLBACK"
+ eng "Got error %d during ROLLBACK"
+ est "Viga %d käsu ROLLBACK täitmisel"
+ fre "Erreur %d lors du ROLLBACK"
+ ger "Fehler %d beim ROLLBACK"
+ hun "%d hiba a ROLLBACK vegrehajtasa soran"
+ ita "Rilevato l'errore %d durante il ROLLBACK"
+ por "Obteve erro %d durante ROLLBACK"
+ rus "Получена ошибка %d в процеÑÑе ROLLBACK"
+ serbian "Greška %d za vreme izvršavanja komande 'ROLLBACK'"
+ spa "Obtenido error %d durante ROLLBACK"
+ swe "Fick fel %d vid ROLLBACK"
+ ukr "Отримано помилку %d під Ñ‡Ð°Ñ ROLLBACK"
+ER_ERROR_DURING_FLUSH_LOGS
+ cze "Chyba %d p-Bři FLUSH_LOGS"
+ dan "Modtog fejl %d mens kommandoen FLUSH_LOGS blev udført"
+ nla "Kreeg fout %d tijdens FLUSH_LOGS"
+ eng "Got error %d during FLUSH_LOGS"
+ est "Viga %d käsu FLUSH_LOGS täitmisel"
+ fre "Erreur %d lors du FLUSH_LOGS"
+ ger "Fehler %d bei FLUSH_LOGS"
+ hun "%d hiba a FLUSH_LOGS vegrehajtasa soran"
+ ita "Rilevato l'errore %d durante il FLUSH_LOGS"
+ por "Obteve erro %d durante FLUSH_LOGS"
+ rus "Получена ошибка %d в процеÑÑе FLUSH_LOGS"
+ serbian "Greška %d za vreme izvršavanja komande 'FLUSH_LOGS'"
+ spa "Obtenido error %d durante FLUSH_LOGS"
+ swe "Fick fel %d vid FLUSH_LOGS"
+ ukr "Отримано помилку %d під Ñ‡Ð°Ñ FLUSH_LOGS"
+ER_ERROR_DURING_CHECKPOINT
+ cze "Chyba %d p-Bři CHECKPOINT"
+ dan "Modtog fejl %d mens kommandoen CHECKPOINT blev udført"
+ nla "Kreeg fout %d tijdens CHECKPOINT"
+ eng "Got error %d during CHECKPOINT"
+ est "Viga %d käsu CHECKPOINT täitmisel"
+ fre "Erreur %d lors du CHECKPOINT"
+ ger "Fehler %d bei CHECKPOINT"
+ hun "%d hiba a CHECKPOINT vegrehajtasa soran"
+ ita "Rilevato l'errore %d durante il CHECKPOINT"
+ por "Obteve erro %d durante CHECKPOINT"
+ rus "Получена ошибка %d в процеÑÑе CHECKPOINT"
+ serbian "Greška %d za vreme izvršavanja komande 'CHECKPOINT'"
+ spa "Obtenido error %d durante CHECKPOINT"
+ swe "Fick fel %d vid CHECKPOINT"
+ ukr "Отримано помилку %d під Ñ‡Ð°Ñ CHECKPOINT"
+ER_NEW_ABORTING_CONNECTION 08S01
+ cze "Spojen-Bí %ld do databáze: '%-.192s' uživatel: '%-.48s' stroj: '%-.64s' (%-.64s) bylo přerušeno"
+ dan "Afbrød forbindelsen %ld til databasen '%-.192s' bruger: '%-.48s' vært: '%-.64s' (%-.64s)"
+ nla "Afgebroken verbinding %ld naar db: '%-.192s' gebruiker: '%-.48s' host: '%-.64s' (%-.64s)"
+ eng "Aborted connection %ld to db: '%-.192s' user: '%-.48s' host: '%-.64s' (%-.64s)"
+ est "Ãœhendus katkestatud %ld andmebaas: '%-.192s' kasutaja: '%-.48s' masin: '%-.64s' (%-.64s)"
+ fre "Connection %ld avortée vers la bd: '%-.192s' utilisateur: '%-.48s' hôte: '%-.64s' (%-.64s)"
+ ger "Abbruch der Verbindung %ld zur Datenbank '%-.192s'. Benutzer: '%-.48s', Host: '%-.64s' (%-.64s)"
+ ita "Interrotta la connessione %ld al db: ''%-.192s' utente: '%-.48s' host: '%-.64s' (%-.64s)"
+ por "Conexão %ld abortada para banco de dados '%-.192s' - usuário '%-.48s' - 'host' '%-.64s' ('%-.64s')"
+ rus "Прервано Ñоединение %ld к базе данных '%-.192s' Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ '%-.48s' Ñ Ñ…Ð¾Ñта '%-.64s' (%-.64s)"
+ serbian "Prekinuta konekcija broj %ld ka bazi: '%-.192s' korisnik je bio: '%-.48s' a host: '%-.64s' (%-.64s)"
+ spa "Abortada conexión %ld para db: '%-.192s' usuario: '%-.48s' servidor: '%-.64s' (%-.64s)"
+ swe "Avbröt länken för tråd %ld till db '%-.192s', användare '%-.48s', host '%-.64s' (%-.64s)"
+ ukr "Перервано з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ %ld до бази данних: '%-.192s' кориÑтувач: '%-.48s' хоÑÑ‚: '%-.64s' (%-.64s)"
+ER_DUMP_NOT_IMPLEMENTED
+ cze "Handler tabulky nepodporuje bin-Bární dump"
+ dan "Denne tabeltype unserstøtter ikke binært tabeldump"
+ nla "De 'handler' voor de tabel ondersteund geen binaire tabel dump"
+ eng "The storage engine for the table does not support binary table dump"
+ fre "Ce type de table ne supporte pas les copies binaires"
+ ger "Die Speicher-Engine für die Tabelle unterstützt keinen binären Tabellen-Dump"
+ ita "Il gestore per la tabella non supporta il dump binario"
+ jpn "The handler for the table does not support binary table dump"
+ por "O manipulador de tabela não suporta 'dump' binário de tabela"
+ rum "The handler for the table does not support binary table dump"
+ rus "Обработчик Ñтой таблицы не поддерживает двоичного ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¾Ð±Ñ€Ð°Ð·Ð° таблицы (dump)"
+ serbian "Handler tabele ne podržava binarni dump tabele"
+ spa "El manipulador de tabla no soporta dump para tabla binaria"
+ swe "Tabellhanteraren klarar inte en binär kopiering av tabellen"
+ ukr "Цей тип таблиці не підтримує бінарну передачу таблиці"
+ER_FLUSH_MASTER_BINLOG_CLOSED
+ eng "Binlog closed, cannot RESET MASTER"
+ ger "Binlog geschlossen. Kann RESET MASTER nicht ausführen"
+ por "Binlog fechado. Não pode fazer RESET MASTER"
+ rus "Двоичный журнал Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð·Ð°ÐºÑ€Ñ‹Ñ‚, невозможно выполнить RESET MASTER"
+ serbian "Binarni log file zatvoren, ne mogu da izvršim komandu 'RESET MASTER'"
+ ukr "Реплікаційний лог закрито, не можу виконати RESET MASTER"
+ER_INDEX_REBUILD
+ cze "P-Břebudování indexu dumpnuté tabulky '%-.192s' nebylo úspěšné"
+ dan "Kunne ikke genopbygge indekset for den dumpede tabel '%-.192s'"
+ nla "Gefaald tijdens heropbouw index van gedumpte tabel '%-.192s'"
+ eng "Failed rebuilding the index of dumped table '%-.192s'"
+ fre "La reconstruction de l'index de la table copiée '%-.192s' a échoué"
+ ger "Neuerstellung des Index der Dump-Tabelle '%-.192s' fehlgeschlagen"
+ greek "Failed rebuilding the index of dumped table '%-.192s'"
+ hun "Failed rebuilding the index of dumped table '%-.192s'"
+ ita "Fallita la ricostruzione dell'indice della tabella copiata '%-.192s'"
+ por "Falhou na reconstrução do índice da tabela 'dumped' '%-.192s'"
+ rus "Ошибка переÑтройки индекÑа Ñохраненной таблицы '%-.192s'"
+ serbian "Izgradnja indeksa dump-ovane tabele '%-.192s' nije uspela"
+ spa "Falla reconstruyendo el indice de la tabla dumped '%-.192s'"
+ ukr "Ðевдале Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ–Ð½Ð´ÐµÐºÑа переданої таблиці '%-.192s'"
+ER_MASTER
+ cze "Chyba masteru: '%-.64s'"
+ dan "Fejl fra master: '%-.64s'"
+ nla "Fout van master: '%-.64s'"
+ eng "Error from master: '%-.64s'"
+ fre "Erreur reçue du maître: '%-.64s'"
+ ger "Fehler vom Master: '%-.64s'"
+ ita "Errore dal master: '%-.64s"
+ por "Erro no 'master' '%-.64s'"
+ rus "Ошибка от головного Ñервера: '%-.64s'"
+ serbian "Greška iz glavnog servera '%-.64s' u klasteru"
+ spa "Error del master: '%-.64s'"
+ swe "Fick en master: '%-.64s'"
+ ukr "Помилка від головного: '%-.64s'"
+ER_MASTER_NET_READ 08S01
+ cze "S-Bíťová chyba pÅ™i Ätení z masteru"
+ dan "Netværksfejl ved læsning fra master"
+ nla "Net fout tijdens lezen van master"
+ eng "Net error reading from master"
+ fre "Erreur de lecture réseau reçue du maître"
+ ger "Netzfehler beim Lesen vom Master"
+ ita "Errore di rete durante la ricezione dal master"
+ por "Erro de rede lendo do 'master'"
+ rus "Возникла ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ð² процеÑÑе коммуникации Ñ Ð³Ð¾Ð»Ð¾Ð²Ð½Ñ‹Ð¼ Ñервером"
+ serbian "Greška u primanju mrežnih paketa sa glavnog servera u klasteru"
+ spa "Error de red leyendo del master"
+ swe "Fick nätverksfel vid läsning från master"
+ ukr "Мережева помилка Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð²Ñ–Ð´ головного"
+ER_MASTER_NET_WRITE 08S01
+ cze "S-Bíťová chyba při zápisu na master"
+ dan "Netværksfejl ved skrivning til master"
+ nla "Net fout tijdens schrijven naar master"
+ eng "Net error writing to master"
+ fre "Erreur d'écriture réseau reçue du maître"
+ ger "Netzfehler beim Schreiben zum Master"
+ ita "Errore di rete durante l'invio al master"
+ por "Erro de rede gravando no 'master'"
+ rus "Возникла ошибка запиÑи в процеÑÑе коммуникации Ñ Ð³Ð¾Ð»Ð¾Ð²Ð½Ñ‹Ð¼ Ñервером"
+ serbian "Greška u slanju mrežnih paketa na glavni server u klasteru"
+ spa "Error de red escribiendo para el master"
+ swe "Fick nätverksfel vid skrivning till master"
+ ukr "Мережева помилка запиÑу до головного"
+ER_FT_MATCHING_KEY_NOT_FOUND
+ cze "-BŽádný sloupec nemá vytvořen fulltextový index"
+ dan "Kan ikke finde en FULLTEXT nøgle som svarer til kolonne listen"
+ nla "Kan geen FULLTEXT index vinden passend bij de kolom lijst"
+ eng "Can't find FULLTEXT index matching the column list"
+ est "Ei suutnud leida FULLTEXT indeksit, mis kattuks kasutatud tulpadega"
+ fre "Impossible de trouver un index FULLTEXT correspondant à cette liste de colonnes"
+ ger "Kann keinen FULLTEXT-Index finden, der der Feldliste entspricht"
+ ita "Impossibile trovare un indice FULLTEXT che corrisponda all'elenco delle colonne"
+ por "Não pode encontrar um índice para o texto todo que combine com a lista de colunas"
+ rus "Ðевозможно отыÑкать полнотекÑтовый (FULLTEXT) индекÑ, ÑоответÑтвующий ÑпиÑку Ñтолбцов"
+ serbian "Ne mogu da pronađem 'FULLTEXT' indeks koli odgovara listi kolona"
+ spa "No puedo encontrar índice FULLTEXT correspondiendo a la lista de columnas"
+ swe "Hittar inte ett FULLTEXT-index i kolumnlistan"
+ ukr "Ðе можу знайти FULLTEXT індекÑ, що відповідає переліку Ñтовбців"
+ER_LOCK_OR_ACTIVE_TRANSACTION
+ cze "Nemohu prov-Bést zadaný příkaz, protože existují aktivní zamÄené tabulky nebo aktivní transakce"
+ dan "Kan ikke udføre den givne kommando fordi der findes aktive, låste tabeller eller fordi der udføres en transaktion"
+ nla "Kan het gegeven commando niet uitvoeren, want u heeft actieve gelockte tabellen of een actieve transactie"
+ eng "Can't execute the given command because you have active locked tables or an active transaction"
+ est "Ei suuda täita antud käsku kuna on aktiivseid lukke või käimasolev transaktsioon"
+ fre "Impossible d'exécuter la commande car vous avez des tables verrouillées ou une transaction active"
+ ger "Kann den angegebenen Befehl wegen einer aktiven Tabellensperre oder einer aktiven Transaktion nicht ausführen"
+ ita "Impossibile eseguire il comando richiesto: tabelle sotto lock o transazione in atto"
+ por "Não pode executar o comando dado porque você tem tabelas ativas travadas ou uma transação ativa"
+ rus "Ðевозможно выполнить указанную команду, поÑкольку у Ð²Ð°Ñ Ð¿Ñ€Ð¸ÑутÑтвуют активно заблокированные таблица или Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð°Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ"
+ serbian "Ne mogu da izvrÅ¡im datu komandu zbog toga Å¡to su tabele zakljuÄane ili je transakcija u toku"
+ spa "No puedo ejecutar el comando dado porque tienes tablas bloqueadas o una transición activa"
+ swe "Kan inte utföra kommandot emedan du har en låst tabell eller an aktiv transaktion"
+ ukr "Ðе можу виконати подану команду тому, що Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð° або виконуєтьÑÑ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ñ–Ñ"
+ER_UNKNOWN_SYSTEM_VARIABLE
+ cze "Nezn-Bámá systémová proměnná '%-.64s'"
+ dan "Ukendt systemvariabel '%-.64s'"
+ nla "Onbekende systeem variabele '%-.64s'"
+ eng "Unknown system variable '%-.64s'"
+ est "Tundmatu süsteemne muutuja '%-.64s'"
+ fre "Variable système '%-.64s' inconnue"
+ ger "Unbekannte Systemvariable '%-.64s'"
+ ita "Variabile di sistema '%-.64s' sconosciuta"
+ por "Variável de sistema '%-.64s' desconhecida"
+ rus "ÐеизвеÑÑ‚Ð½Ð°Ñ ÑиÑÑ‚ÐµÐ¼Ð½Ð°Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ '%-.64s'"
+ serbian "Nepoznata sistemska promenljiva '%-.64s'"
+ spa "Desconocida variable de sistema '%-.64s'"
+ swe "Okänd systemvariabel: '%-.64s'"
+ ukr "Ðевідома ÑиÑтемна змінна '%-.64s'"
+ER_CRASHED_ON_USAGE
+ cze "Tabulka '%-.192s' je ozna-BÄena jako poruÅ¡ená a mÄ›la by být opravena"
+ dan "Tabellen '%-.192s' er markeret med fejl og bør repareres"
+ nla "Tabel '%-.192s' staat als gecrashed gemarkeerd en dient te worden gerepareerd"
+ eng "Table '%-.192s' is marked as crashed and should be repaired"
+ est "Tabel '%-.192s' on märgitud vigaseks ja tuleb parandada"
+ fre "La table '%-.192s' est marquée 'crashed' et devrait être réparée"
+ ger "Tabelle '%-.192s' ist als defekt markiert und sollte repariert werden"
+ ita "La tabella '%-.192s' e` segnalata come corrotta e deve essere riparata"
+ por "Tabela '%-.192s' está marcada como danificada e deve ser reparada"
+ rus "Таблица '%-.192s' помечена как иÑÐ¿Ð¾Ñ€Ñ‡ÐµÐ½Ð½Ð°Ñ Ð¸ должна пройти проверку и ремонт"
+ serbian "Tabela '%-.192s' je markirana kao oštećena i trebala bi biti popravljena"
+ spa "Tabla '%-.192s' está marcada como crashed y debe ser reparada"
+ swe "Tabell '%-.192s' är trasig och bör repareras med REPAIR TABLE"
+ ukr "Таблицю '%-.192s' марковано Ñк зіпÑовану та Ñ—Ñ— потрібно відновити"
+ER_CRASHED_ON_REPAIR
+ cze "Tabulka '%-.192s' je ozna-BÄena jako poruÅ¡ená a poslední (automatická?) oprava se nezdaÅ™ila"
+ dan "Tabellen '%-.192s' er markeret med fejl og sidste (automatiske?) REPAIR fejlede"
+ nla "Tabel '%-.192s' staat als gecrashed gemarkeerd en de laatste (automatische?) reparatie poging mislukte"
+ eng "Table '%-.192s' is marked as crashed and last (automatic?) repair failed"
+ est "Tabel '%-.192s' on märgitud vigaseks ja viimane (automaatne?) parandus ebaõnnestus"
+ fre "La table '%-.192s' est marquée 'crashed' et le dernier 'repair' a échoué"
+ ger "Tabelle '%-.192s' ist als defekt markiert und der letzte (automatische?) Reparaturversuch schlug fehl"
+ ita "La tabella '%-.192s' e` segnalata come corrotta e l'ultima ricostruzione (automatica?) e` fallita"
+ por "Tabela '%-.192s' está marcada como danificada e a última reparação (automática?) falhou"
+ rus "Таблица '%-.192s' помечена как иÑÐ¿Ð¾Ñ€Ñ‡ÐµÐ½Ð½Ð°Ñ Ð¸ поÑледний (автоматичеÑкий?) ремонт не был уÑпешным"
+ serbian "Tabela '%-.192s' je markirana kao oštećena, a zadnja (automatska?) popravka je bila neuspela"
+ spa "Tabla '%-.192s' está marcada como crashed y la última reparación (automactica?) falló"
+ swe "Tabell '%-.192s' är trasig och senast (automatiska?) reparation misslyckades"
+ ukr "Таблицю '%-.192s' марковано Ñк зіпÑовану та оÑтаннє (автоматичне?) Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½Ðµ вдалоÑÑ"
+ER_WARNING_NOT_COMPLETE_ROLLBACK
+ dan "Advarsel: Visse data i tabeller der ikke understøtter transaktioner kunne ikke tilbagestilles"
+ nla "Waarschuwing: Roll back mislukt voor sommige buiten transacties gewijzigde tabellen"
+ eng "Some non-transactional changed tables couldn't be rolled back"
+ est "Hoiatus: mõnesid transaktsioone mittetoetavaid tabeleid ei suudetud tagasi kerida"
+ fre "Attention: certaines tables ne supportant pas les transactions ont été changées et elles ne pourront pas être restituées"
+ ger "Änderungen an einigen nicht transaktionalen Tabellen konnten nicht zurückgerollt werden"
+ ita "Attenzione: Alcune delle modifiche alle tabelle non transazionali non possono essere ripristinate (roll back impossibile)"
+ por "Aviso: Algumas tabelas não-transacionais alteradas não puderam ser reconstituídas (rolled back)"
+ rus "Внимание: по некоторым измененным нетранзакционным таблицам невозможно будет произвеÑти откат транзакции"
+ serbian "Upozorenje: Neke izmenjene tabele ne podržavaju komandu 'ROLLBACK'"
+ spa "Aviso: Algunas tablas no transancionales no pueden tener rolled back"
+ swe "Warning: Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK"
+ ukr "ЗаÑтереженнÑ: ДеÑкі нетранзакційні зміни таблиць не можна буде повернути"
+ER_TRANS_CACHE_FULL
+ dan "Fler-udtryks transaktion krævede mere plads en 'max_binlog_cache_size' bytes. Forhøj værdien af denne variabel og prøv igen"
+ nla "Multi-statement transactie vereist meer dan 'max_binlog_cache_size' bytes opslag. Verhoog deze mysqld variabele en probeer opnieuw"
+ eng "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again"
+ est "Mitme lausendiga transaktsioon nõudis rohkem ruumi kui lubatud 'max_binlog_cache_size' muutujaga. Suurenda muutuja väärtust ja proovi uuesti"
+ fre "Cette transaction à commandes multiples nécessite plus de 'max_binlog_cache_size' octets de stockage, augmentez cette variable de mysqld et réessayez"
+ ger "Transaktionen, die aus mehreren Befehlen bestehen, benötigten mehr als 'max_binlog_cache_size' Bytes an Speicher. Btte vergrössern Sie diese Server-Variable versuchen Sie es noch einmal"
+ ita "La transazione a comandi multipli (multi-statement) ha richiesto piu` di 'max_binlog_cache_size' bytes di disco: aumentare questa variabile di mysqld e riprovare"
+ por "Transações multi-declaradas (multi-statement transactions) requeriram mais do que o valor limite (max_binlog_cache_size) de bytes para armazenagem. Aumente o valor desta variável do mysqld e tente novamente"
+ rus "Транзакции, включающей большое количеÑтво команд, потребовалоÑÑŒ более чем 'max_binlog_cache_size' байт. Увеличьте Ñту переменную Ñервера mysqld и попробуйте еще раз"
+ spa "Multipla transición necesita mas que 'max_binlog_cache_size' bytes de almacenamiento. Aumente esta variable mysqld y tente de nuevo"
+ swe "Transaktionen krävde mera än 'max_binlog_cache_size' minne. Öka denna mysqld-variabel och försök på nytt"
+ ukr "Ð¢Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ñ–Ñ Ð· багатьма виразами вимагає більше ніж 'max_binlog_cache_size' байтів Ð´Ð»Ñ Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ. Збільште цю змінну mysqld та Ñпробуйте знову"
+ER_SLAVE_MUST_STOP
+ dan "Denne handling kunne ikke udføres med kørende slave, brug først kommandoen STOP SLAVE"
+ nla "Deze operatie kan niet worden uitgevoerd met een actieve slave, doe eerst STOP SLAVE"
+ eng "This operation cannot be performed with a running slave; run STOP SLAVE first"
+ fre "Cette opération ne peut être réalisée avec un esclave actif, faites STOP SLAVE d'abord"
+ ger "Diese Operation kann bei einem aktiven Slave nicht durchgeführt werden. Bitte zuerst STOP SLAVE ausführen"
+ ita "Questa operazione non puo' essere eseguita con un database 'slave' che gira, lanciare prima STOP SLAVE"
+ por "Esta operação não pode ser realizada com um 'slave' em execução. Execute STOP SLAVE primeiro"
+ rus "Эту операцию невозможно выполнить при работающем потоке подчиненного Ñервера. Сначала выполните STOP SLAVE"
+ serbian "Ova operacija ne može biti izvršena dok je aktivan podređeni server. Zadajte prvo komandu 'STOP SLAVE' da zaustavite podređeni server."
+ spa "Esta operación no puede ser hecha con el esclavo funcionando, primero use STOP SLAVE"
+ swe "Denna operation kan inte göras under replikering; Gör STOP SLAVE först"
+ ukr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ðµ може бути виконана з запущеним підлеглим, Ñпочатку виконайте STOP SLAVE"
+ER_SLAVE_NOT_RUNNING
+ dan "Denne handling kræver en kørende slave. Konfigurer en slave og brug kommandoen START SLAVE"
+ nla "Deze operatie vereist een actieve slave, configureer slave en doe dan START SLAVE"
+ eng "This operation requires a running slave; configure slave and do START SLAVE"
+ fre "Cette opération nécessite un esclave actif, configurez les esclaves et faites START SLAVE"
+ ger "Diese Operation benötigt einen aktiven Slave. Bitte Slave konfigurieren und mittels START SLAVE aktivieren"
+ ita "Questa operaione richiede un database 'slave', configurarlo ed eseguire START SLAVE"
+ por "Esta operação requer um 'slave' em execução. Configure o 'slave' e execute START SLAVE"
+ rus "Ð”Ð»Ñ Ñтой операции требуетÑÑ Ñ€Ð°Ð±Ð¾Ñ‚Ð°ÑŽÑ‰Ð¸Ð¹ подчиненный Ñервер. Сначала выполните START SLAVE"
+ serbian "Ova operacija zahteva da je aktivan podređeni server. Konfigurišite prvo podređeni server i onda izvršite komandu 'START SLAVE'"
+ spa "Esta operación necesita el esclavo funcionando, configure esclavo y haga el START SLAVE"
+ swe "Denna operation kan endast göras under replikering; Konfigurera slaven och gör START SLAVE"
+ ukr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð²Ð¸Ð¼Ð°Ð³Ð°Ñ” запущеного підлеглого, зконфігуруйте підлеглого та виконайте START SLAVE"
+ER_BAD_SLAVE
+ dan "Denne server er ikke konfigureret som slave. Ret in config-filen eller brug kommandoen CHANGE MASTER TO"
+ nla "De server is niet geconfigureerd als slave, fix in configuratie bestand of met CHANGE MASTER TO"
+ eng "The server is not configured as slave; fix in config file or with CHANGE MASTER TO"
+ fre "Le server n'est pas configuré comme un esclave, changez le fichier de configuration ou utilisez CHANGE MASTER TO"
+ ger "Der Server ist nicht als Slave konfiguriert. Bitte in der Konfigurationsdatei oder mittels CHANGE MASTER TO beheben"
+ ita "Il server non e' configurato come 'slave', correggere il file di configurazione cambiando CHANGE MASTER TO"
+ por "O servidor não está configurado como 'slave'. Acerte o arquivo de configuração ou use CHANGE MASTER TO"
+ rus "Этот Ñервер не наÑтроен как подчиненный. ВнеÑите иÑÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð² конфигурационном файле или Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ CHANGE MASTER TO"
+ serbian "Server nije konfigurisan kao podređeni server, ispravite konfiguracioni file ili na njemu izvršite komandu 'CHANGE MASTER TO'"
+ spa "El servidor no está configurado como esclavo, edite el archivo config file o con CHANGE MASTER TO"
+ swe "Servern är inte konfigurerade som en replikationsslav. Ändra konfigurationsfilen eller gör CHANGE MASTER TO"
+ ukr "Сервер не зконфігуровано Ñк підлеглий, виправте це у файлі конфігурації або з CHANGE MASTER TO"
+ER_MASTER_INFO
+ eng "Could not initialize master info structure; more error messages can be found in the MySQL error log"
+ fre "Impossible d'initialiser les structures d'information de maître, vous trouverez des messages d'erreur supplémentaires dans le journal des erreurs de MySQL"
+ ger "Konnte Master-Info-Struktur nicht initialisieren. Weitere Fehlermeldungen können im MySQL-Error-Log eingesehen werden"
+ serbian "Nisam mogao da inicijalizujem informacionu strukturu glavnog servera, proverite da li imam privilegije potrebne za pristup file-u 'master.info'"
+ swe "Kunde inte initialisera replikationsstrukturerna. See MySQL fel fil för mera information"
+ER_SLAVE_THREAD
+ dan "Kunne ikke danne en slave-tråd; check systemressourcerne"
+ nla "Kon slave thread niet aanmaken, controleer systeem resources"
+ eng "Could not create slave thread; check system resources"
+ fre "Impossible de créer une tâche esclave, vérifiez les ressources système"
+ ger "Konnte Slave-Thread nicht starten. Bitte System-Ressourcen überprüfen"
+ ita "Impossibile creare il thread 'slave', controllare le risorse di sistema"
+ por "Não conseguiu criar 'thread' de 'slave'. Verifique os recursos do sistema"
+ rus "Ðевозможно Ñоздать поток подчиненного Ñервера. Проверьте ÑиÑтемные реÑурÑÑ‹"
+ serbian "Nisam mogao da startujem thread za podređeni server, proverite sistemske resurse"
+ spa "No puedo crear el thread esclavo, verifique recursos del sistema"
+ swe "Kunde inte starta en tråd för replikering"
+ ukr "Ðе можу Ñтворити підлеглу гілку, перевірте ÑиÑтемні реÑурÑи"
+ER_TOO_MANY_USER_CONNECTIONS 42000
+ dan "Brugeren %-.64s har allerede mere end 'max_user_connections' aktive forbindelser"
+ nla "Gebruiker %-.64s heeft reeds meer dan 'max_user_connections' actieve verbindingen"
+ eng "User %-.64s already has more than 'max_user_connections' active connections"
+ est "Kasutajal %-.64s on juba rohkem ühendusi kui lubatud 'max_user_connections' muutujaga"
+ fre "L'utilisateur %-.64s possède déjà plus de 'max_user_connections' connexions actives"
+ ger "Benutzer '%-.64s' hat mehr als 'max_user_connections' aktive Verbindungen"
+ ita "L'utente %-.64s ha gia' piu' di 'max_user_connections' connessioni attive"
+ por "Usuário '%-.64s' já possui mais que o valor máximo de conexões (max_user_connections) ativas"
+ rus "У Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ %-.64s уже больше чем 'max_user_connections' активных Ñоединений"
+ serbian "Korisnik %-.64s već ima više aktivnih konekcija nego što je to određeno 'max_user_connections' promenljivom"
+ spa "Usario %-.64s ya tiene mas que 'max_user_connections' conexiones activas"
+ swe "Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar"
+ ukr "КориÑтувач %-.64s вже має більше ніж 'max_user_connections' активних з'єднань"
+ER_SET_CONSTANTS_ONLY
+ dan "Du må kun bruge konstantudtryk med SET"
+ nla "U mag alleen constante expressies gebruiken bij SET"
+ eng "You may only use constant expressions with SET"
+ est "Ainult konstantsed suurused on lubatud SET klauslis"
+ fre "Seules les expressions constantes sont autorisées avec SET"
+ ger "Bei SET dürfen nur konstante Ausdrücke verwendet werden"
+ ita "Si possono usare solo espressioni costanti con SET"
+ por "Você pode usar apenas expressões constantes com SET"
+ rus "Ð’Ñ‹ можете иÑпользовать в SET только конÑтантные выражениÑ"
+ serbian "Možete upotrebiti samo konstantan iskaz sa komandom 'SET'"
+ spa "Tu solo debes usar expresiones constantes con SET"
+ swe "Man kan endast använda konstantuttryck med SET"
+ ukr "Можна викориÑтовувати лише вирази зі Ñталими у SET"
+ER_LOCK_WAIT_TIMEOUT
+ dan "Lock wait timeout overskredet"
+ nla "Lock wacht tijd overschreden"
+ eng "Lock wait timeout exceeded; try restarting transaction"
+ est "Kontrollaeg ületatud luku järel ootamisel; Proovi transaktsiooni otsast alata"
+ fre "Timeout sur l'obtention du verrou"
+ ger "Beim Warten auf eine Sperre wurde die zulässige Wartezeit überschritten. Bitte versuchen Sie, die Transaktion neu zu starten"
+ ita "E' scaduto il timeout per l'attesa del lock"
+ por "Tempo de espera (timeout) de travamento excedido. Tente reiniciar a transação."
+ rus "Таймаут Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ иÑтек; попробуйте перезапуÑтить транзакцию"
+ serbian "Vremenski limit za zakljuÄavanje tabele je istekao; Probajte da ponovo startujete transakciju"
+ spa "Tiempo de bloqueo de espera excedido"
+ swe "Fick inte ett lås i tid ; Försök att starta om transaktionen"
+ ukr "Затримку Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ñ‡ÐµÑ€Ð¿Ð°Ð½Ð¾"
+ER_LOCK_TABLE_FULL
+ dan "Det totale antal låse overstiger størrelsen på låse-tabellen"
+ nla "Het totale aantal locks overschrijdt de lock tabel grootte"
+ eng "The total number of locks exceeds the lock table size"
+ est "Lukkude koguarv ületab lukutabeli suuruse"
+ fre "Le nombre total de verrou dépasse la taille de la table des verrous"
+ ger "Die Gesamtzahl der Sperren überschreitet die Größe der Sperrtabelle"
+ ita "Il numero totale di lock e' maggiore della grandezza della tabella di lock"
+ por "O número total de travamentos excede o tamanho da tabela de travamentos"
+ rus "Общее количеÑтво блокировок превыÑило размеры таблицы блокировок"
+ serbian "Broj totalnih zakljuÄavanja tabele premaÅ¡uje veliÄinu tabele zakljuÄavanja"
+ spa "El número total de bloqueos excede el tamaño de bloqueo de la tabla"
+ swe "Antal lås överskrider antalet reserverade lås"
+ ukr "Загальна кількіÑÑ‚ÑŒ блокувань перевищила розмір блокувань Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ–"
+ER_READ_ONLY_TRANSACTION 25000
+ dan "Update lås kan ikke opnås under en READ UNCOMMITTED transaktion"
+ nla "Update locks kunnen niet worden verkregen tijdens een READ UNCOMMITTED transactie"
+ eng "Update locks cannot be acquired during a READ UNCOMMITTED transaction"
+ est "Uuenduslukke ei saa kasutada READ UNCOMMITTED transaktsiooni käigus"
+ fre "Un verrou en update ne peut être acquit pendant une transaction READ UNCOMMITTED"
+ ger "Während einer READ-UNCOMMITTED-Transaktion können keine UPDATE-Sperren angefordert werden"
+ ita "I lock di aggiornamento non possono essere acquisiti durante una transazione 'READ UNCOMMITTED'"
+ por "Travamentos de atualização não podem ser obtidos durante uma transação de tipo READ UNCOMMITTED"
+ rus "Блокировки обновлений Ð½ÐµÐ»ÑŒÐ·Ñ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ в процеÑÑе Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ð½Ðµ принÑтой (в режиме READ UNCOMMITTED) транзакции"
+ serbian "ZakljuÄavanja izmena ne mogu biti realizovana sve dok traje 'READ UNCOMMITTED' transakcija"
+ spa "Bloqueos de actualización no pueden ser adqueridos durante una transición READ UNCOMMITTED"
+ swe "Updateringslås kan inte göras när man använder READ UNCOMMITTED"
+ ukr "Оновити Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ можливо на протÑзі транзакції READ UNCOMMITTED"
+ER_DROP_DB_WITH_READ_LOCK
+ dan "DROP DATABASE er ikke tilladt mens en tråd holder på globalt read lock"
+ nla "DROP DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit"
+ eng "DROP DATABASE not allowed while thread is holding global read lock"
+ est "DROP DATABASE ei ole lubatud kui lõim omab globaalset READ lukku"
+ fre "DROP DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture"
+ ger "DROP DATABASE ist nicht erlaubt, solange der Thread eine globale Lesesperre hält"
+ ita "DROP DATABASE non e' permesso mentre il thread ha un lock globale di lettura"
+ por "DROP DATABASE não permitido enquanto uma 'thread' está mantendo um travamento global de leitura"
+ rus "Ðе допуÑкаетÑÑ DROP DATABASE, пока поток держит глобальную блокировку чтениÑ"
+ serbian "Komanda 'DROP DATABASE' nije dozvoljena dok thread globalno zakljuÄava Äitanje podataka"
+ spa "DROP DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global"
+ swe "DROP DATABASE är inte tillåtet när man har ett globalt läslås"
+ ukr "DROP DATABASE не дозволено доки гілка перебуває під загальним блокуваннÑм читаннÑ"
+ER_CREATE_DB_WITH_READ_LOCK
+ dan "CREATE DATABASE er ikke tilladt mens en tråd holder på globalt read lock"
+ nla "CREATE DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit"
+ eng "CREATE DATABASE not allowed while thread is holding global read lock"
+ est "CREATE DATABASE ei ole lubatud kui lõim omab globaalset READ lukku"
+ fre "CREATE DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture"
+ ger "CREATE DATABASE ist nicht erlaubt, solange der Thread eine globale Lesesperre hält"
+ ita "CREATE DATABASE non e' permesso mentre il thread ha un lock globale di lettura"
+ por "CREATE DATABASE não permitido enquanto uma 'thread' está mantendo um travamento global de leitura"
+ rus "Ðе допуÑкаетÑÑ CREATE DATABASE, пока поток держит глобальную блокировку чтениÑ"
+ serbian "Komanda 'CREATE DATABASE' nije dozvoljena dok thread globalno zakljuÄava Äitanje podataka"
+ spa "CREATE DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global"
+ swe "CREATE DATABASE är inte tillåtet när man har ett globalt läslås"
+ ukr "CREATE DATABASE не дозволено доки гілка перебуває під загальним блокуваннÑм читаннÑ"
+ER_WRONG_ARGUMENTS
+ nla "Foutieve parameters voor %s"
+ eng "Incorrect arguments to %s"
+ est "Vigased parameetrid %s-le"
+ fre "Mauvais arguments à %s"
+ ger "Falsche Argumente für %s"
+ ita "Argomenti errati a %s"
+ por "Argumentos errados para %s"
+ rus "Ðеверные параметры Ð´Ð»Ñ %s"
+ serbian "Pogrešni argumenti prosleđeni na %s"
+ spa "Argumentos errados para %s"
+ swe "Felaktiga argument till %s"
+ ukr "Хибний аргумент Ð´Ð»Ñ %s"
+ER_NO_PERMISSION_TO_CREATE_USER 42000
+ nla "'%-.48s'@'%-.64s' mag geen nieuwe gebruikers creeren"
+ eng "'%-.48s'@'%-.64s' is not allowed to create new users"
+ est "Kasutajal '%-.48s'@'%-.64s' ei ole lubatud luua uusi kasutajaid"
+ fre "'%-.48s'@'%-.64s' n'est pas autorisé à créer de nouveaux utilisateurs"
+ ger "'%-.48s'@'%-.64s' ist nicht berechtigt, neue Benutzer hinzuzufügen"
+ ita "A '%-.48s'@'%-.64s' non e' permesso creare nuovi utenti"
+ por "Não é permitido a '%-.48s'@'%-.64s' criar novos usuários"
+ rus "'%-.48s'@'%-.64s' не разрешаетÑÑ Ñоздавать новых пользователей"
+ serbian "Korisniku '%-.48s'@'%-.64s' nije dozvoljeno da kreira nove korisnike"
+ spa "'%-.48s`@`%-.64s` no es permitido para crear nuevos usuarios"
+ swe "'%-.48s'@'%-.64s' har inte rättighet att skapa nya användare"
+ ukr "КориÑтувачу '%-.48s'@'%-.64s' не дозволено Ñтворювати нових кориÑтувачів"
+ER_UNION_TABLES_IN_DIFFERENT_DIR
+ nla "Incorrecte tabel definitie; alle MERGE tabellen moeten tot dezelfde database behoren"
+ eng "Incorrect table definition; all MERGE tables must be in the same database"
+ est "Vigane tabelimääratlus; kõik MERGE tabeli liikmed peavad asuma samas andmebaasis"
+ fre "Définition de table incorrecte; toutes les tables MERGE doivent être dans la même base de donnée"
+ ger "Falsche Tabellendefinition. Alle MERGE-Tabellen müssen sich in derselben Datenbank befinden"
+ ita "Definizione della tabella errata; tutte le tabelle di tipo MERGE devono essere nello stesso database"
+ por "Definição incorreta da tabela. Todas as tabelas contidas na junção devem estar no mesmo banco de dados."
+ rus "Ðеверное определение таблицы; Ð’Ñе таблицы в MERGE должны принадлежать одной и той же базе данных"
+ serbian "Pogrešna definicija tabele; sve 'MERGE' tabele moraju biti u istoj bazi podataka"
+ spa "Incorrecta definición de la tabla; Todas las tablas MERGE deben estar en el mismo banco de datos"
+ swe "Felaktig tabelldefinition; alla tabeller i en MERGE-tabell måste vara i samma databas"
+ER_LOCK_DEADLOCK 40001
+ nla "Deadlock gevonden tijdens lock-aanvraag poging; Probeer herstart van de transactie"
+ eng "Deadlock found when trying to get lock; try restarting transaction"
+ est "Lukustamisel tekkis tupik (deadlock); alusta transaktsiooni otsast"
+ fre "Deadlock découvert en essayant d'obtenir les verrous : essayez de redémarrer la transaction"
+ ger "Beim Versuch, eine Sperre anzufordern, ist ein Deadlock aufgetreten. Versuchen Sie, die Transaktion neu zu starten"
+ ita "Trovato deadlock durante il lock; Provare a far ripartire la transazione"
+ por "Encontrado um travamento fatal (deadlock) quando tentava obter uma trava. Tente reiniciar a transação."
+ rus "Возникла Ñ‚ÑƒÐ¿Ð¸ÐºÐ¾Ð²Ð°Ñ ÑÐ¸Ñ‚ÑƒÐ°Ñ†Ð¸Ñ Ð² процеÑÑе Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸; Попробуйте перезапуÑтить транзакцию"
+ serbian "Unakrsno zakljuÄavanje pronaÄ‘eno kada sam pokuÅ¡ao da dobijem pravo na zakljuÄavanje; Probajte da restartujete transakciju"
+ spa "Encontrado deadlock cuando tentando obtener el bloqueo; Tente recomenzar la transición"
+ swe "Fick 'DEADLOCK' vid låsförsök av block/rad. Försök att starta om transaktionen"
+ER_TABLE_CANT_HANDLE_FT
+ nla "Het gebruikte tabel type ondersteund geen FULLTEXT indexen"
+ eng "The used table type doesn't support FULLTEXT indexes"
+ est "Antud tabelitüüp ei toeta FULLTEXT indekseid"
+ fre "Le type de table utilisé ne supporte pas les index FULLTEXT"
+ ger "Der verwendete Tabellentyp unterstützt keine FULLTEXT-Indizes"
+ ita "La tabella usata non supporta gli indici FULLTEXT"
+ por "O tipo de tabela utilizado não suporta índices de texto completo (fulltext indexes)"
+ rus "ИÑпользуемый тип таблиц не поддерживает полнотекÑтовых индекÑов"
+ serbian "Upotrebljeni tip tabele ne podržava 'FULLTEXT' indekse"
+ spa "El tipo de tabla usada no soporta índices FULLTEXT"
+ swe "Tabelltypen har inte hantering av FULLTEXT-index"
+ ukr "ВикориÑтаний тип таблиці не підтримує FULLTEXT індекÑів"
+ER_CANNOT_ADD_FOREIGN
+ nla "Kan foreign key beperking niet toevoegen"
+ eng "Cannot add foreign key constraint"
+ fre "Impossible d'ajouter des contraintes d'index externe"
+ ger "Fremdschlüssel-Beschränkung kann nicht hinzugefügt werden"
+ ita "Impossibile aggiungere il vincolo di integrita' referenziale (foreign key constraint)"
+ por "Não pode acrescentar uma restrição de chave estrangeira"
+ rus "Ðевозможно добавить Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð²Ð½ÐµÑˆÐ½ÐµÐ³Ð¾ ключа"
+ serbian "Ne mogu da dodam proveru spoljnog kljuÄa"
+ spa "No puede adicionar clave extranjera constraint"
+ swe "Kan inte lägga till 'FOREIGN KEY constraint'"
+ER_NO_REFERENCED_ROW 23000
+ nla "Kan onderliggende rij niet toevoegen: foreign key beperking gefaald"
+ eng "Cannot add or update a child row: a foreign key constraint fails"
+ fre "Impossible d'ajouter un enregistrement fils : une constrainte externe l'empèche"
+ ger "Hinzufügen oder Aktualisieren eines Kind-Datensatzes schlug aufgrund einer Fremdschlüssel-Beschränkung fehl"
+ greek "Cannot add a child row: a foreign key constraint fails"
+ hun "Cannot add a child row: a foreign key constraint fails"
+ ita "Impossibile aggiungere la riga: un vincolo d'integrita' referenziale non e' soddisfatto"
+ norwegian-ny "Cannot add a child row: a foreign key constraint fails"
+ por "Não pode acrescentar uma linha filha: uma restrição de chave estrangeira falhou"
+ rus "Ðевозможно добавить или обновить дочернюю Ñтроку: проверка ограничений внешнего ключа не выполнÑетÑÑ"
+ spa "No puede adicionar una línea hijo: falla de clave extranjera constraint"
+ swe "FOREIGN KEY-konflikt: Kan inte skriva barn"
+ER_ROW_IS_REFERENCED 23000
+ eng "Cannot delete or update a parent row: a foreign key constraint fails"
+ fre "Impossible de supprimer un enregistrement père : une constrainte externe l'empèche"
+ ger "Löschen oder Aktualisieren eines Eltern-Datensatzes schlug aufgrund einer Fremdschlüssel-Beschränkung fehl"
+ greek "Cannot delete a parent row: a foreign key constraint fails"
+ hun "Cannot delete a parent row: a foreign key constraint fails"
+ ita "Impossibile cancellare la riga: un vincolo d'integrita' referenziale non e' soddisfatto"
+ por "Não pode apagar uma linha pai: uma restrição de chave estrangeira falhou"
+ rus "Ðевозможно удалить или обновить родительÑкую Ñтроку: проверка ограничений внешнего ключа не выполнÑетÑÑ"
+ serbian "Ne mogu da izbriÅ¡em roditeljski slog: provera spoljnog kljuÄa je neuspela"
+ spa "No puede deletar una línea padre: falla de clave extranjera constraint"
+ swe "FOREIGN KEY-konflikt: Kan inte radera fader"
+ER_CONNECT_TO_MASTER 08S01
+ nla "Fout bij opbouwen verbinding naar master: %-.128s"
+ eng "Error connecting to master: %-.128s"
+ ger "Fehler bei der Verbindung zum Master: %-.128s"
+ ita "Errore durante la connessione al master: %-.128s"
+ por "Erro conectando com o master: %-.128s"
+ rus "Ошибка ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ Ð³Ð¾Ð»Ð¾Ð²Ð½Ñ‹Ð¼ Ñервером: %-.128s"
+ spa "Error de coneccion a master: %-.128s"
+ swe "Fick fel vid anslutning till master: %-.128s"
+ER_QUERY_ON_MASTER
+ nla "Fout bij uitvoeren query op master: %-.128s"
+ eng "Error running query on master: %-.128s"
+ ger "Beim Ausführen einer Abfrage auf dem Master trat ein Fehler auf: %-.128s"
+ ita "Errore eseguendo una query sul master: %-.128s"
+ por "Erro rodando consulta no master: %-.128s"
+ rus "Ошибка Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа на головном Ñервере: %-.128s"
+ spa "Error executando el query en master: %-.128s"
+ swe "Fick fel vid utförande av command på mastern: %-.128s"
+ER_ERROR_WHEN_EXECUTING_COMMAND
+ nla "Fout tijdens uitvoeren van commando %s: %-.128s"
+ eng "Error when executing command %s: %-.128s"
+ est "Viga käsu %s täitmisel: %-.128s"
+ ger "Fehler beim Ausführen des Befehls %s: %-.128s"
+ ita "Errore durante l'esecuzione del comando %s: %-.128s"
+ por "Erro quando executando comando %s: %-.128s"
+ rus "Ошибка при выполнении команды %s: %-.128s"
+ serbian "Greška pri izvršavanju komande %s: %-.128s"
+ spa "Error de %s: %-.128s"
+ swe "Fick fel vid utförande av %s: %-.128s"
+ER_WRONG_USAGE
+ nla "Foutief gebruik van %s en %s"
+ eng "Incorrect usage of %s and %s"
+ est "Vigane %s ja %s kasutus"
+ ger "Falsche Verwendung von %s und %s"
+ ita "Uso errato di %s e %s"
+ por "Uso errado de %s e %s"
+ rus "Ðеверное иÑпользование %s и %s"
+ serbian "Pogrešna upotreba %s i %s"
+ spa "Equivocado uso de %s y %s"
+ swe "Felaktig använding av %s and %s"
+ ukr "Wrong usage of %s and %s"
+ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 21000
+ nla "De gebruikte SELECT commando's hebben een verschillend aantal kolommen"
+ eng "The used SELECT statements have a different number of columns"
+ est "Tulpade arv kasutatud SELECT lausetes ei kattu"
+ ger "Die verwendeten SELECT-Befehle liefern unterschiedliche Anzahlen von Feldern zurück"
+ ita "La SELECT utilizzata ha un numero di colonne differente"
+ por "Os comandos SELECT usados têm diferente número de colunas"
+ rus "ИÑпользованные операторы выборки (SELECT) дают разное количеÑтво Ñтолбцов"
+ serbian "Upotrebljene 'SELECT' komande adresiraju razliÄit broj kolona"
+ spa "El comando SELECT usado tiene diferente número de columnas"
+ swe "SELECT-kommandona har olika antal kolumner"
+ER_CANT_UPDATE_WITH_READLOCK
+ nla "Kan de query niet uitvoeren vanwege een conflicterende read lock"
+ eng "Can't execute the query because you have a conflicting read lock"
+ est "Ei suuda täita päringut konfliktse luku tõttu"
+ ger "Augrund eines READ-LOCK-Konflikts kann die Abfrage nicht ausgeführt werden"
+ ita "Impossibile eseguire la query perche' c'e' un conflitto con in lock di lettura"
+ por "Não posso executar a consulta porque você tem um conflito de travamento de leitura"
+ rus "Ðевозможно иÑполнить запроÑ, поÑкольку у Ð²Ð°Ñ ÑƒÑтановлены конфликтующие блокировки чтениÑ"
+ serbian "Ne mogu da izvrÅ¡im upit zbog toga Å¡to imate zakljuÄavanja Äitanja podataka u konfliktu"
+ spa "No puedo ejecutar el query porque usted tiene conflicto de traba de lectura"
+ swe "Kan inte utföra kommandot emedan du har ett READ-lås"
+ER_MIXING_NOT_ALLOWED
+ nla "Het combineren van transactionele en niet-transactionele tabellen is uitgeschakeld."
+ eng "Mixing of transactional and non-transactional tables is disabled"
+ est "Transaktsioone toetavate ning mittetoetavate tabelite kooskasutamine ei ole lubatud"
+ ger "Die gleichzeitige Verwendung von Tabellen mit und ohne Transaktionsunterstützung ist deaktiviert"
+ ita "E' disabilitata la possibilita' di mischiare tabelle transazionali e non-transazionali"
+ por "Mistura de tabelas transacional e não-transacional está desabilitada"
+ rus "ИÑпользование транзакционных таблиц нарÑду Ñ Ð½ÐµÑ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ð¾Ð½Ð½Ñ‹Ð¼Ð¸ запрещено"
+ serbian "MeÅ¡anje tabela koje podržavaju transakcije i onih koje ne podržavaju transakcije je iskljuÄeno"
+ spa "Mezla de transancional y no-transancional tablas está deshabilitada"
+ swe "Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat"
+ER_DUP_ARGUMENT
+ nla "Optie '%s' tweemaal gebruikt in opdracht"
+ eng "Option '%s' used twice in statement"
+ est "Määrangut '%s' on lauses kasutatud topelt"
+ ger "Option '%s' wird im Befehl zweimal verwendet"
+ ita "L'opzione '%s' e' stata usata due volte nel comando"
+ por "Opção '%s' usada duas vezes no comando"
+ rus "ÐžÐ¿Ñ†Ð¸Ñ '%s' дважды иÑпользована в выражении"
+ spa "Opción '%s' usada dos veces en el comando"
+ swe "Option '%s' användes två gånger"
+ER_USER_LIMIT_REACHED 42000
+ nla "Gebruiker '%-.64s' heeft het maximale gebruik van de '%s' faciliteit overschreden (huidige waarde: %ld)"
+ eng "User '%-.64s' has exceeded the '%s' resource (current value: %ld)"
+ ger "Benutzer '%-.64s' hat die Ressourcenbeschränkung '%s' überschritten (aktueller Wert: %ld)"
+ ita "L'utente '%-.64s' ha ecceduto la risorsa '%s' (valore corrente: %ld)"
+ por "Usuário '%-.64s' tem excedido o '%s' recurso (atual valor: %ld)"
+ rus "Пользователь '%-.64s' превыÑил иÑпользование реÑурÑа '%s' (текущее значение: %ld)"
+ spa "Usuario '%-.64s' ha excedido el recurso '%s' (actual valor: %ld)"
+ swe "Användare '%-.64s' har överskridit '%s' (nuvarande värde: %ld)"
+ER_SPECIFIC_ACCESS_DENIED_ERROR 42000
+ nla "Toegang geweigerd. U moet het %-.128s privilege hebben voor deze operatie"
+ eng "Access denied; you need (at least one of) the %-.128s privilege(s) for this operation"
+ ger "Kein Zugriff. Hierfür wird die Berechtigung %-.128s benötigt"
+ ita "Accesso non consentito. Serve il privilegio %-.128s per questa operazione"
+ por "Acesso negado. Você precisa o privilégio %-.128s para essa operação"
+ rus "Ð’ доÑтупе отказано. Вам нужны привилегии %-.128s Ð´Ð»Ñ Ñтой операции"
+ spa "Acceso negado. Usted necesita el privilegio %-.128s para esta operación"
+ swe "Du har inte privlegiet '%-.128s' som behövs för denna operation"
+ ukr "Access denied. You need the %-.128s privilege for this operation"
+ER_LOCAL_VARIABLE
+ nla "Variabele '%-.64s' is SESSION en kan niet worden gebruikt met SET GLOBAL"
+ eng "Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL"
+ ger "Variable '%-.64s' ist eine lokale Variable und kann nicht mit SET GLOBAL verändert werden"
+ ita "La variabile '%-.64s' e' una variabile locale ( SESSION ) e non puo' essere cambiata usando SET GLOBAL"
+ por "Variável '%-.64s' é uma SESSION variável e não pode ser usada com SET GLOBAL"
+ rus "ÐŸÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ '%-.64s' ÑвлÑетÑÑ Ð¿Ð¾Ñ‚Ð¾ÐºÐ¾Ð²Ð¾Ð¹ (SESSION) переменной и не может быть изменена Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ SET GLOBAL"
+ spa "Variable '%-.64s' es una SESSION variable y no puede ser usada con SET GLOBAL"
+ swe "Variabel '%-.64s' är en SESSION variabel och kan inte ändrad med SET GLOBAL"
+ER_GLOBAL_VARIABLE
+ nla "Variabele '%-.64s' is GLOBAL en dient te worden gewijzigd met SET GLOBAL"
+ eng "Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL"
+ ger "Variable '%-.64s' ist eine globale Variable und muss mit SET GLOBAL verändert werden"
+ ita "La variabile '%-.64s' e' una variabile globale ( GLOBAL ) e deve essere cambiata usando SET GLOBAL"
+ por "Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL"
+ rus "ÐŸÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ '%-.64s' ÑвлÑетÑÑ Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ð¾Ð¹ (GLOBAL) переменной, и ее Ñледует изменÑÑ‚ÑŒ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ SET GLOBAL"
+ spa "Variable '%-.64s' es una GLOBAL variable y no puede ser configurada con SET GLOBAL"
+ swe "Variabel '%-.64s' är en GLOBAL variabel och bör sättas med SET GLOBAL"
+ER_NO_DEFAULT 42000
+ nla "Variabele '%-.64s' heeft geen standaard waarde"
+ eng "Variable '%-.64s' doesn't have a default value"
+ ger "Variable '%-.64s' hat keinen Vorgabewert"
+ ita "La variabile '%-.64s' non ha un valore di default"
+ por "Variável '%-.64s' não tem um valor padrão"
+ rus "ÐŸÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ '%-.64s' не имеет Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию"
+ spa "Variable '%-.64s' no tiene un valor patrón"
+ swe "Variabel '%-.64s' har inte ett DEFAULT-värde"
+ER_WRONG_VALUE_FOR_VAR 42000
+ nla "Variabele '%-.64s' kan niet worden gewijzigd naar de waarde '%-.200s'"
+ eng "Variable '%-.64s' can't be set to the value of '%-.200s'"
+ ger "Variable '%-.64s' kann nicht auf '%-.200s' gesetzt werden"
+ ita "Alla variabile '%-.64s' non puo' essere assegato il valore '%-.200s'"
+ por "Variável '%-.64s' não pode ser configurada para o valor de '%-.200s'"
+ rus "ÐŸÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ '%-.64s' не может быть уÑтановлена в значение '%-.200s'"
+ spa "Variable '%-.64s' no puede ser configurada para el valor de '%-.200s'"
+ swe "Variabel '%-.64s' kan inte sättas till '%-.200s'"
+ER_WRONG_TYPE_FOR_VAR 42000
+ nla "Foutief argumenttype voor variabele '%-.64s'"
+ eng "Incorrect argument type to variable '%-.64s'"
+ ger "Falscher Argumenttyp für Variable '%-.64s'"
+ ita "Tipo di valore errato per la variabile '%-.64s'"
+ por "Tipo errado de argumento para variável '%-.64s'"
+ rus "Ðеверный тип аргумента Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð¾Ð¹ '%-.64s'"
+ spa "Tipo de argumento equivocado para variable '%-.64s'"
+ swe "Fel typ av argument till variabel '%-.64s'"
+ER_VAR_CANT_BE_READ
+ nla "Variabele '%-.64s' kan alleen worden gewijzigd, niet gelezen"
+ eng "Variable '%-.64s' can only be set, not read"
+ ger "Variable '%-.64s' kann nur verändert, nicht gelesen werden"
+ ita "Alla variabile '%-.64s' e' di sola scrittura quindi puo' essere solo assegnato un valore, non letto"
+ por "Variável '%-.64s' somente pode ser configurada, não lida"
+ rus "ÐŸÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ '%-.64s' может быть только уÑтановлена, но не Ñчитана"
+ spa "Variable '%-.64s' solamente puede ser configurada, no leída"
+ swe "Variabeln '%-.64s' kan endast sättas, inte läsas"
+ER_CANT_USE_OPTION_HERE 42000
+ nla "Foutieve toepassing/plaatsing van '%s'"
+ eng "Incorrect usage/placement of '%s'"
+ ger "Falsche Verwendung oder Platzierung von '%s'"
+ ita "Uso/posizione di '%s' sbagliato"
+ por "Errado uso/colocação de '%s'"
+ rus "Ðеверное иÑпользование или в неверном меÑте указан '%s'"
+ spa "Equivocado uso/colocación de '%s'"
+ swe "Fel använding/placering av '%s'"
+ER_NOT_SUPPORTED_YET 42000
+ nla "Deze versie van MySQL ondersteunt nog geen '%s'"
+ eng "This version of MySQL doesn't yet support '%s'"
+ ger "Diese MySQL-Version unterstützt '%s' nicht"
+ ita "Questa versione di MySQL non supporta ancora '%s'"
+ por "Esta versão de MySQL não suporta ainda '%s'"
+ rus "Эта верÑÐ¸Ñ MySQL пока еще не поддерживает '%s'"
+ spa "Esta versión de MySQL no soporta todavia '%s'"
+ swe "Denna version av MySQL kan ännu inte utföra '%s'"
+ER_MASTER_FATAL_ERROR_READING_BINLOG
+ nla "Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log"
+ eng "Got fatal error %d from master when reading data from binary log: '%-.128s'"
+ ger "Schwerer Fehler %d: '%-.128s vom Master beim Lesen des binären Logs"
+ ita "Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario"
+ por "Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log"
+ rus "Получена неиÑÐ¿Ñ€Ð°Ð²Ð¸Ð¼Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° %d: '%-.128s' от головного Ñервера в процеÑÑе выборки данных из двоичного журнала"
+ spa "Recibió fatal error %d: '%-.128s' del master cuando leyendo datos del binary log"
+ swe "Fick fatalt fel %d: '%-.128s' från master vid läsning av binärloggen"
+ER_SLAVE_IGNORED_TABLE
+ eng "Slave SQL thread ignored the query because of replicate-*-table rules"
+ ger "Slave-SQL-Thread hat die Abfrage aufgrund von replicate-*-table-Regeln ignoriert"
+ nla "Slave SQL thread negeerde de query vanwege replicate-*-table opties"
+ por "Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela"
+ spa "Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla"
+ swe "Slav SQL tråden ignorerade frågan pga en replicate-*-table regel"
+ER_INCORRECT_GLOBAL_LOCAL_VAR
+ eng "Variable '%-.192s' is a %s variable"
+ serbian "Promenljiva '%-.192s' je %s promenljiva"
+ ger "Variable '%-.192s' ist eine %s-Variable"
+ nla "Variabele '%-.192s' is geen %s variabele"
+ spa "Variable '%-.192s' es una %s variable"
+ swe "Variabel '%-.192s' är av typ %s"
+ER_WRONG_FK_DEF 42000
+ eng "Incorrect foreign key definition for '%-.192s': %s"
+ ger "Falsche Fremdschlüssel-Definition für '%-.192s': %s"
+ nla "Incorrecte foreign key definitie voor '%-.192s': %s"
+ por "Definição errada da chave estrangeira para '%-.192s': %s"
+ spa "Equivocada definición de llave extranjera para '%-.192s': %s"
+ swe "Felaktig FOREIGN KEY-definition för '%-.192s': %s"
+ER_KEY_REF_DO_NOT_MATCH_TABLE_REF
+ eng "Key reference and table reference don't match"
+ ger "Schlüssel- und Tabellenverweis passen nicht zusammen"
+ nla "Sleutel- en tabelreferentie komen niet overeen"
+ por "Referência da chave e referência da tabela não coincidem"
+ spa "Referencia de llave y referencia de tabla no coinciden"
+ swe "Nyckelreferensen och tabellreferensen stämmer inte överens"
+ER_OPERAND_COLUMNS 21000
+ eng "Operand should contain %d column(s)"
+ ger "Operand sollte %d Spalte(n) enthalten"
+ nla "Operand behoort %d kolommen te bevatten"
+ rus "Операнд должен Ñодержать %d колонок"
+ spa "Operando debe tener %d columna(s)"
+ ukr "Операнд має ÑкладатиÑÑ Ð· %d Ñтовбців"
+ER_SUBQUERY_NO_1_ROW 21000
+ eng "Subquery returns more than 1 row"
+ ger "Unterabfrage lieferte mehr als einen Datensatz zurück"
+ nla "Subquery retourneert meer dan 1 rij"
+ por "Subconsulta retorna mais que 1 registro"
+ rus "ÐŸÐ¾Ð´Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰Ð°ÐµÑ‚ более одной запиÑи"
+ spa "Subconsulta retorna mas que 1 línea"
+ swe "Subquery returnerade mer än 1 rad"
+ ukr "Підзапит повертає більш нiж 1 запиÑ"
+ER_UNKNOWN_STMT_HANDLER
+ dan "Unknown prepared statement handler (%.*s) given to %s"
+ eng "Unknown prepared statement handler (%.*s) given to %s"
+ ger "Unbekannter Prepared-Statement-Handler (%.*s) für %s angegeben"
+ nla "Onebekende prepared statement handler (%.*s) voor %s aangegeven"
+ por "Desconhecido manipulador de declaração preparado (%.*s) determinado para %s"
+ spa "Desconocido preparado comando handler (%.*s) dado para %s"
+ swe "Okänd PREPARED STATEMENT id (%.*s) var given till %s"
+ ukr "Unknown prepared statement handler (%.*s) given to %s"
+ER_CORRUPT_HELP_DB
+ eng "Help database is corrupt or does not exist"
+ ger "Die Hilfe-Datenbank ist beschädigt oder existiert nicht"
+ nla "Help database is beschadigd of bestaat niet"
+ por "Banco de dado de ajuda corrupto ou não existente"
+ spa "Base de datos Help está corrupto o no existe"
+ swe "Hjälpdatabasen finns inte eller är skadad"
+ER_CYCLIC_REFERENCE
+ eng "Cyclic reference on subqueries"
+ ger "Zyklischer Verweis in Unterabfragen"
+ nla "Cyclische verwijzing in subqueries"
+ por "Referência cíclica em subconsultas"
+ rus "ЦикличеÑÐºÐ°Ñ ÑÑылка на подзапроÑ"
+ spa "Cíclica referencia en subconsultas"
+ swe "Cyklisk referens i subqueries"
+ ukr "Циклічне поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° підзапит"
+ER_AUTO_CONVERT
+ eng "Converting column '%s' from %s to %s"
+ ger "Feld '%s' wird von %s nach %s umgewandelt"
+ nla "Veld '%s' wordt van %s naar %s geconverteerd"
+ por "Convertendo coluna '%s' de %s para %s"
+ rus "Преобразование Ð¿Ð¾Ð»Ñ '%s' из %s в %s"
+ spa "Convirtiendo columna '%s' de %s para %s"
+ swe "Konvertar kolumn '%s' från %s till %s"
+ ukr "ÐŸÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñтовбца '%s' з %s у %s"
+ER_ILLEGAL_REFERENCE 42S22
+ eng "Reference '%-.64s' not supported (%s)"
+ ger "Verweis '%-.64s' wird nicht unterstützt (%s)"
+ nla "Verwijzing '%-.64s' niet ondersteund (%s)"
+ por "Referência '%-.64s' não suportada (%s)"
+ rus "СÑылка '%-.64s' не поддерживаетÑÑ (%s)"
+ spa "Referencia '%-.64s' no soportada (%s)"
+ swe "Referens '%-.64s' stöds inte (%s)"
+ ukr "ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ '%-.64s' не пiдтримуетÑÑ (%s)"
+ER_DERIVED_MUST_HAVE_ALIAS 42000
+ eng "Every derived table must have its own alias"
+ ger "Für jede abgeleitete Tabelle muss ein eigener Alias angegeben werden"
+ nla "Voor elke afgeleide tabel moet een unieke alias worden gebruikt"
+ por "Cada tabela derivada deve ter seu próprio alias"
+ spa "Cada tabla derivada debe tener su propio alias"
+ swe "Varje 'derived table' måste ha sitt eget alias"
+ER_SELECT_REDUCED 01000
+ eng "Select %u was reduced during optimization"
+ ger "Select %u wurde während der Optimierung reduziert"
+ nla "Select %u werd geredureerd tijdens optimtalisatie"
+ por "Select %u foi reduzido durante otimização"
+ rus "Select %u был упразднен в процеÑÑе оптимизации"
+ spa "Select %u fué reducido durante optimización"
+ swe "Select %u reducerades vid optimiering"
+ ukr "Select %u was ÑкаÑовано при оптимiзацii"
+ER_TABLENAME_NOT_ALLOWED_HERE 42000
+ eng "Table '%-.192s' from one of the SELECTs cannot be used in %-.32s"
+ ger "Tabelle '%-.192s', die in einem der SELECT-Befehle verwendet wurde, kann nicht in %-.32s verwendet werden"
+ nla "Tabel '%-.192s' uit een van de SELECTS kan niet in %-.32s gebruikt worden"
+ por "Tabela '%-.192s' de um dos SELECTs não pode ser usada em %-.32s"
+ spa "Tabla '%-.192s' de uno de los SELECT no puede ser usada en %-.32s"
+ swe "Tabell '%-.192s' från en SELECT kan inte användas i %-.32s"
+ER_NOT_SUPPORTED_AUTH_MODE 08004
+ eng "Client does not support authentication protocol requested by server; consider upgrading MySQL client"
+ ger "Client unterstützt das vom Server erwartete Authentifizierungsprotokoll nicht. Bitte aktualisieren Sie Ihren MySQL-Client"
+ nla "Client ondersteunt het door de server verwachtte authenticatieprotocol niet. Overweeg een nieuwere MySQL client te gebruiken"
+ por "Cliente não suporta o protocolo de autenticação exigido pelo servidor; considere a atualização do cliente MySQL"
+ spa "Cliente no soporta protocolo de autenticación solicitado por el servidor; considere actualizar el cliente MySQL"
+ swe "Klienten stöder inte autentiseringsprotokollet som begärts av servern; överväg uppgradering av klientprogrammet."
+ER_SPATIAL_CANT_HAVE_NULL 42000
+ eng "All parts of a SPATIAL index must be NOT NULL"
+ ger "Alle Teile eines SPATIAL-Index müssen als NOT NULL deklariert sein"
+ nla "Alle delete van een SPATIAL index dienen als NOT NULL gedeclareerd te worden"
+ por "Todas as partes de uma SPATIAL index devem ser NOT NULL"
+ spa "Todas las partes de una SPATIAL index deben ser NOT NULL"
+ swe "Alla delar av en SPATIAL index måste vara NOT NULL"
+ER_COLLATION_CHARSET_MISMATCH 42000
+ eng "COLLATION '%s' is not valid for CHARACTER SET '%s'"
+ ger "COLLATION '%s' ist für CHARACTER SET '%s' ungültig"
+ nla "COLLATION '%s' is niet geldig voor CHARACTER SET '%s'"
+ por "COLLATION '%s' não é válida para CHARACTER SET '%s'"
+ spa "COLLATION '%s' no es válido para CHARACTER SET '%s'"
+ swe "COLLATION '%s' är inte tillåtet för CHARACTER SET '%s'"
+ER_SLAVE_WAS_RUNNING
+ eng "Slave is already running"
+ ger "Slave läuft bereits"
+ nla "Slave is reeds actief"
+ por "O slave já está rodando"
+ spa "Slave ya está funcionando"
+ swe "Slaven har redan startat"
+ER_SLAVE_WAS_NOT_RUNNING
+ eng "Slave already has been stopped"
+ ger "Slave wurde bereits angehalten"
+ nla "Slave is reeds gestopt"
+ por "O slave já está parado"
+ spa "Slave ya fué parado"
+ swe "Slaven har redan stoppat"
+ER_TOO_BIG_FOR_UNCOMPRESS
+ eng "Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)"
+ ger "Unkomprimierte Daten sind zu groß. Die maximale Größe beträgt %d (wahrscheinlich wurde die Länge der unkomprimierten Daten beschädigt)"
+ nla "Ongecomprimeerder data is te groot; de maximum lengte is %d (waarschijnlijk, de lengte van de gecomprimeerde data was beschadigd)"
+ por "Tamanho muito grande dos dados des comprimidos. O máximo tamanho é %d. (provavelmente, o comprimento dos dados descomprimidos está corrupto)"
+ spa "Tamaño demasiado grande para datos descomprimidos. El máximo tamaño es %d. (probablemente, extensión de datos descomprimidos fué corrompida)"
+ER_ZLIB_Z_MEM_ERROR
+ eng "ZLIB: Not enough memory"
+ ger "ZLIB: Nicht genug Speicher"
+ nla "ZLIB: Onvoldoende geheugen"
+ por "ZLIB: Não suficiente memória disponível"
+ spa "Z_MEM_ERROR: No suficiente memoria para zlib"
+ER_ZLIB_Z_BUF_ERROR
+ eng "ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)"
+ ger "ZLIB: Im Ausgabepuffer ist nicht genug Platz vorhanden (wahrscheinlich wurde die Länge der unkomprimierten Daten beschädigt)"
+ nla "ZLIB: Onvoldoende ruimte in uitgaande buffer (waarschijnlijk, de lengte van de ongecomprimeerde data was beschadigd)"
+ por "ZLIB: Não suficiente espaço no buffer emissor (provavelmente, o comprimento dos dados descomprimidos está corrupto)"
+ spa "Z_BUF_ERROR: No suficiente espacio en el búfer de salida para zlib (probablemente, extensión de datos descomprimidos fué corrompida)"
+ER_ZLIB_Z_DATA_ERROR
+ eng "ZLIB: Input data corrupted"
+ ger "ZLIB: Eingabedaten beschädigt"
+ nla "ZLIB: Invoer data beschadigd"
+ por "ZLIB: Dados de entrada está corrupto"
+ spa "ZLIB: Dato de entrada fué corrompido para zlib"
+ER_CUT_VALUE_GROUP_CONCAT
+ eng "Row %u was cut by GROUP_CONCAT()"
+ER_WARN_TOO_FEW_RECORDS 01000
+ eng "Row %ld doesn't contain data for all columns"
+ ger "Zeile %ld enthält nicht für alle Felder Daten"
+ nla "Rij %ld bevat niet de data voor alle kolommen"
+ por "Conta de registro é menor que a conta de coluna na linha %ld"
+ spa "Línea %ld no contiene datos para todas las columnas"
+ER_WARN_TOO_MANY_RECORDS 01000
+ eng "Row %ld was truncated; it contained more data than there were input columns"
+ ger "Zeile %ld gekürzt, die Zeile enthielt mehr Daten, als es Eingabefelder gibt"
+ nla "Regel %ld ingekort, bevatte meer data dan invoer kolommen"
+ por "Conta de registro é maior que a conta de coluna na linha %ld"
+ spa "Línea %ld fué truncada; La misma contine mas datos que las que existen en las columnas de entrada"
+ER_WARN_NULL_TO_NOTNULL 22004
+ eng "Column set to default value; NULL supplied to NOT NULL column '%s' at row %ld"
+ ger "Feld auf Vorgabewert gesetzt, da NULL für NOT-NULL-Feld '%s' in Zeile %ld angegeben"
+ por "Dado truncado, NULL fornecido para NOT NULL coluna '%s' na linha %ld"
+ spa "Datos truncado, NULL suministrado para NOT NULL columna '%s' en la línea %ld"
+ER_WARN_DATA_OUT_OF_RANGE 22003
+ eng "Out of range value for column '%s' at row %ld"
+WARN_DATA_TRUNCATED 01000
+ eng "Data truncated for column '%s' at row %ld"
+ ger "Daten abgeschnitten für Feld '%s' in Zeile %ld"
+ por "Dado truncado para coluna '%s' na linha %ld"
+ spa "Datos truncados para columna '%s' en la línea %ld"
+ER_WARN_USING_OTHER_HANDLER
+ eng "Using storage engine %s for table '%s'"
+ ger "Für Tabelle '%s' wird Speicher-Engine %s benutzt"
+ por "Usando engine de armazenamento %s para tabela '%s'"
+ spa "Usando motor de almacenamiento %s para tabla '%s'"
+ swe "Använder handler %s för tabell '%s'"
+ER_CANT_AGGREGATE_2COLLATIONS
+ eng "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'"
+ ger "Unerlaubte Mischung von Sortierreihenfolgen (%s, %s) und (%s, %s) für Operation '%s'"
+ por "Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'"
+ spa "Ilegal mezcla de collations (%s,%s) y (%s,%s) para operación '%s'"
+ER_DROP_USER
+ eng "Cannot drop one or more of the requested users"
+ ger "Kann einen oder mehrere der angegebenen Benutzer nicht löschen"
+ER_REVOKE_GRANTS
+ eng "Can't revoke all privileges for one or more of the requested users"
+ ger "Kann nicht alle Berechtigungen widerrufen, die für einen oder mehrere Benutzer gewährt wurden"
+ por "Não pode revocar todos os privilégios, grant para um ou mais dos usuários pedidos"
+ spa "No puede revocar todos los privilegios, derecho para uno o mas de los usuarios solicitados"
+ER_CANT_AGGREGATE_3COLLATIONS
+ eng "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'"
+ ger "Unerlaubte Mischung von Sortierreihenfolgen (%s, %s), (%s, %s), (%s, %s) für Operation '%s'"
+ por "Ilegal combinação de collations (%s,%s), (%s,%s), (%s,%s) para operação '%s'"
+ spa "Ilegal mezcla de collations (%s,%s), (%s,%s), (%s,%s) para operación '%s'"
+ER_CANT_AGGREGATE_NCOLLATIONS
+ eng "Illegal mix of collations for operation '%s'"
+ ger "Unerlaubte Mischung von Sortierreihenfolgen für Operation '%s'"
+ por "Ilegal combinação de collations para operação '%s'"
+ spa "Ilegal mezcla de collations para operación '%s'"
+ER_VARIABLE_IS_NOT_STRUCT
+ eng "Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)"
+ ger "Variable '%-.64s' ist keine Variablen-Komponente (kann nicht als XXXX.variablen_name verwendet werden)"
+ por "Variável '%-.64s' não é uma variável componente (Não pode ser usada como XXXX.variável_nome)"
+ spa "Variable '%-.64s' no es una variable componente (No puede ser usada como XXXX.variable_name)"
+ER_UNKNOWN_COLLATION
+ eng "Unknown collation: '%-.64s'"
+ ger "Unbekannte Sortierreihenfolge: '%-.64s'"
+ por "Collation desconhecida: '%-.64s'"
+ spa "Collation desconocida: '%-.64s'"
+ER_SLAVE_IGNORED_SSL_PARAMS
+ eng "SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started"
+ ger "SSL-Parameter in CHANGE MASTER werden ignoriert, weil dieser MySQL-Slave ohne SSL-Unterstützung kompiliert wurde. Sie können aber später verwendet werden, wenn ein MySQL-Slave mit SSL gestartet wird"
+ por "SSL parâmetros em CHANGE MASTER são ignorados porque este escravo MySQL foi compilado sem o SSL suporte. Os mesmos podem ser usados mais tarde quando o escravo MySQL com SSL seja iniciado."
+ spa "Parametros SSL en CHANGE MASTER son ignorados porque este slave MySQL fue compilado sin soporte SSL; pueden ser usados despues cuando el slave MySQL con SSL sea inicializado"
+ER_SERVER_IS_IN_SECURE_AUTH_MODE
+ eng "Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format"
+ ger "Server läuft im Modus --secure-auth, aber '%s'@'%s' hat ein Passwort im alten Format. Bitte Passwort ins neue Format ändern"
+ por "Servidor está rodando em --secure-auth modo, porêm '%s'@'%s' tem senha no formato antigo; por favor troque a senha para o novo formato"
+ rus "Сервер запущен в режиме --secure-auth (безопаÑной авторизации), но Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ '%s'@'%s' пароль Ñохранён в Ñтаром формате; необходимо обновить формат паролÑ"
+ spa "Servidor está rodando en modo --secure-auth, pero '%s'@'%s' tiene clave en el antiguo formato; por favor cambie la clave para el nuevo formato"
+ER_WARN_FIELD_RESOLVED
+ eng "Field or reference '%-.192s%s%-.192s%s%-.192s' of SELECT #%d was resolved in SELECT #%d"
+ ger "Feld oder Verweis '%-.192s%s%-.192s%s%-.192s' im SELECT-Befehl Nr. %d wurde im SELECT-Befehl Nr. %d aufgelöst"
+ por "Campo ou referência '%-.192s%s%-.192s%s%-.192s' de SELECT #%d foi resolvido em SELECT #%d"
+ rus "Поле или ÑÑылка '%-.192s%s%-.192s%s%-.192s' из SELECTа #%d была найдена в SELECTе #%d"
+ spa "Campo o referencia '%-.192s%s%-.192s%s%-.192s' de SELECT #%d fue resolvido en SELECT #%d"
+ ukr "Стовбець або поÑÐ¸Ð»Ð°Ð½Ð½Ñ '%-.192s%s%-.192s%s%-.192s' із SELECTу #%d було знайдене у SELECTÑ– #%d"
+ER_BAD_SLAVE_UNTIL_COND
+ eng "Incorrect parameter or combination of parameters for START SLAVE UNTIL"
+ ger "Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL"
+ por "Parâmetro ou combinação de parâmetros errado para START SLAVE UNTIL"
+ spa "Parametro equivocado o combinación de parametros para START SLAVE UNTIL"
+ER_MISSING_SKIP_SLAVE
+ eng "It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you will get problems if you get an unexpected slave's mysqld restart"
+ ger "Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn ein Slave-Server unerwartet neu startet"
+ por "É recomendado para rodar com --skip-slave-start quando fazendo replicação passo-por-passo com START SLAVE UNTIL, de outra forma você não está seguro em caso de inesperada reinicialição do mysqld escravo"
+ spa "Es recomendado rodar con --skip-slave-start cuando haciendo replicación step-by-step con START SLAVE UNTIL, a menos que usted no esté seguro en caso de inesperada reinicialización del mysqld slave"
+ER_UNTIL_COND_IGNORED
+ eng "SQL thread is not to be started so UNTIL options are ignored"
+ ger "SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert"
+ por "Thread SQL não pode ser inicializado tal que opções UNTIL são ignoradas"
+ spa "SQL thread no es inicializado tal que opciones UNTIL son ignoradas"
+ER_WRONG_NAME_FOR_INDEX 42000
+ eng "Incorrect index name '%-.100s'"
+ ger "Falscher Indexname '%-.100s'"
+ por "Incorreto nome de índice '%-.100s'"
+ spa "Nombre de índice incorrecto '%-.100s'"
+ swe "Felaktigt index namn '%-.100s'"
+ER_WRONG_NAME_FOR_CATALOG 42000
+ eng "Incorrect catalog name '%-.100s'"
+ ger "Falscher Katalogname '%-.100s'"
+ por "Incorreto nome de catálogo '%-.100s'"
+ spa "Nombre de catalog incorrecto '%-.100s'"
+ swe "Felaktigt katalog namn '%-.100s'"
+ER_WARN_QC_RESIZE
+ eng "Query cache failed to set size %lu; new query cache size is %lu"
+ ger "Änderung der Query-Cache-Größe auf %lu fehlgeschlagen; neue Query-Cache-Größe ist %lu"
+ por "Falha em Query cache para configurar tamanho %lu, novo tamanho de query cache é %lu"
+ rus "Кеш запроÑов не может уÑтановить размер %lu, новый размер кеша зпроÑов - %lu"
+ spa "Query cache fallada para configurar tamaño %lu, nuevo tamaño de query cache es %lu"
+ swe "Storleken av "Query cache" kunde inte sättas till %lu, ny storlek är %lu"
+ ukr "Кеш запитів неÑпроможен вÑтановити розмір %lu, новий розмір кеша запитів - %lu"
+ER_BAD_FT_COLUMN
+ eng "Column '%-.192s' cannot be part of FULLTEXT index"
+ ger "Feld '%-.192s' kann nicht Teil eines FULLTEXT-Index sein"
+ por "Coluna '%-.192s' não pode ser parte de índice FULLTEXT"
+ spa "Columna '%-.192s' no puede ser parte de FULLTEXT index"
+ swe "Kolumn '%-.192s' kan inte vara del av ett FULLTEXT index"
+ER_UNKNOWN_KEY_CACHE
+ eng "Unknown key cache '%-.100s'"
+ ger "Unbekannter Schlüssel-Cache '%-.100s'"
+ por "Key cache desconhecida '%-.100s'"
+ spa "Desconocida key cache '%-.100s'"
+ swe "Okänd nyckel cache '%-.100s'"
+ER_WARN_HOSTNAME_WONT_WORK
+ eng "MySQL is started in --skip-name-resolve mode; you must restart it without this switch for this grant to work"
+ ger "MySQL wurde mit --skip-name-resolve gestartet. Diese Option darf nicht verwendet werden, damit diese Rechtevergabe möglich ist"
+ por "MySQL foi inicializado em modo --skip-name-resolve. Você necesita reincializá-lo sem esta opção para este grant funcionar"
+ spa "MySQL esta inicializado en modo --skip-name-resolve. Usted necesita reinicializarlo sin esta opción para este derecho funcionar"
+ER_UNKNOWN_STORAGE_ENGINE 42000
+ eng "Unknown storage engine '%s'"
+ ger "Unbekannte Speicher-Engine '%s'"
+ por "Motor de tabela desconhecido '%s'"
+ spa "Desconocido motor de tabla '%s'"
+ER_WARN_DEPRECATED_SYNTAX
+ eng "'%s' is deprecated and will be removed in a future release. Please use %s instead"
+ ger "'%s' ist veraltet. Bitte benutzen Sie '%s'"
+ por "'%s' é desatualizado. Use '%s' em seu lugar"
+ spa "'%s' está desaprobado, use '%s' en su lugar"
+ER_NON_UPDATABLE_TABLE
+ eng "The target table %-.100s of the %s is not updatable"
+ ger "Die Zieltabelle %-.100s von %s ist nicht aktualisierbar"
+ por "A tabela destino %-.100s do %s não é atualizável"
+ rus "Таблица %-.100s в %s не может изменÑÑ‚ÑÑ"
+ spa "La tabla destino %-.100s del %s no es actualizable"
+ swe "Tabell %-.100s använd med '%s' är inte uppdateringsbar"
+ ukr "Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ %-.100s у %s не може оновлюватиÑÑŒ"
+ER_FEATURE_DISABLED
+ eng "The '%s' feature is disabled; you need MySQL built with '%s' to have it working"
+ ger "Das Feature '%s' ist ausgeschaltet, Sie müssen MySQL mit '%s' übersetzen, damit es verfügbar ist"
+ por "O recurso '%s' foi desativado; você necessita MySQL construído com '%s' para ter isto funcionando"
+ spa "El recurso '%s' fue deshabilitado; usted necesita construir MySQL con '%s' para tener eso funcionando"
+ swe "'%s' är inte aktiverad; För att aktivera detta måste du bygga om MySQL med '%s' definerad"
+ER_OPTION_PREVENTS_STATEMENT
+ eng "The MySQL server is running with the %s option so it cannot execute this statement"
+ ger "Der MySQL-Server läuft mit der Option %s und kann diese Anweisung deswegen nicht ausführen"
+ por "O servidor MySQL está rodando com a opção %s razão pela qual não pode executar esse commando"
+ spa "El servidor MySQL está rodando con la opción %s tal que no puede ejecutar este comando"
+ swe "MySQL är startad med %s. Pga av detta kan du inte använda detta kommando"
+ER_DUPLICATED_VALUE_IN_TYPE
+ eng "Column '%-.100s' has duplicated value '%-.64s' in %s"
+ ger "Feld '%-.100s' hat doppelten Wert '%-.64s' in %s"
+ por "Coluna '%-.100s' tem valor duplicado '%-.64s' em %s"
+ spa "Columna '%-.100s' tiene valor doblado '%-.64s' en %s"
+ER_TRUNCATED_WRONG_VALUE 22007
+ eng "Truncated incorrect %-.32s value: '%-.128s'"
+ ger "Falscher %-.32s-Wert gekürzt: '%-.128s'"
+ por "Truncado errado %-.32s valor: '%-.128s'"
+ spa "Equivocado truncado %-.32s valor: '%-.128s'"
+ER_TOO_MUCH_AUTO_TIMESTAMP_COLS
+ eng "Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
+ ger "Fehlerhafte Tabellendefinition. Es kann nur eine einzige TIMESTAMP-Spalte mit CURRENT_TIMESTAMP als DEFAULT oder in einer ON-UPDATE-Klausel geben"
+ por "Incorreta definição de tabela; Pode ter somente uma coluna TIMESTAMP com CURRENT_TIMESTAMP em DEFAULT ou ON UPDATE cláusula"
+ spa "Incorrecta definición de tabla; Solamente debe haber una columna TIMESTAMP con CURRENT_TIMESTAMP en DEFAULT o ON UPDATE cláusula"
+ER_INVALID_ON_UPDATE
+ eng "Invalid ON UPDATE clause for '%-.192s' column"
+ ger "Ungültige ON-UPDATE-Klausel für Spalte '%-.192s'"
+ por "Inválida cláusula ON UPDATE para campo '%-.192s'"
+ spa "Inválido ON UPDATE cláusula para campo '%-.192s'"
+ER_UNSUPPORTED_PS
+ eng "This command is not supported in the prepared statement protocol yet"
+ ger "Dieser Befehl wird im Protokoll für vorbereitete Anweisungen noch nicht unterstützt"
+ER_GET_ERRMSG
+ dan "Modtog fejl %d '%-.100s' fra %s"
+ eng "Got error %d '%-.100s' from %s"
+ ger "Fehler %d '%-.100s' von %s"
+ nor "Mottok feil %d '%-.100s' fa %s"
+ norwegian-ny "Mottok feil %d '%-.100s' fra %s"
+ER_GET_TEMPORARY_ERRMSG
+ dan "Modtog temporary fejl %d '%-.100s' fra %s"
+ eng "Got temporary error %d '%-.100s' from %s"
+ ger "Temporärer Fehler %d '%-.100s' von %s"
+ nor "Mottok temporary feil %d '%-.100s' fra %s"
+ norwegian-ny "Mottok temporary feil %d '%-.100s' fra %s"
+ER_UNKNOWN_TIME_ZONE
+ eng "Unknown or incorrect time zone: '%-.64s'"
+ ger "Unbekannte oder falsche Zeitzone: '%-.64s'"
+ER_WARN_INVALID_TIMESTAMP
+ eng "Invalid TIMESTAMP value in column '%s' at row %ld"
+ ger "Ungültiger TIMESTAMP-Wert in Feld '%s', Zeile %ld"
+ER_INVALID_CHARACTER_STRING
+ eng "Invalid %s character string: '%.64s'"
+ ger "Ungültiger %s-Zeichen-String: '%.64s'"
+ER_WARN_ALLOWED_PACKET_OVERFLOWED
+ eng "Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+ ger "Ergebnis von %s() war größer als max_allowed_packet (%ld) Bytes und wurde deshalb gekürzt"
+ER_CONFLICTING_DECLARATIONS
+ eng "Conflicting declarations: '%s%s' and '%s%s'"
+ ger "Widersprüchliche Deklarationen: '%s%s' und '%s%s'"
+ER_SP_NO_RECURSIVE_CREATE 2F003
+ eng "Can't create a %s from within another stored routine"
+ ger "Kann kein %s innerhalb einer anderen gespeicherten Routine erzeugen"
+ER_SP_ALREADY_EXISTS 42000
+ eng "%s %s already exists"
+ ger "%s %s existiert bereits"
+ER_SP_DOES_NOT_EXIST 42000
+ eng "%s %s does not exist"
+ ger "%s %s existiert nicht"
+ER_SP_DROP_FAILED
+ eng "Failed to DROP %s %s"
+ ger "DROP %s %s ist fehlgeschlagen"
+ER_SP_STORE_FAILED
+ eng "Failed to CREATE %s %s"
+ ger "CREATE %s %s ist fehlgeschlagen"
+ER_SP_LILABEL_MISMATCH 42000
+ eng "%s with no matching label: %s"
+ ger "%s ohne passende Marke: %s"
+ER_SP_LABEL_REDEFINE 42000
+ eng "Redefining label %s"
+ ger "Neudefinition der Marke %s"
+ER_SP_LABEL_MISMATCH 42000
+ eng "End-label %s without match"
+ ger "Ende-Marke %s ohne zugehörigen Anfang"
+ER_SP_UNINIT_VAR 01000
+ eng "Referring to uninitialized variable %s"
+ ger "Zugriff auf nichtinitialisierte Variable %s"
+ER_SP_BADSELECT 0A000
+ eng "PROCEDURE %s can't return a result set in the given context"
+ ger "PROCEDURE %s kann im gegebenen Kontext keine Ergebnismenge zurückgeben"
+ER_SP_BADRETURN 42000
+ eng "RETURN is only allowed in a FUNCTION"
+ ger "RETURN ist nur innerhalb einer FUNCTION erlaubt"
+ER_SP_BADSTATEMENT 0A000
+ eng "%s is not allowed in stored procedures"
+ ger "%s ist in gespeicherten Prozeduren nicht erlaubt"
+ER_UPDATE_LOG_DEPRECATED_IGNORED 42000
+ eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored. This option will be removed in MySQL 5.6."
+ ger "Das Update-Log ist veraltet und wurde durch das Binär-Log ersetzt. SET SQL_LOG_UPDATE wird ignoriert. Diese Option wird in MySQL 5.6 entfernt."
+ER_UPDATE_LOG_DEPRECATED_TRANSLATED 42000
+ eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN. This option will be removed in MySQL 5.6."
+ ger "Das Update-Log ist veraltet und wurde durch das Binär-Log ersetzt. SET SQL_LOG_UPDATE wurde in SET SQL_LOG_BIN übersetzt. Diese Option wird in MySQL 5.6 entfernt."
+ER_QUERY_INTERRUPTED 70100
+ eng "Query execution was interrupted"
+ ger "Ausführung der Abfrage wurde unterbrochen"
+ER_SP_WRONG_NO_OF_ARGS 42000
+ eng "Incorrect number of arguments for %s %s; expected %u, got %u"
+ ger "Falsche Anzahl von Argumenten für %s %s; erwarte %u, erhalte %u"
+ER_SP_COND_MISMATCH 42000
+ eng "Undefined CONDITION: %s"
+ ger "Undefinierte CONDITION: %s"
+ER_SP_NORETURN 42000
+ eng "No RETURN found in FUNCTION %s"
+ ger "Kein RETURN in FUNCTION %s gefunden"
+ER_SP_NORETURNEND 2F005
+ eng "FUNCTION %s ended without RETURN"
+ ger "FUNCTION %s endete ohne RETURN"
+ER_SP_BAD_CURSOR_QUERY 42000
+ eng "Cursor statement must be a SELECT"
+ ger "Cursor-Anweisung muss ein SELECT sein"
+ER_SP_BAD_CURSOR_SELECT 42000
+ eng "Cursor SELECT must not have INTO"
+ ger "Cursor-SELECT darf kein INTO haben"
+ER_SP_CURSOR_MISMATCH 42000
+ eng "Undefined CURSOR: %s"
+ ger "Undefinierter CURSOR: %s"
+ER_SP_CURSOR_ALREADY_OPEN 24000
+ eng "Cursor is already open"
+ ger "Cursor ist schon geöffnet"
+ER_SP_CURSOR_NOT_OPEN 24000
+ eng "Cursor is not open"
+ ger "Cursor ist nicht geöffnet"
+ER_SP_UNDECLARED_VAR 42000
+ eng "Undeclared variable: %s"
+ ger "Nicht deklarierte Variable: %s"
+ER_SP_WRONG_NO_OF_FETCH_ARGS
+ eng "Incorrect number of FETCH variables"
+ ger "Falsche Anzahl von FETCH-Variablen"
+ER_SP_FETCH_NO_DATA 02000
+ eng "No data - zero rows fetched, selected, or processed"
+ ger "Keine Daten - null Zeilen geholt (fetch), ausgewählt oder verarbeitet"
+ER_SP_DUP_PARAM 42000
+ eng "Duplicate parameter: %s"
+ ger "Doppelter Parameter: %s"
+ER_SP_DUP_VAR 42000
+ eng "Duplicate variable: %s"
+ ger "Doppelte Variable: %s"
+ER_SP_DUP_COND 42000
+ eng "Duplicate condition: %s"
+ ger "Doppelte Bedingung: %s"
+ER_SP_DUP_CURS 42000
+ eng "Duplicate cursor: %s"
+ ger "Doppelter Cursor: %s"
+ER_SP_CANT_ALTER
+ eng "Failed to ALTER %s %s"
+ ger "ALTER %s %s fehlgeschlagen"
+ER_SP_SUBSELECT_NYI 0A000
+ eng "Subquery value not supported"
+ ger "Subquery-Wert wird nicht unterstützt"
+ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 0A000
+ eng "%s is not allowed in stored function or trigger"
+ ger "%s ist in gespeicherten Funktionen und in Triggern nicht erlaubt"
+ER_SP_VARCOND_AFTER_CURSHNDLR 42000
+ eng "Variable or condition declaration after cursor or handler declaration"
+ ger "Deklaration einer Variablen oder einer Bedingung nach der Deklaration eines Cursors oder eines Handlers"
+ER_SP_CURSOR_AFTER_HANDLER 42000
+ eng "Cursor declaration after handler declaration"
+ ger "Deklaration eines Cursors nach der Deklaration eines Handlers"
+ER_SP_CASE_NOT_FOUND 20000
+ eng "Case not found for CASE statement"
+ ger "Fall für CASE-Anweisung nicht gefunden"
+ER_FPARSER_TOO_BIG_FILE
+ eng "Configuration file '%-.192s' is too big"
+ ger "Konfigurationsdatei '%-.192s' ist zu groß"
+ rus "Слишком большой конфигурационный файл '%-.192s'"
+ ukr "Занадто великий конфігураційний файл '%-.192s'"
+ER_FPARSER_BAD_HEADER
+ eng "Malformed file type header in file '%-.192s'"
+ ger "Nicht wohlgeformter Dateityp-Header in Datei '%-.192s'"
+ rus "Ðеверный заголовок типа файла '%-.192s'"
+ ukr "Ðевірний заголовок типу у файлі '%-.192s'"
+ER_FPARSER_EOF_IN_COMMENT
+ eng "Unexpected end of file while parsing comment '%-.200s'"
+ ger "Unerwartetes Dateiende beim Parsen des Kommentars '%-.200s'"
+ rus "Ðеожиданный конец файла в коментарии '%-.200s'"
+ ukr "ÐеÑподіванний кінець файлу у коментарі '%-.200s'"
+ER_FPARSER_ERROR_IN_PARAMETER
+ eng "Error while parsing parameter '%-.192s' (line: '%-.192s')"
+ ger "Fehler beim Parsen des Parameters '%-.192s' (Zeile: '%-.192s')"
+ rus "Ошибка при раÑпознавании параметра '%-.192s' (Ñтрока: '%-.192s')"
+ ukr "Помилка в роÑпізнаванні параметру '%-.192s' (Ñ€Ñдок: '%-.192s')"
+ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER
+ eng "Unexpected end of file while skipping unknown parameter '%-.192s'"
+ ger "Unerwartetes Dateiende beim Ãœberspringen des unbekannten Parameters '%-.192s'"
+ rus "Ðеожиданный конец файла при пропуÑке неизвеÑтного параметра '%-.192s'"
+ ukr "ÐеÑподіванний кінець файлу у Ñпробі проминути невідомий параметр '%-.192s'"
+ER_VIEW_NO_EXPLAIN
+ eng "EXPLAIN/SHOW can not be issued; lacking privileges for underlying table"
+ ger "EXPLAIN/SHOW kann nicht verlangt werden. Rechte für zugrunde liegende Tabelle fehlen"
+ rus "EXPLAIN/SHOW не может быть выполненно; недоÑтаточно прав на такблицы запроÑа"
+ ukr "EXPLAIN/SHOW не може бути віконано; немає прав на тиблиці запиту"
+ER_FRM_UNKNOWN_TYPE
+ eng "File '%-.192s' has unknown type '%-.64s' in its header"
+ ger "Datei '%-.192s' hat unbekannten Typ '%-.64s' im Header"
+ rus "Файл '%-.192s' Ñодержит неизвеÑтный тип '%-.64s' в заголовке"
+ ukr "Файл '%-.192s' має невідомий тип '%-.64s' у заголовку"
+ER_WRONG_OBJECT
+ eng "'%-.192s.%-.192s' is not %s"
+ ger "'%-.192s.%-.192s' ist nicht %s"
+ rus "'%-.192s.%-.192s' - не %s"
+ ukr "'%-.192s.%-.192s' не є %s"
+ER_NONUPDATEABLE_COLUMN
+ eng "Column '%-.192s' is not updatable"
+ ger "Feld '%-.192s' ist nicht aktualisierbar"
+ rus "Столбец '%-.192s' не обновлÑемый"
+ ukr "Стовбець '%-.192s' не може бути зминений"
+ER_VIEW_SELECT_DERIVED
+ eng "View's SELECT contains a subquery in the FROM clause"
+ ger "SELECT der View enthält eine Subquery in der FROM-Klausel"
+ rus "View SELECT Ñодержит Ð¿Ð¾Ð´Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð² конÑтрукции FROM"
+ ukr "View SELECT має підзапит у конÑтрукції FROM"
+ER_VIEW_SELECT_CLAUSE
+ eng "View's SELECT contains a '%s' clause"
+ ger "SELECT der View enthält eine '%s'-Klausel"
+ rus "View SELECT Ñодержит конÑтрукцию '%s'"
+ ukr "View SELECT має конÑтрукцію '%s'"
+ER_VIEW_SELECT_VARIABLE
+ eng "View's SELECT contains a variable or parameter"
+ ger "SELECT der View enthält eine Variable oder einen Parameter"
+ rus "View SELECT Ñодержит переменную или параметр"
+ ukr "View SELECT має зминну або параметер"
+ER_VIEW_SELECT_TMPTABLE
+ eng "View's SELECT refers to a temporary table '%-.192s'"
+ ger "SELECT der View verweist auf eine temporäre Tabelle '%-.192s'"
+ rus "View SELECT Ñодержит ÑÑылку на временную таблицу '%-.192s'"
+ ukr "View SELECT викориÑтовує тимчаÑову таблицю '%-.192s'"
+ER_VIEW_WRONG_LIST
+ eng "View's SELECT and view's field list have different column counts"
+ ger "SELECT- und Feldliste der Views haben unterschiedliche Anzahlen von Spalten"
+ rus "View SELECT и ÑпиÑок полей view имеют разное количеÑтво Ñтолбцов"
+ ukr "View SELECT Ñ– перелік Ñтовбців view мають різну кількіÑÑ‚ÑŒ Ñковбців"
+ER_WARN_VIEW_MERGE
+ eng "View merge algorithm can't be used here for now (assumed undefined algorithm)"
+ ger "View-Merge-Algorithmus kann hier momentan nicht verwendet werden (undefinierter Algorithmus wird angenommen)"
+ rus "Ðлгоритм ÑлиÑÐ½Ð¸Ñ view не может быть иÑпользован ÑÐµÐ¹Ñ‡Ð°Ñ (алгоритм будет неопеределенным)"
+ ukr "Ðлгоритм Ð·Ð»Ð¸Ð²Ð°Ð½Ð½Ñ view не може бути викориÑтаний зараз (алгоритм буде невизначений)"
+ER_WARN_VIEW_WITHOUT_KEY
+ eng "View being updated does not have complete key of underlying table in it"
+ ger "Die aktualisierte View enthält nicht den vollständigen Schlüssel der zugrunde liegenden Tabelle"
+ rus "ОбновлÑемый view не Ñодержит ключа иÑпользованных(ой) в нем таблиц(Ñ‹)"
+ ukr "View, що оновлюетьÑÑ, не міÑтить повного ключа таблиці(ÑŒ), що викоріÑтана в ньюому"
+ER_VIEW_INVALID
+ eng "View '%-.192s.%-.192s' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them"
+ER_SP_NO_DROP_SP
+ eng "Can't drop or alter a %s from within another stored routine"
+ ger "Kann eine %s nicht von innerhalb einer anderen gespeicherten Routine löschen oder ändern"
+ER_SP_GOTO_IN_HNDLR
+ eng "GOTO is not allowed in a stored procedure handler"
+ ger "GOTO ist im Handler einer gespeicherten Prozedur nicht erlaubt"
+ER_TRG_ALREADY_EXISTS
+ eng "Trigger already exists"
+ ger "Trigger existiert bereits"
+ER_TRG_DOES_NOT_EXIST
+ eng "Trigger does not exist"
+ ger "Trigger existiert nicht"
+ER_TRG_ON_VIEW_OR_TEMP_TABLE
+ eng "Trigger's '%-.192s' is view or temporary table"
+ ger "'%-.192s' des Triggers ist View oder temporäre Tabelle"
+ER_TRG_CANT_CHANGE_ROW
+ eng "Updating of %s row is not allowed in %strigger"
+ ger "Aktualisieren einer %s-Zeile ist in einem %s-Trigger nicht erlaubt"
+ER_TRG_NO_SUCH_ROW_IN_TRG
+ eng "There is no %s row in %s trigger"
+ ger "Es gibt keine %s-Zeile im %s-Trigger"
+ER_NO_DEFAULT_FOR_FIELD
+ eng "Field '%-.192s' doesn't have a default value"
+ ger "Feld '%-.192s' hat keinen Vorgabewert"
+ER_DIVISION_BY_ZERO 22012
+ eng "Division by 0"
+ ger "Division durch 0"
+ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+ eng "Incorrect %-.32s value: '%-.128s' for column '%.192s' at row %ld"
+ ger "Falscher %-.32s-Wert: '%-.128s' für Feld '%.192s' in Zeile %ld"
+ER_ILLEGAL_VALUE_FOR_TYPE 22007
+ eng "Illegal %s '%-.192s' value found during parsing"
+ ger "Nicht zulässiger %s-Wert '%-.192s' beim Parsen gefunden"
+ER_VIEW_NONUPD_CHECK
+ eng "CHECK OPTION on non-updatable view '%-.192s.%-.192s'"
+ ger "CHECK OPTION auf nicht-aktualisierbarem View '%-.192s.%-.192s'"
+ rus "CHECK OPTION Ð´Ð»Ñ Ð½ÐµÐ¾Ð±Ð½Ð¾Ð²Ð»Ñемого VIEW '%-.192s.%-.192s'"
+ ukr "CHECK OPTION Ð´Ð»Ñ VIEW '%-.192s.%-.192s' що не може бути оновленним"
+ER_VIEW_CHECK_FAILED
+ eng "CHECK OPTION failed '%-.192s.%-.192s'"
+ ger "CHECK OPTION fehlgeschlagen: '%-.192s.%-.192s'"
+ rus "проверка CHECK OPTION Ð´Ð»Ñ VIEW '%-.192s.%-.192s' провалилаÑÑŒ"
+ ukr "Перевірка CHECK OPTION Ð´Ð»Ñ VIEW '%-.192s.%-.192s' не пройшла"
+ER_PROCACCESS_DENIED_ERROR 42000
+ eng "%-.16s command denied to user '%-.48s'@'%-.64s' for routine '%-.192s'"
+ ger "Befehl %-.16s nicht zulässig für Benutzer '%-.48s'@'%-.64s' in Routine '%-.192s'"
+ER_RELAY_LOG_FAIL
+ eng "Failed purging old relay logs: %s"
+ ger "Bereinigen alter Relais-Logs fehlgeschlagen: %s"
+ER_PASSWD_LENGTH
+ eng "Password hash should be a %d-digit hexadecimal number"
+ ger "Passwort-Hash sollte eine Hexdaezimalzahl mit %d Stellen sein"
+ER_UNKNOWN_TARGET_BINLOG
+ eng "Target log not found in binlog index"
+ ger "Ziel-Log im Binlog-Index nicht gefunden"
+ER_IO_ERR_LOG_INDEX_READ
+ eng "I/O error reading log index file"
+ ger "Fehler beim Lesen der Log-Index-Datei"
+ER_BINLOG_PURGE_PROHIBITED
+ eng "Server configuration does not permit binlog purge"
+ ger "Server-Konfiguration erlaubt keine Binlog-Bereinigung"
+ER_FSEEK_FAIL
+ eng "Failed on fseek()"
+ ger "fseek() fehlgeschlagen"
+ER_BINLOG_PURGE_FATAL_ERR
+ eng "Fatal error during log purge"
+ ger "Schwerwiegender Fehler bei der Log-Bereinigung"
+ER_LOG_IN_USE
+ eng "A purgeable log is in use, will not purge"
+ ger "Ein zu bereinigendes Log wird gerade benutzt, daher keine Bereinigung"
+ER_LOG_PURGE_UNKNOWN_ERR
+ eng "Unknown error during log purge"
+ ger "Unbekannter Fehler bei Log-Bereinigung"
+ER_RELAY_LOG_INIT
+ eng "Failed initializing relay log position: %s"
+ ger "Initialisierung der Relais-Log-Position fehlgeschlagen: %s"
+ER_NO_BINARY_LOGGING
+ eng "You are not using binary logging"
+ ger "Sie verwenden keine Binärlogs"
+ER_RESERVED_SYNTAX
+ eng "The '%-.64s' syntax is reserved for purposes internal to the MySQL server"
+ ger "Die Schreibweise '%-.64s' ist für interne Zwecke des MySQL-Servers reserviert"
+ER_WSAS_FAILED
+ eng "WSAStartup Failed"
+ ger "WSAStartup fehlgeschlagen"
+ER_DIFF_GROUPS_PROC
+ eng "Can't handle procedures with different groups yet"
+ ger "Kann Prozeduren mit unterschiedlichen Gruppen noch nicht verarbeiten"
+ER_NO_GROUP_FOR_PROC
+ eng "Select must have a group with this procedure"
+ ger "SELECT muss bei dieser Prozedur ein GROUP BY haben"
+ER_ORDER_WITH_PROC
+ eng "Can't use ORDER clause with this procedure"
+ ger "Kann bei dieser Prozedur keine ORDER-BY-Klausel verwenden"
+ER_LOGGING_PROHIBIT_CHANGING_OF
+ eng "Binary logging and replication forbid changing the global server %s"
+ ger "Binärlogs und Replikation verhindern Wechsel des globalen Servers %s"
+ER_NO_FILE_MAPPING
+ eng "Can't map file: %-.200s, errno: %d"
+ ger "Kann Datei nicht abbilden: %-.200s, Fehler: %d"
+ER_WRONG_MAGIC
+ eng "Wrong magic in %-.64s"
+ ger "Falsche magische Zahlen in %-.64s"
+ER_PS_MANY_PARAM
+ eng "Prepared statement contains too many placeholders"
+ ger "Vorbereitete Anweisung enthält zu viele Platzhalter"
+ER_KEY_PART_0
+ eng "Key part '%-.192s' length cannot be 0"
+ ger "Länge des Schlüsselteils '%-.192s' kann nicht 0 sein"
+ER_VIEW_CHECKSUM
+ eng "View text checksum failed"
+ ger "View-Text-Prüfsumme fehlgeschlagen"
+ rus "Проверка контрольной Ñуммы текÑта VIEW провалилаÑÑŒ"
+ ukr "Перевірка контрольної Ñуми текÑту VIEW не пройшла"
+ER_VIEW_MULTIUPDATE
+ eng "Can not modify more than one base table through a join view '%-.192s.%-.192s'"
+ ger "Kann nicht mehr als eine Basistabelle über Join-View '%-.192s.%-.192s' ändern"
+ rus "ÐÐµÐ»ÑŒÐ·Ñ Ð¸Ð·Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ больше чем одну базовую таблицу иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¼Ð½Ð¾Ð³Ð¾Ñ‚Ð°Ð±Ð»Ð¸Ñ‡Ð½Ñ‹Ð¹ VIEW '%-.192s.%-.192s'"
+ ukr "Ðеможливо оновити більш ниж одну базову таблицю выкориÑтовуючи VIEW '%-.192s.%-.192s', що міÑÑ‚Ñ–Ñ‚ÑŒ декілька таблиць"
+ER_VIEW_NO_INSERT_FIELD_LIST
+ eng "Can not insert into join view '%-.192s.%-.192s' without fields list"
+ ger "Kann nicht ohne Feldliste in Join-View '%-.192s.%-.192s' einfügen"
+ rus "ÐÐµÐ»ÑŒÐ·Ñ Ð²ÑтавлÑÑ‚ÑŒ запиÑи в многотабличный VIEW '%-.192s.%-.192s' без ÑпиÑка полей"
+ ukr "Ðеможливо уÑтавити Ñ€Ñдки у VIEW '%-.192s.%-.192s', що міÑтить декілька таблиць, без ÑпиÑку Ñтовбців"
+ER_VIEW_DELETE_MERGE_VIEW
+ eng "Can not delete from join view '%-.192s.%-.192s'"
+ ger "Kann nicht aus Join-View '%-.192s.%-.192s' löschen"
+ rus "ÐÐµÐ»ÑŒÐ·Ñ ÑƒÐ´Ð°Ð»ÑÑ‚ÑŒ из многотабличного VIEW '%-.192s.%-.192s'"
+ ukr "Ðеможливо видалити Ñ€Ñдки у VIEW '%-.192s.%-.192s', що міÑтить декілька таблиць"
+ER_CANNOT_USER
+ eng "Operation %s failed for %.256s"
+ ger "Operation %s schlug fehl für %.256s"
+ norwegian-ny "Operation %s failed for '%.256s'"
+ER_XAER_NOTA XAE04
+ eng "XAER_NOTA: Unknown XID"
+ ger "XAER_NOTA: Unbekannte XID"
+ER_XAER_INVAL XAE05
+ eng "XAER_INVAL: Invalid arguments (or unsupported command)"
+ ger "XAER_INVAL: Ungültige Argumente (oder nicht unterstützter Befehl)"
+ER_XAER_RMFAIL XAE07
+ eng "XAER_RMFAIL: The command cannot be executed when global transaction is in the %.64s state"
+ ger "XAER_RMFAIL: DEr Befehl kann nicht ausgeführt werden, wenn die globale Transaktion im Zustand %.64s ist"
+ rus "XAER_RMFAIL: Ñту команду Ð½ÐµÐ»ÑŒÐ·Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÑÑ‚ÑŒ когда Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ð°Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ Ð½Ð°Ñ…Ð¾Ð´Ð¸Ñ‚ÑÑ Ð² ÑоÑтоÑнии '%.64s'"
+ER_XAER_OUTSIDE XAE09
+ eng "XAER_OUTSIDE: Some work is done outside global transaction"
+ ger "XAER_OUTSIDE: Einige Arbeiten werden außerhalb der globalen Transaktion verrichtet"
+ER_XAER_RMERR XAE03
+ eng "XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency"
+ ger "XAER_RMERR: Schwerwiegender Fehler im Transaktionszweig - prüfen Sie Ihre Daten auf Konsistenz"
+ER_XA_RBROLLBACK XA100
+ eng "XA_RBROLLBACK: Transaction branch was rolled back"
+ ger "XA_RBROLLBACK: Transaktionszweig wurde zurückgerollt"
+ER_NONEXISTING_PROC_GRANT 42000
+ eng "There is no such grant defined for user '%-.48s' on host '%-.64s' on routine '%-.192s'"
+ ger "Es gibt diese Berechtigung für Benutzer '%-.48s' auf Host '%-.64s' für Routine '%-.192s' nicht"
+ER_PROC_AUTO_GRANT_FAIL
+ eng "Failed to grant EXECUTE and ALTER ROUTINE privileges"
+ ger "Gewährung von EXECUTE- und ALTER-ROUTINE-Rechten fehlgeschlagen"
+ER_PROC_AUTO_REVOKE_FAIL
+ eng "Failed to revoke all privileges to dropped routine"
+ ger "Rücknahme aller Rechte für die gelöschte Routine fehlgeschlagen"
+ER_DATA_TOO_LONG 22001
+ eng "Data too long for column '%s' at row %ld"
+ ger "Daten zu lang für Feld '%s' in Zeile %ld"
+ER_SP_BAD_SQLSTATE 42000
+ eng "Bad SQLSTATE: '%s'"
+ ger "Ungültiger SQLSTATE: '%s'"
+ER_STARTUP
+ eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d %s"
+ ger "%s: bereit für Verbindungen.\nVersion: '%s' Socket: '%s' Port: %d %s"
+ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR
+ eng "Can't load value from file with fixed size rows to variable"
+ ger "Kann Wert aus Datei mit Zeilen fester Größe nicht in Variable laden"
+ER_CANT_CREATE_USER_WITH_GRANT 42000
+ eng "You are not allowed to create a user with GRANT"
+ ger "Sie dürfen keinen Benutzer mit GRANT anlegen"
+ER_WRONG_VALUE_FOR_TYPE
+ eng "Incorrect %-.32s value: '%-.128s' for function %-.32s"
+ ger "Falscher %-.32s-Wert: '%-.128s' für Funktion %-.32s"
+ER_TABLE_DEF_CHANGED
+ eng "Table definition has changed, please retry transaction"
+ ger "Tabellendefinition wurde geändert, bitte starten Sie die Transaktion neu"
+ER_SP_DUP_HANDLER 42000
+ eng "Duplicate handler declared in the same block"
+ ger "Doppelter Handler im selben Block deklariert"
+ER_SP_NOT_VAR_ARG 42000
+ eng "OUT or INOUT argument %d for routine %s is not a variable or NEW pseudo-variable in BEFORE trigger"
+ ger "OUT- oder INOUT-Argument %d für Routine %s ist keine Variable"
+ER_SP_NO_RETSET 0A000
+ eng "Not allowed to return a result set from a %s"
+ ger "Rückgabe einer Ergebnismenge aus einer %s ist nicht erlaubt"
+ER_CANT_CREATE_GEOMETRY_OBJECT 22003
+ eng "Cannot get geometry object from data you send to the GEOMETRY field"
+ ger "Kann kein Geometrieobjekt aus den Daten machen, die Sie dem GEOMETRY-Feld übergeben haben"
+ER_FAILED_ROUTINE_BREAK_BINLOG
+ eng "A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes"
+ ger "Eine Routine, die weder NO SQL noch READS SQL DATA in der Deklaration hat, schlug fehl und Binärlogging ist aktiv. Wenn Nicht-Transaktions-Tabellen aktualisiert wurden, enthält das Binärlog ihre Änderungen nicht"
+ER_BINLOG_UNSAFE_ROUTINE
+ eng "This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)"
+ ger "Diese Routine hat weder DETERMINISTIC, NO SQL noch READS SQL DATA in der Deklaration und Binärlogging ist aktiv (*vielleicht* sollten Sie die weniger sichere Variable log_bin_trust_function_creators verwenden)"
+ER_BINLOG_CREATE_ROUTINE_NEED_SUPER
+ eng "You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)"
+ ger "Sie haben keine SUPER-Berechtigung und Binärlogging ist aktiv (*vielleicht* sollten Sie die weniger sichere Variable log_bin_trust_function_creators verwenden)"
+ER_EXEC_STMT_WITH_OPEN_CURSOR
+ eng "You can't execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it."
+ ger "Sie können keine vorbereitete Anweisung ausführen, die mit einem geöffneten Cursor verknüpft ist. Setzen Sie die Anweisung zurück, um sie neu auszuführen"
+ER_STMT_HAS_NO_OPEN_CURSOR
+ eng "The statement (%lu) has no open cursor."
+ ger "Die Anweisung (%lu) hat keinen geöffneten Cursor"
+ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
+ eng "Explicit or implicit commit is not allowed in stored function or trigger."
+ ger "Explizites oder implizites Commit ist in gespeicherten Funktionen und in Triggern nicht erlaubt"
+ER_NO_DEFAULT_FOR_VIEW_FIELD
+ eng "Field of view '%-.192s.%-.192s' underlying table doesn't have a default value"
+ ger "Ein Feld der dem View '%-.192s.%-.192s' zugrundeliegenden Tabelle hat keinen Vorgabewert"
+ER_SP_NO_RECURSION
+ eng "Recursive stored functions and triggers are not allowed."
+ ger "Rekursive gespeicherte Routinen und Triggers sind nicht erlaubt"
+ER_TOO_BIG_SCALE 42000 S1009
+ eng "Too big scale %d specified for column '%-.192s'. Maximum is %lu."
+ ger "Zu großer Skalierungsfaktor %d für Feld '%-.192s' angegeben. Maximum ist %lu"
+ER_TOO_BIG_PRECISION 42000 S1009
+ eng "Too big precision %d specified for column '%-.192s'. Maximum is %lu."
+ ger "Zu große Genauigkeit %d für Feld '%-.192s' angegeben. Maximum ist %lu"
+ER_M_BIGGER_THAN_D 42000 S1009
+ eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s')."
+ ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.192s')"
+ER_WRONG_LOCK_OF_SYSTEM_TABLE
+ eng "You can't combine write-locking of system tables with other tables or lock types"
+ ger "Sie können Schreibsperren auf der Systemtabelle nicht mit anderen Tabellen kombinieren"
+ER_CONNECT_TO_FOREIGN_DATA_SOURCE
+ eng "Unable to connect to foreign data source: %.64s"
+ ger "Kann nicht mit Fremddatenquelle verbinden: %.64s"
+ER_QUERY_ON_FOREIGN_DATA_SOURCE
+ eng "There was a problem processing the query on the foreign data source. Data source error: %-.64s"
+ ger "Bei der Verarbeitung der Abfrage ist in der Fremddatenquelle ein Problem aufgetreten. Datenquellenfehlermeldung: %-.64s"
+ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST
+ eng "The foreign data source you are trying to reference does not exist. Data source error: %-.64s"
+ ger "Die Fremddatenquelle, auf die Sie zugreifen wollen, existiert nicht. Datenquellenfehlermeldung: %-.64s"
+ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE
+ eng "Can't create federated table. The data source connection string '%-.64s' is not in the correct format"
+ ger "Kann föderierte Tabelle nicht erzeugen. Der Datenquellen-Verbindungsstring '%-.64s' hat kein korrektes Format"
+ER_FOREIGN_DATA_STRING_INVALID
+ eng "The data source connection string '%-.64s' is not in the correct format"
+ ger "Der Datenquellen-Verbindungsstring '%-.64s' hat kein korrektes Format"
+ER_CANT_CREATE_FEDERATED_TABLE
+ eng "Can't create federated table. Foreign data src error: %-.64s"
+ ger "Kann föderierte Tabelle nicht erzeugen. Fremddatenquellenfehlermeldung: %-.64s"
+ER_TRG_IN_WRONG_SCHEMA
+ eng "Trigger in wrong schema"
+ ger "Trigger im falschen Schema"
+ER_STACK_OVERRUN_NEED_MORE
+ eng "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use 'mysqld --thread_stack=#' to specify a bigger stack."
+ ger "Thread-Stack-Überlauf: %ld Bytes eines %ld-Byte-Stacks in Verwendung, und %ld Bytes benötigt. Verwenden Sie 'mysqld --thread_stack=#', um einen größeren Stack anzugeben"
+ER_TOO_LONG_BODY 42000 S1009
+ eng "Routine body for '%-.100s' is too long"
+ ger "Routinen-Body für '%-.100s' ist zu lang"
+ER_WARN_CANT_DROP_DEFAULT_KEYCACHE
+ eng "Cannot drop default keycache"
+ ger "Der vorgabemäßige Schlüssel-Cache kann nicht gelöscht werden"
+ER_TOO_BIG_DISPLAYWIDTH 42000 S1009
+ eng "Display width out of range for column '%-.192s' (max = %lu)"
+ ger "Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%-.192s' (Maximum: %lu)"
+ER_XAER_DUPID XAE08
+ eng "XAER_DUPID: The XID already exists"
+ ger "XAER_DUPID: Die XID existiert bereits"
+ER_DATETIME_FUNCTION_OVERFLOW 22008
+ eng "Datetime function: %-.32s field overflow"
+ ger "Datetime-Funktion: %-.32s Feldüberlauf"
+ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
+ eng "Can't update table '%-.192s' in stored function/trigger because it is already used by statement which invoked this stored function/trigger."
+ ger "Kann Tabelle '%-.192s' in gespeicherter Funktion oder Trigger nicht aktualisieren, weil sie bereits von der Anweisung verwendet wird, die diese gespeicherte Funktion oder den Trigger aufrief"
+ER_VIEW_PREVENT_UPDATE
+ eng "The definition of table '%-.192s' prevents operation %.192s on table '%-.192s'."
+ ger "Die Definition der Tabelle '%-.192s' verhindert die Operation %.192s auf Tabelle '%-.192s'"
+ER_PS_NO_RECURSION
+ eng "The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner"
+ ger "Die vorbereitete Anweisung enthält einen Aufruf einer gespeicherten Routine, die auf eben dieselbe Anweisung verweist. Es ist nicht erlaubt, eine vorbereitete Anweisung in solch rekursiver Weise auszuführen"
+ER_SP_CANT_SET_AUTOCOMMIT
+ eng "Not allowed to set autocommit from a stored function or trigger"
+ ger "Es ist nicht erlaubt, innerhalb einer gespeicherten Funktion oder eines Triggers AUTOCOMMIT zu setzen"
+ER_MALFORMED_DEFINER
+ eng "Definer is not fully qualified"
+ ger "Definierer des View ist nicht vollständig spezifiziert"
+ER_VIEW_FRM_NO_USER
+ eng "View '%-.192s'.'%-.192s' has no definer information (old table format). Current user is used as definer. Please recreate the view!"
+ ger "View '%-.192s'.'%-.192s' hat keine Definierer-Information (altes Tabellenformat). Der aktuelle Benutzer wird als Definierer verwendet. Bitte erstellen Sie den View neu"
+ER_VIEW_OTHER_USER
+ eng "You need the SUPER privilege for creation view with '%-.192s'@'%-.192s' definer"
+ ger "Sie brauchen die SUPER-Berechtigung, um einen View mit dem Definierer '%-.192s'@'%-.192s' zu erzeugen"
+ER_NO_SUCH_USER
+ eng "The user specified as a definer ('%-.64s'@'%-.64s') does not exist"
+ER_FORBID_SCHEMA_CHANGE
+ eng "Changing schema from '%-.192s' to '%-.192s' is not allowed."
+ ger "Wechsel des Schemas von '%-.192s' auf '%-.192s' ist nicht erlaubt"
+ER_ROW_IS_REFERENCED_2 23000
+ eng "Cannot delete or update a parent row: a foreign key constraint fails (%.192s)"
+ ger "Kann Eltern-Zeile nicht löschen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl (%.192s)"
+ER_NO_REFERENCED_ROW_2 23000
+ eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)"
+ ger "Kann Kind-Zeile nicht hinzufügen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl (%.192s)"
+ER_SP_BAD_VAR_SHADOW 42000
+ eng "Variable '%-.64s' must be quoted with `...`, or renamed"
+ ger "Variable '%-.64s' muss mit `...` geschützt oder aber umbenannt werden"
+ER_TRG_NO_DEFINER
+ eng "No definer attribute for trigger '%-.192s'.'%-.192s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger."
+ ger "Kein Definierer-Attribut für Trigger '%-.192s'.'%-.192s'. Der Trigger wird mit der Autorisierung des Aufrufers aktiviert, der möglicherweise keine zureichenden Berechtigungen hat. Bitte legen Sie den Trigger neu an."
+ER_OLD_FILE_FORMAT
+ eng "'%-.192s' has an old format, you should re-create the '%s' object(s)"
+ ger "'%-.192s' hat altes Format, Sie sollten die '%s'-Objekt(e) neu erzeugen"
+ER_SP_RECURSION_LIMIT
+ eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.192s"
+ ger "Rekursionsgrenze %d (durch Variable max_sp_recursion_depth gegeben) wurde für Routine %.192s überschritten"
+ER_SP_PROC_TABLE_CORRUPT
+ eng "Failed to load routine %-.192s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)"
+ ger "Routine %-.192s konnte nicht geladen werden. Die Tabelle mysql.proc fehlt, ist beschädigt, oder enthält fehlerhaften Daten (interner Code: %d)"
+ER_SP_WRONG_NAME 42000
+ eng "Incorrect routine name '%-.192s'"
+ ger "Ungültiger Routinenname '%-.192s'"
+ER_TABLE_NEEDS_UPGRADE
+ eng "Table upgrade required. Please do \"REPAIR TABLE `%-.32s`\" or dump/reload to fix it!"
+ ger "Tabellenaktualisierung erforderlich. Bitte zum Reparieren \"REPAIR TABLE `%-.32s`\" eingeben!"
+ER_SP_NO_AGGREGATE 42000
+ eng "AGGREGATE is not supported for stored functions"
+ ger "AGGREGATE wird bei gespeicherten Funktionen nicht unterstützt"
+ER_MAX_PREPARED_STMT_COUNT_REACHED 42000
+ eng "Can't create more than max_prepared_stmt_count statements (current value: %lu)"
+ ger "Kann nicht mehr Anweisungen als max_prepared_stmt_count erzeugen (aktueller Wert: %lu)"
+ER_VIEW_RECURSIVE
+ eng "`%-.192s`.`%-.192s` contains view recursion"
+ ger "`%-.192s`.`%-.192s` enthält View-Rekursion"
+ER_NON_GROUPING_FIELD_USED 42000
+ eng "non-grouping field '%-.192s' is used in %-.64s clause"
+ ger "In der %-.192s-Klausel wird das die Nicht-Gruppierungsspalte '%-.64s' verwendet"
+ER_TABLE_CANT_HANDLE_SPKEYS
+ eng "The used table type doesn't support SPATIAL indexes"
+ ger "Der verwendete Tabellentyp unterstützt keine SPATIAL-Indizes"
+ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
+ eng "Triggers can not be created on system tables"
+ ger "Trigger können nicht auf Systemtabellen erzeugt werden"
+ER_REMOVED_SPACES
+ eng "Leading spaces are removed from name '%s'"
+ ger "Führende Leerzeichen werden aus dem Namen '%s' entfernt"
+ER_AUTOINC_READ_FAILED
+ eng "Failed to read auto-increment value from storage engine"
+ ger "Lesen des Autoincrement-Werts von der Speicher-Engine fehlgeschlagen"
+ER_USERNAME
+ eng "user name"
+ ger "Benutzername"
+ER_HOSTNAME
+ eng "host name"
+ ger "Hostname"
+ER_WRONG_STRING_LENGTH
+ eng "String '%-.70s' is too long for %s (should be no longer than %d)"
+ ger "String '%-.70s' ist zu lang für %s (sollte nicht länger sein als %d)"
+ER_NON_INSERTABLE_TABLE
+ eng "The target table %-.100s of the %s is not insertable-into"
+ ger "Die Zieltabelle %-.100s von %s ist nicht einfügbar"
+ER_ADMIN_WRONG_MRG_TABLE
+ eng "Table '%-.64s' is differently defined or of non-MyISAM type or doesn't exist"
+ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT
+ eng "Too high level of nesting for select"
+ER_NAME_BECOMES_EMPTY
+ eng "Name '%-.64s' has become ''"
+ER_AMBIGUOUS_FIELD_TERM
+ eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY"
+ER_FOREIGN_SERVER_EXISTS
+ eng "The foreign server, %s, you are trying to create already exists."
+ER_FOREIGN_SERVER_DOESNT_EXIST
+ eng "The foreign server name you are trying to reference does not exist. Data source error: %-.64s"
+ ger "Die externe Verbindung, auf die Sie zugreifen wollen, existiert nicht. Datenquellenfehlermeldung: %-.64s"
+ER_ILLEGAL_HA_CREATE_OPTION
+ eng "Table storage engine '%-.64s' does not support the create option '%.64s'"
+ ger "Speicher-Engine '%-.64s' der Tabelle unterstützt die Option '%.64s' nicht"
+ER_PARTITION_REQUIRES_VALUES_ERROR
+ eng "Syntax error: %-.64s PARTITIONING requires definition of VALUES %-.64s for each partition"
+ ger "Fehler in der SQL-Syntax: %-.64s-PARTITIONierung erfordert Definition von VALUES %-.64s für jede Partition"
+ swe "Syntaxfel: %-.64s PARTITIONering kräver definition av VALUES %-.64s för varje partition"
+ER_PARTITION_WRONG_VALUES_ERROR
+ eng "Only %-.64s PARTITIONING can use VALUES %-.64s in partition definition"
+ ger "Nur %-.64s-PARTITIONierung kann VALUES %-.64s in der Partitionsdefinition verwenden"
+ swe "Endast %-.64s partitionering kan använda VALUES %-.64s i definition av partitionen"
+ER_PARTITION_MAXVALUE_ERROR
+ eng "MAXVALUE can only be used in last partition definition"
+ ger "MAXVALUE kann nur für die Definition der letzten Partition verwendet werden"
+ swe "MAXVALUE kan bara användas i definitionen av den sista partitionen"
+ER_PARTITION_SUBPARTITION_ERROR
+ eng "Subpartitions can only be hash partitions and by key"
+ ger "Unterpartitionen dürfen nur HASH- oder KEY-Partitionen sein"
+ swe "Subpartitioner kan bara vara hash och key partitioner"
+ER_PARTITION_SUBPART_MIX_ERROR
+ eng "Must define subpartitions on all partitions if on one partition"
+ ger "Unterpartitionen können nur Hash- oder Key-Partitionen sein"
+ swe "Subpartitioner måste definieras på alla partitioner om på en"
+ER_PARTITION_WRONG_NO_PART_ERROR
+ eng "Wrong number of partitions defined, mismatch with previous setting"
+ ger "Falsche Anzahl von Partitionen definiert, stimmt nicht mit vorherigen Einstellungen überein"
+ swe "Antal partitioner definierade och antal partitioner är inte lika"
+ER_PARTITION_WRONG_NO_SUBPART_ERROR
+ eng "Wrong number of subpartitions defined, mismatch with previous setting"
+ ger "Falsche Anzahl von Unterpartitionen definiert, stimmt nicht mit vorherigen Einstellungen überein"
+ swe "Antal subpartitioner definierade och antal subpartitioner är inte lika"
+ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
+ eng "Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed"
+ ger "Konstante oder Random-Ausdrücke in (Unter-)Partitionsfunktionen sind nicht erlaubt"
+ swe "Konstanta uttryck eller slumpmässiga uttryck är inte tillåtna (sub)partitioneringsfunktioner"
+ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR
+ eng "Expression in RANGE/LIST VALUES must be constant"
+ ger "Ausdrücke in RANGE/LIST VALUES müssen konstant sein"
+ swe "Uttryck i RANGE/LIST VALUES måste vara ett konstant uttryck"
+ER_FIELD_NOT_FOUND_PART_ERROR
+ eng "Field in list of fields for partition function not found in table"
+ ger "Felder in der Feldliste der Partitionierungsfunktion wurden in der Tabelle nicht gefunden"
+ swe "Fält i listan av fält för partitionering med key inte funnen i tabellen"
+ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR
+ eng "List of fields is only allowed in KEY partitions"
+ ger "Eine Feldliste ist nur in KEY-Partitionen erlaubt"
+ swe "En lista av fält är endast tillåtet för KEY partitioner"
+ER_INCONSISTENT_PARTITION_INFO_ERROR
+ eng "The partition info in the frm file is not consistent with what can be written into the frm file"
+ ger "Die Partitionierungsinformationen in der frm-Datei stimmen nicht mit dem überein, was in die frm-Datei geschrieben werden kann"
+ swe "Partitioneringsinformationen i frm-filen är inte konsistent med vad som kan skrivas i frm-filen"
+ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
+ eng "The %-.192s function returns the wrong type"
+ ger "Die %-.192s-Funktion gibt einen falschen Typ zurück"
+ swe "%-.192s-funktionen returnerar felaktig typ"
+ER_PARTITIONS_MUST_BE_DEFINED_ERROR
+ eng "For %-.64s partitions each partition must be defined"
+ ger "Für %-.64s-Partitionen muss jede Partition definiert sein"
+ swe "För %-.64s partitionering så måste varje partition definieras"
+ER_RANGE_NOT_INCREASING_ERROR
+ eng "VALUES LESS THAN value must be strictly increasing for each partition"
+ ger "Werte in VALUES LESS THAN müssen für jede Partition strikt aufsteigend sein"
+ swe "Värden i VALUES LESS THAN måste vara strikt växande för varje partition"
+ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR
+ eng "VALUES value must be of same type as partition function"
+ ger "VALUES-Werte müssen vom selben Typ wie die Partitionierungsfunktion sein"
+ swe "Värden i VALUES måste vara av samma typ som partitioneringsfunktionen"
+ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR
+ eng "Multiple definition of same constant in list partitioning"
+ ger "Mehrfachdefinition derselben Konstante bei Listen-Partitionierung"
+ swe "Multipel definition av samma konstant i list partitionering"
+ER_PARTITION_ENTRY_ERROR
+ eng "Partitioning can not be used stand-alone in query"
+ ger "Partitionierung kann in einer Abfrage nicht alleinstehend benutzt werden"
+ swe "Partitioneringssyntax kan inte användas på egen hand i en SQL-fråga"
+ER_MIX_HANDLER_ERROR
+ eng "The mix of handlers in the partitions is not allowed in this version of MySQL"
+ ger "Das Vermischen von Handlern in Partitionen ist in dieser Version von MySQL nicht erlaubt"
+ swe "Denna mix av lagringsmotorer är inte tillåten i denna version av MySQL"
+ER_PARTITION_NOT_DEFINED_ERROR
+ eng "For the partitioned engine it is necessary to define all %-.64s"
+ ger "Für die partitionierte Engine müssen alle %-.64s definiert sein"
+ swe "För partitioneringsmotorn så är det nödvändigt att definiera alla %-.64s"
+ER_TOO_MANY_PARTITIONS_ERROR
+ eng "Too many partitions (including subpartitions) were defined"
+ ger "Es wurden zu vielen Partitionen (einschließlich Unterpartitionen) definiert"
+ swe "För många partitioner (inkluderande subpartitioner) definierades"
+ER_SUBPARTITION_ERROR
+ eng "It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning"
+ ger "RANGE/LIST-Partitionierung kann bei Unterpartitionen nur zusammen mit HASH/KEY-Partitionierung verwendet werden"
+ swe "Det är endast möjligt att blanda RANGE/LIST partitionering med HASH/KEY partitionering för subpartitionering"
+ER_CANT_CREATE_HANDLER_FILE
+ eng "Failed to create specific handler file"
+ ger "Erzeugen einer spezifischen Handler-Datei fehlgeschlagen"
+ swe "Misslyckades med att skapa specifik fil i lagringsmotor"
+ER_BLOB_FIELD_IN_PART_FUNC_ERROR
+ eng "A BLOB field is not allowed in partition function"
+ ger "In der Partitionierungsfunktion sind BLOB-Spalten nicht erlaubt"
+ swe "Ett BLOB-fält är inte tillåtet i partitioneringsfunktioner"
+ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF
+ eng "A %-.192s must include all columns in the table's partitioning function"
+ER_NO_PARTS_ERROR
+ eng "Number of %-.64s = 0 is not an allowed value"
+ ger "Eine Anzahl von %-.64s = 0 ist kein erlaubter Wert"
+ swe "Antal %-.64s = 0 är inte ett tillåten värde"
+ER_PARTITION_MGMT_ON_NONPARTITIONED
+ eng "Partition management on a not partitioned table is not possible"
+ ger "Partitionsverwaltung einer nicht partitionierten Tabelle ist nicht möglich"
+ swe "Partitioneringskommando på en opartitionerad tabell är inte möjligt"
+ER_FOREIGN_KEY_ON_PARTITIONED
+ eng "Foreign key clause is not yet supported in conjunction with partitioning"
+ ger "Fremdschlüssel-Beschränkungen sind im Zusammenhang mit Partitionierung nicht zulässig"
+ swe "Foreign key klausul är inte ännu implementerad i kombination med partitionering"
+ER_DROP_PARTITION_NON_EXISTENT
+ eng "Error in list of partitions to %-.64s"
+ ger "Fehler in der Partitionsliste bei %-.64s"
+ swe "Fel i listan av partitioner att %-.64s"
+ER_DROP_LAST_PARTITION
+ eng "Cannot remove all partitions, use DROP TABLE instead"
+ ger "Es lassen sich nicht sämtliche Partitionen löschen, benutzen Sie statt dessen DROP TABLE"
+ swe "Det är inte tillåtet att ta bort alla partitioner, använd DROP TABLE istället"
+ER_COALESCE_ONLY_ON_HASH_PARTITION
+ eng "COALESCE PARTITION can only be used on HASH/KEY partitions"
+ ger "COALESCE PARTITION kann nur auf HASH- oder KEY-Partitionen benutzt werden"
+ swe "COALESCE PARTITION kan bara användas på HASH/KEY partitioner"
+ER_REORG_HASH_ONLY_ON_SAME_NO
+ eng "REORGANIZE PARTITION can only be used to reorganize partitions not to change their numbers"
+ ger "REORGANIZE PARTITION kann nur zur Reorganisation von Partitionen verwendet werden, nicht, um ihre Nummern zu ändern"
+ swe "REORGANIZE PARTITION kan bara användas för att omorganisera partitioner, inte för att ändra deras antal"
+ER_REORG_NO_PARAM_ERROR
+ eng "REORGANIZE PARTITION without parameters can only be used on auto-partitioned tables using HASH PARTITIONs"
+ ger "REORGANIZE PARTITION ohne Parameter kann nur für auto-partitionierte Tabellen verwendet werden, die HASH-Partitionierung benutzen"
+ swe "REORGANIZE PARTITION utan parametrar kan bara användas på auto-partitionerade tabeller som använder HASH partitionering"
+ER_ONLY_ON_RANGE_LIST_PARTITION
+ eng "%-.64s PARTITION can only be used on RANGE/LIST partitions"
+ ger "%-.64s PARTITION kann nur für RANGE- oder LIST-Partitionen verwendet werden"
+ swe "%-.64s PARTITION kan bara användas på RANGE/LIST-partitioner"
+ER_ADD_PARTITION_SUBPART_ERROR
+ eng "Trying to Add partition(s) with wrong number of subpartitions"
+ ger "Es wurde versucht, eine oder mehrere Partitionen mit der falschen Anzahl von Unterpartitionen hinzuzufügen"
+ swe "ADD PARTITION med fel antal subpartitioner"
+ER_ADD_PARTITION_NO_NEW_PARTITION
+ eng "At least one partition must be added"
+ ger "Es muss zumindest eine Partition hinzugefügt werden"
+ swe "Åtminstone en partition måste läggas till vid ADD PARTITION"
+ER_COALESCE_PARTITION_NO_PARTITION
+ eng "At least one partition must be coalesced"
+ ger "Zumindest eine Partition muss mit COALESCE PARTITION zusammengefügt werden"
+ swe "Åtminstone en partition måste slås ihop vid COALESCE PARTITION"
+ER_REORG_PARTITION_NOT_EXIST
+ eng "More partitions to reorganize than there are partitions"
+ ger "Es wurde versucht, mehr Partitionen als vorhanden zu reorganisieren"
+ swe "Fler partitioner att reorganisera än det finns partitioner"
+ER_SAME_NAME_PARTITION
+ eng "Duplicate partition name %-.192s"
+ ger "Doppelter Partitionsname: %-.192s"
+ swe "Duplicerat partitionsnamn %-.192s"
+ER_NO_BINLOG_ERROR
+ eng "It is not allowed to shut off binlog on this command"
+ ger "Es es nicht erlaubt, bei diesem Befehl binlog abzuschalten"
+ swe "Det är inte tillåtet att stänga av binlog på detta kommando"
+ER_CONSECUTIVE_REORG_PARTITIONS
+ eng "When reorganizing a set of partitions they must be in consecutive order"
+ ger "Bei der Reorganisation eines Satzes von Partitionen müssen diese in geordneter Reihenfolge vorliegen"
+ swe "När ett antal partitioner omorganiseras måste de vara i konsekutiv ordning"
+ER_REORG_OUTSIDE_RANGE
+ eng "Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range"
+ ger "Die Reorganisation von RANGE-Partitionen kann Gesamtbereiche nicht verändern, mit Ausnahme der letzten Partition, die den Bereich erweitern kann"
+ swe "Reorganisering av rangepartitioner kan inte ändra den totala intervallet utom för den sista partitionen där intervallet kan utökas"
+ER_PARTITION_FUNCTION_FAILURE
+ eng "Partition function not supported in this version for this handler"
+ ger "Partitionsfunktion in dieser Version dieses Handlers nicht unterstützt"
+ER_PART_STATE_ERROR
+ eng "Partition state cannot be defined from CREATE/ALTER TABLE"
+ ger "Partitionszustand kann nicht von CREATE oder ALTER TABLE aus definiert werden"
+ swe "Partition state kan inte definieras från CREATE/ALTER TABLE"
+ER_LIMITED_PART_RANGE
+ eng "The %-.64s handler only supports 32 bit integers in VALUES"
+ ger "Der Handler %-.64s unterstützt in VALUES nur 32-Bit-Integers"
+ swe "%-.64s stödjer endast 32 bitar i integers i VALUES"
+ER_PLUGIN_IS_NOT_LOADED
+ eng "Plugin '%-.192s' is not loaded"
+ ger "Plugin '%-.192s' ist nicht geladen"
+ER_WRONG_VALUE
+ eng "Incorrect %-.32s value: '%-.128s'"
+ ger "Falscher %-.32s-Wert: '%-.128s'"
+ER_NO_PARTITION_FOR_GIVEN_VALUE
+ eng "Table has no partition for value %-.64s"
+ ger "Tabelle hat für den Wert %-.64s keine Partition"
+ER_FILEGROUP_OPTION_ONLY_ONCE
+ eng "It is not allowed to specify %s more than once"
+ ger "%s darf nicht mehr als einmal angegegeben werden"
+ER_CREATE_FILEGROUP_FAILED
+ eng "Failed to create %s"
+ ger "Anlegen von %s fehlgeschlagen"
+ER_DROP_FILEGROUP_FAILED
+ eng "Failed to drop %s"
+ ger "Löschen (drop) von %s fehlgeschlagen"
+ER_TABLESPACE_AUTO_EXTEND_ERROR
+ eng "The handler doesn't support autoextend of tablespaces"
+ ger "Der Handler unterstützt keine automatische Erweiterung (Autoextend) von Tablespaces"
+ER_WRONG_SIZE_NUMBER
+ eng "A size parameter was incorrectly specified, either number or on the form 10M"
+ ger "Ein Größen-Parameter wurde unkorrekt angegeben, muss entweder Zahl sein oder im Format 10M"
+ER_SIZE_OVERFLOW_ERROR
+ eng "The size number was correct but we don't allow the digit part to be more than 2 billion"
+ ger "Die Zahl für die Größe war korrekt, aber der Zahlanteil darf nicht größer als 2 Milliarden sein"
+ER_ALTER_FILEGROUP_FAILED
+ eng "Failed to alter: %s"
+ ger "Änderung von %s fehlgeschlagen"
+ER_BINLOG_ROW_LOGGING_FAILED
+ eng "Writing one row to the row-based binary log failed"
+ ger "Schreiben einer Zeilen ins zeilenbasierte Binärlog fehlgeschlagen"
+ER_BINLOG_ROW_WRONG_TABLE_DEF
+ eng "Table definition on master and slave does not match: %s"
+ ger "Tabellendefinition auf Master und Slave stimmt nicht überein: %s"
+ER_BINLOG_ROW_RBR_TO_SBR
+ eng "Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events"
+ ger "Slave, die mit --log-slave-updates laufen, müssen zeilenbasiertes Loggen verwenden, um zeilenbasierte Binärlog-Ereignisse loggen zu können"
+ER_EVENT_ALREADY_EXISTS
+ eng "Event '%-.192s' already exists"
+ ger "Event '%-.192s' existiert bereits"
+ER_EVENT_STORE_FAILED
+ eng "Failed to store event %s. Error code %d from storage engine."
+ ger "Speichern von Event %s fehlgeschlagen. Fehlercode der Speicher-Engine: %d"
+ER_EVENT_DOES_NOT_EXIST
+ eng "Unknown event '%-.192s'"
+ ger "Unbekanntes Event '%-.192s'"
+ER_EVENT_CANT_ALTER
+ eng "Failed to alter event '%-.192s'"
+ ger "Ändern des Events '%-.192s' fehlgeschlagen"
+ER_EVENT_DROP_FAILED
+ eng "Failed to drop %s"
+ ger "Löschen von %s fehlgeschlagen"
+ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG
+ eng "INTERVAL is either not positive or too big"
+ ger "INTERVAL ist entweder nicht positiv oder zu groß"
+ER_EVENT_ENDS_BEFORE_STARTS
+ eng "ENDS is either invalid or before STARTS"
+ ger "ENDS ist entweder ungültig oder liegt vor STARTS"
+ER_EVENT_EXEC_TIME_IN_THE_PAST
+ eng "Event execution time is in the past. Event has been disabled"
+ER_EVENT_OPEN_TABLE_FAILED
+ eng "Failed to open mysql.event"
+ ger "Öffnen von mysql.event fehlgeschlagen"
+ER_EVENT_NEITHER_M_EXPR_NOR_M_AT
+ eng "No datetime expression provided"
+ ger "Kein DATETIME-Ausdruck angegeben"
+ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
+ eng "Column count of mysql.%s is wrong. Expected %d, found %d. The table is probably corrupted"
+ ger "Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d gefunden. Tabelle ist wahrscheinlich beschädigt"
+ER_CANNOT_LOAD_FROM_TABLE
+ eng "Cannot load from mysql.%s. The table is probably corrupted"
+ ger "Kann mysql.%s nicht einlesen. Tabelle ist wahrscheinlich beschädigt"
+ER_EVENT_CANNOT_DELETE
+ eng "Failed to delete the event from mysql.event"
+ ger "Löschen des Events aus mysql.event fehlgeschlagen"
+ER_EVENT_COMPILE_ERROR
+ eng "Error during compilation of event's body"
+ ger "Fehler beim Kompilieren des Event-Bodys"
+ER_EVENT_SAME_NAME
+ eng "Same old and new event name"
+ ger "Alter und neuer Event-Name sind gleich"
+ER_EVENT_DATA_TOO_LONG
+ eng "Data for column '%s' too long"
+ ger "Daten der Spalte '%s' zu lang"
+ER_DROP_INDEX_FK
+ eng "Cannot drop index '%-.192s': needed in a foreign key constraint"
+ ger "Kann Index '%-.192s' nicht löschen: wird für einen Fremdschlüssel benötigt"
+# When using this error message, use the ER_WARN_DEPRECATED_SYNTAX error
+# code.
+ER_WARN_DEPRECATED_SYNTAX_WITH_VER
+ eng "The syntax '%s' is deprecated and will be removed in MySQL %s. Please use %s instead"
+ ger "Die Syntax '%s' ist veraltet und wird in MySQL %s entfernt. Bitte benutzen Sie statt dessen %s"
+ER_CANT_WRITE_LOCK_LOG_TABLE
+ eng "You can't write-lock a log table. Only read access is possible"
+ ger "Eine Log-Tabelle kann nicht schreibgesperrt werden. Es ist ohnehin nur Lesezugriff möglich"
+ER_CANT_LOCK_LOG_TABLE
+ eng "You can't use locks with log tables."
+ ger "Log-Tabellen können nicht mit normalen Lesesperren gesperrt werden. Verwenden Sie statt dessen READ LOCAL"
+ER_FOREIGN_DUPLICATE_KEY 23000 S1009
+ eng "Upholding foreign key constraints for table '%.192s', entry '%-.192s', key %d would lead to a duplicate entry"
+ ger "Aufrechterhalten der Fremdschlüssel-Constraints für Tabelle '%.192s', Eintrag '%-.192s', Schlüssel %d würde zu einem doppelten Eintrag führen"
+ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE
+ eng "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use mysql_upgrade to fix this error."
+ ger "Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d erhalten. Erzeugt mit MySQL %d, jetzt unter %d. Bitte benutzen Sie mysql_upgrade, um den Fehler zu beheben"
+ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR
+ eng "Cannot switch out of the row-based binary log format when the session has open temporary tables"
+ ger "Kann nicht aus dem zeilenbasierten Binärlog-Format herauswechseln, wenn die Sitzung offene temporäre Tabellen hat"
+ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT
+ eng "Cannot change the binary logging format inside a stored function or trigger"
+ ger "Das Binärlog-Format kann innerhalb einer gespeicherten Funktion oder eines Triggers nicht geändert werden"
+ER_NDB_CANT_SWITCH_BINLOG_FORMAT
+ eng "The NDB cluster engine does not support changing the binlog format on the fly yet"
+ ger "Die Speicher-Engine NDB Cluster unterstützt das Ändern des Binärlog-Formats zur Laufzeit noch nicht"
+ER_PARTITION_NO_TEMPORARY
+ eng "Cannot create temporary table with partitions"
+ ger "Anlegen temporärer Tabellen mit Partitionen nicht möglich"
+ER_PARTITION_CONST_DOMAIN_ERROR
+ eng "Partition constant is out of partition function domain"
+ ger "Partitionskonstante liegt außerhalb der Partitionsfunktionsdomäne"
+ swe "Partitionskonstanten är utanför partitioneringsfunktionens domän"
+ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+ eng "This partition function is not allowed"
+ ger "Diese Partitionierungsfunktion ist nicht erlaubt"
+ swe "Denna partitioneringsfunktion är inte tillåten"
+ER_DDL_LOG_ERROR
+ eng "Error in DDL log"
+ ger "Fehler im DDL-Log"
+ER_NULL_IN_VALUES_LESS_THAN
+ eng "Not allowed to use NULL value in VALUES LESS THAN"
+ ger "In VALUES LESS THAN dürfen keine NULL-Werte verwendet werden"
+ swe "Det är inte tillåtet att använda NULL-värden i VALUES LESS THAN"
+ER_WRONG_PARTITION_NAME
+ eng "Incorrect partition name"
+ ger "Falscher Partitionsname"
+ swe "Felaktigt partitionsnamn"
+ER_CANT_CHANGE_TX_ISOLATION 25001
+ eng "Transaction isolation level can't be changed while a transaction is in progress"
+ ger "Transaktionsisolationsebene kann während einer laufenden Transaktion nicht geändert werden"
+ER_DUP_ENTRY_AUTOINCREMENT_CASE
+ eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.192s' for key '%-.192s'"
+ ger "ALTER TABLE führt zur Neusequenzierung von auto_increment, wodurch der doppelte Eintrag '%-.192s' für Schlüssel '%-.192s' auftritt"
+ER_EVENT_MODIFY_QUEUE_ERROR
+ eng "Internal scheduler error %d"
+ ger "Interner Scheduler-Fehler %d"
+ER_EVENT_SET_VAR_ERROR
+ eng "Error during starting/stopping of the scheduler. Error code %u"
+ ger "Fehler während des Startens oder Anhalten des Schedulers. Fehlercode %u"
+ER_PARTITION_MERGE_ERROR
+ eng "Engine cannot be used in partitioned tables"
+ ger "Engine kann in partitionierten Tabellen nicht verwendet werden"
+ swe "Engine inte användas i en partitionerad tabell"
+ER_CANT_ACTIVATE_LOG
+ eng "Cannot activate '%-.64s' log"
+ ger "Kann Logdatei '%-.64s' nicht aktivieren"
+ER_RBR_NOT_AVAILABLE
+ eng "The server was not built with row-based replication"
+ER_BASE64_DECODE_ERROR
+ eng "Decoding of base64 string failed"
+ swe "Avkodning av base64 sträng misslyckades"
+ ger "Der Server hat keine zeilenbasierte Replikation"
+ER_EVENT_RECURSION_FORBIDDEN
+ eng "Recursion of EVENT DDL statements is forbidden when body is present"
+ ger "Rekursivität von EVENT-DDL-Anweisungen ist unzulässig wenn ein Hauptteil (Body) existiert"
+ER_EVENTS_DB_ERROR
+ eng "Cannot proceed because system tables used by Event Scheduler were found damaged at server start"
+ ger "Kann nicht weitermachen, weil die Tabellen, die von Events verwendet werden, beim Serverstart als beschädigt markiert wurden"
+ER_ONLY_INTEGERS_ALLOWED
+ eng "Only integers allowed as number here"
+ ger "An dieser Stelle sind nur Ganzzahlen zulässig"
+ER_UNSUPORTED_LOG_ENGINE
+ eng "This storage engine cannot be used for log tables""
+ ger "Diese Speicher-Engine kann für Logtabellen nicht verwendet werden"
+ER_BAD_LOG_STATEMENT
+ eng "You cannot '%s' a log table if logging is enabled"
+ ger "Sie können eine Logtabelle nicht '%s', wenn Loggen angeschaltet ist"
+ER_CANT_RENAME_LOG_TABLE
+ eng "Cannot rename '%s'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to '%s'"
+ ger "Kann '%s' nicht umbenennen. Wenn Loggen angeschaltet ist, müssen beim Umbenennen zu/von einer Logtabelle zwei Tabellen angegeben werden: die Logtabelle zu einer Archivtabelle und eine weitere Tabelle zurück zu '%s'"
+ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 42000
+ eng "Incorrect parameter count in the call to native function '%-.192s'"
+ ger "Falsche Anzahl von Parametern beim Aufruf der nativen Funktion '%-.192s'"
+ER_WRONG_PARAMETERS_TO_NATIVE_FCT 42000
+ eng "Incorrect parameters in the call to native function '%-.192s'"
+ ger "Falscher Parameter beim Aufruf der nativen Funktion '%-.192s'"
+ER_WRONG_PARAMETERS_TO_STORED_FCT 42000
+ eng "Incorrect parameters in the call to stored function '%-.192s'"
+ ger "Falsche Parameter beim Aufruf der gespeicherten Funktion '%-.192s'"
+ER_NATIVE_FCT_NAME_COLLISION
+ eng "This function '%-.192s' has the same name as a native function"
+ ger "Die Funktion '%-.192s' hat denselben Namen wie eine native Funktion"
+# When using this error message, use the ER_DUP_ENTRY error code. See, for
+# example, code in handler.cc.
+ER_DUP_ENTRY_WITH_KEY_NAME 23000 S1009
+ cze "Zvojen-Bý klÃ­Ä '%-.64s' (Äíslo klíÄe '%-.192s')"
+ dan "Ens værdier '%-.64s' for indeks '%-.192s'"
+ nla "Dubbele ingang '%-.64s' voor zoeksleutel '%-.192s'"
+ eng "Duplicate entry '%-.64s' for key '%-.192s'"
+ jps "'%-.64s' 㯠key '%-.192s' ã«ãŠã„ã¦é‡è¤‡ã—ã¦ã„ã¾ã™",
+ est "Kattuv väärtus '%-.64s' võtmele '%-.192s'"
+ fre "Duplicata du champ '%-.64s' pour la clef '%-.192s'"
+ ger "Doppelter Eintrag '%-.64s' für Schlüssel '%-.192s'"
+ greek "Διπλή εγγÏαφή '%-.64s' για το κλειδί '%-.192s'"
+ hun "Duplikalt bejegyzes '%-.64s' a '%-.192s' kulcs szerint."
+ ita "Valore duplicato '%-.64s' per la chiave '%-.192s'"
+ jpn "'%-.64s' 㯠key '%-.192s' ã«ãŠã„ã¦é‡è¤‡ã—ã¦ã„ã¾ã™"
+ kor "ì¤‘ë³µëœ ìž…ë ¥ ê°’ '%-.64s': key '%-.192s'"
+ nor "Like verdier '%-.64s' for nøkkel '%-.192s'"
+ norwegian-ny "Like verdiar '%-.64s' for nykkel '%-.192s'"
+ pol "Powtórzone wyst?pienie '%-.64s' dla klucza '%-.192s'"
+ por "Entrada '%-.64s' duplicada para a chave '%-.192s'"
+ rum "Cimpul '%-.64s' e duplicat pentru cheia '%-.192s'"
+ rus "ДублирующаÑÑÑ Ð·Ð°Ð¿Ð¸ÑÑŒ '%-.64s' по ключу '%-.192s'"
+ serbian "Dupliran unos '%-.64s' za kljuÄ '%-.192s'"
+ slo "Opakovaný kÄ¾ÃºÄ '%-.64s' (Äíslo kľúÄa '%-.192s')"
+ spa "Entrada duplicada '%-.64s' para la clave '%-.192s'"
+ swe "Dubbel nyckel '%-.64s' för nyckel '%-.192s'"
+ ukr "Дублюючий Ð·Ð°Ð¿Ð¸Ñ '%-.64s' Ð´Ð»Ñ ÐºÐ»ÑŽÑ‡Ð° '%-.192s'"
+ER_BINLOG_PURGE_EMFILE
+ eng "Too many files opened, please execute the command again"
+ ger "Zu viele offene Dateien, bitte führen Sie den Befehl noch einmal aus"
+ER_EVENT_CANNOT_CREATE_IN_THE_PAST
+ eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation."
+ER_EVENT_CANNOT_ALTER_IN_THE_PAST
+ eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation."
+ER_SLAVE_INCIDENT
+ eng "The incident %s occured on the master. Message: %-.64s"
+ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT
+ eng "Table has no partition for some existing values"
+ER_BINLOG_UNSAFE_STATEMENT
+ eng "Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. %s"
+ER_SLAVE_FATAL_ERROR
+ eng "Fatal error: %s"
+ER_SLAVE_RELAY_LOG_READ_FAILURE
+ eng "Relay log read failure: %s"
+ER_SLAVE_RELAY_LOG_WRITE_FAILURE
+ eng "Relay log write failure: %s"
+ER_SLAVE_CREATE_EVENT_FAILURE
+ eng "Failed to create %s"
+ER_SLAVE_MASTER_COM_FAILURE
+ eng "Master command %s failed: %s"
+ER_BINLOG_LOGGING_IMPOSSIBLE
+ eng "Binary logging not possible. Message: %s"
+
+ER_VIEW_NO_CREATION_CTX
+ eng "View `%-.64s`.`%-.64s` has no creation context"
+ER_VIEW_INVALID_CREATION_CTX
+ eng "Creation context of view `%-.64s`.`%-.64s' is invalid"
+
+ER_SR_INVALID_CREATION_CTX
+ eng "Creation context of stored routine `%-.64s`.`%-.64s` is invalid"
+
+ER_TRG_CORRUPTED_FILE
+ eng "Corrupted TRG file for table `%-.64s`.`%-.64s`"
+ER_TRG_NO_CREATION_CTX
+ eng "Triggers for table `%-.64s`.`%-.64s` have no creation context"
+ER_TRG_INVALID_CREATION_CTX
+ eng "Trigger creation context of table `%-.64s`.`%-.64s` is invalid"
+
+ER_EVENT_INVALID_CREATION_CTX
+ eng "Creation context of event `%-.64s`.`%-.64s` is invalid"
+
+ER_TRG_CANT_OPEN_TABLE
+ eng "Cannot open table for trigger `%-.64s`.`%-.64s`"
+
+ER_CANT_CREATE_SROUTINE
+ eng "Cannot create stored routine `%-.64s`. Check warnings"
+ER_NEVER_USED
+ eng "Ambiguous slave modes combination. %s"
+
+ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT
+ eng "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement."
+ER_SLAVE_CORRUPT_EVENT
+ eng "Corrupted replication event was detected"
+
+ER_LOAD_DATA_INVALID_COLUMN
+ eng "Invalid column reference (%-.64s) in LOAD DATA"
+
+ER_LOG_PURGE_NO_FILE
+ eng "Being purged log %s was not found"
+
+ER_XA_RBTIMEOUT XA106
+ eng "XA_RBTIMEOUT: Transaction branch was rolled back: took too long"
+
+ER_XA_RBDEADLOCK XA102
+ eng "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected"
+
+ER_NEED_REPREPARE
+ eng "Prepared statement needs to be re-prepared"
+
+ER_DELAYED_NOT_SUPPORTED
+ eng "DELAYED option not supported for table '%-.192s'"
+
+WARN_NO_MASTER_INFO
+ eng "The master info structure does not exist"
+
+WARN_OPTION_IGNORED
+ eng "<%-.64s> option ignored"
+
+WARN_PLUGIN_DELETE_BUILTIN
+ eng "Built-in plugins cannot be deleted"
+
+WARN_PLUGIN_BUSY
+ eng "Plugin is busy and will be uninstalled on shutdown"
+
+ER_VARIABLE_IS_READONLY
+ eng "%s variable '%s' is read-only. Use SET %s to assign the value"
+
+ER_WARN_ENGINE_TRANSACTION_ROLLBACK
+ eng "Storage engine %s does not support rollback for this statement. Transaction rolled back and must be restarted"
+
+ER_SLAVE_HEARTBEAT_FAILURE
+ eng "Unexpected master's heartbeat data: %s"
+ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
+ eng "The requested value for the heartbeat period is either negative or exceeds the maximum allowed (%s seconds)."
+
+ER_NDB_REPLICATION_SCHEMA_ERROR
+ eng "Bad schema for mysql.ndb_replication table. Message: %-.64s"
+ER_CONFLICT_FN_PARSE_ERROR
+ eng "Error in parsing conflict function. Message: %-.64s"
+ER_EXCEPTIONS_WRITE_ERROR
+ eng "Write to exceptions table failed. Message: %-.128s""
+
+ER_TOO_LONG_TABLE_COMMENT
+ eng "Comment for table '%-.64s' is too long (max = %lu)"
+ por "Comentário para a tabela '%-.64s' é longo demais (max = %lu)"
+
+ER_TOO_LONG_FIELD_COMMENT
+ eng "Comment for field '%-.64s' is too long (max = %lu)"
+ por "Comentário para o campo '%-.64s' é longo demais (max = %lu)"
+
+ER_FUNC_INEXISTENT_NAME_COLLISION 42000
+ eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual"
+
+# When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in
+# sql_table.h with the new maximal additional length for explain_filename.
+ER_DATABASE_NAME
+ eng "Database"
+ swe "Databas"
+ER_TABLE_NAME
+ eng "Table"
+ swe "Tabell"
+ER_PARTITION_NAME
+ eng "Partition"
+ swe "Partition"
+ER_SUBPARTITION_NAME
+ eng "Subpartition"
+ swe "Subpartition"
+ER_TEMPORARY_NAME
+ eng "Temporary"
+ swe "Temporär"
+ER_RENAMED_NAME
+ eng "Renamed"
+ swe "Namnändrad"
+ER_TOO_MANY_CONCURRENT_TRXS
+ eng "Too many active concurrent transactions"
+
+WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED
+ eng "Non-ASCII separator arguments are not fully supported"
+
+ER_DEBUG_SYNC_TIMEOUT
+ eng "debug sync point wait timed out"
+ ger "Debug Sync Point Wartezeit überschritten"
+ER_DEBUG_SYNC_HIT_LIMIT
+ eng "debug sync point hit limit reached"
+ ger "Debug Sync Point Hit Limit erreicht"
+
+ER_DUP_SIGNAL_SET 42000
+ eng "Duplicate condition information item '%s'"
+
+# Note that the SQLSTATE is not 01000, it is provided by SIGNAL/RESIGNAL
+ER_SIGNAL_WARN 01000
+ eng "Unhandled user-defined warning condition"
+
+# Note that the SQLSTATE is not 02000, it is provided by SIGNAL/RESIGNAL
+ER_SIGNAL_NOT_FOUND 02000
+ eng "Unhandled user-defined not found condition"
+
+# Note that the SQLSTATE is not HY000, it is provided by SIGNAL/RESIGNAL
+ER_SIGNAL_EXCEPTION HY000
+ eng "Unhandled user-defined exception condition"
+
+ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER 0K000
+ eng "RESIGNAL when handler not active"
+
+ER_SIGNAL_BAD_CONDITION_TYPE
+ eng "SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE"
+
+WARN_COND_ITEM_TRUNCATED
+ eng "Data truncated for condition item '%s'"
+
+ER_COND_ITEM_TOO_LONG
+ eng "Data too long for condition item '%s'"
+
+ER_UNKNOWN_LOCALE
+ eng "Unknown locale: '%-.64s'"
+
+ER_SLAVE_IGNORE_SERVER_IDS
+ eng "The requested server id %d clashes with the slave startup option --replicate-same-server-id"
+ER_QUERY_CACHE_DISABLED
+ eng "Query cache is disabled; restart the server with query_cache_type=1 to enable it"
+ER_SAME_NAME_PARTITION_FIELD
+ eng "Duplicate partition field name '%-.192s'"
+ER_PARTITION_COLUMN_LIST_ERROR
+ eng "Inconsistency in usage of column lists for partitioning"
+ER_WRONG_TYPE_COLUMN_VALUE_ERROR
+ eng "Partition column values of incorrect type"
+ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR
+ eng "Too many fields in '%-.192s'"
+ER_MAXVALUE_IN_VALUES_IN
+ eng "Cannot use MAXVALUE as value in VALUES IN"
+ER_TOO_MANY_VALUES_ERROR
+ eng "Cannot have more than one value for this type of %-.64s partitioning"
+ER_ROW_SINGLE_PARTITION_FIELD_ERROR
+ eng "Row expressions in VALUES IN only allowed for multi-field column partitioning"
+ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD
+ eng "Field '%-.192s' is of a not allowed type for this type of partitioning"
+ER_PARTITION_FIELDS_TOO_LONG
+ eng "The total length of the partitioning fields is too large"
+ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE
+ eng "Cannot execute statement: impossible to write to binary log since both row-incapable engines and statement-incapable engines are involved."
+ER_BINLOG_ROW_MODE_AND_STMT_ENGINE
+ eng "Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging."
+ER_BINLOG_UNSAFE_AND_STMT_ENGINE
+ eng "Cannot execute statement: impossible to write to binary log since statement is unsafe, storage engine is limited to statement-based logging, and BINLOG_FORMAT = MIXED. %s"
+ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE
+ eng "Cannot execute statement: impossible to write to binary log since statement is in row format and at least one table uses a storage engine limited to statement-based logging."
+ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
+ eng "Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging.%s"
+ER_BINLOG_ROW_INJECTION_AND_STMT_MODE
+ eng "Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT."
+ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE
+ eng "Cannot execute statement: impossible to write to binary log since more than one engine is involved and at least one engine is self-logging."
+
+ER_BINLOG_UNSAFE_LIMIT
+ eng "The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted."
+ER_BINLOG_UNSAFE_INSERT_DELAYED
+ eng "The statement is unsafe because it uses INSERT DELAYED. This is unsafe because the times when rows are inserted cannot be predicted."
+ER_BINLOG_UNSAFE_SYSTEM_TABLE
+ eng "The statement is unsafe because it uses the general log, slow query log, or performance_schema table(s). This is unsafe because system tables may differ on slaves."
+ER_BINLOG_UNSAFE_AUTOINC_COLUMNS
+ eng "Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly."
+ER_BINLOG_UNSAFE_UDF
+ eng "Statement is unsafe because it uses a UDF which may not return the same value on the slave."
+ER_BINLOG_UNSAFE_SYSTEM_VARIABLE
+ eng "Statement is unsafe because it uses a system variable that may have a different value on the slave."
+ER_BINLOG_UNSAFE_SYSTEM_FUNCTION
+ eng "Statement is unsafe because it uses a system function that may return a different value on the slave."
+ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS
+ eng "Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction."
+
+ER_MESSAGE_AND_STATEMENT
+ eng "%s Statement: %s"
+
+ER_SLAVE_CONVERSION_FAILED
+ eng "Column %d of table '%-.192s.%-.192s' cannot be converted from type '%-.32s' to type '%-.32s'"
+ER_SLAVE_CANT_CREATE_CONVERSION
+ eng "Can't create conversion table for table '%-.192s.%-.192s'"
+ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
+ eng "Cannot modify @@session.binlog_format inside a transaction"
+ER_PATH_LENGTH
+ eng "The path specified for %.64s is too long."
+ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT
+ eng "The syntax '%s' is deprecated and will be removed in MySQL %s."
+ ger "Die Syntax '%s' ist veraltet und wird in MySQL %s entfernt."
+
+ER_WRONG_NATIVE_TABLE_STRUCTURE
+ eng "Native table '%-.64s'.'%-.64s' has the wrong structure"
+
+ER_WRONG_PERFSCHEMA_USAGE
+ eng "Invalid performance_schema usage."
+ER_WARN_I_S_SKIPPED_TABLE
+ eng "Table '%s'.'%s' was skipped since its definition is being modified by concurrent DDL statement"
+
+ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT
+ eng "Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction"
+ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT
+ eng "Cannot change the binlog direct flag inside a stored function or trigger"
+ER_SPATIAL_MUST_HAVE_GEOM_COL 42000
+ eng "A SPATIAL index may only contain a geometrical type column"
+
+ER_TOO_LONG_INDEX_COMMENT
+ eng "Comment for index '%-.64s' is too long (max = %lu)"
+
+ER_LOCK_ABORTED
+ eng "Wait on a lock was aborted due to a pending exclusive lock"
+
+ER_DATA_OUT_OF_RANGE 22003
+ eng "%s value is out of range in '%s'"
+
+ER_WRONG_SPVAR_TYPE_IN_LIMIT
+ eng "A variable of a non-integer type in LIMIT clause"
+
+ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE
+ eng "Mixing self-logging and non-self-logging engines in a statement is unsafe."
+
+ER_BINLOG_UNSAFE_MIXED_STATEMENT
+ eng "Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them."
+
+ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN
+ eng "Cannot modify @@session.sql_log_bin inside a transaction"
+
+ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN
+ eng "Cannot change the sql_log_bin inside a stored function or trigger"
+
+ER_FAILED_READ_FROM_PAR_FILE
+ eng "Failed to read from the .par file"
+ swe "Misslyckades läsa från .par filen"
+
+ER_VALUES_IS_NOT_INT_TYPE_ERROR
+ eng "VALUES value for partition '%-.64s' must have type INT"
+ swe "Värden i VALUES för partition '%-.64s' måste ha typen INT"
+
+ER_ACCESS_DENIED_NO_PASSWORD_ERROR 28000
+ cze "P-Břístup pro uživatele '%-.48s'@'%-.64s'"
+ dan "Adgang nægtet bruger: '%-.48s'@'%-.64s'"
+ nla "Toegang geweigerd voor gebruiker: '%-.48s'@'%-.64s'"
+ eng "Access denied for user '%-.48s'@'%-.64s'"
+ est "Ligipääs keelatud kasutajale '%-.48s'@'%-.64s'"
+ fre "Accès refusé pour l'utilisateur: '%-.48s'@'@%-.64s'"
+ ger "Benutzer '%-.48s'@'%-.64s' hat keine Zugriffsberechtigung"
+ greek "Δεν επιτέÏεται η Ï€Ïόσβαση στο χÏήστη: '%-.48s'@'%-.64s'"
+ hun "A(z) '%-.48s'@'%-.64s' felhasznalo szamara tiltott eleres."
+ ita "Accesso non consentito per l'utente: '%-.48s'@'%-.64s'"
+ kor "'%-.48s'@'%-.64s' 사용ìžëŠ” ì ‘ê·¼ì´ ê±°ë¶€ ë˜ì—ˆìŠµë‹ˆë‹¤."
+ nor "Tilgang nektet for bruker: '%-.48s'@'%-.64s'"
+ norwegian-ny "Tilgang ikke tillate for brukar: '%-.48s'@'%-.64s'"
+ por "Acesso negado para o usuário '%-.48s'@'%-.64s'"
+ rum "Acces interzis pentru utilizatorul: '%-.48s'@'%-.64s'"
+ rus "ДоÑтуп закрыт Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ '%-.48s'@'%-.64s'"
+ serbian "Pristup je zabranjen korisniku '%-.48s'@'%-.64s'"
+ slo "Zakázaný prístup pre užívateľa: '%-.48s'@'%-.64s'"
+ spa "Acceso negado para usuario: '%-.48s'@'%-.64s'"
+ swe "Användare '%-.48s'@'%-.64s' är ej berättigad att logga in"
+ ukr "ДоÑтуп заборонено Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача: '%-.48s'@'%-.64s'"
+
+ER_SET_PASSWORD_AUTH_PLUGIN
+ eng "SET PASSWORD has no significance for users authenticating via plugins"
+
+ER_GRANT_PLUGIN_USER_EXISTS
+ eng "GRANT with IDENTIFIED WITH is illegal because the user %-.*s already exists"
+
+ER_TRUNCATE_ILLEGAL_FK 42000
+ eng "Cannot truncate a table referenced in a foreign key constraint (%.192s)"
+
+ER_PLUGIN_IS_PERMANENT
+ eng "Plugin '%s' is force_plus_permanent and can not be unloaded"
+
+ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN
+ eng "The requested value for the heartbeat period is less than 1 millisecond. The value is reset to 0, meaning that heartbeating will effectively be disabled."
+
+ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX
+ eng "The requested value for the heartbeat period exceeds the value of `slave_net_timeout' seconds. A sensible value for the period should be less than the timeout."
+
+ER_STMT_CACHE_FULL
+ eng "Multi-row statements required more than 'max_binlog_stmt_cache_size' bytes of storage; increase this mysqld variable and try again"
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
deleted file mode 100644
index bbae17c4327..00000000000
--- a/sql/share/errmsg.txt
+++ /dev/null
@@ -1,6215 +0,0 @@
-languages czech=cze latin2, danish=dan latin1, dutch=nla latin1, english=eng latin1, estonian=est latin7, french=fre latin1, german=ger latin1, greek=greek greek, hungarian=hun latin2, italian=ita latin1, japanese=jpn ujis, japanese-sjis=jps sjis, korean=kor euckr, norwegian-ny=norwegian-ny latin1, norwegian=nor latin1, polish=pol latin2, portuguese=por latin1, romanian=rum latin2, russian=rus koi8r, serbian=serbian cp1250, slovak=slo latin2, spanish=spa latin1, swedish=swe latin1, ukrainian=ukr koi8u;
-
-default-language eng
-
-start-error-number 1000
-
-ER_HASHCHK
- eng "hashchk"
-ER_NISAMCHK
- eng "isamchk"
-ER_NO
- cze "NE"
- dan "NEJ"
- nla "NEE"
- eng "NO"
- est "EI"
- fre "NON"
- ger "Nein"
- greek "Ï×É"
- hun "NEM"
- kor "¾Æ´Ï¿À"
- nor "NEI"
- norwegian-ny "NEI"
- pol "NIE"
- por "NÃO"
- rum "NU"
- rus "îåô"
- serbian "NE"
- slo "NIE"
- ukr "î¶"
-ER_YES
- cze "ANO"
- dan "JA"
- nla "JA"
- eng "YES"
- est "JAH"
- fre "OUI"
- ger "Ja"
- greek "ÍÁÉ"
- hun "IGEN"
- ita "SI"
- kor "¿¹"
- nor "JA"
- norwegian-ny "JA"
- pol "TAK"
- por "SIM"
- rum "DA"
- rus "äá"
- serbian "DA"
- slo "Áno"
- spa "SI"
- ukr "ôáë"
-ER_CANT_CREATE_FILE
- cze "Nemohu vytvo-Bøit soubor '%-.200s' (chybový kód: %d)"
- dan "Kan ikke oprette filen '%-.200s' (Fejlkode: %d)"
- nla "Kan file '%-.200s' niet aanmaken (Errcode: %d)"
- eng "Can't create file '%-.200s' (errno: %d)"
- est "Ei suuda luua faili '%-.200s' (veakood: %d)"
- fre "Ne peut créer le fichier '%-.200s' (Errcode: %d)"
- ger "Kann Datei '%-.200s' nicht erzeugen (Fehler: %d)"
- greek "Áäýíáôç ç äçìéïõñãßá ôïõ áñ÷åßïõ '%-.200s' (êùäéêüò ëÜèïõò: %d)"
- hun "A '%-.200s' file nem hozhato letre (hibakod: %d)"
- ita "Impossibile creare il file '%-.200s' (errno: %d)"
- jpn "'%-.200s' ¥Õ¥¡¥¤¥ë¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)"
- kor "È­ÀÏ '%-.200s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke opprette fila '%-.200s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje opprette fila '%-.200s' (Feilkode: %d)"
- pol "Nie mo¿na stworzyæ pliku '%-.200s' (Kod b³êdu: %d)"
- por "Não pode criar o arquivo '%-.200s' (erro no. %d)"
- rum "Nu pot sa creez fisierul '%-.200s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÆÁÊÌ '%-.200s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da kreiram file '%-.200s' (errno: %d)"
- slo "Nemô¾em vytvori» súbor '%-.200s' (chybový kód: %d)"
- spa "No puedo crear archivo '%-.200s' (Error: %d)"
- swe "Kan inte skapa filen '%-.200s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÆÁÊÌ '%-.200s' (ÐÏÍÉÌËÁ: %d)"
-ER_CANT_CREATE_TABLE
- cze "Nemohu vytvo-Bøit tabulku '%-.200s' (chybový kód: %d)"
- dan "Kan ikke oprette tabellen '%-.200s' (Fejlkode: %d)"
- nla "Kan tabel '%-.200s' niet aanmaken (Errcode: %d)"
- eng "Can't create table '%-.200s' (errno: %d)"
- jps "'%-.200s' ƒe[ƒuƒ‹‚ªì‚ê‚Ü‚¹‚ñ.(errno: %d)",
- est "Ei suuda luua tabelit '%-.200s' (veakood: %d)"
- fre "Ne peut créer la table '%-.200s' (Errcode: %d)"
- ger "Kann Tabelle '%-.200s' nicht erzeugen (Fehler: %d)"
- greek "Áäýíáôç ç äçìéïõñãßá ôïõ ðßíáêá '%-.200s' (êùäéêüò ëÜèïõò: %d)"
- hun "A '%-.200s' tabla nem hozhato letre (hibakod: %d)"
- ita "Impossibile creare la tabella '%-.200s' (errno: %d)"
- jpn "'%-.200s' ¥Æ¡¼¥Ö¥ë¤¬ºî¤ì¤Þ¤»¤ó.(errno: %d)"
- kor "Å×À̺í '%-.200s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke opprette tabellen '%-.200s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje opprette tabellen '%-.200s' (Feilkode: %d)"
- pol "Nie mo¿na stworzyæ tabeli '%-.200s' (Kod b³êdu: %d)"
- por "Não pode criar a tabela '%-.200s' (erro no. %d)"
- rum "Nu pot sa creez tabla '%-.200s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÔÁÂÌÉÃÕ '%-.200s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da kreiram tabelu '%-.200s' (errno: %d)"
- slo "Nemô¾em vytvori» tabuµku '%-.200s' (chybový kód: %d)"
- spa "No puedo crear tabla '%-.200s' (Error: %d)"
- swe "Kan inte skapa tabellen '%-.200s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÔÁÂÌÉÃÀ '%-.200s' (ÐÏÍÉÌËÁ: %d)"
-ER_CANT_CREATE_DB
- cze "Nemohu vytvo-Bøit databázi '%-.192s' (chybový kód: %d)"
- dan "Kan ikke oprette databasen '%-.192s' (Fejlkode: %d)"
- nla "Kan database '%-.192s' niet aanmaken (Errcode: %d)"
- eng "Can't create database '%-.192s' (errno: %d)"
- jps "'%-.192s' ƒf[ƒ^ƒx[ƒX‚ªì‚ê‚Ü‚¹‚ñ (errno: %d)",
- est "Ei suuda luua andmebaasi '%-.192s' (veakood: %d)"
- fre "Ne peut créer la base '%-.192s' (Erreur %d)"
- ger "Kann Datenbank '%-.192s' nicht erzeugen (Fehler: %d)"
- greek "Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.192s' (êùäéêüò ëÜèïõò: %d)"
- hun "Az '%-.192s' adatbazis nem hozhato letre (hibakod: %d)"
- ita "Impossibile creare il database '%-.192s' (errno: %d)"
- jpn "'%-.192s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)"
- kor "µ¥ÀÌŸº£À̽º '%-.192s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke opprette databasen '%-.192s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje opprette databasen '%-.192s' (Feilkode: %d)"
- pol "Nie mo¿na stworzyæ bazy danych '%-.192s' (Kod b³êdu: %d)"
- por "Não pode criar o banco de dados '%-.192s' (erro no. %d)"
- rum "Nu pot sa creez baza de date '%-.192s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.192s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da kreiram bazu '%-.192s' (errno: %d)"
- slo "Nemô¾em vytvori» databázu '%-.192s' (chybový kód: %d)"
- spa "No puedo crear base de datos '%-.192s' (Error: %d)"
- swe "Kan inte skapa databasen '%-.192s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
-ER_DB_CREATE_EXISTS
- cze "Nemohu vytvo-Bøit databázi '%-.192s'; databáze ji¾ existuje"
- dan "Kan ikke oprette databasen '%-.192s'; databasen eksisterer"
- nla "Kan database '%-.192s' niet aanmaken; database bestaat reeds"
- eng "Can't create database '%-.192s'; database exists"
- jps "'%-.192s' ƒf[ƒ^ƒx[ƒX‚ªì‚ê‚Ü‚¹‚ñ.Šù‚É‚»‚̃f[ƒ^ƒx[ƒX‚ª‘¶Ý‚µ‚Ü‚·",
- est "Ei suuda luua andmebaasi '%-.192s': andmebaas juba eksisteerib"
- fre "Ne peut créer la base '%-.192s'; elle existe déjà"
- ger "Kann Datenbank '%-.192s' nicht erzeugen. Datenbank existiert bereits"
- greek "Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.192s'; Ç âÜóç äåäïìÝíùí õðÜñ÷åé Þäç"
- hun "Az '%-.192s' adatbazis nem hozhato letre Az adatbazis mar letezik"
- ita "Impossibile creare il database '%-.192s'; il database esiste"
- jpn "'%-.192s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó.´û¤Ë¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬Â¸ºß¤·¤Þ¤¹"
- kor "µ¥ÀÌŸº£À̽º '%-.192s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÔ"
- nor "Kan ikke opprette databasen '%-.192s'; databasen eksisterer"
- norwegian-ny "Kan ikkje opprette databasen '%-.192s'; databasen eksisterer"
- pol "Nie mo¿na stworzyæ bazy danych '%-.192s'; baza danych ju¿ istnieje"
- por "Não pode criar o banco de dados '%-.192s'; este banco de dados já existe"
- rum "Nu pot sa creez baza de date '%-.192s'; baza de date exista deja"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.192s'. âÁÚÁ ÄÁÎÎÙÈ ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Ne mogu da kreiram bazu '%-.192s'; baza veæ postoji."
- slo "Nemô¾em vytvori» databázu '%-.192s'; databáza existuje"
- spa "No puedo crear base de datos '%-.192s'; la base de datos ya existe"
- swe "Databasen '%-.192s' existerar redan"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.192s'. âÁÚÁ ÄÁÎÎÉÈ ¦ÓÎÕ¤"
-ER_DB_DROP_EXISTS
- cze "Nemohu zru-B¹it databázi '%-.192s', databáze neexistuje"
- dan "Kan ikke slette (droppe) '%-.192s'; databasen eksisterer ikke"
- nla "Kan database '%-.192s' niet verwijderen; database bestaat niet"
- eng "Can't drop database '%-.192s'; database doesn't exist"
- jps "'%-.192s' ƒf[ƒ^ƒx[ƒX‚ð”jŠü‚Å‚«‚Ü‚¹‚ñ. ‚»‚̃f[ƒ^ƒx[ƒX‚ª‚È‚¢‚Ì‚Å‚·.",
- est "Ei suuda kustutada andmebaasi '%-.192s': andmebaasi ei eksisteeri"
- fre "Ne peut effacer la base '%-.192s'; elle n'existe pas"
- ger "Kann Datenbank '%-.192s' nicht löschen; Datenbank nicht vorhanden"
- greek "Áäýíáôç ç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí '%-.192s'. Ç âÜóç äåäïìÝíùí äåí õðÜñ÷åé"
- hun "A(z) '%-.192s' adatbazis nem szuntetheto meg. Az adatbazis nem letezik"
- ita "Impossibile cancellare '%-.192s'; il database non esiste"
- jpn "'%-.192s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤òÇË´þ¤Ç¤­¤Þ¤»¤ó. ¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬¤Ê¤¤¤Î¤Ç¤¹."
- kor "µ¥ÀÌŸº£À̽º '%-.192s'¸¦ Á¦°ÅÇÏÁö ¸øÇß½À´Ï´Ù. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÏÁö ¾ÊÀ½ "
- nor "Kan ikke fjerne (drop) '%-.192s'; databasen eksisterer ikke"
- norwegian-ny "Kan ikkje fjerne (drop) '%-.192s'; databasen eksisterer ikkje"
- pol "Nie mo¿na usun?æ bazy danych '%-.192s'; baza danych nie istnieje"
- por "Não pode eliminar o banco de dados '%-.192s'; este banco de dados não existe"
- rum "Nu pot sa drop baza de date '%-.192s'; baza da date este inexistenta"
- rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.192s'. ôÁËÏÊ ÂÁÚÙ ÄÁÎÎÙÈ ÎÅÔ"
- serbian "Ne mogu da izbrišem bazu '%-.192s'; baza ne postoji."
- slo "Nemô¾em zmaza» databázu '%-.192s'; databáza neexistuje"
- spa "No puedo eliminar base de datos '%-.192s'; la base de datos no existe"
- swe "Kan inte radera databasen '%-.192s'; databasen finns inte"
- ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.192s'. âÁÚÁ ÄÁÎÎÉÈ ÎÅ ¦ÓÎÕ¤"
-ER_DB_DROP_DELETE
- cze "Chyba p-Bøi ru¹ení databáze (nemohu vymazat '%-.192s', chyba %d)"
- dan "Fejl ved sletning (drop) af databasen (kan ikke slette '%-.192s', Fejlkode %d)"
- nla "Fout bij verwijderen database (kan '%-.192s' niet verwijderen, Errcode: %d)"
- eng "Error dropping database (can't delete '%-.192s', errno: %d)"
- jps "ƒf[ƒ^ƒx[ƒX”jŠüƒGƒ‰[ ('%-.192s' ‚ð휂ł«‚Ü‚¹‚ñ, errno: %d)",
- est "Viga andmebaasi kustutamisel (ei suuda kustutada faili '%-.192s', veakood: %d)"
- fre "Ne peut effacer la base '%-.192s' (erreur %d)"
- ger "Fehler beim Löschen der Datenbank ('%-.192s' kann nicht gelöscht werden, Fehler: %d)"
- greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ '%-.192s', êùäéêüò ëÜèïõò: %d)"
- hun "Adatbazis megszuntetesi hiba ('%-.192s' nem torolheto, hibakod: %d)"
- ita "Errore durante la cancellazione del database (impossibile cancellare '%-.192s', errno: %d)"
- jpn "¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.192s' ¤òºï½ü¤Ç¤­¤Þ¤»¤ó, errno: %d)"
- kor "µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯('%-.192s'¸¦ »èÁ¦ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)"
- nor "Feil ved fjerning (drop) av databasen (kan ikke slette '%-.192s', feil %d)"
- norwegian-ny "Feil ved fjerning (drop) av databasen (kan ikkje slette '%-.192s', feil %d)"
- pol "B³?d podczas usuwania bazy danych (nie mo¿na usun?æ '%-.192s', b³?d %d)"
- por "Erro ao eliminar banco de dados (não pode eliminar '%-.192s' - erro no. %d)"
- rum "Eroare dropuind baza de date (nu pot sa sterg '%-.192s', Eroare: %d)"
- rus "ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ ÂÁÚÙ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ '%-.192s', ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da izbrišem bazu (ne mogu da izbrišem '%-.192s', errno: %d)"
- slo "Chyba pri mazaní databázy (nemô¾em zmaza» '%-.192s', chybový kód: %d)"
- spa "Error eliminando la base de datos(no puedo borrar '%-.192s', error %d)"
- swe "Fel vid radering av databasen (Kan inte radera '%-.192s'. Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.192s', ÐÏÍÉÌËÁ: %d)"
-ER_DB_DROP_RMDIR
- cze "Chyba p-Bøi ru¹ení databáze (nemohu vymazat adresáø '%-.192s', chyba %d)"
- dan "Fejl ved sletting af database (kan ikke slette folderen '%-.192s', Fejlkode %d)"
- nla "Fout bij verwijderen database (kan rmdir '%-.192s' niet uitvoeren, Errcode: %d)"
- eng "Error dropping database (can't rmdir '%-.192s', errno: %d)"
- jps "ƒf[ƒ^ƒx[ƒX”jŠüƒGƒ‰[ ('%-.192s' ‚ð rmdir ‚Å‚«‚Ü‚¹‚ñ, errno: %d)",
- est "Viga andmebaasi kustutamisel (ei suuda kustutada kataloogi '%-.192s', veakood: %d)"
- fre "Erreur en effaçant la base (rmdir '%-.192s', erreur %d)"
- ger "Fehler beim Löschen der Datenbank (Verzeichnis '%-.192s' kann nicht gelöscht werden, Fehler: %d)"
- greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ ôïõ öáêÝëëïõ '%-.192s', êùäéêüò ëÜèïõò: %d)"
- hun "Adatbazis megszuntetesi hiba ('%-.192s' nem szuntetheto meg, hibakod: %d)"
- ita "Errore durante la cancellazione del database (impossibile rmdir '%-.192s', errno: %d)"
- jpn "¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.192s' ¤ò rmdir ¤Ç¤­¤Þ¤»¤ó, errno: %d)"
- kor "µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯(rmdir '%-.192s'¸¦ ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)"
- nor "Feil ved sletting av database (kan ikke slette katalogen '%-.192s', feil %d)"
- norwegian-ny "Feil ved sletting av database (kan ikkje slette katalogen '%-.192s', feil %d)"
- pol "B³?d podczas usuwania bazy danych (nie mo¿na wykonaæ rmdir '%-.192s', b³?d %d)"
- por "Erro ao eliminar banco de dados (não pode remover diretório '%-.192s' - erro no. %d)"
- rum "Eroare dropuind baza de date (nu pot sa rmdir '%-.192s', Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ËÁÔÁÌÏÇ '%-.192s', ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da izbrišem bazu (ne mogu da izbrišem direktorijum '%-.192s', errno: %d)"
- slo "Chyba pri mazaní databázy (nemô¾em vymaza» adresár '%-.192s', chybový kód: %d)"
- spa "Error eliminando la base de datos (No puedo borrar directorio '%-.192s', error %d)"
- swe "Fel vid radering av databasen (Kan inte radera biblioteket '%-.192s'. Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÔÅËÕ '%-.192s', ÐÏÍÉÌËÁ: %d)"
-ER_CANT_DELETE_FILE
- cze "Chyba p-Bøi výmazu '%-.192s' (chybový kód: %d)"
- dan "Fejl ved sletning af '%-.192s' (Fejlkode: %d)"
- nla "Fout bij het verwijderen van '%-.192s' (Errcode: %d)"
- eng "Error on delete of '%-.192s' (errno: %d)"
- jps "'%-.192s' ‚Ì휂ªƒGƒ‰[ (errno: %d)",
- est "Viga '%-.192s' kustutamisel (veakood: %d)"
- fre "Erreur en effaçant '%-.192s' (Errcode: %d)"
- ger "Fehler beim Löschen von '%-.192s' (Fehler: %d)"
- greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ '%-.192s' (êùäéêüò ëÜèïõò: %d)"
- hun "Torlesi hiba: '%-.192s' (hibakod: %d)"
- ita "Errore durante la cancellazione di '%-.192s' (errno: %d)"
- jpn "'%-.192s' ¤Îºï½ü¤¬¥¨¥é¡¼ (errno: %d)"
- kor "'%-.192s' »èÁ¦ Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
- nor "Feil ved sletting av '%-.192s' (Feilkode: %d)"
- norwegian-ny "Feil ved sletting av '%-.192s' (Feilkode: %d)"
- pol "B³?d podczas usuwania '%-.192s' (Kod b³êdu: %d)"
- por "Erro na remoção de '%-.192s' (erro no. %d)"
- rum "Eroare incercind sa delete '%-.192s' (Eroare: %d)"
- rus "ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ '%-.192s' (ÏÛÉÂËÁ: %d)"
- serbian "Greška pri brisanju '%-.192s' (errno: %d)"
- slo "Chyba pri mazaní '%-.192s' (chybový kód: %d)"
- spa "Error en el borrado de '%-.192s' (Error: %d)"
- swe "Kan inte radera filen '%-.192s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
-ER_CANT_FIND_SYSTEM_REC
- cze "Nemohu -Bèíst záznam v systémové tabulce"
- dan "Kan ikke læse posten i systemfolderen"
- nla "Kan record niet lezen in de systeem tabel"
- eng "Can't read record in system table"
- jps "system table ‚̃ŒƒR[ƒh‚ð“Ç‚ÞŽ–‚ª‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½",
- est "Ei suuda lugeda kirjet süsteemsest tabelist"
- fre "Ne peut lire un enregistrement de la table 'system'"
- ger "Datensatz in der Systemtabelle nicht lesbar"
- greek "Áäýíáôç ç áíÜãíùóç åããñáöÞò áðü ðßíáêá ôïõ óõóôÞìáôïò"
- hun "Nem olvashato rekord a rendszertablaban"
- ita "Impossibile leggere il record dalla tabella di sistema"
- jpn "system table ¤Î¥ì¥³¡¼¥É¤òÆɤà»ö¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
- kor "system Å×ÀÌºí¿¡¼­ ·¹Äڵ带 ÀÐÀ» ¼ö ¾ø½À´Ï´Ù."
- nor "Kan ikke lese posten i systemkatalogen"
- norwegian-ny "Kan ikkje lese posten i systemkatalogen"
- pol "Nie mo¿na odczytaæ rekordu z tabeli systemowej"
- por "Não pode ler um registro numa tabela do sistema"
- rum "Nu pot sa citesc cimpurile in tabla de system (system table)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÞÉÔÁÔØ ÚÁÐÉÓØ × ÓÉÓÔÅÍÎÏÊ ÔÁÂÌÉÃÅ"
- serbian "Ne mogu da proèitam slog iz sistemske tabele"
- slo "Nemô¾em èíta» záznam v systémovej tabuµke"
- spa "No puedo leer el registro en la tabla del sistema"
- swe "Hittar inte posten i systemregistret"
- ukr "îÅ ÍÏÖÕ ÚÞÉÔÁÔÉ ÚÁÐÉÓ Ú ÓÉÓÔÅÍÎϧ ÔÁÂÌÉæ"
-ER_CANT_GET_STAT
- cze "Nemohu z-Bískat stav '%-.200s' (chybový kód: %d)"
- dan "Kan ikke læse status af '%-.200s' (Fejlkode: %d)"
- nla "Kan de status niet krijgen van '%-.200s' (Errcode: %d)"
- eng "Can't get status of '%-.200s' (errno: %d)"
- jps "'%-.200s' ‚̃XƒeƒCƒ^ƒX‚ª“¾‚ç‚ê‚Ü‚¹‚ñ. (errno: %d)",
- est "Ei suuda lugeda '%-.200s' olekut (veakood: %d)"
- fre "Ne peut obtenir le status de '%-.200s' (Errcode: %d)"
- ger "Kann Status von '%-.200s' nicht ermitteln (Fehler: %d)"
- greek "Áäýíáôç ç ëÞøç ðëçñïöïñéþí ãéá ôçí êáôÜóôáóç ôïõ '%-.200s' (êùäéêüò ëÜèïõò: %d)"
- hun "A(z) '%-.200s' statusza nem allapithato meg (hibakod: %d)"
- ita "Impossibile leggere lo stato di '%-.200s' (errno: %d)"
- jpn "'%-.200s' ¤Î¥¹¥Æ¥¤¥¿¥¹¤¬ÆÀ¤é¤ì¤Þ¤»¤ó. (errno: %d)"
- kor "'%-.200s'ÀÇ »óŸ¦ ¾òÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke lese statusen til '%-.200s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje lese statusen til '%-.200s' (Feilkode: %d)"
- pol "Nie mo¿na otrzymaæ statusu '%-.200s' (Kod b³êdu: %d)"
- por "Não pode obter o status de '%-.200s' (erro no. %d)"
- rum "Nu pot sa obtin statusul lui '%-.200s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÏÌÕÞÉÔØ ÓÔÁÔÕÓÎÕÀ ÉÎÆÏÒÍÁÃÉÀ Ï '%-.200s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da dobijem stanje file-a '%-.200s' (errno: %d)"
- slo "Nemô¾em zisti» stav '%-.200s' (chybový kód: %d)"
- spa "No puedo obtener el estado de '%-.200s' (Error: %d)"
- swe "Kan inte läsa filinformationen (stat) från '%-.200s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÏÔÒÉÍÁÔÉ ÓÔÁÔÕÓ '%-.200s' (ÐÏÍÉÌËÁ: %d)"
-ER_CANT_GET_WD
- cze "Chyba p-Bøi zji¹»ování pracovní adresáø (chybový kód: %d)"
- dan "Kan ikke læse aktive folder (Fejlkode: %d)"
- nla "Kan de werkdirectory niet krijgen (Errcode: %d)"
- eng "Can't get working directory (errno: %d)"
- jps "working directory ‚𓾂鎖‚ª‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½ (errno: %d)",
- est "Ei suuda identifitseerida jooksvat kataloogi (veakood: %d)"
- fre "Ne peut obtenir le répertoire de travail (Errcode: %d)"
- ger "Kann Arbeitsverzeichnis nicht ermitteln (Fehler: %d)"
- greek "Ï öÜêåëëïò åñãáóßáò äåí âñÝèçêå (êùäéêüò ëÜèïõò: %d)"
- hun "A munkakonyvtar nem allapithato meg (hibakod: %d)"
- ita "Impossibile leggere la directory di lavoro (errno: %d)"
- jpn "working directory ¤òÆÀ¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿ (errno: %d)"
- kor "¼öÇà µð·ºÅ丮¸¦ ãÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke lese aktiv katalog(Feilkode: %d)"
- norwegian-ny "Kan ikkje lese aktiv katalog(Feilkode: %d)"
- pol "Nie mo¿na rozpoznaæ aktualnego katalogu (Kod b³êdu: %d)"
- por "Não pode obter o diretório corrente (erro no. %d)"
- rum "Nu pot sa obtin directorul current (working directory) (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÏÐÒÅÄÅÌÉÔØ ÒÁÂÏÞÉÊ ËÁÔÁÌÏÇ (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da dobijem trenutni direktorijum (errno: %d)"
- slo "Nemô¾em zisti» pracovný adresár (chybový kód: %d)"
- spa "No puedo acceder al directorio (Error: %d)"
- swe "Kan inte inte läsa aktivt bibliotek. (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ×ÉÚÎÁÞÉÔÉ ÒÏÂÏÞÕ ÔÅËÕ (ÐÏÍÉÌËÁ: %d)"
-ER_CANT_LOCK
- cze "Nemohu uzamknout soubor (chybov-Bý kód: %d)"
- dan "Kan ikke låse fil (Fejlkode: %d)"
- nla "Kan de file niet blokeren (Errcode: %d)"
- eng "Can't lock file (errno: %d)"
- jps "ƒtƒ@ƒCƒ‹‚ðƒƒbƒN‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
- est "Ei suuda lukustada faili (veakood: %d)"
- fre "Ne peut verrouiller le fichier (Errcode: %d)"
- ger "Datei kann nicht gesperrt werden (Fehler: %d)"
- greek "Ôï áñ÷åßï äåí ìðïñåß íá êëåéäùèåß (êùäéêüò ëÜèïõò: %d)"
- hun "A file nem zarolhato. (hibakod: %d)"
- ita "Impossibile il locking il file (errno: %d)"
- jpn "¥Õ¥¡¥¤¥ë¤ò¥í¥Ã¥¯¤Ç¤­¤Þ¤»¤ó (errno: %d)"
- kor "È­ÀÏÀ» Àá±×Áö(lock) ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke låse fila (Feilkode: %d)"
- norwegian-ny "Kan ikkje låse fila (Feilkode: %d)"
- pol "Nie mo¿na zablokowaæ pliku (Kod b³êdu: %d)"
- por "Não pode travar o arquivo (erro no. %d)"
- rum "Nu pot sa lock fisierul (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÏÓÔÁ×ÉÔØ ÂÌÏËÉÒÏ×ËÕ ÎÁ ÆÁÊÌÅ (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da zakljuèam file (errno: %d)"
- slo "Nemô¾em zamknú» súbor (chybový kód: %d)"
- spa "No puedo bloquear archivo: (Error: %d)"
- swe "Kan inte låsa filen. (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÚÁÂÌÏËÕ×ÁÔÉ ÆÁÊÌ (ÐÏÍÉÌËÁ: %d)"
-ER_CANT_OPEN_FILE
- cze "Nemohu otev-Bøít soubor '%-.200s' (chybový kód: %d)"
- dan "Kan ikke åbne fil: '%-.200s' (Fejlkode: %d)"
- nla "Kan de file '%-.200s' niet openen (Errcode: %d)"
- eng "Can't open file: '%-.200s' (errno: %d)"
- jps "'%-.200s' ƒtƒ@ƒCƒ‹‚ðŠJ‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
- est "Ei suuda avada faili '%-.200s' (veakood: %d)"
- fre "Ne peut ouvrir le fichier: '%-.200s' (Errcode: %d)"
- ger "Kann Datei '%-.200s' nicht öffnen (Fehler: %d)"
- greek "Äåí åßíáé äõíáôü íá áíïé÷ôåß ôï áñ÷åßï: '%-.200s' (êùäéêüò ëÜèïõò: %d)"
- hun "A '%-.200s' file nem nyithato meg (hibakod: %d)"
- ita "Impossibile aprire il file: '%-.200s' (errno: %d)"
- jpn "'%-.200s' ¥Õ¥¡¥¤¥ë¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)"
- kor "È­ÀÏÀ» ¿­Áö ¸øÇß½À´Ï´Ù.: '%-.200s' (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke åpne fila: '%-.200s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje åpne fila: '%-.200s' (Feilkode: %d)"
- pol "Nie mo¿na otworzyæ pliku: '%-.200s' (Kod b³êdu: %d)"
- por "Não pode abrir o arquivo '%-.200s' (erro no. %d)"
- rum "Nu pot sa deschid fisierul: '%-.200s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÆÁÊÌ: '%-.200s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da otvorim file: '%-.200s' (errno: %d)"
- slo "Nemô¾em otvori» súbor: '%-.200s' (chybový kód: %d)"
- spa "No puedo abrir archivo: '%-.200s' (Error: %d)"
- swe "Kan inte använda '%-.200s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÆÁÊÌ: '%-.200s' (ÐÏÍÉÌËÁ: %d)"
-ER_FILE_NOT_FOUND
- cze "Nemohu naj-Bít soubor '%-.200s' (chybový kód: %d)"
- dan "Kan ikke finde fila: '%-.200s' (Fejlkode: %d)"
- nla "Kan de file: '%-.200s' niet vinden (Errcode: %d)"
- eng "Can't find file: '%-.200s' (errno: %d)"
- jps "'%-.200s' ƒtƒ@ƒCƒ‹‚ðŒ©•t‚¯‚鎖‚ª‚Å‚«‚Ü‚¹‚ñ.(errno: %d)",
- est "Ei suuda leida faili '%-.200s' (veakood: %d)"
- fre "Ne peut trouver le fichier: '%-.200s' (Errcode: %d)"
- ger "Kann Datei '%-.200s' nicht finden (Fehler: %d)"
- greek "Äåí âñÝèçêå ôï áñ÷åßï: '%-.200s' (êùäéêüò ëÜèïõò: %d)"
- hun "A(z) '%-.200s' file nem talalhato (hibakod: %d)"
- ita "Impossibile trovare il file: '%-.200s' (errno: %d)"
- jpn "'%-.200s' ¥Õ¥¡¥¤¥ë¤ò¸«ÉÕ¤±¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó.(errno: %d)"
- kor "È­ÀÏÀ» ãÁö ¸øÇß½À´Ï´Ù.: '%-.200s' (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke finne fila: '%-.200s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje finne fila: '%-.200s' (Feilkode: %d)"
- pol "Nie mo¿na znale¥æ pliku: '%-.200s' (Kod b³êdu: %d)"
- por "Não pode encontrar o arquivo '%-.200s' (erro no. %d)"
- rum "Nu pot sa gasesc fisierul: '%-.200s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÆÁÊÌ: '%-.200s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da pronaðem file: '%-.200s' (errno: %d)"
- slo "Nemô¾em nájs» súbor: '%-.200s' (chybový kód: %d)"
- spa "No puedo encontrar archivo: '%-.200s' (Error: %d)"
- swe "Hittar inte filen '%-.200s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ ÆÁÊÌ: '%-.200s' (ÐÏÍÉÌËÁ: %d)"
-ER_CANT_READ_DIR
- cze "Nemohu -Bèíst adresáø '%-.192s' (chybový kód: %d)"
- dan "Kan ikke læse folder '%-.192s' (Fejlkode: %d)"
- nla "Kan de directory niet lezen van '%-.192s' (Errcode: %d)"
- eng "Can't read dir of '%-.192s' (errno: %d)"
- jps "'%-.192s' ƒfƒBƒŒƒNƒgƒŠ‚ª“Ç‚ß‚Ü‚¹‚ñ.(errno: %d)",
- est "Ei suuda lugeda kataloogi '%-.192s' (veakood: %d)"
- fre "Ne peut lire le répertoire de '%-.192s' (Errcode: %d)"
- ger "Verzeichnis von '%-.192s' nicht lesbar (Fehler: %d)"
- greek "Äåí åßíáé äõíáôü íá äéáâáóôåß ï öÜêåëëïò ôïõ '%-.192s' (êùäéêüò ëÜèïõò: %d)"
- hun "A(z) '%-.192s' konyvtar nem olvashato. (hibakod: %d)"
- ita "Impossibile leggere la directory di '%-.192s' (errno: %d)"
- jpn "'%-.192s' ¥Ç¥£¥ì¥¯¥È¥ê¤¬Æɤá¤Þ¤»¤ó.(errno: %d)"
- kor "'%-.192s'µð·ºÅ丮¸¦ ÀÐÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke lese katalogen '%-.192s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje lese katalogen '%-.192s' (Feilkode: %d)"
- pol "Nie mo¿na odczytaæ katalogu '%-.192s' (Kod b³êdu: %d)"
- por "Não pode ler o diretório de '%-.192s' (erro no. %d)"
- rum "Nu pot sa citesc directorul '%-.192s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÞÉÔÁÔØ ËÁÔÁÌÏÇ '%-.192s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da proèitam direktorijum '%-.192s' (errno: %d)"
- slo "Nemô¾em èíta» adresár '%-.192s' (chybový kód: %d)"
- spa "No puedo leer el directorio de '%-.192s' (Error: %d)"
- swe "Kan inte läsa från bibliotek '%-.192s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÐÒÏÞÉÔÁÔÉ ÔÅËÕ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
-ER_CANT_SET_WD
- cze "Nemohu zm-Bìnit adresáø na '%-.192s' (chybový kód: %d)"
- dan "Kan ikke skifte folder til '%-.192s' (Fejlkode: %d)"
- nla "Kan de directory niet veranderen naar '%-.192s' (Errcode: %d)"
- eng "Can't change dir to '%-.192s' (errno: %d)"
- jps "'%-.192s' ƒfƒBƒŒƒNƒgƒŠ‚É chdir ‚Å‚«‚Ü‚¹‚ñ.(errno: %d)",
- est "Ei suuda siseneda kataloogi '%-.192s' (veakood: %d)"
- fre "Ne peut changer le répertoire pour '%-.192s' (Errcode: %d)"
- ger "Kann nicht in das Verzeichnis '%-.192s' wechseln (Fehler: %d)"
- greek "Áäýíáôç ç áëëáãÞ ôïõ ôñÝ÷ïíôïò êáôáëüãïõ óå '%-.192s' (êùäéêüò ëÜèïõò: %d)"
- hun "Konyvtarvaltas nem lehetseges a(z) '%-.192s'-ba. (hibakod: %d)"
- ita "Impossibile cambiare la directory in '%-.192s' (errno: %d)"
- jpn "'%-.192s' ¥Ç¥£¥ì¥¯¥È¥ê¤Ë chdir ¤Ç¤­¤Þ¤»¤ó.(errno: %d)"
- kor "'%-.192s'µð·ºÅ丮·Î À̵¿ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke skifte katalog til '%-.192s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje skifte katalog til '%-.192s' (Feilkode: %d)"
- pol "Nie mo¿na zmieniæ katalogu na '%-.192s' (Kod b³êdu: %d)"
- por "Não pode mudar para o diretório '%-.192s' (erro no. %d)"
- rum "Nu pot sa schimb directorul '%-.192s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÅÒÅÊÔÉ × ËÁÔÁÌÏÇ '%-.192s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da promenim direktorijum na '%-.192s' (errno: %d)"
- slo "Nemô¾em vojs» do adresára '%-.192s' (chybový kód: %d)"
- spa "No puedo cambiar al directorio de '%-.192s' (Error: %d)"
- swe "Kan inte byta till '%-.192s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÐÅÒÅÊÔÉ Õ ÔÅËÕ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
-ER_CHECKREAD
- cze "Z-Báznam byl zmìnìn od posledního ètení v tabulce '%-.192s'"
- dan "Posten er ændret siden sidste læsning '%-.192s'"
- nla "Record is veranderd sinds de laatste lees activiteit in de tabel '%-.192s'"
- eng "Record has changed since last read in table '%-.192s'"
- est "Kirje tabelis '%-.192s' on muutunud viimasest lugemisest saadik"
- fre "Enregistrement modifié depuis sa dernière lecture dans la table '%-.192s'"
- ger "Datensatz hat sich seit dem letzten Zugriff auf Tabelle '%-.192s' geändert"
- greek "Ç åããñáöÞ Ý÷åé áëëÜîåé áðü ôçí ôåëåõôáßá öïñÜ ðïõ áíáóýñèçêå áðü ôïí ðßíáêá '%-.192s'"
- hun "A(z) '%-.192s' tablaban talalhato rekord megvaltozott az utolso olvasas ota"
- ita "Il record e` cambiato dall'ultima lettura della tabella '%-.192s'"
- kor "Å×À̺í '%-.192s'¿¡¼­ ¸¶Áö¸·À¸·Î ÀÐÀº ÈÄ Record°¡ º¯°æµÇ¾ú½À´Ï´Ù."
- nor "Posten har blitt endret siden den ble lest '%-.192s'"
- norwegian-ny "Posten har vorte endra sidan den sist vart lesen '%-.192s'"
- pol "Rekord zosta³ zmieniony od ostaniego odczytania z tabeli '%-.192s'"
- por "Registro alterado desde a última leitura da tabela '%-.192s'"
- rum "Cimpul a fost schimbat de la ultima citire a tabelei '%-.192s'"
- rus "úÁÐÉÓØ ÉÚÍÅÎÉÌÁÓØ Ó ÍÏÍÅÎÔÁ ÐÏÓÌÅÄÎÅÊ ×ÙÂÏÒËÉ × ÔÁÂÌÉÃÅ '%-.192s'"
- serbian "Slog je promenjen od zadnjeg èitanja tabele '%-.192s'"
- slo "Záznam bol zmenený od posledného èítania v tabuµke '%-.192s'"
- spa "El registro ha cambiado desde la ultima lectura de la tabla '%-.192s'"
- swe "Posten har förändrats sedan den lästes i register '%-.192s'"
- ukr "úÁÐÉÓ ÂÕÌÏ ÚͦÎÅÎÏ Ú ÞÁÓÕ ÏÓÔÁÎÎØÏÇÏ ÞÉÔÁÎÎÑ Ú ÔÁÂÌÉæ '%-.192s'"
-ER_DISK_FULL
- cze "Disk je pln-Bý (%s), èekám na uvolnìní nìjakého místa ..."
- dan "Ikke mere diskplads (%s). Venter på at få frigjort plads..."
- nla "Schijf vol (%s). Aan het wachten totdat er ruimte vrij wordt gemaakt..."
- eng "Disk full (%s); waiting for someone to free some space..."
- jps "Disk full (%s). ’N‚©‚ª‰½‚©‚ðŒ¸‚ç‚·‚Ü‚Å‚Ü‚Á‚Ä‚­‚¾‚³‚¢...",
- est "Ketas täis (%s). Ootame kuni tekib vaba ruumi..."
- fre "Disque plein (%s). J'attend que quelqu'un libère de l'espace..."
- ger "Festplatte voll (%s). Warte, bis jemand Platz schafft ..."
- greek "Äåí õðÜñ÷åé ÷þñïò óôï äßóêï (%s). Ðáñáêáëþ, ðåñéìÝíåôå íá åëåõèåñùèåß ÷þñïò..."
- hun "A lemez megtelt (%s)."
- ita "Disco pieno (%s). In attesa che qualcuno liberi un po' di spazio..."
- jpn "Disk full (%s). 狼¤¬²¿¤«¤ò¸º¤é¤¹¤Þ¤Ç¤Þ¤Ã¤Æ¤¯¤À¤µ¤¤..."
- kor "Disk full (%s). ´Ù¸¥ »ç¶÷ÀÌ Áö¿ï¶§±îÁö ±â´Ù¸³´Ï´Ù..."
- nor "Ikke mer diskplass (%s). Venter på å få frigjort plass..."
- norwegian-ny "Ikkje meir diskplass (%s). Ventar på å få frigjort plass..."
- pol "Dysk pe³ny (%s). Oczekiwanie na zwolnienie miejsca..."
- por "Disco cheio (%s). Aguardando alguém liberar algum espaço..."
- rum "Hard-disk-ul este plin (%s). Astept sa se elibereze ceva spatiu..."
- rus "äÉÓË ÚÁÐÏÌÎÅÎ. (%s). ïÖÉÄÁÅÍ, ÐÏËÁ ËÔÏ-ÔÏ ÎÅ ÕÂÅÒÅÔ ÐÏÓÌÅ ÓÅÂÑ ÍÕÓÏÒ..."
- serbian "Disk je pun (%s). Èekam nekoga da doðe i oslobodi nešto mesta..."
- slo "Disk je plný (%s), èakám na uvoµnenie miesta..."
- spa "Disco lleno (%s). Esperando para que se libere algo de espacio..."
- swe "Disken är full (%s). Väntar tills det finns ledigt utrymme..."
- ukr "äÉÓË ÚÁÐÏ×ÎÅÎÉÊ (%s). ÷ÉÞÉËÕÀ, ÄÏËÉ ÚצÌØÎÉÔØÓÑ ÔÒÏÈÉ Í¦ÓÃÑ..."
-ER_DUP_KEY 23000
- cze "Nemohu zapsat, zdvojen-Bý klíè v tabulce '%-.192s'"
- dan "Kan ikke skrive, flere ens nøgler i tabellen '%-.192s'"
- nla "Kan niet schrijven, dubbele zoeksleutel in tabel '%-.192s'"
- eng "Can't write; duplicate key in table '%-.192s'"
- jps "table '%-.192s' ‚É key ‚ªd•¡‚µ‚Ä‚¢‚Ä‘‚«‚±‚ß‚Ü‚¹‚ñ",
- est "Ei saa kirjutada, korduv võti tabelis '%-.192s'"
- fre "Ecriture impossible, doublon dans une clé de la table '%-.192s'"
- ger "Kann nicht speichern, Grund: doppelter Schlüssel in Tabelle '%-.192s'"
- greek "Äåí åßíáé äõíáôÞ ç êáôá÷þñçóç, ç ôéìÞ õðÜñ÷åé Þäç óôïí ðßíáêá '%-.192s'"
- hun "Irasi hiba, duplikalt kulcs a '%-.192s' tablaban."
- ita "Scrittura impossibile: chiave duplicata nella tabella '%-.192s'"
- jpn "table '%-.192s' ¤Ë key ¤¬½ÅÊ£¤·¤Æ¤¤¤Æ½ñ¤­¤³¤á¤Þ¤»¤ó"
- kor "±â·ÏÇÒ ¼ö ¾øÀ¾´Ï´Ù., Å×À̺í '%-.192s'¿¡¼­ Áߺ¹ Å°"
- nor "Kan ikke skrive, flere like nøkler i tabellen '%-.192s'"
- norwegian-ny "Kan ikkje skrive, flere like nyklar i tabellen '%-.192s'"
- pol "Nie mo¿na zapisaæ, powtórzone klucze w tabeli '%-.192s'"
- por "Não pode gravar. Chave duplicada na tabela '%-.192s'"
- rum "Nu pot sa scriu (can't write), cheie duplicata in tabela '%-.192s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÉÚ×ÅÓÔÉ ÚÁÐÉÓØ, ÄÕÂÌÉÒÕÀÝÉÊÓÑ ËÌÀÞ × ÔÁÂÌÉÃÅ '%-.192s'"
- serbian "Ne mogu da pišem pošto postoji duplirani kljuè u tabeli '%-.192s'"
- slo "Nemô¾em zapísa», duplikát kµúèa v tabuµke '%-.192s'"
- spa "No puedo escribir, clave duplicada en la tabla '%-.192s'"
- swe "Kan inte skriva, dubbel söknyckel i register '%-.192s'"
- ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ, ÄÕÂÌÀÀÞÉÊÓÑ ËÌÀÞ × ÔÁÂÌÉæ '%-.192s'"
-ER_ERROR_ON_CLOSE
- cze "Chyba p-Bøi zavírání '%-.192s' (chybový kód: %d)"
- dan "Fejl ved lukning af '%-.192s' (Fejlkode: %d)"
- nla "Fout bij het sluiten van '%-.192s' (Errcode: %d)"
- eng "Error on close of '%-.192s' (errno: %d)"
- est "Viga faili '%-.192s' sulgemisel (veakood: %d)"
- fre "Erreur a la fermeture de '%-.192s' (Errcode: %d)"
- ger "Fehler beim Schließen von '%-.192s' (Fehler: %d)"
- greek "ÐáñïõóéÜóôçêå ðñüâëçìá êëåßíïíôáò ôï '%-.192s' (êùäéêüò ëÜèïõò: %d)"
- hun "Hiba a(z) '%-.192s' zarasakor. (hibakod: %d)"
- ita "Errore durante la chiusura di '%-.192s' (errno: %d)"
- kor "'%-.192s'´Ý´Â Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
- nor "Feil ved lukking av '%-.192s' (Feilkode: %d)"
- norwegian-ny "Feil ved lukking av '%-.192s' (Feilkode: %d)"
- pol "B³?d podczas zamykania '%-.192s' (Kod b³êdu: %d)"
- por "Erro ao fechar '%-.192s' (erro no. %d)"
- rum "Eroare inchizind '%-.192s' (errno: %d)"
- rus "ïÛÉÂËÁ ÐÒÉ ÚÁËÒÙÔÉÉ '%-.192s' (ÏÛÉÂËÁ: %d)"
- serbian "Greška pri zatvaranju '%-.192s' (errno: %d)"
- slo "Chyba pri zatváraní '%-.192s' (chybový kód: %d)"
- spa "Error en el cierre de '%-.192s' (Error: %d)"
- swe "Fick fel vid stängning av '%-.192s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÚÁËÒÉÔÉ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
-ER_ERROR_ON_READ
- cze "Chyba p-Bøi ètení souboru '%-.200s' (chybový kód: %d)"
- dan "Fejl ved læsning af '%-.200s' (Fejlkode: %d)"
- nla "Fout bij het lezen van file '%-.200s' (Errcode: %d)"
- eng "Error reading file '%-.200s' (errno: %d)"
- jps "'%-.200s' ƒtƒ@ƒCƒ‹‚Ì“Ç‚Ýž‚݃Gƒ‰[ (errno: %d)",
- est "Viga faili '%-.200s' lugemisel (veakood: %d)"
- fre "Erreur en lecture du fichier '%-.200s' (Errcode: %d)"
- ger "Fehler beim Lesen der Datei '%-.200s' (Fehler: %d)"
- greek "Ðñüâëçìá êáôÜ ôçí áíÜãíùóç ôïõ áñ÷åßïõ '%-.200s' (êùäéêüò ëÜèïõò: %d)"
- hun "Hiba a '%-.200s'file olvasasakor. (hibakod: %d)"
- ita "Errore durante la lettura del file '%-.200s' (errno: %d)"
- jpn "'%-.200s' ¥Õ¥¡¥¤¥ë¤ÎÆɤ߹þ¤ß¥¨¥é¡¼ (errno: %d)"
- kor "'%-.200s'È­ÀÏ Àб⠿¡·¯ (¿¡·¯¹øÈ£: %d)"
- nor "Feil ved lesing av '%-.200s' (Feilkode: %d)"
- norwegian-ny "Feil ved lesing av '%-.200s' (Feilkode: %d)"
- pol "B³?d podczas odczytu pliku '%-.200s' (Kod b³êdu: %d)"
- por "Erro ao ler arquivo '%-.200s' (erro no. %d)"
- rum "Eroare citind fisierul '%-.200s' (errno: %d)"
- rus "ïÛÉÂËÁ ÞÔÅÎÉÑ ÆÁÊÌÁ '%-.200s' (ÏÛÉÂËÁ: %d)"
- serbian "Greška pri èitanju file-a '%-.200s' (errno: %d)"
- slo "Chyba pri èítaní súboru '%-.200s' (chybový kód: %d)"
- spa "Error leyendo el fichero '%-.200s' (Error: %d)"
- swe "Fick fel vid läsning av '%-.200s' (Felkod %d)"
- ukr "îÅ ÍÏÖÕ ÐÒÏÞÉÔÁÔÉ ÆÁÊÌ '%-.200s' (ÐÏÍÉÌËÁ: %d)"
-ER_ERROR_ON_RENAME
- cze "Chyba p-Bøi pøejmenování '%-.210s' na '%-.210s' (chybový kód: %d)"
- dan "Fejl ved omdøbning af '%-.210s' til '%-.210s' (Fejlkode: %d)"
- nla "Fout bij het hernoemen van '%-.210s' naar '%-.210s' (Errcode: %d)"
- eng "Error on rename of '%-.210s' to '%-.210s' (errno: %d)"
- jps "'%-.210s' ‚ð '%-.210s' ‚É rename ‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
- est "Viga faili '%-.210s' ümbernimetamisel '%-.210s'-ks (veakood: %d)"
- fre "Erreur en renommant '%-.210s' en '%-.210s' (Errcode: %d)"
- ger "Fehler beim Umbenennen von '%-.210s' in '%-.210s' (Fehler: %d)"
- greek "Ðñüâëçìá êáôÜ ôçí ìåôïíïìáóßá ôïõ áñ÷åßïõ '%-.210s' to '%-.210s' (êùäéêüò ëÜèïõò: %d)"
- hun "Hiba a '%-.210s' file atnevezesekor '%-.210s'. (hibakod: %d)"
- ita "Errore durante la rinominazione da '%-.210s' a '%-.210s' (errno: %d)"
- jpn "'%-.210s' ¤ò '%-.210s' ¤Ë rename ¤Ç¤­¤Þ¤»¤ó (errno: %d)"
- kor "'%-.210s'¸¦ '%-.210s'·Î À̸§ º¯°æÁß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
- nor "Feil ved omdøping av '%-.210s' til '%-.210s' (Feilkode: %d)"
- norwegian-ny "Feil ved omdøyping av '%-.210s' til '%-.210s' (Feilkode: %d)"
- pol "B³?d podczas zmieniania nazwy '%-.210s' na '%-.210s' (Kod b³êdu: %d)"
- por "Erro ao renomear '%-.210s' para '%-.210s' (erro no. %d)"
- rum "Eroare incercind sa renumesc '%-.210s' in '%-.210s' (errno: %d)"
- rus "ïÛÉÂËÁ ÐÒÉ ÐÅÒÅÉÍÅÎÏ×ÁÎÉÉ '%-.210s' × '%-.210s' (ÏÛÉÂËÁ: %d)"
- serbian "Greška pri promeni imena '%-.210s' na '%-.210s' (errno: %d)"
- slo "Chyba pri premenovávaní '%-.210s' na '%-.210s' (chybový kód: %d)"
- spa "Error en el renombrado de '%-.210s' a '%-.210s' (Error: %d)"
- swe "Kan inte byta namn från '%-.210s' till '%-.210s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÐÅÒÅÊÍÅÎÕ×ÁÔÉ '%-.210s' Õ '%-.210s' (ÐÏÍÉÌËÁ: %d)"
-ER_ERROR_ON_WRITE
- cze "Chyba p-Bøi zápisu do souboru '%-.200s' (chybový kód: %d)"
- dan "Fejl ved skriving av filen '%-.200s' (Fejlkode: %d)"
- nla "Fout bij het wegschrijven van file '%-.200s' (Errcode: %d)"
- eng "Error writing file '%-.200s' (errno: %d)"
- jps "'%-.200s' ƒtƒ@ƒCƒ‹‚ð‘‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
- est "Viga faili '%-.200s' kirjutamisel (veakood: %d)"
- fre "Erreur d'écriture du fichier '%-.200s' (Errcode: %d)"
- ger "Fehler beim Speichern der Datei '%-.200s' (Fehler: %d)"
- greek "Ðñüâëçìá êáôÜ ôçí áðïèÞêåõóç ôïõ áñ÷åßïõ '%-.200s' (êùäéêüò ëÜèïõò: %d)"
- hun "Hiba a '%-.200s' file irasakor. (hibakod: %d)"
- ita "Errore durante la scrittura del file '%-.200s' (errno: %d)"
- jpn "'%-.200s' ¥Õ¥¡¥¤¥ë¤ò½ñ¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)"
- kor "'%-.200s'È­ÀÏ ±â·Ï Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
- nor "Feil ved skriving av fila '%-.200s' (Feilkode: %d)"
- norwegian-ny "Feil ved skriving av fila '%-.200s' (Feilkode: %d)"
- pol "B³?d podczas zapisywania pliku '%-.200s' (Kod b³êdu: %d)"
- por "Erro ao gravar arquivo '%-.200s' (erro no. %d)"
- rum "Eroare scriind fisierul '%-.200s' (errno: %d)"
- rus "ïÛÉÂËÁ ÚÁÐÉÓÉ × ÆÁÊÌ '%-.200s' (ÏÛÉÂËÁ: %d)"
- serbian "Greška pri upisu '%-.200s' (errno: %d)"
- slo "Chyba pri zápise do súboru '%-.200s' (chybový kód: %d)"
- spa "Error escribiendo el archivo '%-.200s' (Error: %d)"
- swe "Fick fel vid skrivning till '%-.200s' (Felkod %d)"
- ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ ÆÁÊÌ '%-.200s' (ÐÏÍÉÌËÁ: %d)"
-ER_FILE_USED
- cze "'%-.192s' je zam-Bèen proti zmìnám"
- dan "'%-.192s' er låst mod opdateringer"
- nla "'%-.192s' is geblokeerd tegen veranderingen"
- eng "'%-.192s' is locked against change"
- jps "'%-.192s' ‚̓ƒbƒN‚³‚ê‚Ä‚¢‚Ü‚·",
- est "'%-.192s' on lukustatud muudatuste vastu"
- fre "'%-.192s' est verrouillé contre les modifications"
- ger "'%-.192s' ist für Änderungen gesperrt"
- greek "'%-.192s' äåí åðéôñÝðïíôáé áëëáãÝò"
- hun "'%-.192s' a valtoztatas ellen zarolva"
- ita "'%-.192s' e` soggetto a lock contro i cambiamenti"
- jpn "'%-.192s' ¤Ï¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤¹"
- kor "'%-.192s'°¡ º¯°æÇÒ ¼ö ¾øµµ·Ï Àá°ÜÀÖÀ¾´Ï´Ù."
- nor "'%-.192s' er låst mot oppdateringer"
- norwegian-ny "'%-.192s' er låst mot oppdateringar"
- pol "'%-.192s' jest zablokowany na wypadek zmian"
- por "'%-.192s' está com travamento contra alterações"
- rum "'%-.192s' este blocat pentry schimbari (loccked against change)"
- rus "'%-.192s' ÚÁÂÌÏËÉÒÏ×ÁÎ ÄÌÑ ÉÚÍÅÎÅÎÉÊ"
- serbian "'%-.192s' je zakljuèan za upis"
- slo "'%-.192s' je zamknutý proti zmenám"
- spa "'%-.192s' esta bloqueado contra cambios"
- swe "'%-.192s' är låst mot användning"
- ukr "'%-.192s' ÚÁÂÌÏËÏ×ÁÎÉÊ ÎÁ ×ÎÅÓÅÎÎÑ ÚͦÎ"
-ER_FILSORT_ABORT
- cze "T-Bøídìní pøeru¹eno"
- dan "Sortering afbrudt"
- nla "Sorteren afgebroken"
- eng "Sort aborted"
- jps "Sort ’†’f",
- est "Sorteerimine katkestatud"
- fre "Tri alphabétique abandonné"
- ger "Sortiervorgang abgebrochen"
- greek "Ç äéáäéêáóßá ôáîéíüìéóçò áêõñþèçêå"
- hun "Sikertelen rendezes"
- ita "Operazione di ordinamento abbandonata"
- jpn "Sort ̾̂"
- kor "¼ÒÆ®°¡ ÁߴܵǾú½À´Ï´Ù."
- nor "Sortering avbrutt"
- norwegian-ny "Sortering avbrote"
- pol "Sortowanie przerwane"
- por "Ordenação abortada"
- rum "Sortare intrerupta"
- rus "óÏÒÔÉÒÏ×ËÁ ÐÒÅÒ×ÁÎÁ"
- serbian "Sortiranje je prekinuto"
- slo "Triedenie preru¹ené"
- spa "Ordeancion cancelada"
- swe "Sorteringen avbruten"
- ukr "óÏÒÔÕ×ÁÎÎÑ ÐÅÒÅÒ×ÁÎÏ"
-ER_FORM_NOT_FOUND
- cze "Pohled '%-.192s' pro '%-.192s' neexistuje"
- dan "View '%-.192s' eksisterer ikke for '%-.192s'"
- nla "View '%-.192s' bestaat niet voor '%-.192s'"
- eng "View '%-.192s' doesn't exist for '%-.192s'"
- jps "View '%-.192s' ‚ª '%-.192s' ‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "Vaade '%-.192s' ei eksisteeri '%-.192s' jaoks"
- fre "La vue (View) '%-.192s' n'existe pas pour '%-.192s'"
- ger "View '%-.192s' existiert für '%-.192s' nicht"
- greek "Ôï View '%-.192s' äåí õðÜñ÷åé ãéá '%-.192s'"
- hun "A(z) '%-.192s' nezet nem letezik a(z) '%-.192s'-hoz"
- ita "La view '%-.192s' non esiste per '%-.192s'"
- jpn "View '%-.192s' ¤¬ '%-.192s' ¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "ºä '%-.192s'°¡ '%-.192s'¿¡¼­´Â Á¸ÀçÇÏÁö ¾ÊÀ¾´Ï´Ù."
- nor "View '%-.192s' eksisterer ikke for '%-.192s'"
- norwegian-ny "View '%-.192s' eksisterar ikkje for '%-.192s'"
- pol "Widok '%-.192s' nie istnieje dla '%-.192s'"
- por "Visão '%-.192s' não existe para '%-.192s'"
- rum "View '%-.192s' nu exista pentru '%-.192s'"
- rus "ðÒÅÄÓÔÁ×ÌÅÎÉÅ '%-.192s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ ÄÌÑ '%-.192s'"
- serbian "View '%-.192s' ne postoji za '%-.192s'"
- slo "Pohµad '%-.192s' neexistuje pre '%-.192s'"
- spa "La vista '%-.192s' no existe para '%-.192s'"
- swe "Formulär '%-.192s' finns inte i '%-.192s'"
- ukr "÷ÉÇÌÑÄ '%-.192s' ÎÅ ¦ÓÎÕ¤ ÄÌÑ '%-.192s'"
-ER_GET_ERRNO
- cze "Obsluha tabulky vr-Bátila chybu %d"
- dan "Modtog fejl %d fra tabel håndteringen"
- nla "Fout %d van tabel handler"
- eng "Got error %d from storage engine"
- est "Tabeli handler tagastas vea %d"
- fre "Reçu l'erreur %d du handler de la table"
- ger "Fehler %d (Speicher-Engine)"
- greek "ÅëÞöèç ìÞíõìá ëÜèïõò %d áðü ôïí ÷åéñéóôÞ ðßíáêá (table handler)"
- hun "%d hibajelzes a tablakezelotol"
- ita "Rilevato l'errore %d dal gestore delle tabelle"
- jpn "Got error %d from table handler"
- kor "Å×À̺í handler¿¡¼­ %d ¿¡·¯°¡ ¹ß»ý ÇÏ¿´½À´Ï´Ù."
- nor "Mottok feil %d fra tabell håndterer"
- norwegian-ny "Mottok feil %d fra tabell handterar"
- pol "Otrzymano b³?d %d z obs³ugi tabeli"
- por "Obteve erro %d no manipulador de tabelas"
- rum "Eroarea %d obtinuta din handlerul tabelei"
- rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d ÏÔ ÏÂÒÁÂÏÔÞÉËÁ ÔÁÂÌÉÃ"
- serbian "Handler tabela je vratio grešku %d"
- slo "Obsluha tabuµky vrátila chybu %d"
- spa "Error %d desde el manejador de la tabla"
- swe "Fick felkod %d från databashanteraren"
- ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d ×¦Ä ÄÅÓËÒÉÐÔÏÒÁ ÔÁÂÌÉæ"
-ER_ILLEGAL_HA
- cze "Obsluha tabulky '%-.192s' nem-Bá tento parametr"
- dan "Denne mulighed eksisterer ikke for tabeltypen '%-.192s'"
- nla "Tabel handler voor '%-.192s' heeft deze optie niet"
- eng "Table storage engine for '%-.192s' doesn't have this option"
- est "Tabeli '%-.192s' handler ei toeta antud operatsiooni"
- fre "Le handler de la table '%-.192s' n'a pas cette option"
- ger "Diese Option gibt es nicht (Speicher-Engine für '%-.192s')"
- greek "Ï ÷åéñéóôÞò ðßíáêá (table handler) ãéá '%-.192s' äåí äéáèÝôåé áõôÞ ôçí åðéëïãÞ"
- hun "A(z) '%-.192s' tablakezelonek nincs ilyen opcioja"
- ita "Il gestore delle tabelle per '%-.192s' non ha questa opzione"
- jpn "Table handler for '%-.192s' doesn't have this option"
- kor "'%-.192s'ÀÇ Å×À̺í handler´Â ÀÌ·¯ÇÑ ¿É¼ÇÀ» Á¦°øÇÏÁö ¾ÊÀ¾´Ï´Ù."
- nor "Tabell håndtereren for '%-.192s' har ikke denne muligheten"
- norwegian-ny "Tabell håndteraren for '%-.192s' har ikkje denne moglegheita"
- pol "Obs³uga tabeli '%-.192s' nie posiada tej opcji"
- por "Manipulador de tabela para '%-.192s' não tem esta opção"
- rum "Handlerul tabelei pentru '%-.192s' nu are aceasta optiune"
- rus "ïÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ '%-.192s' ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÜÔÕ ×ÏÚÍÏÖÎÏÓÔØ"
- serbian "Handler tabela za '%-.192s' nema ovu opciju"
- slo "Obsluha tabuµky '%-.192s' nemá tento parameter"
- spa "El manejador de la tabla de '%-.192s' no tiene esta opcion"
- swe "Tabellhanteraren for tabell '%-.192s' stödjer ej detta"
- ukr "äÅÓËÒÉÐÔÏÒ ÔÁÂÌÉæ '%-.192s' ÎÅ ÍÁ¤ 椧 ×ÌÁÓÔÉ×ÏÓÔ¦"
-ER_KEY_NOT_FOUND
- cze "Nemohu naj-Bít záznam v '%-.192s'"
- dan "Kan ikke finde posten i '%-.192s'"
- nla "Kan record niet vinden in '%-.192s'"
- eng "Can't find record in '%-.192s'"
- jps "'%-.192s'‚Ì‚È‚©‚ɃŒƒR[ƒh‚ªŒ©•t‚©‚è‚Ü‚¹‚ñ",
- est "Ei suuda leida kirjet '%-.192s'-s"
- fre "Ne peut trouver l'enregistrement dans '%-.192s'"
- ger "Kann Datensatz in '%-.192s' nicht finden"
- greek "Áäýíáôç ç áíåýñåóç åããñáöÞò óôï '%-.192s'"
- hun "Nem talalhato a rekord '%-.192s'-ben"
- ita "Impossibile trovare il record in '%-.192s'"
- jpn "'%-.192s'¤Î¤Ê¤«¤Ë¥ì¥³¡¼¥É¤¬¸«ÉÕ¤«¤ê¤Þ¤»¤ó"
- kor "'%-.192s'¿¡¼­ ·¹Äڵ带 ãÀ» ¼ö ¾øÀ¾´Ï´Ù."
- nor "Kan ikke finne posten i '%-.192s'"
- norwegian-ny "Kan ikkje finne posten i '%-.192s'"
- pol "Nie mo¿na znale¥æ rekordu w '%-.192s'"
- por "Não pode encontrar registro em '%-.192s'"
- rum "Nu pot sa gasesc recordul in '%-.192s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÚÁÐÉÓØ × '%-.192s'"
- serbian "Ne mogu da pronaðem slog u '%-.192s'"
- slo "Nemô¾em nájs» záznam v '%-.192s'"
- spa "No puedo encontrar el registro en '%-.192s'"
- swe "Hittar inte posten '%-.192s'"
- ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ Õ '%-.192s'"
-ER_NOT_FORM_FILE
- cze "Nespr-Bávná informace v souboru '%-.200s'"
- dan "Forkert indhold i: '%-.200s'"
- nla "Verkeerde info in file: '%-.200s'"
- eng "Incorrect information in file: '%-.200s'"
- jps "ƒtƒ@ƒCƒ‹ '%-.200s' ‚Ì info ‚ªŠÔˆá‚Á‚Ä‚¢‚é‚悤‚Å‚·",
- est "Vigane informatsioon failis '%-.200s'"
- fre "Information erronnée dans le fichier: '%-.200s'"
- ger "Falsche Information in Datei '%-.200s'"
- greek "ËÜèïò ðëçñïöïñßåò óôï áñ÷åßï: '%-.200s'"
- hun "Ervenytelen info a file-ban: '%-.200s'"
- ita "Informazione errata nel file: '%-.200s'"
- jpn "¥Õ¥¡¥¤¥ë '%-.200s' ¤Î info ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹"
- kor "È­ÀÏÀÇ ºÎÁ¤È®ÇÑ Á¤º¸: '%-.200s'"
- nor "Feil informasjon i filen: '%-.200s'"
- norwegian-ny "Feil informasjon i fila: '%-.200s'"
- pol "Niew³a?ciwa informacja w pliku: '%-.200s'"
- por "Informação incorreta no arquivo '%-.200s'"
- rum "Informatie incorecta in fisierul: '%-.200s'"
- rus "îÅËÏÒÒÅËÔÎÁÑ ÉÎÆÏÒÍÁÃÉÑ × ÆÁÊÌÅ '%-.200s'"
- serbian "Pogrešna informacija u file-u: '%-.200s'"
- slo "Nesprávna informácia v súbore: '%-.200s'"
- spa "Informacion erronea en el archivo: '%-.200s'"
- swe "Felaktig fil: '%-.200s'"
- ukr "èÉÂÎÁ ¦ÎÆÏÒÍÁÃ¦Ñ Õ ÆÁÊ̦: '%-.200s'"
-ER_NOT_KEYFILE
- cze "Nespr-Bávný klíè pro tabulku '%-.200s'; pokuste se ho opravit"
- dan "Fejl i indeksfilen til tabellen '%-.200s'; prøv at reparere den"
- nla "Verkeerde zoeksleutel file voor tabel: '%-.200s'; probeer het te repareren"
- eng "Incorrect key file for table '%-.200s'; try to repair it"
- jps "'%-.200s' ƒe[ƒuƒ‹‚Ì key file ‚ªŠÔˆá‚Á‚Ä‚¢‚é‚悤‚Å‚·. C•œ‚ð‚µ‚Ä‚­‚¾‚³‚¢",
- est "Tabeli '%-.200s' võtmefail on vigane; proovi seda parandada"
- fre "Index corrompu dans la table: '%-.200s'; essayez de le réparer"
- ger "Fehlerhafte Index-Datei für Tabelle '%-.200s'; versuche zu reparieren"
- greek "ËÜèïò áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá: '%-.200s'; Ðáñáêáëþ, äéïñèþóôå ôï!"
- hun "Ervenytelen kulcsfile a tablahoz: '%-.200s'; probalja kijavitani!"
- ita "File chiave errato per la tabella : '%-.200s'; prova a riparalo"
- jpn "'%-.200s' ¥Æ¡¼¥Ö¥ë¤Î key file ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹. ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤"
- kor "'%-.200s' Å×À̺íÀÇ ºÎÁ¤È®ÇÑ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!"
- nor "Tabellen '%-.200s' har feil i nøkkelfilen; forsøk å reparer den"
- norwegian-ny "Tabellen '%-.200s' har feil i nykkelfila; prøv å reparere den"
- pol "Niew³a?ciwy plik kluczy dla tabeli: '%-.200s'; spróbuj go naprawiæ"
- por "Arquivo de índice incorreto para tabela '%-.200s'; tente repará-lo"
- rum "Cheia fisierului incorecta pentru tabela: '%-.200s'; incearca s-o repari"
- rus "îÅËÏÒÒÅËÔÎÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ: '%-.200s'. ðÏÐÒÏÂÕÊÔÅ ×ÏÓÓÔÁÎÏ×ÉÔØ ÅÇÏ"
- serbian "Pogrešan key file za tabelu: '%-.200s'; probajte da ga ispravite"
- slo "Nesprávny kµúè pre tabuµku '%-.200s'; pokúste sa ho opravi»"
- spa "Clave de archivo erronea para la tabla: '%-.200s'; intente repararlo"
- swe "Fatalt fel vid hantering av register '%-.200s'; kör en reparation"
- ukr "èÉÂÎÉÊ ÆÁÊÌ ËÌÀÞÅÊ ÄÌÑ ÔÁÂÌÉæ: '%-.200s'; óÐÒÏÂÕÊÔÅ ÊÏÇÏ ×¦ÄÎÏ×ÉÔÉ"
-ER_OLD_KEYFILE
- cze "Star-Bý klíèový soubor pro '%-.192s'; opravte ho."
- dan "Gammel indeksfil for tabellen '%-.192s'; reparer den"
- nla "Oude zoeksleutel file voor tabel '%-.192s'; repareer het!"
- eng "Old key file for table '%-.192s'; repair it!"
- jps "'%-.192s' ƒe[ƒuƒ‹‚͌¢Œ`Ž®‚Ì key file ‚̂悤‚Å‚·; C•œ‚ð‚µ‚Ä‚­‚¾‚³‚¢",
- est "Tabeli '%-.192s' võtmefail on aegunud; paranda see!"
- fre "Vieux fichier d'index pour la table '%-.192s'; réparez le!"
- ger "Alte Index-Datei für Tabelle '%-.192s'. Bitte reparieren"
- greek "Ðáëáéü áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá '%-.192s'; Ðáñáêáëþ, äéïñèþóôå ôï!"
- hun "Regi kulcsfile a '%-.192s'tablahoz; probalja kijavitani!"
- ita "File chiave vecchio per la tabella '%-.192s'; riparalo!"
- jpn "'%-.192s' ¥Æ¡¼¥Ö¥ë¤Ï¸Å¤¤·Á¼°¤Î key file ¤Î¤è¤¦¤Ç¤¹; ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤"
- kor "'%-.192s' Å×À̺íÀÇ ÀÌÀü¹öÁ¯ÀÇ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!"
- nor "Gammel nøkkelfil for tabellen '%-.192s'; reparer den!"
- norwegian-ny "Gammel nykkelfil for tabellen '%-.192s'; reparer den!"
- pol "Plik kluczy dla tabeli '%-.192s' jest starego typu; napraw go!"
- por "Arquivo de índice desatualizado para tabela '%-.192s'; repare-o!"
- rum "Cheia fisierului e veche pentru tabela '%-.192s'; repar-o!"
- rus "óÔÁÒÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ '%-.192s'; ÏÔÒÅÍÏÎÔÉÒÕÊÔÅ ÅÇÏ!"
- serbian "Zastareo key file za tabelu '%-.192s'; ispravite ga"
- slo "Starý kµúèový súbor pre '%-.192s'; opravte ho!"
- spa "Clave de archivo antigua para la tabla '%-.192s'; reparelo!"
- swe "Gammal nyckelfil '%-.192s'; reparera registret"
- ukr "óÔÁÒÉÊ ÆÁÊÌ ËÌÀÞÅÊ ÄÌÑ ÔÁÂÌÉæ '%-.192s'; ÷¦ÄÎÏצÔØ ÊÏÇÏ!"
-ER_OPEN_AS_READONLY
- cze "'%-.192s' je jen pro -Bètení"
- dan "'%-.192s' er skrivebeskyttet"
- nla "'%-.192s' is alleen leesbaar"
- eng "Table '%-.192s' is read only"
- jps "'%-.192s' ‚Í“Ç‚Ýž‚Ýê—p‚Å‚·",
- est "Tabel '%-.192s' on ainult lugemiseks"
- fre "'%-.192s' est en lecture seulement"
- ger "Tabelle '%-.192s' ist nur lesbar"
- greek "'%-.192s' åðéôñÝðåôáé ìüíï ç áíÜãíùóç"
- hun "'%-.192s' irasvedett"
- ita "'%-.192s' e` di sola lettura"
- jpn "'%-.192s' ¤ÏÆɤ߹þ¤ßÀìÍѤǤ¹"
- kor "Å×À̺í '%-.192s'´Â ÀбâÀü¿ë ÀÔ´Ï´Ù."
- nor "'%-.192s' er skrivebeskyttet"
- norwegian-ny "'%-.192s' er skrivetryggja"
- pol "'%-.192s' jest tylko do odczytu"
- por "Tabela '%-.192s' é somente para leitura"
- rum "Tabela '%-.192s' e read-only"
- rus "ôÁÂÌÉÃÁ '%-.192s' ÐÒÅÄÎÁÚÎÁÞÅÎÁ ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ"
- serbian "Tabelu '%-.192s' je dozvoljeno samo èitati"
- slo "'%-.192s' is èíta» only"
- spa "'%-.192s' es de solo lectura"
- swe "'%-.192s' är skyddad mot förändring"
- ukr "ôÁÂÌÉÃÑ '%-.192s' Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ"
-ER_OUTOFMEMORY HY001 S1001
- cze "M-Bálo pamìti. Pøestartujte daemona a zkuste znovu (je potøeba %d bytù)"
- dan "Ikke mere hukommelse. Genstart serveren og prøv igen (mangler %d bytes)"
- nla "Geen geheugen meer. Herstart server en probeer opnieuw (%d bytes nodig)"
- eng "Out of memory; restart server and try again (needed %d bytes)"
- jps "Out of memory. ƒf[ƒ‚ƒ“‚ðƒŠƒXƒ^[ƒg‚µ‚Ä‚Ý‚Ä‚­‚¾‚³‚¢ (%d bytes •K—v)",
- est "Mälu sai otsa. Proovi MySQL uuesti käivitada (puudu jäi %d baiti)"
- fre "Manque de mémoire. Redémarrez le démon et ré-essayez (%d octets nécessaires)"
- ger "Kein Speicher vorhanden (%d Bytes benötigt). Bitte Server neu starten"
- greek "Äåí õðÜñ÷åé äéáèÝóéìç ìíÞìç. ÐñïóðáèÞóôå ðÜëé, åðáíåêéíþíôáò ôç äéáäéêáóßá (demon) (÷ñåéÜæïíôáé %d bytes)"
- hun "Nincs eleg memoria. Inditsa ujra a demont, es probalja ismet. (%d byte szukseges.)"
- ita "Memoria esaurita. Fai ripartire il demone e riprova (richiesti %d bytes)"
- jpn "Out of memory. ¥Ç¡¼¥â¥ó¤ò¥ê¥¹¥¿¡¼¥È¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤ (%d bytes ɬÍ×)"
- kor "Out of memory. µ¥¸óÀ» Àç ½ÇÇà ÈÄ ´Ù½Ã ½ÃÀÛÇϽÿÀ (needed %d bytes)"
- nor "Ikke mer minne. Star på nytt tjenesten og prøv igjen (trengte %d byter)"
- norwegian-ny "Ikkje meir minne. Start på nytt tenesten og prøv igjen (trengte %d bytar)"
- pol "Zbyt ma³o pamiêci. Uruchom ponownie demona i spróbuj ponownie (potrzeba %d bajtów)"
- por "Sem memória. Reinicie o programa e tente novamente (necessita de %d bytes)"
- rum "Out of memory. Porneste daemon-ul din nou si incearca inca o data (e nevoie de %d bytes)"
- rus "îÅÄÏÓÔÁÔÏÞÎÏ ÐÁÍÑÔÉ. ðÅÒÅÚÁÐÕÓÔÉÔÅ ÓÅÒ×ÅÒ É ÐÏÐÒÏÂÕÊÔÅ ÅÝÅ ÒÁÚ (ÎÕÖÎÏ %d ÂÁÊÔ)"
- serbian "Nema memorije. Restartujte MySQL server i probajte ponovo (potrebno je %d byte-ova)"
- slo "Málo pamäti. Re¹tartujte daemona a skúste znova (je potrebných %d bytov)"
- spa "Memoria insuficiente. Reinicie el demonio e intentelo otra vez (necesita %d bytes)"
- swe "Oväntat slut på minnet, starta om programmet och försök på nytt (Behövde %d bytes)"
- ukr "âÒÁË ÐÁÍ'ÑÔ¦. òÅÓÔÁÒÔÕÊÔÅ ÓÅÒ×ÅÒ ÔÁ ÓÐÒÏÂÕÊÔÅ ÚÎÏ×Õ (ÐÏÔÒ¦ÂÎÏ %d ÂÁÊÔ¦×)"
-ER_OUT_OF_SORTMEMORY HY001 S1001
- cze "M-Bálo pamìti pro tøídìní. Zvy¹te velikost tøídícího bufferu"
- dan "Ikke mere sorteringshukommelse. Øg sorteringshukommelse (sort buffer size) for serveren"
- nla "Geen geheugen om te sorteren. Verhoog de server sort buffer size"
- eng "Out of sort memory; increase server sort buffer size"
- jps "Out of sort memory. sort buffer size ‚ª‘«‚è‚È‚¢‚悤‚Å‚·.",
- est "Mälu sai sorteerimisel otsa. Suurenda MySQL-i sorteerimispuhvrit"
- fre "Manque de mémoire pour le tri. Augmentez-la."
- ger "Kein Speicher zum Sortieren vorhanden. sort_buffer_size sollte im Server erhöht werden"
- greek "Äåí õðÜñ÷åé äéáèÝóéìç ìíÞìç ãéá ôáîéíüìéóç. ÁõîÞóôå ôï sort buffer size ãéá ôç äéáäéêáóßá (demon)"
- hun "Nincs eleg memoria a rendezeshez. Novelje a rendezo demon puffermeretet"
- ita "Memoria per gli ordinamenti esaurita. Incrementare il 'sort_buffer' al demone"
- jpn "Out of sort memory. sort buffer size ¤¬Â­¤ê¤Ê¤¤¤è¤¦¤Ç¤¹."
- kor "Out of sort memory. daemon sort bufferÀÇ Å©±â¸¦ Áõ°¡½ÃÅ°¼¼¿ä"
- nor "Ikke mer sorteringsminne. Øk sorteringsminnet (sort buffer size) for tjenesten"
- norwegian-ny "Ikkje meir sorteringsminne. Auk sorteringsminnet (sorteringsbffer storleik) for tenesten"
- pol "Zbyt ma³o pamiêci dla sortowania. Zwiêksz wielko?æ bufora demona dla sortowania"
- por "Sem memória para ordenação. Aumente tamanho do 'buffer' de ordenação"
- rum "Out of memory pentru sortare. Largeste marimea buffer-ului pentru sortare in daemon (sort buffer size)"
- rus "îÅÄÏÓÔÁÔÏÞÎÏ ÐÁÍÑÔÉ ÄÌÑ ÓÏÒÔÉÒÏ×ËÉ. õ×ÅÌÉÞØÔÅ ÒÁÚÍÅÒ ÂÕÆÅÒÁ ÓÏÒÔÉÒÏ×ËÉ ÎÁ ÓÅÒ×ÅÒÅ"
- serbian "Nema memorije za sortiranje. Poveæajte velièinu sort buffer-a MySQL server-u"
- slo "Málo pamäti pre triedenie, zvý¹te veµkos» triediaceho bufferu"
- spa "Memoria de ordenacion insuficiente. Incremente el tamano del buffer de ordenacion"
- swe "Sorteringsbufferten räcker inte till. Kontrollera startparametrarna"
- ukr "âÒÁË ÐÁÍ'ÑÔ¦ ÄÌÑ ÓÏÒÔÕ×ÁÎÎÑ. ôÒÅÂÁ Ú¦ÌØÛÉÔÉ ÒÏÚÍ¦Ò ÂÕÆÅÒÁ ÓÏÒÔÕ×ÁÎÎÑ Õ ÓÅÒ×ÅÒÁ"
-ER_UNEXPECTED_EOF
- cze "Neo-Bèekávaný konec souboru pøi ètení '%-.192s' (chybový kód: %d)"
- dan "Uventet afslutning på fil (eof) ved læsning af filen '%-.192s' (Fejlkode: %d)"
- nla "Onverwachte eof gevonden tijdens het lezen van file '%-.192s' (Errcode: %d)"
- eng "Unexpected EOF found when reading file '%-.192s' (errno: %d)"
- jps "'%-.192s' ƒtƒ@ƒCƒ‹‚ð“Ç‚Ýž‚Ý’†‚É EOF ‚ª—\Šú‚¹‚ÊŠ‚ÅŒ»‚ê‚Ü‚µ‚½. (errno: %d)",
- est "Ootamatu faililõpumärgend faili '%-.192s' lugemisel (veakood: %d)"
- fre "Fin de fichier inattendue en lisant '%-.192s' (Errcode: %d)"
- ger "Unerwartetes Ende beim Lesen der Datei '%-.192s' (Fehler: %d)"
- greek "ÊáôÜ ôç äéÜñêåéá ôçò áíÜãíùóçò, âñÝèçêå áðñïóäüêçôá ôï ôÝëïò ôïõ áñ÷åßïõ '%-.192s' (êùäéêüò ëÜèïõò: %d)"
- hun "Varatlan filevege-jel a '%-.192s'olvasasakor. (hibakod: %d)"
- ita "Fine del file inaspettata durante la lettura del file '%-.192s' (errno: %d)"
- jpn "'%-.192s' ¥Õ¥¡¥¤¥ë¤òÆɤ߹þ¤ßÃæ¤Ë EOF ¤¬Í½´ü¤»¤Ì½ê¤Ç¸½¤ì¤Þ¤·¤¿. (errno: %d)"
- kor "'%-.192s' È­ÀÏÀ» Àд µµÁß À߸øµÈ eofÀ» ¹ß°ß (¿¡·¯¹øÈ£: %d)"
- nor "Uventet slutt på fil (eof) ved lesing av filen '%-.192s' (Feilkode: %d)"
- norwegian-ny "Uventa slutt på fil (eof) ved lesing av fila '%-.192s' (Feilkode: %d)"
- pol "Nieoczekiwany 'eof' napotkany podczas czytania z pliku '%-.192s' (Kod b³êdu: %d)"
- por "Encontrado fim de arquivo inesperado ao ler arquivo '%-.192s' (erro no. %d)"
- rum "Sfirsit de fisier neasteptat in citirea fisierului '%-.192s' (errno: %d)"
- rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ '%-.192s' (ÏÛÉÂËÁ: %d)"
- serbian "Neoèekivani kraj pri èitanju file-a '%-.192s' (errno: %d)"
- slo "Neoèakávaný koniec súboru pri èítaní '%-.192s' (chybový kód: %d)"
- spa "Inesperado fin de ficheroU mientras leiamos el archivo '%-.192s' (Error: %d)"
- swe "Oväntat filslut vid läsning från '%-.192s' (Felkod: %d)"
- ukr "èÉÂÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
-ER_CON_COUNT_ERROR 08004
- cze "P-Bøíli¹ mnoho spojení"
- dan "For mange forbindelser (connections)"
- nla "Te veel verbindingen"
- eng "Too many connections"
- jps "Ú‘±‚ª‘½‚·‚¬‚Ü‚·",
- est "Liiga palju samaaegseid ühendusi"
- fre "Trop de connexions"
- ger "Zu viele Verbindungen"
- greek "ÕðÜñ÷ïõí ðïëëÝò óõíäÝóåéò..."
- hun "Tul sok kapcsolat"
- ita "Troppe connessioni"
- jpn "Àܳ¤¬Â¿¤¹¤®¤Þ¤¹"
- kor "³Ê¹« ¸¹Àº ¿¬°á... max_connectionÀ» Áõ°¡ ½ÃÅ°½Ã¿À..."
- nor "For mange tilkoblinger (connections)"
- norwegian-ny "For mange tilkoplingar (connections)"
- pol "Zbyt wiele po³?czeñ"
- por "Excesso de conexões"
- rum "Prea multe conectiuni"
- rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÓÏÅÄÉÎÅÎÉÊ"
- serbian "Previše konekcija"
- slo "Príli¹ mnoho spojení"
- spa "Demasiadas conexiones"
- swe "För många anslutningar"
- ukr "úÁÂÁÇÁÔÏ Ú'¤ÄÎÁÎØ"
-ER_OUT_OF_RESOURCES
- cze "M-Bálo prostoru/pamìti pro thread"
- dan "Udgået for tråde/hukommelse"
- nla "Geen thread geheugen meer; controleer of mysqld of andere processen al het beschikbare geheugen gebruikt. Zo niet, dan moet u wellicht 'ulimit' gebruiken om mysqld toe te laten meer geheugen te benutten, of u kunt extra swap ruimte toevoegen"
- eng "Out of memory; check if mysqld or some other process uses all available memory; if not, you may have to use 'ulimit' to allow mysqld to use more memory or you can add more swap space"
- jps "Out of memory; mysqld ‚©‚»‚Ì‘¼‚̃vƒƒZƒX‚ªƒƒ‚ƒŠ[‚ð‘S‚ÄŽg‚Á‚Ä‚¢‚é‚©Šm”F‚µ‚Ä‚­‚¾‚³‚¢. ƒƒ‚ƒŠ[‚ðŽg‚¢Ø‚Á‚Ä‚¢‚È‚¢ê‡A'ulimit' ‚ðݒ肵‚Ä mysqld ‚̃ƒ‚ƒŠ[Žg—pŒÀŠE—ʂ𑽂­‚·‚é‚©Aswap space ‚ð‘‚₵‚Ä‚Ý‚Ä‚­‚¾‚³‚¢",
- est "Mälu sai otsa. Võimalik, et aitab swap-i lisamine või käsu 'ulimit' abil MySQL-le rohkema mälu kasutamise lubamine"
- fre "Manque de 'threads'/mémoire"
- ger "Kein Speicher mehr vorhanden. Prüfen Sie, ob mysqld oder ein anderer Prozess den gesamten Speicher verbraucht. Wenn nicht, sollten Sie mit 'ulimit' dafür sorgen, dass mysqld mehr Speicher benutzen darf, oder mehr Swap-Speicher einrichten"
- greek "Ðñüâëçìá ìå ôç äéáèÝóéìç ìíÞìç (Out of thread space/memory)"
- hun "Elfogyott a thread-memoria"
- ita "Fine dello spazio/memoria per i thread"
- jpn "Out of memory; mysqld ¤«¤½¤Î¾¤Î¥×¥í¥»¥¹¤¬¥á¥â¥ê¡¼¤òÁ´¤Æ»È¤Ã¤Æ¤¤¤ë¤«³Îǧ¤·¤Æ¤¯¤À¤µ¤¤. ¥á¥â¥ê¡¼¤ò»È¤¤ÀڤäƤ¤¤Ê¤¤¾ì¹ç¡¢'ulimit' ¤òÀßÄꤷ¤Æ mysqld ¤Î¥á¥â¥ê¡¼»ÈÍѸ³¦Î̤ò¿¤¯¤¹¤ë¤«¡¢swap space ¤òÁý¤ä¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤"
- kor "Out of memory; mysqld³ª ¶Ç´Ù¸¥ ÇÁ·Î¼¼¼­¿¡¼­ »ç¿ë°¡´ÉÇÑ ¸Þ¸ð¸®¸¦ »ç¿ëÇÑÁö äũÇϽÿÀ. ¸¸¾à ±×·¸Áö ¾Ê´Ù¸é ulimit ¸í·ÉÀ» ÀÌ¿¿ëÇÏ¿© ´õ¸¹Àº ¸Þ¸ð¸®¸¦ »ç¿ëÇÒ ¼ö ÀÖµµ·Ï Çϰųª ½º¿Ò ½ºÆÐÀ̽º¸¦ Áõ°¡½ÃÅ°½Ã¿À"
- nor "Tomt for tråd plass/minne"
- norwegian-ny "Tomt for tråd plass/minne"
- pol "Zbyt ma³o miejsca/pamiêci dla w?tku"
- por "Sem memória. Verifique se o mysqld ou algum outro processo está usando toda memória disponível. Se não, você pode ter que usar 'ulimit' para permitir ao mysqld usar mais memória ou você pode adicionar mais área de 'swap'"
- rum "Out of memory; Verifica daca mysqld sau vreun alt proces foloseste toate memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui mysqld sa foloseasca mai multa memorie ori adauga mai mult spatiu pentru swap (swap space)"
- rus "îÅÄÏÓÔÁÔÏÞÎÏ ÐÁÍÑÔÉ; ÕÄÏÓÔÏ×ÅÒØÔÅÓØ, ÞÔÏ mysqld ÉÌÉ ËÁËÏÊ-ÌÉÂÏ ÄÒÕÇÏÊ ÐÒÏÃÅÓÓ ÎÅ ÚÁÎÉÍÁÅÔ ×ÓÀ ÄÏÓÔÕÐÎÕÀ ÐÁÍÑÔØ. åÓÌÉ ÎÅÔ, ÔÏ ×Ù ÍÏÖÅÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ulimit, ÞÔÏÂÙ ×ÙÄÅÌÉÔØ ÄÌÑ mysqld ÂÏÌØÛÅ ÐÁÍÑÔÉ, ÉÌÉ Õ×ÅÌÉÞÉÔØ ÏÂßÅÍ ÆÁÊÌÁ ÐÏÄËÁÞËÉ"
- serbian "Nema memorije; Proverite da li MySQL server ili neki drugi proces koristi svu slobodnu memoriju. (UNIX: Ako ne, probajte da upotrebite 'ulimit' komandu da biste dozvolili daemon-u da koristi više memorije ili probajte da dodate više swap memorije)"
- slo "Málo miesta-pamäti pre vlákno"
- spa "Memoria/espacio de tranpaso insuficiente"
- swe "Fick slut på minnet. Kontrollera om mysqld eller någon annan process använder allt tillgängligt minne. Om inte, försök använda 'ulimit' eller allokera mera swap"
- ukr "âÒÁË ÐÁÍ'ÑÔ¦; ðÅÒÅצÒÔÅ ÞÉ mysqld ÁÂÏ Ñ˦ÓØ ¦ÎÛ¦ ÐÒÏÃÅÓÉ ×ÉËÏÒÉÓÔÏ×ÕÀÔØ ÕÓÀ ÄÏÓÔÕÐÎÕ ÐÁÍ'ÑÔØ. ñË Î¦, ÔÏ ×É ÍÏÖÅÔÅ ÓËÏÒÉÓÔÁÔÉÓÑ 'ulimit', ÁÂÉ ÄÏÚ×ÏÌÉÔÉ mysqld ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ Â¦ÌØÛÅ ÐÁÍ'ÑÔ¦ ÁÂÏ ×É ÍÏÖÅÔÅ ÄÏÄÁÔÉ Â¦ÌØÛŠͦÓÃÑ Ð¦Ä Ó×ÁÐ"
-ER_BAD_HOST_ERROR 08S01
- cze "Nemohu zjistit jm-Béno stroje pro Va¹i adresu"
- dan "Kan ikke få værtsnavn for din adresse"
- nla "Kan de hostname niet krijgen van uw adres"
- eng "Can't get hostname for your address"
- jps "‚»‚Ì address ‚Ì hostname ‚ªˆø‚¯‚Ü‚¹‚ñ.",
- est "Ei suuda lahendada IP aadressi masina nimeks"
- fre "Ne peut obtenir de hostname pour votre adresse"
- ger "Kann Hostnamen für diese Adresse nicht erhalten"
- greek "Äåí Ýãéíå ãíùóôü ôï hostname ãéá ôçí address óáò"
- hun "A gepnev nem allapithato meg a cimbol"
- ita "Impossibile risalire al nome dell'host dall'indirizzo (risoluzione inversa)"
- jpn "¤½¤Î address ¤Î hostname ¤¬°ú¤±¤Þ¤»¤ó."
- kor "´ç½ÅÀÇ ÄÄÇ»ÅÍÀÇ È£½ºÆ®À̸§À» ¾òÀ» ¼ö ¾øÀ¾´Ï´Ù."
- nor "Kan ikke få tak i vertsnavn for din adresse"
- norwegian-ny "Kan ikkje få tak i vertsnavn for di adresse"
- pol "Nie mo¿na otrzymaæ nazwy hosta dla twojego adresu"
- por "Não pode obter nome do 'host' para seu endereço"
- rum "Nu pot sa obtin hostname-ul adresei tale"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÏÌÕÞÉÔØ ÉÍÑ ÈÏÓÔÁ ÄÌÑ ×ÁÛÅÇÏ ÁÄÒÅÓÁ"
- serbian "Ne mogu da dobijem ime host-a za vašu IP adresu"
- slo "Nemô¾em zisti» meno hostiteµa pre va¹u adresu"
- spa "No puedo obtener el nombre de maquina de tu direccion"
- swe "Kan inte hitta 'hostname' för din adress"
- ukr "îÅ ÍÏÖÕ ×ÉÚÎÁÞÉÔÉ ¦Í'Ñ ÈÏÓÔÕ ÄÌÑ ×ÁÛϧ ÁÄÒÅÓÉ"
-ER_HANDSHAKE_ERROR 08S01
- cze "Chyba p-Bøi ustavování spojení"
- dan "Forkert håndtryk (handshake)"
- nla "Verkeerde handshake"
- eng "Bad handshake"
- est "Väär handshake"
- fre "Mauvais 'handshake'"
- ger "Ungültiger Handshake"
- greek "Ç áíáãíþñéóç (handshake) äåí Ýãéíå óùóôÜ"
- hun "A kapcsolatfelvetel nem sikerult (Bad handshake)"
- ita "Negoziazione impossibile"
- nor "Feil håndtrykk (handshake)"
- norwegian-ny "Feil handtrykk (handshake)"
- pol "Z³y uchwyt(handshake)"
- por "Negociação de acesso falhou"
- rum "Prost inceput de conectie (bad handshake)"
- rus "îÅËÏÒÒÅËÔÎÏÅ ÐÒÉ×ÅÔÓÔ×ÉÅ"
- serbian "Loš poèetak komunikacije (handshake)"
- slo "Chyba pri nadväzovaní spojenia"
- spa "Protocolo erroneo"
- swe "Fel vid initiering av kommunikationen med klienten"
- ukr "îÅצÒÎÁ ÕÓÔÁÎÏ×ËÁ Ú×'ÑÚËÕ"
-ER_DBACCESS_DENIED_ERROR 42000
- cze "P-Bøístup pro u¾ivatele '%-.48s'@'%-.64s' k databázi '%-.192s' není povolen"
- dan "Adgang nægtet bruger: '%-.48s'@'%-.64s' til databasen '%-.192s'"
- nla "Toegang geweigerd voor gebruiker: '%-.48s'@'%-.64s' naar database '%-.192s'"
- eng "Access denied for user '%-.48s'@'%-.64s' to database '%-.192s'"
- jps "ƒ†[ƒU[ '%-.48s'@'%-.64s' ‚Ì '%-.192s' ƒf[ƒ^ƒx[ƒX‚ւ̃AƒNƒZƒX‚ð‹‘”Û‚µ‚Ü‚·",
- est "Ligipääs keelatud kasutajale '%-.48s'@'%-.64s' andmebaasile '%-.192s'"
- fre "Accès refusé pour l'utilisateur: '%-.48s'@'@%-.64s'. Base '%-.192s'"
- ger "Benutzer '%-.48s'@'%-.64s' hat keine Zugriffsberechtigung für Datenbank '%-.192s'"
- greek "Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.48s'@'%-.64s' óôç âÜóç äåäïìÝíùí '%-.192s'"
- hun "A(z) '%-.48s'@'%-.64s' felhasznalo szamara tiltott eleres az '%-.192s' adabazishoz."
- ita "Accesso non consentito per l'utente: '%-.48s'@'%-.64s' al database '%-.192s'"
- jpn "¥æ¡¼¥¶¡¼ '%-.48s'@'%-.64s' ¤Î '%-.192s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥¢¥¯¥»¥¹¤òµñÈݤ·¤Þ¤¹"
- kor "'%-.48s'@'%-.64s' »ç¿ëÀÚ´Â '%-.192s' µ¥ÀÌŸº£À̽º¿¡ Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù."
- nor "Tilgang nektet for bruker: '%-.48s'@'%-.64s' til databasen '%-.192s' nektet"
- norwegian-ny "Tilgang ikkje tillate for brukar: '%-.48s'@'%-.64s' til databasen '%-.192s' nekta"
- por "Acesso negado para o usuário '%-.48s'@'%-.64s' ao banco de dados '%-.192s'"
- rum "Acces interzis pentru utilizatorul: '%-.48s'@'%-.64s' la baza de date '%-.192s'"
- rus "äÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s'@'%-.64s' ÄÏÓÔÕÐ Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.192s' ÚÁËÒÙÔ"
- serbian "Pristup je zabranjen korisniku '%-.48s'@'%-.64s' za bazu '%-.192s'"
- slo "Zakázaný prístup pre u¾ívateµa: '%-.48s'@'%-.64s' k databázi '%-.192s'"
- spa "Acceso negado para usuario: '%-.48s'@'%-.64s' para la base de datos '%-.192s'"
- swe "Användare '%-.48s'@'%-.64s' är ej berättigad att använda databasen %-.192s"
- ukr "äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s'@'%-.64s' ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ '%-.192s'"
-ER_ACCESS_DENIED_ERROR 28000
- cze "P-Bøístup pro u¾ivatele '%-.48s'@'%-.64s' (s heslem %s)"
- dan "Adgang nægtet bruger: '%-.48s'@'%-.64s' (Bruger adgangskode: %s)"
- nla "Toegang geweigerd voor gebruiker: '%-.48s'@'%-.64s' (Wachtwoord gebruikt: %s)"
- eng "Access denied for user '%-.48s'@'%-.64s' (using password: %s)"
- jps "ƒ†[ƒU[ '%-.48s'@'%-.64s' ‚ð‹‘”Û‚µ‚Ü‚·.uUsing password: %s)",
- est "Ligipääs keelatud kasutajale '%-.48s'@'%-.64s' (kasutab parooli: %s)"
- fre "Accès refusé pour l'utilisateur: '%-.48s'@'@%-.64s' (mot de passe: %s)"
- ger "Benutzer '%-.48s'@'%-.64s' hat keine Zugriffsberechtigung (verwendetes Passwort: %s)"
- greek "Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.48s'@'%-.64s' (÷ñÞóç password: %s)"
- hun "A(z) '%-.48s'@'%-.64s' felhasznalo szamara tiltott eleres. (Hasznalja a jelszot: %s)"
- ita "Accesso non consentito per l'utente: '%-.48s'@'%-.64s' (Password: %s)"
- jpn "¥æ¡¼¥¶¡¼ '%-.48s'@'%-.64s' ¤òµñÈݤ·¤Þ¤¹.uUsing password: %s)"
- kor "'%-.48s'@'%-.64s' »ç¿ëÀÚ´Â Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù. (using password: %s)"
- nor "Tilgang nektet for bruker: '%-.48s'@'%-.64s' (Bruker passord: %s)"
- norwegian-ny "Tilgang ikke tillate for brukar: '%-.48s'@'%-.64s' (Brukar passord: %s)"
- por "Acesso negado para o usuário '%-.48s'@'%-.64s' (senha usada: %s)"
- rum "Acces interzis pentru utilizatorul: '%-.48s'@'%-.64s' (Folosind parola: %s)"
- rus "äÏÓÔÕÐ ÚÁËÒÙÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s'@'%-.64s' (ÂÙÌ ÉÓÐÏÌØÚÏ×ÁÎ ÐÁÒÏÌØ: %s)"
- serbian "Pristup je zabranjen korisniku '%-.48s'@'%-.64s' (koristi lozinku: '%s')"
- slo "Zakázaný prístup pre u¾ívateµa: '%-.48s'@'%-.64s' (pou¾itie hesla: %s)"
- spa "Acceso negado para usuario: '%-.48s'@'%-.64s' (Usando clave: %s)"
- swe "Användare '%-.48s'@'%-.64s' är ej berättigad att logga in (Använder lösen: %s)"
- ukr "äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s'@'%-.64s' (÷ÉËÏÒÉÓÔÁÎÏ ÐÁÒÏÌØ: %s)"
-ER_NO_DB_ERROR 3D000
- cze "Nebyla vybr-Bána ¾ádná databáze"
- dan "Ingen database valgt"
- nla "Geen database geselecteerd"
- eng "No database selected"
- jps "ƒf[ƒ^ƒx[ƒX‚ª‘I‘ð‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ.",
- est "Andmebaasi ei ole valitud"
- fre "Aucune base n'a été sélectionnée"
- ger "Keine Datenbank ausgewählt"
- greek "Äåí åðéëÝ÷èçêå âÜóç äåäïìÝíùí"
- hun "Nincs kivalasztott adatbazis"
- ita "Nessun database selezionato"
- jpn "¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ÁªÂò¤µ¤ì¤Æ¤¤¤Þ¤»¤ó."
- kor "¼±ÅÃµÈ µ¥ÀÌŸº£À̽º°¡ ¾ø½À´Ï´Ù."
- nor "Ingen database valgt"
- norwegian-ny "Ingen database vald"
- pol "Nie wybrano ¿adnej bazy danych"
- por "Nenhum banco de dados foi selecionado"
- rum "Nici o baza de data nu a fost selectata inca"
- rus "âÁÚÁ ÄÁÎÎÙÈ ÎÅ ×ÙÂÒÁÎÁ"
- serbian "Ni jedna baza nije selektovana"
- slo "Nebola vybraná databáza"
- spa "Base de datos no seleccionada"
- swe "Ingen databas i användning"
- ukr "âÁÚÕ ÄÁÎÎÉÈ ÎÅ ×ÉÂÒÁÎÏ"
-ER_UNKNOWN_COM_ERROR 08S01
- cze "Nezn-Bámý pøíkaz"
- dan "Ukendt kommando"
- nla "Onbekend commando"
- eng "Unknown command"
- jps "‚»‚̃Rƒ}ƒ“ƒh‚͉½H",
- est "Tundmatu käsk"
- fre "Commande inconnue"
- ger "Unbekannter Befehl"
- greek "Áãíùóôç åíôïëÞ"
- hun "Ervenytelen parancs"
- ita "Comando sconosciuto"
- jpn "¤½¤Î¥³¥Þ¥ó¥É¤Ï²¿¡©"
- kor "¸í·É¾î°¡ ¹ºÁö ¸ð¸£°Ú¾î¿ä..."
- nor "Ukjent kommando"
- norwegian-ny "Ukjent kommando"
- pol "Nieznana komenda"
- por "Comando desconhecido"
- rum "Comanda invalida"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ËÏÍÁÎÄÁ ËÏÍÍÕÎÉËÁÃÉÏÎÎÏÇÏ ÐÒÏÔÏËÏÌÁ"
- serbian "Nepoznata komanda"
- slo "Neznámy príkaz"
- spa "Comando desconocido"
- swe "Okänt commando"
- ukr "îÅצÄÏÍÁ ËÏÍÁÎÄÁ"
-ER_BAD_NULL_ERROR 23000
- cze "Sloupec '%-.192s' nem-Bù¾e být null"
- dan "Kolonne '%-.192s' kan ikke være NULL"
- nla "Kolom '%-.192s' kan niet null zijn"
- eng "Column '%-.192s' cannot be null"
- jps "Column '%-.192s' ‚Í null ‚É‚Í‚Å‚«‚È‚¢‚Ì‚Å‚·",
- est "Tulp '%-.192s' ei saa omada nullväärtust"
- fre "Le champ '%-.192s' ne peut être vide (null)"
- ger "Feld '%-.192s' darf nicht NULL sein"
- greek "Ôï ðåäßï '%-.192s' äåí ìðïñåß íá åßíáé êåíü (null)"
- hun "A(z) '%-.192s' oszlop erteke nem lehet nulla"
- ita "La colonna '%-.192s' non puo` essere nulla"
- jpn "Column '%-.192s' ¤Ï null ¤Ë¤Ï¤Ç¤­¤Ê¤¤¤Î¤Ç¤¹"
- kor "Ä®·³ '%-.192s'´Â ³Î(Null)ÀÌ µÇ¸é ¾ÈµË´Ï´Ù. "
- nor "Kolonne '%-.192s' kan ikke vere null"
- norwegian-ny "Kolonne '%-.192s' kan ikkje vere null"
- pol "Kolumna '%-.192s' nie mo¿e byæ null"
- por "Coluna '%-.192s' não pode ser vazia"
- rum "Coloana '%-.192s' nu poate sa fie null"
- rus "óÔÏÌÂÅà '%-.192s' ÎÅ ÍÏÖÅÔ ÐÒÉÎÉÍÁÔØ ×ÅÌÉÞÉÎÕ NULL"
- serbian "Kolona '%-.192s' ne može biti NULL"
- slo "Pole '%-.192s' nemô¾e by» null"
- spa "La columna '%-.192s' no puede ser nula"
- swe "Kolumn '%-.192s' får inte vara NULL"
- ukr "óÔÏ×ÂÅÃØ '%-.192s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÎÕÌØÏ×ÉÍ"
-ER_BAD_DB_ERROR 42000
- cze "Nezn-Bámá databáze '%-.192s'"
- dan "Ukendt database '%-.192s'"
- nla "Onbekende database '%-.192s'"
- eng "Unknown database '%-.192s'"
- jps "'%-.192s' ‚È‚ñ‚ăf[ƒ^ƒx[ƒX‚Í’m‚è‚Ü‚¹‚ñ.",
- est "Tundmatu andmebaas '%-.192s'"
- fre "Base '%-.192s' inconnue"
- ger "Unbekannte Datenbank '%-.192s'"
- greek "Áãíùóôç âÜóç äåäïìÝíùí '%-.192s'"
- hun "Ervenytelen adatbazis: '%-.192s'"
- ita "Database '%-.192s' sconosciuto"
- jpn "'%-.192s' ¤Ê¤ó¤Æ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ÏÃΤê¤Þ¤»¤ó."
- kor "µ¥ÀÌŸº£À̽º '%-.192s'´Â ¾Ë¼ö ¾øÀ½"
- nor "Ukjent database '%-.192s'"
- norwegian-ny "Ukjent database '%-.192s'"
- pol "Nieznana baza danych '%-.192s'"
- por "Banco de dados '%-.192s' desconhecido"
- rum "Baza de data invalida '%-.192s'"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ÂÁÚÁ ÄÁÎÎÙÈ '%-.192s'"
- serbian "Nepoznata baza '%-.192s'"
- slo "Neznáma databáza '%-.192s'"
- spa "Base de datos desconocida '%-.192s'"
- swe "Okänd databas: '%-.192s'"
- ukr "îÅצÄÏÍÁ ÂÁÚÁ ÄÁÎÎÉÈ '%-.192s'"
-ER_TABLE_EXISTS_ERROR 42S01
- cze "Tabulka '%-.192s' ji-B¾ existuje"
- dan "Tabellen '%-.192s' findes allerede"
- nla "Tabel '%-.192s' bestaat al"
- eng "Table '%-.192s' already exists"
- jps "Table '%-.192s' ‚ÍŠù‚É‚ ‚è‚Ü‚·",
- est "Tabel '%-.192s' juba eksisteerib"
- fre "La table '%-.192s' existe déjà"
- ger "Tabelle '%-.192s' bereits vorhanden"
- greek "Ï ðßíáêáò '%-.192s' õðÜñ÷åé Þäç"
- hun "A(z) '%-.192s' tabla mar letezik"
- ita "La tabella '%-.192s' esiste gia`"
- jpn "Table '%-.192s' ¤Ï´û¤Ë¤¢¤ê¤Þ¤¹"
- kor "Å×À̺í '%-.192s'´Â ÀÌ¹Ì Á¸ÀçÇÔ"
- nor "Tabellen '%-.192s' eksisterer allerede"
- norwegian-ny "Tabellen '%-.192s' eksisterar allereide"
- pol "Tabela '%-.192s' ju¿ istnieje"
- por "Tabela '%-.192s' já existe"
- rum "Tabela '%-.192s' exista deja"
- rus "ôÁÂÌÉÃÁ '%-.192s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Tabela '%-.192s' veæ postoji"
- slo "Tabuµka '%-.192s' u¾ existuje"
- spa "La tabla '%-.192s' ya existe"
- swe "Tabellen '%-.192s' finns redan"
- ukr "ôÁÂÌÉÃÑ '%-.192s' ×ÖÅ ¦ÓÎÕ¤"
-ER_BAD_TABLE_ERROR 42S02
- cze "Nezn-Bámá tabulka '%-.100s'"
- dan "Ukendt tabel '%-.100s'"
- nla "Onbekende tabel '%-.100s'"
- eng "Unknown table '%-.100s'"
- jps "table '%-.100s' ‚Í‚ ‚è‚Ü‚¹‚ñ.",
- est "Tundmatu tabel '%-.100s'"
- fre "Table '%-.100s' inconnue"
- ger "Unbekannte Tabelle '%-.100s'"
- greek "Áãíùóôïò ðßíáêáò '%-.100s'"
- hun "Ervenytelen tabla: '%-.100s'"
- ita "Tabella '%-.100s' sconosciuta"
- jpn "table '%-.100s' ¤Ï¤¢¤ê¤Þ¤»¤ó."
- kor "Å×À̺í '%-.100s'´Â ¾Ë¼ö ¾øÀ½"
- nor "Ukjent tabell '%-.100s'"
- norwegian-ny "Ukjent tabell '%-.100s'"
- pol "Nieznana tabela '%-.100s'"
- por "Tabela '%-.100s' desconhecida"
- rum "Tabela '%-.100s' este invalida"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.100s'"
- serbian "Nepoznata tabela '%-.100s'"
- slo "Neznáma tabuµka '%-.100s'"
- spa "Tabla '%-.100s' desconocida"
- swe "Okänd tabell '%-.100s'"
- ukr "îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.100s'"
-ER_NON_UNIQ_ERROR 23000
- cze "Sloupec '%-.192s' v %-.192s nen-Bí zcela jasný"
- dan "Felt: '%-.192s' i tabel %-.192s er ikke entydigt"
- nla "Kolom: '%-.192s' in %-.192s is niet eenduidig"
- eng "Column '%-.192s' in %-.192s is ambiguous"
- est "Väli '%-.192s' %-.192s-s ei ole ühene"
- fre "Champ: '%-.192s' dans %-.192s est ambigu"
- ger "Feld '%-.192s' in %-.192s ist nicht eindeutig"
- greek "Ôï ðåäßï: '%-.192s' óå %-.192s äåí Ý÷åé êáèïñéóôåß"
- hun "A(z) '%-.192s' oszlop %-.192s-ben ketertelmu"
- ita "Colonna: '%-.192s' di %-.192s e` ambigua"
- jpn "Column: '%-.192s' in %-.192s is ambiguous"
- kor "Ä®·³: '%-.192s' in '%-.192s' ÀÌ ¸ðÈ£ÇÔ"
- nor "Felt: '%-.192s' i tabell %-.192s er ikke entydig"
- norwegian-ny "Kolonne: '%-.192s' i tabell %-.192s er ikkje eintydig"
- pol "Kolumna: '%-.192s' w %-.192s jest dwuznaczna"
- por "Coluna '%-.192s' em '%-.192s' é ambígua"
- rum "Coloana: '%-.192s' in %-.192s este ambigua"
- rus "óÔÏÌÂÅÃ '%-.192s' × %-.192s ÚÁÄÁÎ ÎÅÏÄÎÏÚÎÁÞÎÏ"
- serbian "Kolona '%-.192s' u %-.192s nije jedinstvena u kontekstu"
- slo "Pole: '%-.192s' v %-.192s je nejasné"
- spa "La columna: '%-.192s' en %-.192s es ambigua"
- swe "Kolumn '%-.192s' i %-.192s är inte unik"
- ukr "óÔÏ×ÂÅÃØ '%-.192s' Õ %-.192s ×ÉÚÎÁÞÅÎÉÊ ÎÅÏÄÎÏÚÎÁÞÎÏ"
-ER_SERVER_SHUTDOWN 08S01
- cze "Prob-Bíhá ukonèování práce serveru"
- dan "Database nedlukning er i gang"
- nla "Bezig met het stoppen van de server"
- eng "Server shutdown in progress"
- jps "Server ‚ð shutdown ’†...",
- est "Serveri seiskamine käib"
- fre "Arrêt du serveur en cours"
- ger "Der Server wird heruntergefahren"
- greek "Åíáñîç äéáäéêáóßáò áðïóýíäåóçò ôïõ åîõðçñåôçôÞ (server shutdown)"
- hun "A szerver leallitasa folyamatban"
- ita "Shutdown del server in corso"
- jpn "Server ¤ò shutdown Ãæ..."
- kor "Server°¡ ¼Ë´Ù¿î ÁßÀÔ´Ï´Ù."
- nor "Database nedkobling er i gang"
- norwegian-ny "Tenar nedkopling er i gang"
- pol "Trwa koñczenie dzia³ania serwera"
- por "'Shutdown' do servidor em andamento"
- rum "Terminarea serverului este in desfasurare"
- rus "óÅÒ×ÅÒ ÎÁÈÏÄÉÔÓÑ × ÐÒÏÃÅÓÓÅ ÏÓÔÁÎÏ×ËÉ"
- serbian "Gašenje servera je u toku"
- slo "Prebieha ukonèovanie práce servera"
- spa "Desconexion de servidor en proceso"
- swe "Servern går nu ned"
- ukr "úÁ×ÅÒÛÕ¤ÔØÓÑ ÒÁÂÏÔÁ ÓÅÒ×ÅÒÁ"
-ER_BAD_FIELD_ERROR 42S22 S0022
- cze "Nezn-Bámý sloupec '%-.192s' v %-.192s"
- dan "Ukendt kolonne '%-.192s' i tabel %-.192s"
- nla "Onbekende kolom '%-.192s' in %-.192s"
- eng "Unknown column '%-.192s' in '%-.192s'"
- jps "'%-.192s' column ‚Í '%-.192s' ‚É‚Í‚ ‚è‚Ü‚¹‚ñ.",
- est "Tundmatu tulp '%-.192s' '%-.192s'-s"
- fre "Champ '%-.192s' inconnu dans %-.192s"
- ger "Unbekanntes Tabellenfeld '%-.192s' in %-.192s"
- greek "Áãíùóôï ðåäßï '%-.192s' óå '%-.192s'"
- hun "A(z) '%-.192s' oszlop ervenytelen '%-.192s'-ben"
- ita "Colonna sconosciuta '%-.192s' in '%-.192s'"
- jpn "'%-.192s' column ¤Ï '%-.192s' ¤Ë¤Ï¤¢¤ê¤Þ¤»¤ó."
- kor "Unknown Ä®·³ '%-.192s' in '%-.192s'"
- nor "Ukjent kolonne '%-.192s' i tabell %-.192s"
- norwegian-ny "Ukjent felt '%-.192s' i tabell %-.192s"
- pol "Nieznana kolumna '%-.192s' w %-.192s"
- por "Coluna '%-.192s' desconhecida em '%-.192s'"
- rum "Coloana invalida '%-.192s' in '%-.192s'"
- rus "îÅÉÚ×ÅÓÔÎÙÊ ÓÔÏÌÂÅà '%-.192s' × '%-.192s'"
- serbian "Nepoznata kolona '%-.192s' u '%-.192s'"
- slo "Neznáme pole '%-.192s' v '%-.192s'"
- spa "La columna '%-.192s' en %-.192s es desconocida"
- swe "Okänd kolumn '%-.192s' i %-.192s"
- ukr "îÅצÄÏÍÉÊ ÓÔÏ×ÂÅÃØ '%-.192s' Õ '%-.192s'"
-ER_WRONG_FIELD_WITH_GROUP 42000 S1009
- cze "Pou-B¾ité '%-.192s' nebylo v group by"
- dan "Brugte '%-.192s' som ikke var i group by"
- nla "Opdracht gebruikt '%-.192s' dat niet in de GROUP BY voorkomt"
- eng "'%-.192s' isn't in GROUP BY"
- jps "'%-.192s' isn't in GROUP BY",
- est "'%-.192s' puudub GROUP BY klauslis"
- fre "'%-.192s' n'est pas dans 'group by'"
- ger "'%-.192s' ist nicht in GROUP BY vorhanden"
- greek "×ñçóéìïðïéÞèçêå '%-.192s' ðïõ äåí õðÞñ÷å óôï group by"
- hun "Used '%-.192s' with wasn't in group by"
- ita "Usato '%-.192s' che non e` nel GROUP BY"
- kor "'%-.192s'Àº GROUP BY¼Ó¿¡ ¾øÀ½"
- nor "Brukte '%-.192s' som ikke var i group by"
- norwegian-ny "Brukte '%-.192s' som ikkje var i group by"
- pol "U¿yto '%-.192s' bez umieszczenia w group by"
- por "'%-.192s' não está em 'GROUP BY'"
- rum "'%-.192s' nu exista in clauza GROUP BY"
- rus "'%-.192s' ÎÅ ÐÒÉÓÕÔÓÔ×ÕÅÔ × GROUP BY"
- serbian "Entitet '%-.192s' nije naveden u komandi 'GROUP BY'"
- slo "Pou¾ité '%-.192s' nebolo v 'group by'"
- spa "Usado '%-.192s' el cual no esta group by"
- swe "'%-.192s' finns inte i GROUP BY"
- ukr "'%-.192s' ÎÅ ¤ Õ GROUP BY"
-ER_WRONG_GROUP_FIELD 42000 S1009
- cze "Nemohu pou-B¾ít group na '%-.192s'"
- dan "Kan ikke gruppere på '%-.192s'"
- nla "Kan '%-.192s' niet groeperen"
- eng "Can't group on '%-.192s'"
- est "Ei saa grupeerida '%-.192s' järgi"
- fre "Ne peut regrouper '%-.192s'"
- ger "Gruppierung über '%-.192s' nicht möglich"
- greek "Áäýíáôç ç ïìáäïðïßçóç (group on) '%-.192s'"
- hun "A group nem hasznalhato: '%-.192s'"
- ita "Impossibile raggruppare per '%-.192s'"
- kor "'%-.192s'¸¦ ±×·ìÇÒ ¼ö ¾øÀ½"
- nor "Kan ikke gruppere på '%-.192s'"
- norwegian-ny "Kan ikkje gruppere på '%-.192s'"
- pol "Nie mo¿na grupowaæ po '%-.192s'"
- por "Não pode agrupar em '%-.192s'"
- rum "Nu pot sa grupez pe (group on) '%-.192s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÉÚ×ÅÓÔÉ ÇÒÕÐÐÉÒÏ×ËÕ ÐÏ '%-.192s'"
- serbian "Ne mogu da grupišem po '%-.192s'"
- slo "Nemô¾em pou¾i» 'group' na '%-.192s'"
- spa "No puedo agrupar por '%-.192s'"
- swe "Kan inte använda GROUP BY med '%-.192s'"
- ukr "îÅ ÍÏÖÕ ÇÒÕÐÕ×ÁÔÉ ÐÏ '%-.192s'"
-ER_WRONG_SUM_SELECT 42000 S1009
- cze "P-Bøíkaz obsahuje zároveò funkci sum a sloupce"
- dan "Udtrykket har summer (sum) funktioner og kolonner i samme udtryk"
- nla "Opdracht heeft totaliseer functies en kolommen in dezelfde opdracht"
- eng "Statement has sum functions and columns in same statement"
- est "Lauses on korraga nii tulbad kui summeerimisfunktsioonid"
- fre "Vous demandez la fonction sum() et des champs dans la même commande"
- ger "Die Verwendung von Summierungsfunktionen und Spalten im selben Befehl ist nicht erlaubt"
- greek "Ç äéáôýðùóç ðåñéÝ÷åé sum functions êáé columns óôçí ßäéá äéáôýðùóç"
- ita "Il comando ha una funzione SUM e una colonna non specificata nella GROUP BY"
- kor "Statement °¡ sum±â´ÉÀ» µ¿ÀÛÁßÀÌ°í Ä®·³µµ µ¿ÀÏÇÑ statementÀÔ´Ï´Ù."
- nor "Uttrykket har summer (sum) funksjoner og kolonner i samme uttrykk"
- norwegian-ny "Uttrykket har summer (sum) funksjoner og kolonner i same uttrykk"
- pol "Zapytanie ma funkcje sumuj?ce i kolumny w tym samym zapytaniu"
- por "Cláusula contém funções de soma e colunas juntas"
- rum "Comanda are functii suma si coloane in aceeasi comanda"
- rus "÷ÙÒÁÖÅÎÉÅ ÓÏÄÅÒÖÉÔ ÇÒÕÐÐÏ×ÙÅ ÆÕÎËÃÉÉ É ÓÔÏÌÂÃÙ, ÎÏ ÎÅ ×ËÌÀÞÁÅÔ GROUP BY. á ËÁË ×Ù ÕÍÕÄÒÉÌÉÓØ ÐÏÌÕÞÉÔØ ÜÔÏ ÓÏÏÂÝÅÎÉÅ Ï ÏÛÉÂËÅ?"
- serbian "Izraz ima 'SUM' agregatnu funkciju i kolone u isto vreme"
- slo "Príkaz obsahuje zároveò funkciu 'sum' a poµa"
- spa "El estamento tiene funciones de suma y columnas en el mismo estamento"
- swe "Kommandot har både sum functions och enkla funktioner"
- ukr "õ ×ÉÒÁÚ¦ ×ÉËÏÒÉÓÔÁÎÏ Ð¦ÄÓÕÍÏ×ÕÀÞ¦ ÆÕÎËæ§ ÐÏÒÑÄ Ú ¦ÍÅÎÁÍÉ ÓÔÏ×Âæ×"
-ER_WRONG_VALUE_COUNT 21S01
- cze "Po-Bèet sloupcù neodpovídá zadané hodnotì"
- dan "Kolonne tæller stemmer ikke med antallet af værdier"
- nla "Het aantal kolommen komt niet overeen met het aantal opgegeven waardes"
- eng "Column count doesn't match value count"
- est "Tulpade arv erineb väärtuste arvust"
- ger "Die Anzahl der Spalten entspricht nicht der Anzahl der Werte"
- greek "Ôï Column count äåí ôáéñéÜæåé ìå ôï value count"
- hun "Az oszlopban levo ertek nem egyezik meg a szamitott ertekkel"
- ita "Il numero delle colonne non e` uguale al numero dei valori"
- kor "Ä®·³ÀÇ Ä«¿îÆ®°¡ °ªÀÇ Ä«¿îÆ®¿Í ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù."
- nor "Felt telling stemmer verdi telling"
- norwegian-ny "Kolonne telling stemmer verdi telling"
- pol "Liczba kolumn nie odpowiada liczbie warto?ci"
- por "Contagem de colunas não confere com a contagem de valores"
- rum "Numarul de coloane nu este acelasi cu numarul valoarei"
- rus "ëÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ× ÎÅ ÓÏ×ÐÁÄÁÅÔ Ó ËÏÌÉÞÅÓÔ×ÏÍ ÚÎÁÞÅÎÉÊ"
- serbian "Broj kolona ne odgovara broju vrednosti"
- slo "Poèet polí nezodpovedá zadanej hodnote"
- spa "La columna con count no tiene valores para contar"
- swe "Antalet kolumner motsvarar inte antalet värden"
- ukr "ë¦ÌØ˦ÓÔØ ÓÔÏ×ÂÃ¦× ÎÅ ÓЦ×ÐÁÄÁ¤ Ú Ë¦ÌØ˦ÓÔÀ ÚÎÁÞÅÎØ"
-ER_TOO_LONG_IDENT 42000 S1009
- cze "Jm-Béno identifikátoru '%-.100s' je pøíli¹ dlouhé"
- dan "Navnet '%-.100s' er for langt"
- nla "Naam voor herkenning '%-.100s' is te lang"
- eng "Identifier name '%-.100s' is too long"
- jps "Identifier name '%-.100s' ‚Í’·‚·‚¬‚Ü‚·",
- est "Identifikaatori '%-.100s' nimi on liiga pikk"
- fre "Le nom de l'identificateur '%-.100s' est trop long"
- ger "Name des Bezeichners '%-.100s' ist zu lang"
- greek "Ôï identifier name '%-.100s' åßíáé ðïëý ìåãÜëï"
- hun "A(z) '%-.100s' azonositonev tul hosszu."
- ita "Il nome dell'identificatore '%-.100s' e` troppo lungo"
- jpn "Identifier name '%-.100s' ¤ÏŤ¹¤®¤Þ¤¹"
- kor "Identifier '%-.100s'´Â ³Ê¹« ±æ±º¿ä."
- nor "Identifikator '%-.100s' er for lang"
- norwegian-ny "Identifikator '%-.100s' er for lang"
- pol "Nazwa identyfikatora '%-.100s' jest zbyt d³uga"
- por "Nome identificador '%-.100s' é longo demais"
- rum "Numele indentificatorului '%-.100s' este prea lung"
- rus "óÌÉÛËÏÍ ÄÌÉÎÎÙÊ ÉÄÅÎÔÉÆÉËÁÔÏÒ '%-.100s'"
- serbian "Ime '%-.100s' je predugaèko"
- slo "Meno identifikátora '%-.100s' je príli¹ dlhé"
- spa "El nombre del identificador '%-.100s' es demasiado grande"
- swe "Kolumnnamn '%-.100s' är för långt"
- ukr "¶Í'Ñ ¦ÄÅÎÔÉƦËÁÔÏÒÁ '%-.100s' ÚÁÄÏ×ÇÅ"
-ER_DUP_FIELDNAME 42S21 S1009
- cze "Zdvojen-Bé jméno sloupce '%-.192s'"
- dan "Feltnavnet '%-.192s' findes allerede"
- nla "Dubbele kolom naam '%-.192s'"
- eng "Duplicate column name '%-.192s'"
- jps "'%-.192s' ‚Æ‚¢‚¤ column –¼‚Íd•¡‚µ‚Ä‚Ü‚·",
- est "Kattuv tulba nimi '%-.192s'"
- fre "Nom du champ '%-.192s' déjà utilisé"
- ger "Doppelter Spaltenname: '%-.192s'"
- greek "ÅðáíÜëçøç column name '%-.192s'"
- hun "Duplikalt oszlopazonosito: '%-.192s'"
- ita "Nome colonna duplicato '%-.192s'"
- jpn "'%-.192s' ¤È¤¤¤¦ column ̾¤Ï½ÅÊ£¤·¤Æ¤Þ¤¹"
- kor "Áߺ¹µÈ Ä®·³ À̸§: '%-.192s'"
- nor "Feltnavnet '%-.192s' eksisterte fra før"
- norwegian-ny "Feltnamnet '%-.192s' eksisterte frå før"
- pol "Powtórzona nazwa kolumny '%-.192s'"
- por "Nome da coluna '%-.192s' duplicado"
- rum "Numele coloanei '%-.192s' e duplicat"
- rus "äÕÂÌÉÒÕÀÝÅÅÓÑ ÉÍÑ ÓÔÏÌÂÃÁ '%-.192s'"
- serbian "Duplirano ime kolone '%-.192s'"
- slo "Opakované meno poµa '%-.192s'"
- spa "Nombre de columna duplicado '%-.192s'"
- swe "Kolumnnamn '%-.192s finns flera gånger"
- ukr "äÕÂÌÀÀÞÅ ¦Í'Ñ ÓÔÏ×ÂÃÑ '%-.192s'"
-ER_DUP_KEYNAME 42000 S1009
- cze "Zdvojen-Bé jméno klíèe '%-.192s'"
- dan "Indeksnavnet '%-.192s' findes allerede"
- nla "Dubbele zoeksleutel naam '%-.192s'"
- eng "Duplicate key name '%-.192s'"
- jps "'%-.192s' ‚Æ‚¢‚¤ key ‚Ì–¼‘O‚Íd•¡‚µ‚Ä‚¢‚Ü‚·",
- est "Kattuv võtme nimi '%-.192s'"
- fre "Nom de clef '%-.192s' déjà utilisé"
- ger "Doppelter Name für Schlüssel vorhanden: '%-.192s'"
- greek "ÅðáíÜëçøç key name '%-.192s'"
- hun "Duplikalt kulcsazonosito: '%-.192s'"
- ita "Nome chiave duplicato '%-.192s'"
- jpn "'%-.192s' ¤È¤¤¤¦ key ¤Î̾Á°¤Ï½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
- kor "Áߺ¹µÈ Å° À̸§ : '%-.192s'"
- nor "Nøkkelnavnet '%-.192s' eksisterte fra før"
- norwegian-ny "Nøkkelnamnet '%-.192s' eksisterte frå før"
- pol "Powtórzony nazwa klucza '%-.192s'"
- por "Nome da chave '%-.192s' duplicado"
- rum "Numele cheiei '%-.192s' e duplicat"
- rus "äÕÂÌÉÒÕÀÝÅÅÓÑ ÉÍÑ ËÌÀÞÁ '%-.192s'"
- serbian "Duplirano ime kljuèa '%-.192s'"
- slo "Opakované meno kµúèa '%-.192s'"
- spa "Nombre de clave duplicado '%-.192s'"
- swe "Nyckelnamn '%-.192s' finns flera gånger"
- ukr "äÕÂÌÀÀÞÅ ¦Í'Ñ ËÌÀÞÁ '%-.192s'"
-# When using this error code, please use ER(ER_DUP_ENTRY_WITH_KEY_NAME)
-# for the message string. See, for example, code in handler.cc.
-ER_DUP_ENTRY 23000 S1009
- cze "Zdvojen-Bý klíè '%-.192s' (èíslo klíèe %d)"
- dan "Ens værdier '%-.192s' for indeks %d"
- nla "Dubbele ingang '%-.192s' voor zoeksleutel %d"
- eng "Duplicate entry '%-.192s' for key %d"
- jps "'%-.192s' ‚Í key %d ‚É‚¨‚¢‚Äd•¡‚µ‚Ä‚¢‚Ü‚·",
- est "Kattuv väärtus '%-.192s' võtmele %d"
- fre "Duplicata du champ '%-.192s' pour la clef %d"
- ger "Doppelter Eintrag '%-.192s' für Schlüssel %d"
- greek "ÄéðëÞ åããñáöÞ '%-.192s' ãéá ôï êëåéäß %d"
- hun "Duplikalt bejegyzes '%-.192s' a %d kulcs szerint."
- ita "Valore duplicato '%-.192s' per la chiave %d"
- jpn "'%-.192s' ¤Ï key %d ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
- kor "Áߺ¹µÈ ÀÔ·Â °ª '%-.192s': key %d"
- nor "Like verdier '%-.192s' for nøkkel %d"
- norwegian-ny "Like verdiar '%-.192s' for nykkel %d"
- pol "Powtórzone wyst?pienie '%-.192s' dla klucza %d"
- por "Entrada '%-.192s' duplicada para a chave %d"
- rum "Cimpul '%-.192s' e duplicat pentru cheia %d"
- rus "äÕÂÌÉÒÕÀÝÁÑÓÑ ÚÁÐÉÓØ '%-.192s' ÐÏ ËÌÀÞÕ %d"
- serbian "Dupliran unos '%-.192s' za kljuè '%d'"
- slo "Opakovaný kµúè '%-.192s' (èíslo kµúèa %d)"
- spa "Entrada duplicada '%-.192s' para la clave %d"
- swe "Dubbel nyckel '%-.192s' för nyckel %d"
- ukr "äÕÂÌÀÀÞÉÊ ÚÁÐÉÓ '%-.192s' ÄÌÑ ËÌÀÞÁ %d"
-ER_WRONG_FIELD_SPEC 42000 S1009
- cze "Chybn-Bá specifikace sloupce '%-.192s'"
- dan "Forkert kolonnespecifikaton for felt '%-.192s'"
- nla "Verkeerde kolom specificatie voor kolom '%-.192s'"
- eng "Incorrect column specifier for column '%-.192s'"
- est "Vigane tulba kirjeldus tulbale '%-.192s'"
- fre "Mauvais paramètre de champ pour le champ '%-.192s'"
- ger "Falsche Spezifikation für Feld '%-.192s'"
- greek "ÅóöáëìÝíï column specifier ãéá ôï ðåäßï '%-.192s'"
- hun "Rossz oszlopazonosito: '%-.192s'"
- ita "Specifica errata per la colonna '%-.192s'"
- kor "Ä®·³ '%-.192s'ÀÇ ºÎÁ¤È®ÇÑ Ä®·³ Á¤ÀÇÀÚ"
- nor "Feil kolonne spesifikator for felt '%-.192s'"
- norwegian-ny "Feil kolonne spesifikator for kolonne '%-.192s'"
- pol "B³êdna specyfikacja kolumny dla kolumny '%-.192s'"
- por "Especificador de coluna incorreto para a coluna '%-.192s'"
- rum "Specificandul coloanei '%-.192s' este incorect"
- rus "îÅËÏÒÒÅËÔÎÙÊ ÏÐÒÅÄÅÌÉÔÅÌØ ÓÔÏÌÂÃÁ ÄÌÑ ÓÔÏÌÂÃÁ '%-.192s'"
- serbian "Pogrešan naziv kolone za kolonu '%-.192s'"
- slo "Chyba v ¹pecifikácii poµa '%-.192s'"
- spa "Especificador de columna erroneo para la columna '%-.192s'"
- swe "Felaktigt kolumntyp för kolumn '%-.192s'"
- ukr "îÅצÒÎÉÊ ÓÐÅÃÉƦËÁÔÏÒ ÓÔÏ×ÂÃÑ '%-.192s'"
-ER_PARSE_ERROR 42000 s1009
- cze "%s bl-Bízko '%-.80s' na øádku %d"
- dan "%s nær '%-.80s' på linje %d"
- nla "%s bij '%-.80s' in regel %d"
- eng "%s near '%-.80s' at line %d"
- jps "%s : '%-.80s' •t‹ß : %d s–Ú",
- est "%s '%-.80s' ligidal real %d"
- fre "%s près de '%-.80s' à la ligne %d"
- ger "%s bei '%-.80s' in Zeile %d"
- greek "%s ðëçóßïí '%-.80s' óôç ãñáììÞ %d"
- hun "A %s a '%-.80s'-hez kozeli a %d sorban"
- ita "%s vicino a '%-.80s' linea %d"
- jpn "%s : '%-.80s' ÉÕ¶á : %d ¹ÔÌÜ"
- kor "'%s' ¿¡·¯ °°À¾´Ï´Ù. ('%-.80s' ¸í·É¾î ¶óÀÎ %d)"
- nor "%s nær '%-.80s' på linje %d"
- norwegian-ny "%s attmed '%-.80s' på line %d"
- pol "%s obok '%-.80s' w linii %d"
- por "%s próximo a '%-.80s' na linha %d"
- rum "%s linga '%-.80s' pe linia %d"
- rus "%s ÏËÏÌÏ '%-.80s' ÎÁ ÓÔÒÏËÅ %d"
- serbian "'%s' u iskazu '%-.80s' na liniji %d"
- slo "%s blízko '%-.80s' na riadku %d"
- spa "%s cerca '%-.80s' en la linea %d"
- swe "%s nära '%-.80s' på rad %d"
- ukr "%s ¦ÌÑ '%-.80s' × ÓÔÒÏæ %d"
-ER_EMPTY_QUERY 42000
- cze "V-Býsledek dotazu je prázdný"
- dan "Forespørgsel var tom"
- nla "Query was leeg"
- eng "Query was empty"
- jps "Query ‚ª‹ó‚Å‚·.",
- est "Tühi päring"
- fre "Query est vide"
- ger "Leere Abfrage"
- greek "Ôï åñþôçìá (query) ðïõ èÝóáôå Þôáí êåíü"
- hun "Ures lekerdezes."
- ita "La query e` vuota"
- jpn "Query ¤¬¶õ¤Ç¤¹."
- kor "Äõ¸®°á°ú°¡ ¾ø½À´Ï´Ù."
- nor "Forespørsel var tom"
- norwegian-ny "Førespurnad var tom"
- pol "Zapytanie by³o puste"
- por "Consulta (query) estava vazia"
- rum "Query-ul a fost gol"
- rus "úÁÐÒÏÓ ÏËÁÚÁÌÓÑ ÐÕÓÔÙÍ"
- serbian "Upit je bio prazan"
- slo "Výsledok po¾iadavky bol prázdny"
- spa "La query estaba vacia"
- swe "Frågan var tom"
- ukr "ðÕÓÔÉÊ ÚÁÐÉÔ"
-ER_NONUNIQ_TABLE 42000 S1009
- cze "Nejednozna-Bèná tabulka/alias: '%-.192s'"
- dan "Tabellen/aliaset: '%-.192s' er ikke unikt"
- nla "Niet unieke waarde tabel/alias: '%-.192s'"
- eng "Not unique table/alias: '%-.192s'"
- jps "'%-.192s' ‚͈êˆÓ‚Ì table/alias –¼‚Å‚Í‚ ‚è‚Ü‚¹‚ñ",
- est "Ei ole unikaalne tabel/alias '%-.192s'"
- fre "Table/alias: '%-.192s' non unique"
- ger "Tabellenname/Alias '%-.192s' nicht eindeutig"
- greek "Áäýíáôç ç áíåýñåóç unique table/alias: '%-.192s'"
- hun "Nem egyedi tabla/alias: '%-.192s'"
- ita "Tabella/alias non unico: '%-.192s'"
- jpn "'%-.192s' ¤Ï°ì°Õ¤Î table/alias ̾¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
- kor "Unique ÇÏÁö ¾ÊÀº Å×À̺í/alias: '%-.192s'"
- nor "Ikke unikt tabell/alias: '%-.192s'"
- norwegian-ny "Ikkje unikt tabell/alias: '%-.192s'"
- pol "Tabela/alias nie s? unikalne: '%-.192s'"
- por "Tabela/alias '%-.192s' não única"
- rum "Tabela/alias: '%-.192s' nu este unic"
- rus "ðÏ×ÔÏÒÑÀÝÁÑÓÑ ÔÁÂÌÉÃÁ/ÐÓÅ×ÄÏÎÉÍ '%-.192s'"
- serbian "Tabela ili alias nisu bili jedinstveni: '%-.192s'"
- slo "Nie jednoznaèná tabuµka/alias: '%-.192s'"
- spa "Tabla/alias: '%-.192s' es no unica"
- swe "Icke unikt tabell/alias: '%-.192s'"
- ukr "îÅÕΦËÁÌØÎÁ ÔÁÂÌÉÃÑ/ÐÓÅ×ÄÏΦÍ: '%-.192s'"
-ER_INVALID_DEFAULT 42000 S1009
- cze "Chybn-Bá defaultní hodnota pro '%-.192s'"
- dan "Ugyldig standardværdi for '%-.192s'"
- nla "Foutieve standaard waarde voor '%-.192s'"
- eng "Invalid default value for '%-.192s'"
- est "Vigane vaikeväärtus '%-.192s' jaoks"
- fre "Valeur par défaut invalide pour '%-.192s'"
- ger "Fehlerhafter Vorgabewert (DEFAULT) für '%-.192s'"
- greek "ÅóöáëìÝíç ðñïêáèïñéóìÝíç ôéìÞ (default value) ãéá '%-.192s'"
- hun "Ervenytelen ertek: '%-.192s'"
- ita "Valore di default non valido per '%-.192s'"
- kor "'%-.192s'ÀÇ À¯È¿ÇÏÁö ¸øÇÑ µðÆúÆ® °ªÀ» »ç¿ëÇϼ̽À´Ï´Ù."
- nor "Ugyldig standardverdi for '%-.192s'"
- norwegian-ny "Ugyldig standardverdi for '%-.192s'"
- pol "Niew³a?ciwa warto?æ domy?lna dla '%-.192s'"
- por "Valor padrão (default) inválido para '%-.192s'"
- rum "Valoarea de default este invalida pentru '%-.192s'"
- rus "îÅËÏÒÒÅËÔÎÏÅ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ '%-.192s'"
- serbian "Loša default vrednost za '%-.192s'"
- slo "Chybná implicitná hodnota pre '%-.192s'"
- spa "Valor por defecto invalido para '%-.192s'"
- swe "Ogiltigt DEFAULT värde för '%-.192s'"
- ukr "îÅצÒÎÅ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ ÄÌÑ '%-.192s'"
-ER_MULTIPLE_PRI_KEY 42000 S1009
- cze "Definov-Báno více primárních klíèù"
- dan "Flere primærnøgler specificeret"
- nla "Meerdere primaire zoeksleutels gedefinieerd"
- eng "Multiple primary key defined"
- jps "•¡”‚Ì primary key ‚ª’è‹`‚³‚ê‚Ü‚µ‚½",
- est "Mitut primaarset võtit ei saa olla"
- fre "Plusieurs clefs primaires définies"
- ger "Mehrere Primärschlüssel (PRIMARY KEY) definiert"
- greek "Ðåñéóóüôåñá áðü Ýíá primary key ïñßóôçêáí"
- hun "Tobbszoros elsodleges kulcs definialas."
- ita "Definite piu` chiave primarie"
- jpn "Ê£¿ô¤Î primary key ¤¬ÄêµÁ¤µ¤ì¤Þ¤·¤¿"
- kor "Multiple primary key°¡ Á¤ÀǵǾî ÀÖ½¿"
- nor "Fleire primærnøkle spesifisert"
- norwegian-ny "Fleire primærnyklar spesifisert"
- pol "Zdefiniowano wiele kluczy podstawowych"
- por "Definida mais de uma chave primária"
- rum "Chei primare definite de mai multe ori"
- rus "õËÁÚÁÎÏ ÎÅÓËÏÌØËÏ ÐÅÒ×ÉÞÎÙÈ ËÌÀÞÅÊ"
- serbian "Definisani višestruki primarni kljuèevi"
- slo "Zadefinovaných viac primárnych kµúèov"
- spa "Multiples claves primarias definidas"
- swe "Flera PRIMARY KEY använda"
- ukr "ðÅÒ×ÉÎÎÏÇÏ ËÌÀÞÁ ×ÉÚÎÁÞÅÎÏ ÎÅÏÄÎÏÒÁÚÏ×Ï"
-ER_TOO_MANY_KEYS 42000 S1009
- cze "Zad-Báno pøíli¹ mnoho klíèù, je povoleno nejvíce %d klíèù"
- dan "For mange nøgler specificeret. Kun %d nøgler må bruges"
- nla "Teveel zoeksleutels gedefinieerd. Maximaal zijn %d zoeksleutels toegestaan"
- eng "Too many keys specified; max %d keys allowed"
- jps "key ‚ÌŽw’肪‘½‚·‚¬‚Ü‚·. key ‚ÍÅ‘å %d ‚Ü‚Å‚Å‚·",
- est "Liiga palju võtmeid. Maksimaalselt võib olla %d võtit"
- fre "Trop de clefs sont définies. Maximum de %d clefs alloué"
- ger "Zu viele Schlüssel definiert. Maximal %d Schlüssel erlaubt"
- greek "ÐÜñá ðïëëÜ key ïñßóèçêáí. Ôï ðïëý %d åðéôñÝðïíôáé"
- hun "Tul sok kulcs. Maximum %d kulcs engedelyezett."
- ita "Troppe chiavi. Sono ammesse max %d chiavi"
- jpn "key ¤Î»ØÄ꤬¿¤¹¤®¤Þ¤¹. key ¤ÏºÇÂç %d ¤Þ¤Ç¤Ç¤¹"
- kor "³Ê¹« ¸¹Àº Å°°¡ Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù.. ÃÖ´ë %dÀÇ Å°°¡ °¡´ÉÇÔ"
- nor "For mange nøkler spesifisert. Maks %d nøkler tillatt"
- norwegian-ny "For mange nykler spesifisert. Maks %d nyklar tillatt"
- pol "Okre?lono zbyt wiele kluczy. Dostêpnych jest maksymalnie %d kluczy"
- por "Especificadas chaves demais. O máximo permitido são %d chaves"
- rum "Prea multe chei. Numarul de chei maxim este %d"
- rus "õËÁÚÁÎÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ËÌÀÞÅÊ. òÁÚÒÅÛÁÅÔÓÑ ÕËÁÚÙ×ÁÔØ ÎÅ ÂÏÌÅÅ %d ËÌÀÞÅÊ"
- serbian "Navedeno je previše kljuèeva. Maksimum %d kljuèeva je dozvoljeno"
- slo "Zadaných ríli¹ veµa kµúèov. Najviac %d kµúèov je povolených"
- spa "Demasiadas claves primarias declaradas. Un maximo de %d claves son permitidas"
- swe "För många nycklar använda. Man får ha högst %d nycklar"
- ukr "úÁÂÁÇÁÔÏ ËÌÀÞ¦× ÚÁÚÎÁÞÅÎÏ. äÏÚ×ÏÌÅÎÏ ÎŠ¦ÌØÛÅ %d ËÌÀÞ¦×"
-ER_TOO_MANY_KEY_PARTS 42000 S1009
- cze "Zad-Báno pøíli¹ mnoho èást klíèù, je povoleno nejvíce %d èástí"
- dan "For mange nøgledele specificeret. Kun %d dele må bruges"
- nla "Teveel zoeksleutel onderdelen gespecificeerd. Maximaal %d onderdelen toegestaan"
- eng "Too many key parts specified; max %d parts allowed"
- est "Võti koosneb liiga paljudest osadest. Maksimaalselt võib olla %d osa"
- fre "Trop de parties specifiées dans la clef. Maximum de %d parties"
- ger "Zu viele Teilschlüssel definiert. Maximal %d Teilschlüssel erlaubt"
- greek "ÐÜñá ðïëëÜ key parts ïñßóèçêáí. Ôï ðïëý %d åðéôñÝðïíôáé"
- hun "Tul sok kulcsdarabot definialt. Maximum %d resz engedelyezett"
- ita "Troppe parti di chiave specificate. Sono ammesse max %d parti"
- kor "³Ê¹« ¸¹Àº Å° ºÎºÐ(parts)µéÀÌ Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù.. ÃÖ´ë %d ºÎºÐÀÌ °¡´ÉÇÔ"
- nor "For mange nøkkeldeler spesifisert. Maks %d deler tillatt"
- norwegian-ny "For mange nykkeldelar spesifisert. Maks %d delar tillatt"
- pol "Okre?lono zbyt wiele czê?ci klucza. Dostêpnych jest maksymalnie %d czê?ci"
- por "Especificadas partes de chave demais. O máximo permitido são %d partes"
- rum "Prea multe chei. Numarul de chei maxim este %d"
- rus "õËÁÚÁÎÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÞÁÓÔÅÊ ÓÏÓÔÁ×ÎÏÇÏ ËÌÀÞÁ. òÁÚÒÅÛÁÅÔÓÑ ÕËÁÚÙ×ÁÔØ ÎÅ ÂÏÌÅÅ %d ÞÁÓÔÅÊ"
- serbian "Navedeno je previše delova kljuèa. Maksimum %d delova je dozvoljeno"
- slo "Zadaných ríli¹ veµa èastí kµúèov. Je povolených najviac %d èastí"
- spa "Demasiadas partes de clave declaradas. Un maximo de %d partes son permitidas"
- swe "För många nyckeldelar använda. Man får ha högst %d nyckeldelar"
- ukr "úÁÂÁÇÁÔÏ ÞÁÓÔÉÎ ËÌÀÞÁ ÚÁÚÎÁÞÅÎÏ. äÏÚ×ÏÌÅÎÏ ÎŠ¦ÌØÛÅ %d ÞÁÓÔÉÎ"
-ER_TOO_LONG_KEY 42000 S1009
- cze "Zadan-Bý klíè byl pøíli¹ dlouhý, nejvìt¹í délka klíèe je %d"
- dan "Specificeret nøgle var for lang. Maksimal nøglelængde er %d"
- nla "Gespecificeerde zoeksleutel was te lang. De maximale lengte is %d"
- eng "Specified key was too long; max key length is %d bytes"
- jps "key ‚ª’·‚·‚¬‚Ü‚·. key ‚Ì’·‚³‚ÍÅ‘å %d ‚Å‚·",
- est "Võti on liiga pikk. Maksimaalne võtmepikkus on %d"
- fre "La clé est trop longue. Longueur maximale: %d"
- ger "Schlüssel ist zu lang. Die maximale Schlüssellänge beträgt %d"
- greek "Ôï êëåéäß ðïõ ïñßóèçêå åßíáé ðïëý ìåãÜëï. Ôï ìÝãéóôï ìÞêïò åßíáé %d"
- hun "A megadott kulcs tul hosszu. Maximalis kulcshosszusag: %d"
- ita "La chiave specificata e` troppo lunga. La max lunghezza della chiave e` %d"
- jpn "key ¤¬Ä¹¤¹¤®¤Þ¤¹. key ¤ÎŤµ¤ÏºÇÂç %d ¤Ç¤¹"
- kor "Á¤ÀÇµÈ Å°°¡ ³Ê¹« ±é´Ï´Ù. ÃÖ´ë Å°ÀÇ ±æÀÌ´Â %dÀÔ´Ï´Ù."
- nor "Spesifisert nøkkel var for lang. Maks nøkkellengde er is %d"
- norwegian-ny "Spesifisert nykkel var for lang. Maks nykkellengde er %d"
- pol "Zdefinowany klucz jest zbyt d³ugi. Maksymaln? d³ugo?ci? klucza jest %d"
- por "Chave especificada longa demais. O comprimento de chave máximo permitido é %d"
- rum "Cheia specificata este prea lunga. Marimea maxima a unei chei este de %d"
- rus "õËÁÚÁÎ ÓÌÉÛËÏÍ ÄÌÉÎÎÙÊ ËÌÀÞ. íÁËÓÉÍÁÌØÎÁÑ ÄÌÉÎÁ ËÌÀÞÁ ÓÏÓÔÁ×ÌÑÅÔ %d ÂÁÊÔ"
- serbian "Navedeni kljuè je predug. Maksimalna dužina kljuèa je %d"
- slo "Zadaný kµúè je príli¹ dlhý, najväè¹ia då¾ka kµúèa je %d"
- spa "Declaracion de clave demasiado larga. La maxima longitud de clave es %d"
- swe "För lång nyckel. Högsta tillåtna nyckellängd är %d"
- ukr "úÁÚÎÁÞÅÎÉÊ ËÌÀÞ ÚÁÄÏ×ÇÉÊ. îÁʦÌØÛÁ ÄÏ×ÖÉÎÁ ËÌÀÞÁ %d ÂÁÊÔ¦×"
-ER_KEY_COLUMN_DOES_NOT_EXITS 42000 S1009
- cze "Kl-Bíèový sloupec '%-.192s' v tabulce neexistuje"
- dan "Nøglefeltet '%-.192s' eksisterer ikke i tabellen"
- nla "Zoeksleutel kolom '%-.192s' bestaat niet in tabel"
- eng "Key column '%-.192s' doesn't exist in table"
- jps "Key column '%-.192s' ‚ªƒe[ƒuƒ‹‚É‚ ‚è‚Ü‚¹‚ñ.",
- est "Võtme tulp '%-.192s' puudub tabelis"
- fre "La clé '%-.192s' n'existe pas dans la table"
- ger "In der Tabelle gibt es kein Schlüsselfeld '%-.192s'"
- greek "Ôï ðåäßï êëåéäß '%-.192s' äåí õðÜñ÷åé óôïí ðßíáêá"
- hun "A(z) '%-.192s'kulcsoszlop nem letezik a tablaban"
- ita "La colonna chiave '%-.192s' non esiste nella tabella"
- jpn "Key column '%-.192s' ¤¬¥Æ¡¼¥Ö¥ë¤Ë¤¢¤ê¤Þ¤»¤ó."
- kor "Key Ä®·³ '%-.192s'´Â Å×ÀÌºí¿¡ Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
- nor "Nøkkel felt '%-.192s' eksiterer ikke i tabellen"
- norwegian-ny "Nykkel kolonne '%-.192s' eksiterar ikkje i tabellen"
- pol "Kolumna '%-.192s' zdefiniowana w kluczu nie istnieje w tabeli"
- por "Coluna chave '%-.192s' não existe na tabela"
- rum "Coloana cheie '%-.192s' nu exista in tabela"
- rus "ëÌÀÞÅ×ÏÊ ÓÔÏÌÂÅà '%-.192s' × ÔÁÂÌÉÃÅ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Kljuèna kolona '%-.192s' ne postoji u tabeli"
- slo "Kµúèový ståpec '%-.192s' v tabuµke neexistuje"
- spa "La columna clave '%-.192s' no existe en la tabla"
- swe "Nyckelkolumn '%-.192s' finns inte"
- ukr "ëÌÀÞÏ×ÉÊ ÓÔÏ×ÂÅÃØ '%-.192s' ÎÅ ¦ÓÎÕ¤ Õ ÔÁÂÌÉæ"
-ER_BLOB_USED_AS_KEY 42000 S1009
- cze "Blob sloupec '%-.192s' nem-Bù¾e být pou¾it jako klíè"
- dan "BLOB feltet '%-.192s' kan ikke bruges ved specifikation af indeks"
- nla "BLOB kolom '%-.192s' kan niet gebruikt worden bij zoeksleutel specificatie"
- eng "BLOB column '%-.192s' can't be used in key specification with the used table type"
- est "BLOB-tüüpi tulpa '%-.192s' ei saa kasutada võtmena"
- fre "Champ BLOB '%-.192s' ne peut être utilisé dans une clé"
- ger "BLOB-Feld '%-.192s' kann beim verwendeten Tabellentyp nicht als Schlüssel verwendet werden"
- greek "Ðåäßï ôýðïõ Blob '%-.192s' äåí ìðïñåß íá ÷ñçóéìïðïéçèåß óôïí ïñéóìü åíüò êëåéäéïý (key specification)"
- hun "Blob objektum '%-.192s' nem hasznalhato kulcskent"
- ita "La colonna BLOB '%-.192s' non puo` essere usata nella specifica della chiave"
- kor "BLOB Ä®·³ '%-.192s'´Â Å° Á¤ÀÇ¿¡¼­ »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù."
- nor "Blob felt '%-.192s' kan ikke brukes ved spesifikasjon av nøkler"
- norwegian-ny "Blob kolonne '%-.192s' kan ikkje brukast ved spesifikasjon av nyklar"
- pol "Kolumna typu Blob '%-.192s' nie mo¿e byæ u¿yta w specyfikacji klucza"
- por "Coluna BLOB '%-.192s' não pode ser utilizada na especificação de chave para o tipo de tabela usado"
- rum "Coloana de tip BLOB '%-.192s' nu poate fi folosita in specificarea cheii cu tipul de tabla folosit"
- rus "óÔÏÌÂÅà ÔÉÐÁ BLOB '%-.192s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ËÁË ÚÎÁÞÅÎÉÅ ËÌÀÞÁ × ÔÁÂÌÉÃÅ ÔÁËÏÇÏ ÔÉÐÁ"
- serbian "BLOB kolona '%-.192s' ne može biti upotrebljena za navoðenje kljuèa sa tipom tabele koji se trenutno koristi"
- slo "Blob pole '%-.192s' nemô¾e by» pou¾ité ako kµúè"
- spa "La columna Blob '%-.192s' no puede ser usada en una declaracion de clave"
- swe "En BLOB '%-.192s' kan inte vara nyckel med den använda tabelltypen"
- ukr "BLOB ÓÔÏ×ÂÅÃØ '%-.192s' ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÉÊ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ × ÃØÏÍÕ ÔÉЦ ÔÁÂÌÉæ"
-ER_TOO_BIG_FIELDLENGTH 42000 S1009
- cze "P-Bøíli¹ velká délka sloupce '%-.192s' (nejvíce %lu). Pou¾ijte BLOB"
- dan "For stor feltlængde for kolonne '%-.192s' (maks = %lu). Brug BLOB i stedet"
- nla "Te grote kolomlengte voor '%-.192s' (max = %lu). Maak hiervoor gebruik van het type BLOB"
- eng "Column length too big for column '%-.192s' (max = %lu); use BLOB or TEXT instead"
- jps "column '%-.192s' ‚Í,Šm•Û‚·‚é column ‚Ì‘å‚«‚³‚ª‘½‚·‚¬‚Ü‚·. (Å‘å %lu ‚Ü‚Å). BLOB ‚ð‚©‚í‚è‚ÉŽg—p‚µ‚Ä‚­‚¾‚³‚¢.",
- est "Tulba '%-.192s' pikkus on liiga pikk (maksimaalne pikkus: %lu). Kasuta BLOB väljatüüpi"
- fre "Champ '%-.192s' trop long (max = %lu). Utilisez un BLOB"
- ger "Feldlänge für Feld '%-.192s' zu groß (maximal %lu). BLOB- oder TEXT-Spaltentyp verwenden!"
- greek "Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.192s' (max = %lu). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB"
- hun "A(z) '%-.192s' oszlop tul hosszu. (maximum = %lu). Hasznaljon BLOB tipust inkabb."
- ita "La colonna '%-.192s' e` troppo grande (max=%lu). Utilizza un BLOB."
- jpn "column '%-.192s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礭¤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %lu ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤."
- kor "Ä®·³ '%-.192s'ÀÇ Ä®·³ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %lu). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä."
- nor "For stor nøkkellengde for kolonne '%-.192s' (maks = %lu). Bruk BLOB istedenfor"
- norwegian-ny "For stor nykkellengde for felt '%-.192s' (maks = %lu). Bruk BLOB istadenfor"
- pol "Zbyt du¿a d³ugo?æ kolumny '%-.192s' (maks. = %lu). W zamian u¿yj typu BLOB"
- por "Comprimento da coluna '%-.192s' grande demais (max = %lu); use BLOB em seu lugar"
- rum "Lungimea coloanei '%-.192s' este prea lunga (maximum = %lu). Foloseste BLOB mai bine"
- rus "óÌÉÛËÏÍ ÂÏÌØÛÁÑ ÄÌÉÎÁ ÓÔÏÌÂÃÁ '%-.192s' (ÍÁËÓÉÍÕÍ = %lu). éÓÐÏÌØÚÕÊÔÅ ÔÉÐ BLOB ÉÌÉ TEXT ×ÍÅÓÔÏ ÔÅËÕÝÅÇÏ"
- serbian "Previše podataka za kolonu '%-.192s' (maksimum je %lu). Upotrebite BLOB polje"
- slo "Príli¹ veµká då¾ka pre pole '%-.192s' (maximum = %lu). Pou¾ite BLOB"
- spa "Longitud de columna demasiado grande para la columna '%-.192s' (maximo = %lu).Usar BLOB en su lugar"
- swe "För stor kolumnlängd angiven för '%-.192s' (max= %lu). Använd en BLOB instället"
- ukr "úÁÄÏ×ÇÁ ÄÏ×ÖÉÎÁ ÓÔÏ×ÂÃÑ '%-.192s' (max = %lu). ÷ÉËÏÒÉÓÔÁÊÔÅ ÔÉÐ BLOB"
-ER_WRONG_AUTO_KEY 42000 S1009
- cze "M-Bù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè"
- dan "Der kan kun specificeres eet AUTO_INCREMENT-felt, og det skal være indekseret"
- nla "Er kan slechts 1 autofield zijn en deze moet als zoeksleutel worden gedefinieerd."
- eng "Incorrect table definition; there can be only one auto column and it must be defined as a key"
- jps "ƒe[ƒuƒ‹‚Ì’è‹`‚ªˆá‚¢‚Ü‚·; there can be only one auto column and it must be defined as a key",
- est "Vigane tabelikirjeldus; Tabelis tohib olla üks auto_increment tüüpi tulp ning see peab olema defineeritud võtmena"
- fre "Un seul champ automatique est permis et il doit être indexé"
- ger "Falsche Tabellendefinition. Es darf nur eine AUTO_INCREMENT-Spalte geben, und diese muss als Schlüssel definiert werden"
- greek "Ìðïñåß íá õðÜñ÷åé ìüíï Ýíá auto field êáé ðñÝðåé íá Ý÷åé ïñéóèåß óáí key"
- hun "Csak egy auto mezo lehetseges, es azt kulcskent kell definialni."
- ita "Puo` esserci solo un campo AUTO e deve essere definito come chiave"
- jpn "¥Æ¡¼¥Ö¥ë¤ÎÄêµÁ¤¬°ã¤¤¤Þ¤¹; there can be only one auto column and it must be defined as a key"
- kor "ºÎÁ¤È®ÇÑ Å×À̺í Á¤ÀÇ; Å×À̺íÀº ÇϳªÀÇ auto Ä®·³ÀÌ Á¸ÀçÇÏ°í Å°·Î Á¤ÀǵǾîÁ®¾ß ÇÕ´Ï´Ù."
- nor "Bare ett auto felt kan være definert som nøkkel."
- norwegian-ny "Bare eitt auto felt kan være definert som nøkkel."
- pol "W tabeli mo¿e byæ tylko jedno pole auto i musi ono byæ zdefiniowane jako klucz"
- por "Definição incorreta de tabela. Somente é permitido um único campo auto-incrementado e ele tem que ser definido como chave"
- rum "Definitia tabelei este incorecta; Nu pot fi mai mult de o singura coloana de tip auto si aceasta trebuie definita ca cheie"
- rus "îÅËÏÒÒÅËÔÎÏÅ ÏÐÒÅÄÅÌÅÎÉÅ ÔÁÂÌÉÃÙ: ÍÏÖÅÔ ÓÕÝÅÓÔ×Ï×ÁÔØ ÔÏÌØËÏ ÏÄÉÎ Á×ÔÏÉÎËÒÅÍÅÎÔÎÙÊ ÓÔÏÌÂÅÃ, É ÏÎ ÄÏÌÖÅÎ ÂÙÔØ ÏÐÒÅÄÅÌÅÎ ËÁË ËÌÀÞ"
- serbian "Pogrešna definicija tabele; U tabeli može postojati samo jedna 'AUTO' kolona i ona mora biti istovremeno definisana kao kolona kljuèa"
- slo "Mô¾ete ma» iba jedno AUTO pole a to musí by» definované ako kµúè"
- spa "Puede ser solamente un campo automatico y este debe ser definido como una clave"
- swe "Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel"
- ukr "îÅצÒÎÅ ×ÉÚÎÁÞÅÎÎÑ ÔÁÂÌÉæ; íÏÖÅ ÂÕÔÉ ÌÉÛÅ ÏÄÉÎ Á×ÔÏÍÁÔÉÞÎÉÊ ÓÔÏ×ÂÅÃØ, ÝÏ ÐÏ×ÉÎÅÎ ÂÕÔÉ ×ÉÚÎÁÞÅÎÉÊ ÑË ËÌÀÞ"
-ER_READY
- cze "%s: p-Bøipraven na spojení\nVersion: '%s' socket: '%s' port: %d""
- dan "%s: klar til tilslutninger\nVersion: '%s' socket: '%s' port: %d""
- nla "%s: klaar voor verbindingen\nVersion: '%s' socket: '%s' port: %d""
- eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d"
- jps "%s: €”õŠ®—¹\nVersion: '%s' socket: '%s' port: %d"",
- est "%s: ootab ühendusi\nVersion: '%s' socket: '%s' port: %d""
- fre "%s: Prêt pour des connexions\nVersion: '%s' socket: '%s' port: %d""
- ger "%s: Bereit für Verbindungen.\nVersion: '%s' Socket: '%s' Port: %d"
- greek "%s: óå áíáìïíÞ óõíäÝóåùí\nVersion: '%s' socket: '%s' port: %d""
- hun "%s: kapcsolatra kesz\nVersion: '%s' socket: '%s' port: %d""
- ita "%s: Pronto per le connessioni\nVersion: '%s' socket: '%s' port: %d""
- jpn "%s: ½àÈ÷´°Î»\nVersion: '%s' socket: '%s' port: %d""
- kor "%s: ¿¬°á ÁغñÁßÀÔ´Ï´Ù\nVersion: '%s' socket: '%s' port: %d""
- nor "%s: klar for tilkoblinger\nVersion: '%s' socket: '%s' port: %d""
- norwegian-ny "%s: klar for tilkoblingar\nVersion: '%s' socket: '%s' port: %d""
- pol "%s: gotowe do po³?czenia\nVersion: '%s' socket: '%s' port: %d""
- por "%s: Pronto para conexões\nVersion: '%s' socket: '%s' port: %d""
- rum "%s: sint gata pentru conectii\nVersion: '%s' socket: '%s' port: %d""
- rus "%s: çÏÔÏ× ÐÒÉÎÉÍÁÔØ ÓÏÅÄÉÎÅÎÉÑ.\n÷ÅÒÓÉÑ: '%s' ÓÏËÅÔ: '%s' ÐÏÒÔ: %d"
- serbian "%s: Spreman za konekcije\nVersion: '%s' socket: '%s' port: %d""
- slo "%s: pripravený na spojenie\nVersion: '%s' socket: '%s' port: %d""
- spa "%s: preparado para conexiones\nVersion: '%s' socket: '%s' port: %d""
- swe "%s: klar att ta emot klienter\nVersion: '%s' socket: '%s' port: %d""
- ukr "%s: çÏÔÏ×ÉÊ ÄÌÑ Ú'¤ÄÎÁÎØ!\nVersion: '%s' socket: '%s' port: %d""
-ER_NORMAL_SHUTDOWN
- cze "%s: norm-Bální ukonèení\n"
- dan "%s: Normal nedlukning\n"
- nla "%s: Normaal afgesloten \n"
- eng "%s: Normal shutdown\n"
- est "%s: MySQL lõpetas\n"
- fre "%s: Arrêt normal du serveur\n"
- ger "%s: Normal heruntergefahren\n"
- greek "%s: ÖõóéïëïãéêÞ äéáäéêáóßá shutdown\n"
- hun "%s: Normal leallitas\n"
- ita "%s: Shutdown normale\n"
- kor "%s: Á¤»óÀûÀÎ shutdown\n"
- nor "%s: Normal avslutning\n"
- norwegian-ny "%s: Normal nedkopling\n"
- pol "%s: Standardowe zakoñczenie dzia³ania\n"
- por "%s: 'Shutdown' normal\n"
- rum "%s: Terminare normala\n"
- rus "%s: ëÏÒÒÅËÔÎÁÑ ÏÓÔÁÎÏ×ËÁ\n"
- serbian "%s: Normalno gašenje\n"
- slo "%s: normálne ukonèenie\n"
- spa "%s: Apagado normal\n"
- swe "%s: Normal avslutning\n"
- ukr "%s: îÏÒÍÁÌØÎÅ ÚÁ×ÅÒÛÅÎÎÑ\n"
-ER_GOT_SIGNAL
- cze "%s: p-Bøijat signal %d, konèím\n"
- dan "%s: Fangede signal %d. Afslutter!!\n"
- nla "%s: Signaal %d. Systeem breekt af!\n"
- eng "%s: Got signal %d. Aborting!\n"
- jps "%s: Got signal %d. ’†’f!\n",
- est "%s: sain signaali %d. Lõpetan!\n"
- fre "%s: Reçu le signal %d. Abandonne!\n"
- ger "%s: Signal %d erhalten. Abbruch!\n"
- greek "%s: ÅëÞöèç ôï ìÞíõìá %d. Ç äéáäéêáóßá åãêáôáëåßðåôáé!\n"
- hun "%s: %d jelzes. Megszakitva!\n"
- ita "%s: Ricevuto segnale %d. Interruzione!\n"
- jpn "%s: Got signal %d. ̾̂!\n"
- kor "%s: %d ½ÅÈ£°¡ µé¾î¿ÔÀ½. ÁßÁö!\n"
- nor "%s: Oppdaget signal %d. Avslutter!\n"
- norwegian-ny "%s: Oppdaga signal %d. Avsluttar!\n"
- pol "%s: Otrzymano sygna³ %d. Koñczenie dzia³ania!\n"
- por "%s: Obteve sinal %d. Abortando!\n"
- rum "%s: Semnal %d obtinut. Aborting!\n"
- rus "%s: ðÏÌÕÞÅÎ ÓÉÇÎÁÌ %d. ðÒÅËÒÁÝÁÅÍ!\n"
- serbian "%s: Dobio signal %d. Prekidam!\n"
- slo "%s: prijatý signál %d, ukonèenie (Abort)!\n"
- spa "%s: Recibiendo signal %d. Abortando!\n"
- swe "%s: Fick signal %d. Avslutar!\n"
- ukr "%s: ïÔÒÉÍÁÎÏ ÓÉÇÎÁÌ %d. ðÅÒÅÒÉ×ÁÀÓØ!\n"
-ER_SHUTDOWN_COMPLETE
- cze "%s: ukon-Bèení práce hotovo\n"
- dan "%s: Server lukket\n"
- nla "%s: Afsluiten afgerond\n"
- eng "%s: Shutdown complete\n"
- jps "%s: Shutdown Š®—¹\n",
- est "%s: Lõpp\n"
- fre "%s: Arrêt du serveur terminé\n"
- ger "%s: Herunterfahren beendet\n"
- greek "%s: Ç äéáäéêáóßá Shutdown ïëïêëçñþèçêå\n"
- hun "%s: A leallitas kesz\n"
- ita "%s: Shutdown completato\n"
- jpn "%s: Shutdown ´°Î»\n"
- kor "%s: Shutdown ÀÌ ¿Ï·áµÊ!\n"
- nor "%s: Avslutning komplett\n"
- norwegian-ny "%s: Nedkopling komplett\n"
- pol "%s: Zakoñczenie dzia³ania wykonane\n"
- por "%s: 'Shutdown' completo\n"
- rum "%s: Terminare completa\n"
- rus "%s: ïÓÔÁÎÏ×ËÁ ÚÁ×ÅÒÛÅÎÁ\n"
- serbian "%s: Gašenje završeno\n"
- slo "%s: práca ukonèená\n"
- spa "%s: Apagado completado\n"
- swe "%s: Avslutning klar\n"
- ukr "%s: òÏÂÏÔÕ ÚÁ×ÅÒÛÅÎÏ\n"
-ER_FORCING_CLOSE 08S01
- cze "%s: n-Básilné uzavøení threadu %ld u¾ivatele '%-.48s'\n"
- dan "%s: Forceret nedlukning af tråd: %ld bruger: '%-.48s'\n"
- nla "%s: Afsluiten afgedwongen van thread %ld gebruiker: '%-.48s'\n"
- eng "%s: Forcing close of thread %ld user: '%-.48s'\n"
- jps "%s: ƒXƒŒƒbƒh %ld ‹­§I—¹ user: '%-.48s'\n",
- est "%s: Sulgen jõuga lõime %ld kasutaja: '%-.48s'\n"
- fre "%s: Arrêt forcé de la tâche (thread) %ld utilisateur: '%-.48s'\n"
- ger "%s: Thread %ld zwangsweise beendet. Benutzer: '%-.48s'\n"
- greek "%s: Ôï thread èá êëåßóåé %ld user: '%-.48s'\n"
- hun "%s: A(z) %ld thread kenyszeritett zarasa. Felhasznalo: '%-.48s'\n"
- ita "%s: Forzata la chiusura del thread %ld utente: '%-.48s'\n"
- jpn "%s: ¥¹¥ì¥Ã¥É %ld ¶¯À©½ªÎ» user: '%-.48s'\n"
- kor "%s: thread %ldÀÇ °­Á¦ Á¾·á user: '%-.48s'\n"
- nor "%s: Påtvinget avslutning av tråd %ld bruker: '%-.48s'\n"
- norwegian-ny "%s: Påtvinga avslutning av tråd %ld brukar: '%-.48s'\n"
- pol "%s: Wymuszenie zamkniêcia w?tku %ld u¿ytkownik: '%-.48s'\n"
- por "%s: Forçando finalização da 'thread' %ld - usuário '%-.48s'\n"
- rum "%s: Terminare fortata a thread-ului %ld utilizatorului: '%-.48s'\n"
- rus "%s: ðÒÉÎÕÄÉÔÅÌØÎÏ ÚÁËÒÙ×ÁÅÍ ÐÏÔÏË %ld ÐÏÌØÚÏ×ÁÔÅÌÑ: '%-.48s'\n"
- serbian "%s: Usiljeno gašenje thread-a %ld koji pripada korisniku: '%-.48s'\n"
- slo "%s: násilné ukonèenie vlákna %ld u¾ívateµa '%-.48s'\n"
- spa "%s: Forzando a cerrar el thread %ld usuario: '%-.48s'\n"
- swe "%s: Stänger av tråd %ld; användare: '%-.48s'\n"
- ukr "%s: ðÒÉÓËÏÒÀÀ ÚÁËÒÉÔÔÑ Ç¦ÌËÉ %ld ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s'\n"
-ER_IPSOCK_ERROR 08S01
- cze "Nemohu vytvo-Bøit IP socket"
- dan "Kan ikke oprette IP socket"
- nla "Kan IP-socket niet openen"
- eng "Can't create IP socket"
- jps "IP socket ‚ªì‚ê‚Ü‚¹‚ñ",
- est "Ei suuda luua IP socketit"
- fre "Ne peut créer la connexion IP (socket)"
- ger "Kann IP-Socket nicht erzeugen"
- greek "Äåí åßíáé äõíáôÞ ç äçìéïõñãßá IP socket"
- hun "Az IP socket nem hozhato letre"
- ita "Impossibile creare il socket IP"
- jpn "IP socket ¤¬ºî¤ì¤Þ¤»¤ó"
- kor "IP ¼ÒÄÏÀ» ¸¸µéÁö ¸øÇß½À´Ï´Ù."
- nor "Kan ikke opprette IP socket"
- norwegian-ny "Kan ikkje opprette IP socket"
- pol "Nie mo¿na stworzyæ socket'u IP"
- por "Não pode criar o soquete IP"
- rum "Nu pot crea IP socket"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ IP-ÓÏËÅÔ"
- serbian "Ne mogu da kreiram IP socket"
- slo "Nemô¾em vytvori» IP socket"
- spa "No puedo crear IP socket"
- swe "Kan inte skapa IP-socket"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ IP ÒÏÚ'¤Í"
-ER_NO_SUCH_INDEX 42S12 S1009
- cze "Tabulka '%-.192s' nem-Bá index odpovídající CREATE INDEX. Vytvoøte tabulku znovu"
- dan "Tabellen '%-.192s' har ikke den nøgle, som blev brugt i CREATE INDEX. Genopret tabellen"
- nla "Tabel '%-.192s' heeft geen INDEX zoals deze gemaakt worden met CREATE INDEX. Maak de tabel opnieuw"
- eng "Table '%-.192s' has no index like the one used in CREATE INDEX; recreate the table"
- jps "Table '%-.192s' ‚Í‚»‚̂悤‚È index ‚ðŽ‚Á‚Ä‚¢‚Ü‚¹‚ñ(CREATE INDEX ŽÀsŽž‚ÉŽw’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ). ƒe[ƒuƒ‹‚ðì‚è’¼‚µ‚Ä‚­‚¾‚³‚¢",
- est "Tabelil '%-.192s' puuduvad võtmed. Loo tabel uuesti"
- fre "La table '%-.192s' n'a pas d'index comme celle utilisée dans CREATE INDEX. Recréez la table"
- ger "Tabelle '%-.192s' besitzt keinen wie den in CREATE INDEX verwendeten Index. Tabelle neu anlegen"
- greek "Ï ðßíáêáò '%-.192s' äåí Ý÷åé åõñåôÞñéï (index) óáí áõôü ðïõ ÷ñçóéìïðïéåßôå óôçí CREATE INDEX. Ðáñáêáëþ, îáíáäçìéïõñãÞóôå ôïí ðßíáêá"
- hun "A(z) '%-.192s' tablahoz nincs meg a CREATE INDEX altal hasznalt index. Alakitsa at a tablat"
- ita "La tabella '%-.192s' non ha nessun indice come quello specificatato dalla CREATE INDEX. Ricrea la tabella"
- jpn "Table '%-.192s' ¤Ï¤½¤Î¤è¤¦¤Ê index ¤ò»ý¤Ã¤Æ¤¤¤Þ¤»¤ó(CREATE INDEX ¼Â¹Ô»þ¤Ë»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó). ¥Æ¡¼¥Ö¥ë¤òºî¤êľ¤·¤Æ¤¯¤À¤µ¤¤"
- kor "Å×À̺í '%-.192s'´Â À妽º¸¦ ¸¸µéÁö ¾Ê¾Ò½À´Ï´Ù. alter Å×À̺í¸í·ÉÀ» ÀÌ¿ëÇÏ¿© Å×À̺íÀ» ¼öÁ¤Çϼ¼¿ä..."
- nor "Tabellen '%-.192s' har ingen index som den som er brukt i CREATE INDEX. Gjenopprett tabellen"
- norwegian-ny "Tabellen '%-.192s' har ingen index som den som er brukt i CREATE INDEX. Oprett tabellen på nytt"
- pol "Tabela '%-.192s' nie ma indeksu takiego jak w CREATE INDEX. Stwórz tabelê"
- por "Tabela '%-.192s' não possui um índice como o usado em CREATE INDEX. Recrie a tabela"
- rum "Tabela '%-.192s' nu are un index ca acela folosit in CREATE INDEX. Re-creeaza tabela"
- rus "÷ ÔÁÂÌÉÃÅ '%-.192s' ÎÅÔ ÔÁËÏÇÏ ÉÎÄÅËÓÁ, ËÁË × CREATE INDEX. óÏÚÄÁÊÔÅ ÔÁÂÌÉÃÕ ÚÁÎÏ×Ï"
- serbian "Tabela '%-.192s' nema isti indeks kao onaj upotrebljen pri komandi 'CREATE INDEX'. Napravite tabelu ponovo"
- slo "Tabuµka '%-.192s' nemá index zodpovedajúci CREATE INDEX. Vytvorte tabulku znova"
- spa "La tabla '%-.192s' no tiene indice como el usado en CREATE INDEX. Crea de nuevo la tabla"
- swe "Tabellen '%-.192s' har inget index som motsvarar det angivna i CREATE INDEX. Skapa om tabellen"
- ukr "ôÁÂÌÉÃÑ '%-.192s' ÍÁ¤ ¦ÎÄÅËÓ, ÝÏ ÎÅ ÓЦ×ÐÁÄÁ¤ Ú ×ËÁÚÁÎÎÉÍ Õ CREATE INDEX. óÔ×ÏÒ¦ÔØ ÔÁÂÌÉÃÀ ÚÎÏ×Õ"
-ER_WRONG_FIELD_TERMINATORS 42000 S1009
- cze "Argument separ-Bátoru polo¾ek nebyl oèekáván. Pøeètìte si manuál"
- dan "Felt adskiller er ikke som forventet, se dokumentationen"
- nla "De argumenten om velden te scheiden zijn anders dan verwacht. Raadpleeg de handleiding"
- eng "Field separator argument is not what is expected; check the manual"
- est "Väljade eraldaja erineb oodatust. Tutvu kasutajajuhendiga"
- fre "Séparateur de champs inconnu. Vérifiez dans le manuel"
- ger "Feldbegrenzer-Argument ist nicht in der erwarteten Form. Bitte im Handbuch nachlesen"
- greek "Ï äéá÷ùñéóôÞò ðåäßùí äåí åßíáé áõôüò ðïõ áíáìåíüôáí. Ðáñáêáëþ áíáôñÝîôå óôï manual"
- hun "A mezoelvalaszto argumentumok nem egyeznek meg a varttal. Nezze meg a kezikonyvben!"
- ita "L'argomento 'Field separator' non e` quello atteso. Controlla il manuale"
- kor "ÇÊµå ±¸ºÐÀÚ ÀμöµéÀÌ ¿ÏÀüÇÏÁö ¾Ê½À´Ï´Ù. ¸Þ´º¾óÀ» ã¾Æ º¸¼¼¿ä."
- nor "Felt skiller argumentene er ikke som forventet, se dokumentasjonen"
- norwegian-ny "Felt skiljer argumenta er ikkje som venta, sjå dokumentasjonen"
- pol "Nie oczekiwano separatora. Sprawd¥ podrêcznik"
- por "Argumento separador de campos não é o esperado. Cheque o manual"
- rum "Argumentul pentru separatorul de cimpuri este diferit de ce ma asteptam. Verifica manualul"
- rus "áÒÇÕÍÅÎÔ ÒÁÚÄÅÌÉÔÅÌÑ ÐÏÌÅÊ - ÎÅ ÔÏÔ, ËÏÔÏÒÙÊ ÏÖÉÄÁÌÓÑ. ïÂÒÁÝÁÊÔÅÓØ Ë ÄÏËÕÍÅÎÔÁÃÉÉ"
- serbian "Argument separatora polja nije ono što se oèekivalo. Proverite uputstvo MySQL server-a"
- slo "Argument oddeµovaè polí nezodpovedá po¾iadavkám. Skontrolujte v manuáli"
- spa "Los separadores de argumentos del campo no son los especificados. Comprueba el manual"
- swe "Fältseparatorerna är vad som förväntades. Kontrollera mot manualen"
- ukr "èÉÂÎÉÊ ÒÏÚĦÌÀ×ÁÞ ÐÏ̦×. ðÏÞÉÔÁÊÔÅ ÄÏËÕÍÅÎÔÁæÀ"
-ER_BLOBS_AND_NO_TERMINATED 42000 S1009
- cze "Nen-Bí mo¾né pou¾ít pevný rowlength s BLOBem. Pou¾ijte 'fields terminated by'."
- dan "Man kan ikke bruge faste feltlængder med BLOB. Brug i stedet 'fields terminated by'."
- nla "Bij het gebruik van BLOBs is het niet mogelijk om vaste rijlengte te gebruiken. Maak s.v.p. gebruik van 'fields terminated by'."
- eng "You can't use fixed rowlength with BLOBs; please use 'fields terminated by'"
- est "BLOB-tüüpi väljade olemasolul ei saa kasutada fikseeritud väljapikkust. Vajalik 'fields terminated by' määrang."
- fre "Vous ne pouvez utiliser des lignes de longueur fixe avec des BLOBs. Utiliser 'fields terminated by'."
- ger "Eine feste Zeilenlänge kann für BLOB-Felder nicht verwendet werden. Bitte 'fields terminated by' verwenden"
- greek "Äåí ìðïñåßôå íá ÷ñçóéìïðïéÞóåôå fixed rowlength óå BLOBs. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå 'fields terminated by'."
- hun "Fix hosszusagu BLOB-ok nem hasznalhatok. Hasznalja a 'mezoelvalaszto jelet' ."
- ita "Non possono essere usate righe a lunghezza fissa con i BLOB. Usa 'FIELDS TERMINATED BY'."
- jpn "You can't use fixed rowlength with BLOBs; please use 'fields terminated by'."
- kor "BLOB·Î´Â °íÁ¤±æÀÌÀÇ lowlength¸¦ »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù. 'fields terminated by'¸¦ »ç¿ëÇϼ¼¿ä."
- nor "En kan ikke bruke faste feltlengder med BLOB. Vennlisgt bruk 'fields terminated by'."
- norwegian-ny "Ein kan ikkje bruke faste feltlengder med BLOB. Vennlisgt bruk 'fields terminated by'."
- pol "Nie mo¿na u¿yæ sta³ej d³ugo?ci wiersza z polami typu BLOB. U¿yj 'fields terminated by'."
- por "Você não pode usar comprimento de linha fixo com BLOBs. Por favor, use campos com comprimento limitado."
- rum "Nu poti folosi lungime de cimp fix pentru BLOB-uri. Foloseste 'fields terminated by'."
- rus "æÉËÓÉÒÏ×ÁÎÎÙÊ ÒÁÚÍÅÒ ÚÁÐÉÓÉ Ó ÐÏÌÑÍÉ ÔÉÐÁ BLOB ÉÓÐÏÌØÚÏ×ÁÔØ ÎÅÌØÚÑ, ÐÒÉÍÅÎÑÊÔÅ 'fields terminated by'"
- serbian "Ne možete koristiti fiksnu velièinu sloga kada imate BLOB polja. Molim koristite 'fields terminated by' opciju."
- slo "Nie je mo¾né pou¾i» fixnú då¾ku s BLOBom. Pou¾ite 'fields terminated by'."
- spa "No puedes usar longitudes de filas fijos con BLOBs. Por favor usa 'campos terminados por '."
- swe "Man kan inte använda fast radlängd med blobs. Använd 'fields terminated by'"
- ukr "îÅ ÍÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÓÔÁÌÕ ÄÏ×ÖÉÎÕ ÓÔÒÏËÉ Ú BLOB. úËÏÒÉÓÔÁÊÔÅÓÑ 'fields terminated by'"
-ER_TEXTFILE_NOT_READABLE
- cze "Soubor '%-.128s' mus-Bí být v adresáøi databáze nebo èitelný pro v¹echny"
- dan "Filen '%-.128s' skal være i database-folderen og kunne læses af alle"
- nla "Het bestand '%-.128s' dient in de database directory voor the komen of leesbaar voor iedereen te zijn."
- eng "The file '%-.128s' must be in the database directory or be readable by all"
- jps "ƒtƒ@ƒCƒ‹ '%-.128s' ‚Í databse ‚Ì directory ‚É‚ ‚é‚©‘S‚Ẵ†[ƒU[‚ª“Ç‚ß‚é‚悤‚É‹–‰Â‚³‚ê‚Ä‚¢‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ.",
- est "Fail '%-.128s' peab asuma andmebaasi kataloogis või olema kõigile loetav"
- fre "Le fichier '%-.128s' doit être dans le répertoire de la base et lisible par tous"
- ger "Datei '%-.128s' muss im Datenbank-Verzeichnis vorhanden oder lesbar für alle sein"
- greek "Ôï áñ÷åßï '%-.128s' ðñÝðåé íá õðÜñ÷åé óôï database directory Þ íá ìðïñåß íá äéáâáóôåß áðü üëïõò"
- hun "A(z) '%-.128s'-nak az adatbazis konyvtarban kell lennie, vagy mindenki szamara olvashatonak"
- ita "Il file '%-.128s' deve essere nella directory del database e deve essere leggibile da tutti"
- jpn "¥Õ¥¡¥¤¥ë '%-.128s' ¤Ï databse ¤Î directory ¤Ë¤¢¤ë¤«Á´¤Æ¤Î¥æ¡¼¥¶¡¼¤¬Æɤá¤ë¤è¤¦¤Ëµö²Ä¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó."
- kor "'%-.128s' È­ÀÏ´Â µ¥ÀÌŸº£À̽º µð·ºÅ丮¿¡ Á¸ÀçÇϰųª ¸ðµÎ¿¡°Ô Àб⠰¡´ÉÇÏ¿©¾ß ÇÕ´Ï´Ù."
- nor "Filen '%-.128s' må være i database-katalogen for å være lesbar for alle"
- norwegian-ny "Filen '%-.128s' må være i database-katalogen for å være lesbar for alle"
- pol "Plik '%-.128s' musi znajdowaæ sie w katalogu bazy danych lub mieæ prawa czytania przez wszystkich"
- por "Arquivo '%-.128s' tem que estar no diretório do banco de dados ou ter leitura possível para todos"
- rum "Fisierul '%-.128s' trebuie sa fie in directorul bazei de data sau trebuie sa poata sa fie citit de catre toata lumea (verifica permisiile)"
- rus "æÁÊÌ '%-.128s' ÄÏÌÖÅÎ ÎÁÈÏÄÉÔØÓÑ × ÔÏÍ ÖÅ ËÁÔÁÌÏÇÅ, ÞÔÏ É ÂÁÚÁ ÄÁÎÎÙÈ, ÉÌÉ ÂÙÔØ ÏÂÝÅÄÏÓÔÕÐÎÙÍ ÄÌÑ ÞÔÅÎÉÑ"
- serbian "File '%-.128s' mora biti u direktorijumu gde su file-ovi baze i mora imati odgovarajuæa prava pristupa"
- slo "Súbor '%-.128s' musí by» v adresári databázy, alebo èitateµný pre v¹etkých"
- spa "El archivo '%-.128s' debe estar en el directorio de la base de datos o ser de lectura por todos"
- swe "Textfilen '%-.128s' måste finnas i databasbiblioteket eller vara läsbar för alla"
- ukr "æÁÊÌ '%-.128s' ÐÏ×ÉÎÅÎ ÂÕÔÉ Õ ÔÅæ ÂÁÚÉ ÄÁÎÎÉÈ ÁÂÏ ÍÁÔÉ ×ÓÔÁÎÏ×ÌÅÎÅ ÐÒÁ×Ï ÎÁ ÞÉÔÁÎÎÑ ÄÌÑ ÕÓ¦È"
-ER_FILE_EXISTS_ERROR
- cze "Soubor '%-.200s' ji-B¾ existuje"
- dan "Filen '%-.200s' eksisterer allerede"
- nla "Het bestand '%-.200s' bestaat reeds"
- eng "File '%-.200s' already exists"
- jps "File '%-.200s' ‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·",
- est "Fail '%-.200s' juba eksisteerib"
- fre "Le fichier '%-.200s' existe déjà"
- ger "Datei '%-.200s' bereits vorhanden"
- greek "Ôï áñ÷åßï '%-.200s' õðÜñ÷åé Þäç"
- hun "A '%-.200s' file mar letezik."
- ita "Il file '%-.200s' esiste gia`"
- jpn "File '%-.200s' ¤Ï´û¤Ë¸ºß¤·¤Þ¤¹"
- kor "'%-.200s' È­ÀÏÀº ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù."
- nor "Filen '%-.200s' eksisterte allerede"
- norwegian-ny "Filen '%-.200s' eksisterte allereide"
- pol "Plik '%-.200s' ju¿ istnieje"
- por "Arquivo '%-.200s' já existe"
- rum "Fisierul '%-.200s' exista deja"
- rus "æÁÊÌ '%-.200s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "File '%-.200s' veæ postoji"
- slo "Súbor '%-.200s' u¾ existuje"
- spa "El archivo '%-.200s' ya existe"
- swe "Filen '%-.200s' existerar redan"
- ukr "æÁÊÌ '%-.200s' ×ÖÅ ¦ÓÎÕ¤"
-ER_LOAD_INFO
- cze "Z-Báznamù: %ld Vymazáno: %ld Pøeskoèeno: %ld Varování: %ld"
- dan "Poster: %ld Fjernet: %ld Sprunget over: %ld Advarsler: %ld"
- nla "Records: %ld Verwijderd: %ld Overgeslagen: %ld Waarschuwingen: %ld"
- eng "Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld"
- jps "ƒŒƒR[ƒh”: %ld íœ: %ld Skipped: %ld Warnings: %ld",
- est "Kirjeid: %ld Kustutatud: %ld Vahele jäetud: %ld Hoiatusi: %ld"
- fre "Enregistrements: %ld Effacés: %ld Non traités: %ld Avertissements: %ld"
- ger "Datensätze: %ld Gelöscht: %ld Ausgelassen: %ld Warnungen: %ld"
- greek "ÅããñáöÝò: %ld ÄéáãñáöÝò: %ld ÐáñåêÜìöèçóáí: %ld ÐñïåéäïðïéÞóåéò: %ld"
- hun "Rekordok: %ld Torolve: %ld Skipped: %ld Warnings: %ld"
- ita "Records: %ld Cancellati: %ld Saltati: %ld Avvertimenti: %ld"
- jpn "¥ì¥³¡¼¥É¿ô: %ld ºï½ü: %ld Skipped: %ld Warnings: %ld"
- kor "·¹ÄÚµå: %ld°³ »èÁ¦: %ld°³ ½ºÅµ: %ld°³ °æ°í: %ld°³"
- nor "Poster: %ld Fjernet: %ld Hoppet over: %ld Advarsler: %ld"
- norwegian-ny "Poster: %ld Fjerna: %ld Hoppa over: %ld Åtvaringar: %ld"
- pol "Recordów: %ld Usuniêtych: %ld Pominiêtych: %ld Ostrze¿eñ: %ld"
- por "Registros: %ld - Deletados: %ld - Ignorados: %ld - Avisos: %ld"
- rum "Recorduri: %ld Sterse: %ld Sarite (skipped): %ld Atentionari (warnings): %ld"
- rus "úÁÐÉÓÅÊ: %ld õÄÁÌÅÎÏ: %ld ðÒÏÐÕÝÅÎÏ: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld"
- serbian "Slogova: %ld Izbrisano: %ld Preskoèeno: %ld Upozorenja: %ld"
- slo "Záznamov: %ld Zmazaných: %ld Preskoèených: %ld Varovania: %ld"
- spa "Registros: %ld Borrados: %ld Saltados: %ld Peligros: %ld"
- swe "Rader: %ld Bortagna: %ld Dubletter: %ld Varningar: %ld"
- ukr "úÁÐÉÓ¦×: %ld ÷ÉÄÁÌÅÎÏ: %ld ðÒÏÐÕÝÅÎÏ: %ld úÁÓÔÅÒÅÖÅÎØ: %ld"
-ER_ALTER_INFO
- cze "Z-Báznamù: %ld Zdvojených: %ld"
- dan "Poster: %ld Ens: %ld"
- nla "Records: %ld Dubbel: %ld"
- eng "Records: %ld Duplicates: %ld"
- jps "ƒŒƒR[ƒh”: %ld d•¡: %ld",
- est "Kirjeid: %ld Kattuvaid: %ld"
- fre "Enregistrements: %ld Doublons: %ld"
- ger "Datensätze: %ld Duplikate: %ld"
- greek "ÅããñáöÝò: %ld ÅðáíáëÞøåéò: %ld"
- hun "Rekordok: %ld Duplikalva: %ld"
- ita "Records: %ld Duplicati: %ld"
- jpn "¥ì¥³¡¼¥É¿ô: %ld ½ÅÊ£: %ld"
- kor "·¹ÄÚµå: %ld°³ Áߺ¹: %ld°³"
- nor "Poster: %ld Like: %ld"
- norwegian-ny "Poster: %ld Like: %ld"
- pol "Rekordów: %ld Duplikatów: %ld"
- por "Registros: %ld - Duplicados: %ld"
- rum "Recorduri: %ld Duplicate: %ld"
- rus "úÁÐÉÓÅÊ: %ld äÕÂÌÉËÁÔÏ×: %ld"
- serbian "Slogova: %ld Duplikata: %ld"
- slo "Záznamov: %ld Opakovaných: %ld"
- spa "Registros: %ld Duplicados: %ld"
- swe "Rader: %ld Dubletter: %ld"
- ukr "úÁÐÉÓ¦×: %ld äÕÂ̦ËÁÔ¦×: %ld"
-ER_WRONG_SUB_KEY
- cze "Chybn-Bá podèást klíèe -- není to øetìzec nebo je del¹í ne¾ délka èásti klíèe"
- dan "Forkert indeksdel. Den anvendte nøgledel er ikke en streng eller længden er større end nøglelængden"
- nla "Foutief sub-gedeelte van de zoeksleutel. De gebruikte zoeksleutel is geen onderdeel van een string of of de gebruikte lengte is langer dan de zoeksleutel"
- eng "Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys"
- est "Vigane võtme osa. Kasutatud võtmeosa ei ole string tüüpi, määratud pikkus on pikem kui võtmeosa või tabelihandler ei toeta seda tüüpi võtmeid"
- fre "Mauvaise sous-clef. Ce n'est pas un 'string' ou la longueur dépasse celle définie dans la clef"
- ger "Falscher Unterteilschlüssel. Der verwendete Schlüsselteil ist entweder kein String, die verwendete Länge ist länger als der Teilschlüssel oder die Speicher-Engine unterstützt keine Unterteilschlüssel"
- greek "ÅóöáëìÝíï sub part key. Ôï ÷ñçóéìïðïéïýìåíï key part äåí åßíáé string Þ ôï ìÞêïò ôïõ åßíáé ìåãáëýôåñï"
- hun "Rossz alkulcs. A hasznalt kulcsresz nem karaktersorozat vagy hosszabb, mint a kulcsresz"
- ita "Sotto-parte della chiave errata. La parte di chiave utilizzata non e` una stringa o la lunghezza e` maggiore della parte di chiave."
- jpn "Incorrect prefix key; the used key part isn't a string or the used length is longer than the key part"
- kor "ºÎÁ¤È®ÇÑ ¼­¹ö ÆÄÆ® Å°. »ç¿ëµÈ Å° ÆÄÆ®°¡ ½ºÆ®¸µÀÌ ¾Æ´Ï°Å³ª Å° ÆÄÆ®ÀÇ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù."
- nor "Feil delnøkkel. Den brukte delnøkkelen er ikke en streng eller den oppgitte lengde er lengre enn nøkkel lengden"
- norwegian-ny "Feil delnykkel. Den brukte delnykkelen er ikkje ein streng eller den oppgitte lengda er lengre enn nykkellengden"
- pol "B³êdna podczê?æ klucza. U¿yta czê?æ klucza nie jest ³añcuchem lub u¿yta d³ugo?æ jest wiêksza ni¿ czê?æ klucza"
- por "Sub parte da chave incorreta. A parte da chave usada não é uma 'string' ou o comprimento usado é maior que parte da chave ou o manipulador de tabelas não suporta sub chaves únicas"
- rum "Componentul cheii este incorrect. Componentul folosit al cheii nu este un sir sau lungimea folosita este mai lunga decit lungimea cheii"
- rus "îÅËÏÒÒÅËÔÎÁÑ ÞÁÓÔØ ËÌÀÞÁ. éÓÐÏÌØÚÕÅÍÁÑ ÞÁÓÔØ ËÌÀÞÁ ÎÅ Ñ×ÌÑÅÔÓÑ ÓÔÒÏËÏÊ, ÕËÁÚÁÎÎÁÑ ÄÌÉÎÁ ÂÏÌØÛÅ, ÞÅÍ ÄÌÉÎÁ ÞÁÓÔÉ ËÌÀÞÁ, ÉÌÉ ÏÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÕÎÉËÁÌØÎÙÅ ÞÁÓÔÉ ËÌÀÞÁ"
- serbian "Pogrešan pod-kljuè dela kljuèa. Upotrebljeni deo kljuèa nije string, upotrebljena dužina je veæa od dela kljuèa ili handler tabela ne podržava jedinstvene pod-kljuèeve"
- slo "Incorrect prefix key; the used key part isn't a string or the used length is longer than the key part"
- spa "Parte de la clave es erronea. Una parte de la clave no es una cadena o la longitud usada es tan grande como la parte de la clave"
- swe "Felaktig delnyckel. Nyckeldelen är inte en sträng eller den angivna längden är längre än kolumnlängden"
- ukr "îÅצÒÎÁ ÞÁÓÔÉÎÁ ËÌÀÞÁ. ÷ÉËÏÒÉÓÔÁÎÁ ÞÁÓÔÉÎÁ ËÌÀÞÁ ÎÅ ¤ ÓÔÒÏËÏÀ, ÚÁÄÏ×ÇÁ ÁÂÏ ×ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ ÕΦËÁÌØÎÉÈ ÞÁÓÔÉÎ ËÌÀÞÅÊ"
-ER_CANT_REMOVE_ALL_FIELDS 42000
- cze "Nen-Bí mo¾né vymazat v¹echny polo¾ky s ALTER TABLE. Pou¾ijte DROP TABLE"
- dan "Man kan ikke slette alle felter med ALTER TABLE. Brug DROP TABLE i stedet."
- nla "Het is niet mogelijk alle velden te verwijderen met ALTER TABLE. Gebruik a.u.b. DROP TABLE hiervoor!"
- eng "You can't delete all columns with ALTER TABLE; use DROP TABLE instead"
- jps "ALTER TABLE ‚Å‘S‚Ä‚Ì column ‚Í휂ł«‚Ü‚¹‚ñ. DROP TABLE ‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢",
- est "ALTER TABLE kasutades ei saa kustutada kõiki tulpasid. Kustuta tabel DROP TABLE abil"
- fre "Vous ne pouvez effacer tous les champs avec ALTER TABLE. Utilisez DROP TABLE"
- ger "Mit ALTER TABLE können nicht alle Felder auf einmal gelöscht werden. Dafür DROP TABLE verwenden"
- greek "Äåí åßíáé äõíáôÞ ç äéáãñáöÞ üëùí ôùí ðåäßùí ìå ALTER TABLE. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå DROP TABLE"
- hun "Az osszes mezo nem torolheto az ALTER TABLE-lel. Hasznalja a DROP TABLE-t helyette"
- ita "Non si possono cancellare tutti i campi con una ALTER TABLE. Utilizzare DROP TABLE"
- jpn "ALTER TABLE ¤ÇÁ´¤Æ¤Î column ¤Ïºï½ü¤Ç¤­¤Þ¤»¤ó. DROP TABLE ¤ò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤"
- kor "ALTER TABLE ¸í·ÉÀ¸·Î´Â ¸ðµç Ä®·³À» Áö¿ï ¼ö ¾ø½À´Ï´Ù. DROP TABLE ¸í·ÉÀ» ÀÌ¿ëÇϼ¼¿ä."
- nor "En kan ikke slette alle felt med ALTER TABLE. Bruk DROP TABLE isteden."
- norwegian-ny "Ein kan ikkje slette alle felt med ALTER TABLE. Bruk DROP TABLE istadenfor."
- pol "Nie mo¿na usun?æ wszystkich pól wykorzystuj?c ALTER TABLE. W zamian u¿yj DROP TABLE"
- por "Você não pode deletar todas as colunas com ALTER TABLE; use DROP TABLE em seu lugar"
- rum "Nu poti sterge toate coloanele cu ALTER TABLE. Foloseste DROP TABLE in schimb"
- rus "îÅÌØÚÑ ÕÄÁÌÉÔØ ×ÓÅ ÓÔÏÌÂÃÙ Ó ÐÏÍÏÝØÀ ALTER TABLE. éÓÐÏÌØÚÕÊÔÅ DROP TABLE"
- serbian "Ne možete da izbrišete sve kolone pomoæu komande 'ALTER TABLE'. Upotrebite komandu 'DROP TABLE' ako želite to da uradite"
- slo "One nemô¾em zmaza» all fields with ALTER TABLE; use DROP TABLE instead"
- spa "No puede borrar todos los campos con ALTER TABLE. Usa DROP TABLE para hacerlo"
- swe "Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället"
- ukr "îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ×Ó¦ ÓÔÏ×Âæ ÚÁ ÄÏÐÏÍÏÇÏÀ ALTER TABLE. äÌÑ ÃØÏÇÏ ÓËÏÒÉÓÔÁÊÔÅÓÑ DROP TABLE"
-ER_CANT_DROP_FIELD_OR_KEY 42000
- cze "Nemohu zru-B¹it '%-.192s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe"
- dan "Kan ikke udføre DROP '%-.192s'. Undersøg om feltet/nøglen eksisterer."
- nla "Kan '%-.192s' niet weggooien. Controleer of het veld of de zoeksleutel daadwerkelijk bestaat."
- eng "Can't DROP '%-.192s'; check that column/key exists"
- jps "'%-.192s' ‚ð”jŠü‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½; check that column/key exists",
- est "Ei suuda kustutada '%-.192s'. Kontrolli kas tulp/võti eksisteerib"
- fre "Ne peut effacer (DROP) '%-.192s'. Vérifiez s'il existe"
- ger "Kann '%-.192s' nicht löschen. Existiert die Spalte oder der Schlüssel?"
- greek "Áäýíáôç ç äéáãñáöÞ (DROP) '%-.192s'. Ðáñáêáëþ åëÝãîôå áí ôï ðåäßï/êëåéäß õðÜñ÷åé"
- hun "A DROP '%-.192s' nem lehetseges. Ellenorizze, hogy a mezo/kulcs letezik-e"
- ita "Impossibile cancellare '%-.192s'. Controllare che il campo chiave esista"
- jpn "'%-.192s' ¤òÇË´þ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿; check that column/key exists"
- kor "'%-.192s'¸¦ DROPÇÒ ¼ö ¾ø½À´Ï´Ù. Ä®·³À̳ª Å°°¡ Á¸ÀçÇÏ´ÂÁö äũÇϼ¼¿ä."
- nor "Kan ikke DROP '%-.192s'. Undersøk om felt/nøkkel eksisterer."
- norwegian-ny "Kan ikkje DROP '%-.192s'. Undersøk om felt/nøkkel eksisterar."
- pol "Nie mo¿na wykonaæ operacji DROP '%-.192s'. Sprawd¥, czy to pole/klucz istnieje"
- por "Não se pode fazer DROP '%-.192s'. Confira se esta coluna/chave existe"
- rum "Nu pot sa DROP '%-.192s'. Verifica daca coloana/cheia exista"
- rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ (DROP) '%-.192s'. õÂÅÄÉÔÅÓØ ÞÔÏ ÓÔÏÌÂÅÃ/ËÌÀÞ ÄÅÊÓÔ×ÉÔÅÌØÎÏ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Ne mogu da izvršim komandu drop 'DROP' na '%-.192s'. Proverite da li ta kolona (odnosno kljuè) postoji"
- slo "Nemô¾em zru¹i» (DROP) '%-.192s'. Skontrolujte, èi neexistujú záznamy/kµúèe"
- spa "No puedo ELIMINAR '%-.192s'. compuebe que el campo/clave existe"
- swe "Kan inte ta bort '%-.192s'. Kontrollera att fältet/nyckel finns"
- ukr "îÅ ÍÏÖÕ DROP '%-.192s'. ðÅÒÅצÒÔÅ, ÞÉ ÃÅÊ ÓÔÏ×ÂÅÃØ/ËÌÀÞ ¦ÓÎÕ¤"
-ER_INSERT_INFO
- cze "Z-Báznamù: %ld Zdvojených: %ld Varování: %ld"
- dan "Poster: %ld Ens: %ld Advarsler: %ld"
- nla "Records: %ld Dubbel: %ld Waarschuwing: %ld"
- eng "Records: %ld Duplicates: %ld Warnings: %ld"
- jps "ƒŒƒR[ƒh”: %ld d•¡”: %ld Warnings: %ld",
- est "Kirjeid: %ld Kattuvaid: %ld Hoiatusi: %ld"
- fre "Enregistrements: %ld Doublons: %ld Avertissements: %ld"
- ger "Datensätze: %ld Duplikate: %ld Warnungen: %ld"
- greek "ÅããñáöÝò: %ld ÅðáíáëÞøåéò: %ld ÐñïåéäïðïéÞóåéò: %ld"
- hun "Rekordok: %ld Duplikalva: %ld Warnings: %ld"
- ita "Records: %ld Duplicati: %ld Avvertimenti: %ld"
- jpn "¥ì¥³¡¼¥É¿ô: %ld ½ÅÊ£¿ô: %ld Warnings: %ld"
- kor "·¹ÄÚµå: %ld°³ Áߺ¹: %ld°³ °æ°í: %ld°³"
- nor "Poster: %ld Like: %ld Advarsler: %ld"
- norwegian-ny "Postar: %ld Like: %ld Åtvaringar: %ld"
- pol "Rekordów: %ld Duplikatów: %ld Ostrze¿eñ: %ld"
- por "Registros: %ld - Duplicados: %ld - Avisos: %ld"
- rum "Recorduri: %ld Duplicate: %ld Atentionari (warnings): %ld"
- rus "úÁÐÉÓÅÊ: %ld äÕÂÌÉËÁÔÏ×: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld"
- serbian "Slogova: %ld Duplikata: %ld Upozorenja: %ld"
- slo "Záznamov: %ld Opakovaných: %ld Varovania: %ld"
- spa "Registros: %ld Duplicados: %ld Peligros: %ld"
- swe "Rader: %ld Dubletter: %ld Varningar: %ld"
- ukr "úÁÐÉÓ¦×: %ld äÕÂ̦ËÁÔ¦×: %ld úÁÓÔÅÒÅÖÅÎØ: %ld"
-ER_UPDATE_TABLE_USED
- eng "You can't specify target table '%-.192s' for update in FROM clause"
- ger "Die Verwendung der zu aktualisierenden Zieltabelle '%-.192s' ist in der FROM-Klausel nicht zulässig."
- rus "îÅ ÄÏÐÕÓËÁÅÔÓÑ ÕËÁÚÁÎÉÅ ÔÁÂÌÉÃÙ '%-.192s' × ÓÐÉÓËÅ ÔÁÂÌÉà FROM ÄÌÑ ×ÎÅÓÅÎÉÑ × ÎÅÅ ÉÚÍÅÎÅÎÉÊ"
- swe "INSERT-table '%-.192s' får inte finnas i FROM tabell-listan"
- ukr "ôÁÂÌÉÃÑ '%-.192s' ÝÏ ÚͦÎÀ¤ÔØÓÑ ÎÅ ÄÏÚ×ÏÌÅÎÁ Õ ÐÅÒÅ̦ËÕ ÔÁÂÌÉÃØ FROM"
-ER_NO_SUCH_THREAD
- cze "Nezn-Bámá identifikace threadu: %lu"
- dan "Ukendt tråd id: %lu"
- nla "Onbekend thread id: %lu"
- eng "Unknown thread id: %lu"
- jps "thread id: %lu ‚Í‚ ‚è‚Ü‚¹‚ñ",
- est "Tundmatu lõim: %lu"
- fre "Numéro de tâche inconnu: %lu"
- ger "Unbekannte Thread-ID: %lu"
- greek "Áãíùóôï thread id: %lu"
- hun "Ervenytelen szal (thread) id: %lu"
- ita "Thread id: %lu sconosciuto"
- jpn "thread id: %lu ¤Ï¤¢¤ê¤Þ¤»¤ó"
- kor "¾Ë¼ö ¾ø´Â ¾²·¹µå id: %lu"
- nor "Ukjent tråd id: %lu"
- norwegian-ny "Ukjent tråd id: %lu"
- pol "Nieznany identyfikator w?tku: %lu"
- por "'Id' de 'thread' %lu desconhecido"
- rum "Id-ul: %lu thread-ului este necunoscut"
- rus "îÅÉÚ×ÅÓÔÎÙÊ ÎÏÍÅÒ ÐÏÔÏËÁ: %lu"
- serbian "Nepoznat thread identifikator: %lu"
- slo "Neznáma identifikácia vlákna: %lu"
- spa "Identificador del thread: %lu desconocido"
- swe "Finns ingen tråd med id %lu"
- ukr "îÅצÄÏÍÉÊ ¦ÄÅÎÔÉƦËÁÔÏÒ Ç¦ÌËÉ: %lu"
-ER_KILL_DENIED_ERROR
- cze "Nejste vlastn-Bíkem threadu %lu"
- dan "Du er ikke ejer af tråden %lu"
- nla "U bent geen bezitter van thread %lu"
- eng "You are not owner of thread %lu"
- jps "thread %lu ‚̃I[ƒi[‚Å‚Í‚ ‚è‚Ü‚¹‚ñ",
- est "Ei ole lõime %lu omanik"
- fre "Vous n'êtes pas propriétaire de la tâche no: %lu"
- ger "Sie sind nicht Eigentümer von Thread %lu"
- greek "Äåí åßóèå owner ôïõ thread %lu"
- hun "A %lu thread-nek mas a tulajdonosa"
- ita "Utente non proprietario del thread %lu"
- jpn "thread %lu ¤Î¥ª¡¼¥Ê¡¼¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
- kor "¾²·¹µå(Thread) %luÀÇ ¼ÒÀ¯ÀÚ°¡ ¾Æ´Õ´Ï´Ù."
- nor "Du er ikke eier av tråden %lu"
- norwegian-ny "Du er ikkje eigar av tråd %lu"
- pol "Nie jeste? w³a?cicielem w?tku %lu"
- por "Você não é proprietário da 'thread' %lu"
- rum "Nu sinteti proprietarul threadului %lu"
- rus "÷Ù ÎÅ Ñ×ÌÑÅÔÅÓØ ×ÌÁÄÅÌØÃÅÍ ÐÏÔÏËÁ %lu"
- serbian "Vi niste vlasnik thread-a %lu"
- slo "Nie ste vlastníkom vlákna %lu"
- spa "Tu no eres el propietario del thread%lu"
- swe "Du är inte ägare till tråd %lu"
- ukr "÷É ÎÅ ×ÏÌÏÄÁÒ Ç¦ÌËÉ %lu"
-ER_NO_TABLES_USED
- cze "Nejsou pou-B¾ity ¾ádné tabulky"
- dan "Ingen tabeller i brug"
- nla "Geen tabellen gebruikt."
- eng "No tables used"
- est "Ühtegi tabelit pole kasutusel"
- fre "Aucune table utilisée"
- ger "Keine Tabellen verwendet"
- greek "Äåí ÷ñçóéìïðïéÞèçêáí ðßíáêåò"
- hun "Nincs hasznalt tabla"
- ita "Nessuna tabella usata"
- kor "¾î¶² Å×ÀÌºíµµ »ç¿ëµÇÁö ¾Ê¾Ò½À´Ï´Ù."
- nor "Ingen tabeller i bruk"
- norwegian-ny "Ingen tabellar i bruk"
- pol "Nie ma ¿adej u¿ytej tabeli"
- por "Nenhuma tabela usada"
- rum "Nici o tabela folosita"
- rus "îÉËÁËÉÅ ÔÁÂÌÉÃÙ ÎÅ ÉÓÐÏÌØÚÏ×ÁÎÙ"
- serbian "Nema upotrebljenih tabela"
- slo "Nie je pou¾itá ¾iadna tabuµka"
- spa "No ha tablas usadas"
- swe "Inga tabeller angivna"
- ukr "îÅ ×ÉËÏÒÉÓÔÁÎÏ ÔÁÂÌÉÃØ"
-ER_TOO_BIG_SET
- cze "P-Bøíli¹ mnoho øetìzcù pro sloupec %-.192s a SET"
- dan "For mange tekststrenge til specifikationen af SET i kolonne %-.192s"
- nla "Teveel strings voor kolom %-.192s en SET"
- eng "Too many strings for column %-.192s and SET"
- est "Liiga palju string tulbale %-.192s tüübile SET"
- fre "Trop de chaînes dans la colonne %-.192s avec SET"
- ger "Zu viele Strings für Feld %-.192s und SET angegeben"
- greek "ÐÜñá ðïëëÜ strings ãéá ôï ðåäßï %-.192s êáé SET"
- hun "Tul sok karakter: %-.192s es SET"
- ita "Troppe stringhe per la colonna %-.192s e la SET"
- kor "Ä®·³ %-.192s¿Í SET¿¡¼­ ½ºÆ®¸µÀÌ ³Ê¹« ¸¹½À´Ï´Ù."
- nor "For mange tekststrenger kolonne %-.192s og SET"
- norwegian-ny "For mange tekststrengar felt %-.192s og SET"
- pol "Zbyt wiele ³añcuchów dla kolumny %-.192s i polecenia SET"
- por "'Strings' demais para coluna '%-.192s' e SET"
- rum "Prea multe siruri pentru coloana %-.192s si SET"
- rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÚÎÁÞÅÎÉÊ ÄÌÑ ÓÔÏÌÂÃÁ %-.192s × SET"
- serbian "Previše string-ova za kolonu '%-.192s' i komandu 'SET'"
- slo "Príli¹ mnoho re»azcov pre pole %-.192s a SET"
- spa "Muchas strings para columna %-.192s y SET"
- swe "För många alternativ till kolumn %-.192s för SET"
- ukr "úÁÂÁÇÁÔÏ ÓÔÒÏË ÄÌÑ ÓÔÏ×ÂÃÑ %-.192s ÔÁ SET"
-ER_NO_UNIQUE_LOGFILE
- cze "Nemohu vytvo-Bøit jednoznaèné jméno logovacího souboru %-.200s.(1-999)\n"
- dan "Kan ikke lave unikt log-filnavn %-.200s.(1-999)\n"
- nla "Het is niet mogelijk een unieke naam te maken voor de logfile %-.200s.(1-999)\n"
- eng "Can't generate a unique log-filename %-.200s.(1-999)\n"
- est "Ei suuda luua unikaalset logifaili nime %-.200s.(1-999)\n"
- fre "Ne peut générer un unique nom de journal %-.200s.(1-999)\n"
- ger "Kann keinen eindeutigen Dateinamen für die Logdatei %-.200s(1-999) erzeugen\n"
- greek "Áäýíáôç ç äçìéïõñãßá unique log-filename %-.200s.(1-999)\n"
- hun "Egyedi log-filenev nem generalhato: %-.200s.(1-999)\n"
- ita "Impossibile generare un nome del file log unico %-.200s.(1-999)\n"
- kor "Unique ·Î±×È­ÀÏ '%-.200s'¸¦ ¸¸µé¼ö ¾ø½À´Ï´Ù.(1-999)\n"
- nor "Kan ikke lage unikt loggfilnavn %-.200s.(1-999)\n"
- norwegian-ny "Kan ikkje lage unikt loggfilnavn %-.200s.(1-999)\n"
- pol "Nie mo¿na stworzyæ unikalnej nazwy pliku z logiem %-.200s.(1-999)\n"
- por "Não pode gerar um nome de arquivo de 'log' único '%-.200s'.(1-999)\n"
- rum "Nu pot sa generez un nume de log unic %-.200s.(1-999)\n"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÕÎÉËÁÌØÎÏÅ ÉÍÑ ÆÁÊÌÁ ÖÕÒÎÁÌÁ %-.200s.(1-999)\n"
- serbian "Ne mogu da generišem jedinstveno ime log-file-a: '%-.200s.(1-999)'\n"
- slo "Nemô¾em vytvori» unikátne meno log-súboru %-.200s.(1-999)\n"
- spa "No puede crear un unico archivo log %-.200s.(1-999)\n"
- swe "Kan inte generera ett unikt filnamn %-.200s.(1-999)\n"
- ukr "îÅ ÍÏÖÕ ÚÇÅÎÅÒÕ×ÁÔÉ ÕΦËÁÌØÎÅ ¦Í'Ñ log-ÆÁÊÌÕ %-.200s.(1-999)\n"
-ER_TABLE_NOT_LOCKED_FOR_WRITE
- cze "Tabulka '%-.192s' byla zam-Bèena s READ a nemù¾e být zmìnìna"
- dan "Tabellen '%-.192s' var låst med READ lås og kan ikke opdateres"
- nla "Tabel '%-.192s' was gelocked met een lock om te lezen. Derhalve kunnen geen wijzigingen worden opgeslagen."
- eng "Table '%-.192s' was locked with a READ lock and can't be updated"
- jps "Table '%-.192s' ‚Í READ lock ‚É‚È‚Á‚Ä‚¢‚ÄAXV‚Í‚Å‚«‚Ü‚¹‚ñ",
- est "Tabel '%-.192s' on lukustatud READ lukuga ning ei ole muudetav"
- fre "Table '%-.192s' verrouillée lecture (READ): modification impossible"
- ger "Tabelle '%-.192s' ist mit Lesesperre versehen und kann nicht aktualisiert werden"
- greek "Ï ðßíáêáò '%-.192s' Ý÷åé êëåéäùèåß ìå READ lock êáé äåí åðéôñÝðïíôáé áëëáãÝò"
- hun "A(z) '%-.192s' tabla zarolva lett (READ lock) es nem lehet frissiteni"
- ita "La tabella '%-.192s' e` soggetta a lock in lettura e non puo` essere aggiornata"
- jpn "Table '%-.192s' ¤Ï READ lock ¤Ë¤Ê¤Ã¤Æ¤¤¤Æ¡¢¹¹¿·¤Ï¤Ç¤­¤Þ¤»¤ó"
- kor "Å×À̺í '%-.192s'´Â READ ¶ôÀÌ Àá°ÜÀ־ °»½ÅÇÒ ¼ö ¾ø½À´Ï´Ù."
- nor "Tabellen '%-.192s' var låst med READ lås og kan ikke oppdateres"
- norwegian-ny "Tabellen '%-.192s' var låst med READ lås og kan ikkje oppdaterast"
- pol "Tabela '%-.192s' zosta³a zablokowana przez READ i nie mo¿e zostaæ zaktualizowana"
- por "Tabela '%-.192s' foi travada com trava de leitura e não pode ser atualizada"
- rum "Tabela '%-.192s' a fost locked cu un READ lock si nu poate fi actualizata"
- rus "ôÁÂÌÉÃÁ '%-.192s' ÚÁÂÌÏËÉÒÏ×ÁÎÁ ÕÒÏ×ÎÅÍ READ lock É ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÚÍÅÎÅÎÁ"
- serbian "Tabela '%-.192s' je zakljuèana READ lock-om; iz nje se može samo èitati ali u nju se ne može pisati"
- slo "Tabuµka '%-.192s' bola zamknutá s READ a nemô¾e by» zmenená"
- spa "Tabla '%-.192s' fue trabada con un READ lock y no puede ser actualizada"
- swe "Tabell '%-.192s' kan inte uppdateras emedan den är låst för läsning"
- ukr "ôÁÂÌÉÃÀ '%-.192s' ÚÁÂÌÏËÏ×ÁÎÏ Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ, ÔÏÍÕ §§ ÎÅ ÍÏÖÎÁ ÏÎÏ×ÉÔÉ"
-ER_TABLE_NOT_LOCKED
- cze "Tabulka '%-.192s' nebyla zam-Bèena s LOCK TABLES"
- dan "Tabellen '%-.192s' var ikke låst med LOCK TABLES"
- nla "Tabel '%-.192s' was niet gelocked met LOCK TABLES"
- eng "Table '%-.192s' was not locked with LOCK TABLES"
- jps "Table '%-.192s' ‚Í LOCK TABLES ‚É‚æ‚Á‚ăƒbƒN‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "Tabel '%-.192s' ei ole lukustatud käsuga LOCK TABLES"
- fre "Table '%-.192s' non verrouillée: utilisez LOCK TABLES"
- ger "Tabelle '%-.192s' wurde nicht mit LOCK TABLES gesperrt"
- greek "Ï ðßíáêáò '%-.192s' äåí Ý÷åé êëåéäùèåß ìå LOCK TABLES"
- hun "A(z) '%-.192s' tabla nincs zarolva a LOCK TABLES-szel"
- ita "Non e` stato impostato il lock per la tabella '%-.192s' con LOCK TABLES"
- jpn "Table '%-.192s' ¤Ï LOCK TABLES ¤Ë¤è¤Ã¤Æ¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "Å×À̺í '%-.192s'´Â LOCK TABLES ¸í·ÉÀ¸·Î Àá±âÁö ¾Ê¾Ò½À´Ï´Ù."
- nor "Tabellen '%-.192s' var ikke låst med LOCK TABLES"
- norwegian-ny "Tabellen '%-.192s' var ikkje låst med LOCK TABLES"
- pol "Tabela '%-.192s' nie zosta³a zablokowana poleceniem LOCK TABLES"
- por "Tabela '%-.192s' não foi travada com LOCK TABLES"
- rum "Tabela '%-.192s' nu a fost locked cu LOCK TABLES"
- rus "ôÁÂÌÉÃÁ '%-.192s' ÎÅ ÂÙÌÁ ÚÁÂÌÏËÉÒÏ×ÁÎÁ Ó ÐÏÍÏÝØÀ LOCK TABLES"
- serbian "Tabela '%-.192s' nije bila zakljuèana komandom 'LOCK TABLES'"
- slo "Tabuµka '%-.192s' nebola zamknutá s LOCK TABLES"
- spa "Tabla '%-.192s' no fue trabada con LOCK TABLES"
- swe "Tabell '%-.192s' är inte låst med LOCK TABLES"
- ukr "ôÁÂÌÉÃÀ '%-.192s' ÎÅ ÂÕÌÏ ÂÌÏËÏ×ÁÎÏ Ú LOCK TABLES"
-ER_BLOB_CANT_HAVE_DEFAULT 42000
- cze "Blob polo-B¾ka '%-.192s' nemù¾e mít defaultní hodnotu"
- dan "BLOB feltet '%-.192s' kan ikke have en standard værdi"
- nla "Blob veld '%-.192s' can geen standaardwaarde bevatten"
- eng "BLOB/TEXT column '%-.192s' can't have a default value"
- est "BLOB-tüüpi tulp '%-.192s' ei saa omada vaikeväärtust"
- fre "BLOB '%-.192s' ne peut avoir de valeur par défaut"
- ger "BLOB/TEXT-Feld '%-.192s' darf keinen Vorgabewert (DEFAULT) haben"
- greek "Ôá Blob ðåäßá '%-.192s' äåí ìðïñïýí íá Ý÷ïõí ðñïêáèïñéóìÝíåò ôéìÝò (default value)"
- hun "A(z) '%-.192s' blob objektumnak nem lehet alapertelmezett erteke"
- ita "Il campo BLOB '%-.192s' non puo` avere un valore di default"
- jpn "BLOB column '%-.192s' can't have a default value"
- kor "BLOB Ä®·³ '%-.192s' ´Â µðÆúÆ® °ªÀ» °¡Áú ¼ö ¾ø½À´Ï´Ù."
- nor "Blob feltet '%-.192s' kan ikke ha en standard verdi"
- norwegian-ny "Blob feltet '%-.192s' kan ikkje ha ein standard verdi"
- pol "Pole typu blob '%-.192s' nie mo¿e mieæ domy?lnej warto?ci"
- por "Coluna BLOB '%-.192s' não pode ter um valor padrão (default)"
- rum "Coloana BLOB '%-.192s' nu poate avea o valoare default"
- rus "îÅ×ÏÚÍÏÖÎÏ ÕËÁÚÙ×ÁÔØ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ ÓÔÏÌÂÃÁ BLOB '%-.192s'"
- serbian "BLOB kolona '%-.192s' ne može imati default vrednost"
- slo "Pole BLOB '%-.192s' nemô¾e ma» implicitnú hodnotu"
- spa "Campo Blob '%-.192s' no puede tener valores patron"
- swe "BLOB fält '%-.192s' kan inte ha ett DEFAULT-värde"
- ukr "óÔÏ×ÂÅÃØ BLOB '%-.192s' ÎÅ ÍÏÖÅ ÍÁÔÉ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ"
-ER_WRONG_DB_NAME 42000
- cze "Nep-Bøípustné jméno databáze '%-.100s'"
- dan "Ugyldigt database navn '%-.100s'"
- nla "Databasenaam '%-.100s' is niet getoegestaan"
- eng "Incorrect database name '%-.100s'"
- jps "Žw’肵‚½ database –¼ '%-.100s' ‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·",
- est "Vigane andmebaasi nimi '%-.100s'"
- fre "Nom de base de donnée illégal: '%-.100s'"
- ger "Unerlaubter Datenbankname '%-.100s'"
- greek "ËÜèïò üíïìá âÜóçò äåäïìÝíùí '%-.100s'"
- hun "Hibas adatbazisnev: '%-.100s'"
- ita "Nome database errato '%-.100s'"
- jpn "»ØÄꤷ¤¿ database ̾ '%-.100s' ¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹"
- kor "'%-.100s' µ¥ÀÌŸº£À̽ºÀÇ À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù."
- nor "Ugyldig database navn '%-.100s'"
- norwegian-ny "Ugyldig database namn '%-.100s'"
- pol "Niedozwolona nazwa bazy danych '%-.100s'"
- por "Nome de banco de dados '%-.100s' incorreto"
- rum "Numele bazei de date este incorect '%-.100s'"
- rus "îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÂÁÚÙ ÄÁÎÎÙÈ '%-.100s'"
- serbian "Pogrešno ime baze '%-.100s'"
- slo "Neprípustné meno databázy '%-.100s'"
- spa "Nombre de base de datos ilegal '%-.100s'"
- swe "Felaktigt databasnamn '%-.100s'"
- ukr "îÅצÒÎÅ ¦Í'Ñ ÂÁÚÉ ÄÁÎÎÉÈ '%-.100s'"
-ER_WRONG_TABLE_NAME 42000
- cze "Nep-Bøípustné jméno tabulky '%-.100s'"
- dan "Ugyldigt tabel navn '%-.100s'"
- nla "Niet toegestane tabelnaam '%-.100s'"
- eng "Incorrect table name '%-.100s'"
- jps "Žw’肵‚½ table –¼ '%-.100s' ‚Í‚Ü‚¿‚ª‚Á‚Ä‚¢‚Ü‚·",
- est "Vigane tabeli nimi '%-.100s'"
- fre "Nom de table illégal: '%-.100s'"
- ger "Unerlaubter Tabellenname '%-.100s'"
- greek "ËÜèïò üíïìá ðßíáêá '%-.100s'"
- hun "Hibas tablanev: '%-.100s'"
- ita "Nome tabella errato '%-.100s'"
- jpn "»ØÄꤷ¤¿ table ̾ '%-.100s' ¤Ï¤Þ¤Á¤¬¤Ã¤Æ¤¤¤Þ¤¹"
- kor "'%-.100s' Å×À̺í À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù."
- nor "Ugyldig tabell navn '%-.100s'"
- norwegian-ny "Ugyldig tabell namn '%-.100s'"
- pol "Niedozwolona nazwa tabeli '%-.100s'..."
- por "Nome de tabela '%-.100s' incorreto"
- rum "Numele tabelei este incorect '%-.100s'"
- rus "îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÔÁÂÌÉÃÙ '%-.100s'"
- serbian "Pogrešno ime tabele '%-.100s'"
- slo "Neprípustné meno tabuµky '%-.100s'"
- spa "Nombre de tabla ilegal '%-.100s'"
- swe "Felaktigt tabellnamn '%-.100s'"
- ukr "îÅצÒÎÅ ¦Í'Ñ ÔÁÂÌÉæ '%-.100s'"
-ER_TOO_BIG_SELECT 42000
- cze "Zadan-Bý SELECT by procházel pøíli¹ mnoho záznamù a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v poøádku, pou¾ijte SET SQL_BIG_SELECTS=1"
- dan "SELECT ville undersøge for mange poster og ville sandsynligvis tage meget lang tid. Undersøg WHERE delen og brug SET SQL_BIG_SELECTS=1 hvis udtrykket er korrekt"
- nla "Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET SQL_BIG_SELECTS=1 als het stament in orde is."
- eng "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay"
- est "SELECT lause peab läbi vaatama suure hulga kirjeid ja võtaks tõenäoliselt liiga kaua aega. Tasub kontrollida WHERE klauslit ja vajadusel kasutada käsku SET SQL_BIG_SELECTS=1"
- fre "SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vérifiez la clause WHERE et utilisez SET SQL_BIG_SELECTS=1 si SELECT se passe bien"
- ger "Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange dauern. Bitte WHERE-Klausel überprüfen und gegebenenfalls SET SQL_BIG_SELECTS=1 oder SET SQL_MAX_JOIN_SIZE=# verwenden"
- greek "Ôï SELECT èá åîåôÜóåé ìåãÜëï áñéèìü åããñáöþí êáé ðéèáíþò èá êáèõóôåñÞóåé. Ðáñáêáëþ åîåôÜóôå ôéò ðáñáìÝôñïõò ôïõ WHERE êáé ÷ñçóéìïðïéåßóôå SET SQL_BIG_SELECTS=1 áí ôï SELECT åßíáé óùóôü"
- hun "A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET SQL_BIG_SELECTS=1 beallitast, ha a SELECT okay"
- ita "La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET SQL_BIG_SELECTS=1 se e` tutto a posto."
- kor "SELECT ¸í·É¿¡¼­ ³Ê¹« ¸¹Àº ·¹Äڵ带 ã±â ¶§¹®¿¡ ¸¹Àº ½Ã°£ÀÌ ¼Ò¿äµË´Ï´Ù. µû¶ó¼­ WHERE ¹®À» Á¡°ËÇϰųª, ¸¸¾à SELECT°¡ okµÇ¸é SET SQL_BIG_SELECTS=1 ¿É¼ÇÀ» »ç¿ëÇϼ¼¿ä."
- nor "SELECT ville undersøke for mange poster og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt"
- norwegian-ny "SELECT ville undersøkje for mange postar og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt"
- pol "Operacja SELECT bêdzie dotyczy³a zbyt wielu rekordów i prawdopodobnie zajmie bardzo du¿o czasu. Sprawd¥ warunek WHERE i u¿yj SQL_OPTION BIG_SELECTS=1 je?li operacja SELECT jest poprawna"
- por "O SELECT examinaria registros demais e provavelmente levaria muito tempo. Cheque sua cláusula WHERE e use SET SQL_BIG_SELECTS=1, se o SELECT estiver correto"
- rum "SELECT-ul ar examina prea multe cimpuri si probabil ar lua prea mult timp; verifica clauza WHERE si foloseste SET SQL_BIG_SELECTS=1 daca SELECT-ul e okay"
- rus "äÌÑ ÔÁËÏÊ ×ÙÂÏÒËÉ SELECT ÄÏÌÖÅÎ ÂÕÄÅÔ ÐÒÏÓÍÏÔÒÅÔØ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÚÁÐÉÓÅÊ É, ×ÉÄÉÍÏ, ÜÔÏ ÚÁÊÍÅÔ ÏÞÅÎØ ÍÎÏÇÏ ×ÒÅÍÅÎÉ. ðÒÏ×ÅÒØÔÅ ×ÁÛÅ ÕËÁÚÁÎÉÅ WHERE, É, ÅÓÌÉ × ÎÅÍ ×ÓÅ × ÐÏÒÑÄËÅ, ÕËÁÖÉÔÅ SET SQL_BIG_SELECTS=1"
- serbian "Komanda 'SELECT' æe ispitati previše slogova i potrošiti previše vremena. Proverite vaš 'WHERE' filter i upotrebite 'SET OPTION SQL_BIG_SELECTS=1' ako želite baš ovakvu komandu"
- slo "Zadaná po¾iadavka SELECT by prechádzala príli¹ mnoho záznamov a trvala by príli¹ dlho. Skontrolujte tvar WHERE a ak je v poriadku, pou¾ite SET SQL_BIG_SELECTS=1"
- spa "El SELECT puede examinar muchos registros y probablemente con mucho tiempo. Verifique tu WHERE y usa SET SQL_BIG_SELECTS=1 si el SELECT esta correcto"
- swe "Den angivna frågan skulle läsa mer än MAX_JOIN_SIZE rader. Kontrollera din WHERE och använd SET SQL_BIG_SELECTS=1 eller SET MAX_JOIN_SIZE=# ifall du vill hantera stora joins"
- ukr "úÁÐÉÔÕ SELECT ÐÏÔÒ¦ÂÎÏ ÏÂÒÏÂÉÔÉ ÂÁÇÁÔÏ ÚÁÐÉÓ¦×, ÝÏ, ÐÅ×ÎÅ, ÚÁÊÍÅ ÄÕÖÅ ÂÁÇÁÔÏ ÞÁÓÕ. ðÅÒÅצÒÔÅ ×ÁÛÅ WHERE ÔÁ ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ SET SQL_BIG_SELECTS=1, ÑËÝÏ ÃÅÊ ÚÁÐÉÔ SELECT ¤ צÒÎÉÍ"
-ER_UNKNOWN_ERROR
- cze "Nezn-Bámá chyba"
- dan "Ukendt fejl"
- nla "Onbekende Fout"
- eng "Unknown error"
- est "Tundmatu viga"
- fre "Erreur inconnue"
- ger "Unbekannter Fehler"
- greek "ÐñïÝêõøå Üãíùóôï ëÜèïò"
- hun "Ismeretlen hiba"
- ita "Errore sconosciuto"
- kor "¾Ë¼ö ¾ø´Â ¿¡·¯ÀÔ´Ï´Ù."
- nor "Ukjent feil"
- norwegian-ny "Ukjend feil"
- por "Erro desconhecido"
- rum "Eroare unknown"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ÏÛÉÂËÁ"
- serbian "Nepoznata greška"
- slo "Neznámá chyba"
- spa "Error desconocido"
- swe "Oidentifierat fel"
- ukr "îÅצÄÏÍÁ ÐÏÍÉÌËÁ"
-ER_UNKNOWN_PROCEDURE 42000
- cze "Nezn-Bámá procedura %-.192s"
- dan "Ukendt procedure %-.192s"
- nla "Onbekende procedure %-.192s"
- eng "Unknown procedure '%-.192s'"
- est "Tundmatu protseduur '%-.192s'"
- fre "Procédure %-.192s inconnue"
- ger "Unbekannte Prozedur '%-.192s'"
- greek "Áãíùóôç äéáäéêáóßá '%-.192s'"
- hun "Ismeretlen eljaras: '%-.192s'"
- ita "Procedura '%-.192s' sconosciuta"
- kor "¾Ë¼ö ¾ø´Â ¼öÇ๮ : '%-.192s'"
- nor "Ukjent prosedyre %-.192s"
- norwegian-ny "Ukjend prosedyre %-.192s"
- pol "Unkown procedure %-.192s"
- por "'Procedure' '%-.192s' desconhecida"
- rum "Procedura unknown '%-.192s'"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ÐÒÏÃÅÄÕÒÁ '%-.192s'"
- serbian "Nepoznata procedura '%-.192s'"
- slo "Neznámá procedúra '%-.192s'"
- spa "Procedimiento desconocido %-.192s"
- swe "Okänd procedur: %-.192s"
- ukr "îÅצÄÏÍÁ ÐÒÏÃÅÄÕÒÁ '%-.192s'"
-ER_WRONG_PARAMCOUNT_TO_PROCEDURE 42000
- cze "Chybn-Bý poèet parametrù procedury %-.192s"
- dan "Forkert antal parametre til proceduren %-.192s"
- nla "Foutief aantal parameters doorgegeven aan procedure %-.192s"
- eng "Incorrect parameter count to procedure '%-.192s'"
- est "Vale parameetrite hulk protseduurile '%-.192s'"
- fre "Mauvais nombre de paramètres pour la procedure %-.192s"
- ger "Falsche Parameterzahl für Prozedur '%-.192s'"
- greek "ËÜèïò áñéèìüò ðáñáìÝôñùí óôç äéáäéêáóßá '%-.192s'"
- hun "Rossz parameter a(z) '%-.192s'eljaras szamitasanal"
- ita "Numero di parametri errato per la procedura '%-.192s'"
- kor "'%-.192s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆĶó¸ÞÅÍ"
- nor "Feil parameter antall til prosedyren %-.192s"
- norwegian-ny "Feil parameter tal til prosedyra %-.192s"
- pol "Incorrect parameter count to procedure %-.192s"
- por "Número de parâmetros incorreto para a 'procedure' '%-.192s'"
- rum "Procedura '%-.192s' are un numar incorect de parametri"
- rus "îÅËÏÒÒÅËÔÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÐÁÒÁÍÅÔÒÏ× ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.192s'"
- serbian "Pogrešan broj parametara za proceduru '%-.192s'"
- slo "Chybný poèet parametrov procedúry '%-.192s'"
- spa "Equivocado parametro count para procedimiento %-.192s"
- swe "Felaktigt antal parametrar till procedur %-.192s"
- ukr "èÉÂÎÁ ˦ÌØ˦ÓÔØ ÐÁÒÁÍÅÔÒ¦× ÐÒÏÃÅÄÕÒÉ '%-.192s'"
-ER_WRONG_PARAMETERS_TO_PROCEDURE
- cze "Chybn-Bé parametry procedury %-.192s"
- dan "Forkert(e) parametre til proceduren %-.192s"
- nla "Foutieve parameters voor procedure %-.192s"
- eng "Incorrect parameters to procedure '%-.192s'"
- est "Vigased parameetrid protseduurile '%-.192s'"
- fre "Paramètre erroné pour la procedure %-.192s"
- ger "Falsche Parameter für Prozedur '%-.192s'"
- greek "ËÜèïò ðáñÜìåôñïé óôçí äéáäéêáóßá '%-.192s'"
- hun "Rossz parameter a(z) '%-.192s' eljarasban"
- ita "Parametri errati per la procedura '%-.192s'"
- kor "'%-.192s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆĶó¸ÞÅÍ"
- nor "Feil parametre til prosedyren %-.192s"
- norwegian-ny "Feil parameter til prosedyra %-.192s"
- pol "Incorrect parameters to procedure %-.192s"
- por "Parâmetros incorretos para a 'procedure' '%-.192s'"
- rum "Procedura '%-.192s' are parametrii incorecti"
- rus "îÅËÏÒÒÅËÔÎÙÅ ÐÁÒÁÍÅÔÒÙ ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.192s'"
- serbian "Pogrešni parametri prosleðeni proceduri '%-.192s'"
- slo "Chybné parametre procedúry '%-.192s'"
- spa "Equivocados parametros para procedimiento %-.192s"
- swe "Felaktiga parametrar till procedur %-.192s"
- ukr "èÉÂÎÉÊ ÐÁÒÁÍÅÔÅÒ ÐÒÏÃÅÄÕÒÉ '%-.192s'"
-ER_UNKNOWN_TABLE 42S02
- cze "Nezn-Bámá tabulka '%-.192s' v %-.32s"
- dan "Ukendt tabel '%-.192s' i %-.32s"
- nla "Onbekende tabel '%-.192s' in %-.32s"
- eng "Unknown table '%-.192s' in %-.32s"
- est "Tundmatu tabel '%-.192s' %-.32s-s"
- fre "Table inconnue '%-.192s' dans %-.32s"
- ger "Unbekannte Tabelle '%-.192s' in '%-.32s'"
- greek "Áãíùóôïò ðßíáêáò '%-.192s' óå %-.32s"
- hun "Ismeretlen tabla: '%-.192s' %-.32s-ban"
- ita "Tabella '%-.192s' sconosciuta in %-.32s"
- jpn "Unknown table '%-.192s' in %-.32s"
- kor "¾Ë¼ö ¾ø´Â Å×À̺í '%-.192s' (µ¥ÀÌŸº£À̽º %-.32s)"
- nor "Ukjent tabell '%-.192s' i %-.32s"
- norwegian-ny "Ukjend tabell '%-.192s' i %-.32s"
- pol "Unknown table '%-.192s' in %-.32s"
- por "Tabela '%-.192s' desconhecida em '%-.32s'"
- rum "Tabla '%-.192s' invalida in %-.32s"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.192s' × %-.32s"
- serbian "Nepoznata tabela '%-.192s' u '%-.32s'"
- slo "Neznáma tabuµka '%-.192s' v %-.32s"
- spa "Tabla desconocida '%-.192s' in %-.32s"
- swe "Okänd tabell '%-.192s' i '%-.32s'"
- ukr "îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.192s' Õ %-.32s"
-ER_FIELD_SPECIFIED_TWICE 42000
- cze "Polo-B¾ka '%-.192s' je zadána dvakrát"
- dan "Feltet '%-.192s' er anvendt to gange"
- nla "Veld '%-.192s' is dubbel gespecificeerd"
- eng "Column '%-.192s' specified twice"
- est "Tulp '%-.192s' on määratletud topelt"
- fre "Champ '%-.192s' spécifié deux fois"
- ger "Feld '%-.192s' wurde zweimal angegeben"
- greek "Ôï ðåäßï '%-.192s' Ý÷åé ïñéóèåß äýï öïñÝò"
- hun "A(z) '%-.192s' mezot ketszer definialta"
- ita "Campo '%-.192s' specificato 2 volte"
- kor "Ä®·³ '%-.192s'´Â µÎ¹ø Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù."
- nor "Feltet '%-.192s' er spesifisert to ganger"
- norwegian-ny "Feltet '%-.192s' er spesifisert to gangar"
- pol "Field '%-.192s' specified twice"
- por "Coluna '%-.192s' especificada duas vezes"
- rum "Coloana '%-.192s' specificata de doua ori"
- rus "óÔÏÌÂÅà '%-.192s' ÕËÁÚÁÎ Ä×ÁÖÄÙ"
- serbian "Kolona '%-.192s' je navedena dva puta"
- slo "Pole '%-.192s' je zadané dvakrát"
- spa "Campo '%-.192s' especificado dos veces"
- swe "Fält '%-.192s' är redan använt"
- ukr "óÔÏ×ÂÅÃØ '%-.192s' ÚÁÚÎÁÞÅÎÏ Äצަ"
-ER_INVALID_GROUP_FUNC_USE
- cze "Nespr-Bávné pou¾ití funkce group"
- dan "Forkert brug af grupperings-funktion"
- nla "Ongeldig gebruik van GROUP-functie"
- eng "Invalid use of group function"
- est "Vigane grupeerimisfunktsiooni kasutus"
- fre "Utilisation invalide de la clause GROUP"
- ger "Falsche Verwendung einer Gruppierungsfunktion"
- greek "ÅóöáëìÝíç ÷ñÞóç ôçò group function"
- hun "A group funkcio ervenytelen hasznalata"
- ita "Uso non valido di una funzione di raggruppamento"
- kor "À߸øµÈ ±×·ì ÇÔ¼ö¸¦ »ç¿ëÇÏ¿´½À´Ï´Ù."
- por "Uso inválido de função de agrupamento (GROUP)"
- rum "Folosire incorecta a functiei group"
- rus "îÅÐÒÁ×ÉÌØÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÇÒÕÐÐÏ×ÙÈ ÆÕÎËÃÉÊ"
- serbian "Pogrešna upotreba 'GROUP' funkcije"
- slo "Nesprávne pou¾itie funkcie GROUP"
- spa "Invalido uso de función en grupo"
- swe "Felaktig användning av SQL grupp function"
- ukr "èÉÂÎÅ ×ÉËÏÒÉÓÔÁÎÎÑ ÆÕÎËæ§ ÇÒÕÐÕ×ÁÎÎÑ"
-ER_UNSUPPORTED_EXTENSION 42000
- cze "Tabulka '%-.192s' pou-B¾ívá roz¹íøení, které v této verzi MySQL není"
- dan "Tabellen '%-.192s' bruger et filtypenavn som ikke findes i denne MySQL version"
- nla "Tabel '%-.192s' gebruikt een extensie, die niet in deze MySQL-versie voorkomt."
- eng "Table '%-.192s' uses an extension that doesn't exist in this MySQL version"
- est "Tabel '%-.192s' kasutab laiendust, mis ei eksisteeri antud MySQL versioonis"
- fre "Table '%-.192s' : utilise une extension invalide pour cette version de MySQL"
- ger "Tabelle '%-.192s' verwendet eine Erweiterung, die in dieser MySQL-Version nicht verfügbar ist"
- greek "Ï ðßíáêò '%-.192s' ÷ñçóéìïðïéåß êÜðïéï extension ðïõ äåí õðÜñ÷åé óôçí Ýêäïóç áõôÞ ôçò MySQL"
- hun "A(z) '%-.192s' tabla olyan bovitest hasznal, amely nem letezik ebben a MySQL versioban."
- ita "La tabella '%-.192s' usa un'estensione che non esiste in questa versione di MySQL"
- kor "Å×À̺í '%-.192s'´Â È®Àå¸í·ÉÀ» ÀÌ¿ëÇÏÁö¸¸ ÇöÀçÀÇ MySQL ¹öÁ¯¿¡¼­´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
- nor "Table '%-.192s' uses a extension that doesn't exist in this MySQL version"
- norwegian-ny "Table '%-.192s' uses a extension that doesn't exist in this MySQL version"
- pol "Table '%-.192s' uses a extension that doesn't exist in this MySQL version"
- por "Tabela '%-.192s' usa uma extensão que não existe nesta versão do MySQL"
- rum "Tabela '%-.192s' foloseste o extensire inexistenta in versiunea curenta de MySQL"
- rus "÷ ÔÁÂÌÉÃÅ '%-.192s' ÉÓÐÏÌØÚÕÀÔÓÑ ×ÏÚÍÏÖÎÏÓÔÉ, ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÍÙÅ × ÜÔÏÊ ×ÅÒÓÉÉ MySQL"
- serbian "Tabela '%-.192s' koristi ekstenziju koje ne postoji u ovoj verziji MySQL-a"
- slo "Tabuµka '%-.192s' pou¾íva roz¹írenie, ktoré v tejto verzii MySQL nie je"
- spa "Tabla '%-.192s' usa una extensión que no existe en esta MySQL versión"
- swe "Tabell '%-.192s' har en extension som inte finns i denna version av MySQL"
- ukr "ôÁÂÌÉÃÑ '%-.192s' ×ÉËÏÒÉÓÔÏ×Õ¤ ÒÏÚÛÉÒÅÎÎÑ, ÝÏ ÎÅ ¦ÓÎÕ¤ Õ Ã¦Ê ×ÅÒÓ¦§ MySQL"
-ER_TABLE_MUST_HAVE_COLUMNS 42000
- cze "Tabulka mus-Bí mít alespoò jeden sloupec"
- dan "En tabel skal have mindst een kolonne"
- nla "Een tabel moet minstens 1 kolom bevatten"
- eng "A table must have at least 1 column"
- jps "ƒe[ƒuƒ‹‚ÍÅ’á 1 ŒÂ‚Ì column ‚ª•K—v‚Å‚·",
- est "Tabelis peab olema vähemalt üks tulp"
- fre "Une table doit comporter au moins une colonne"
- ger "Eine Tabelle muss mindestens eine Spalte besitzen"
- greek "Åíáò ðßíáêáò ðñÝðåé íá Ý÷åé ôïõëÜ÷éóôïí Ýíá ðåäßï"
- hun "A tablanak legalabb egy oszlopot tartalmazni kell"
- ita "Una tabella deve avere almeno 1 colonna"
- jpn "¥Æ¡¼¥Ö¥ë¤ÏºÇÄã 1 ¸Ä¤Î column ¤¬É¬ÍפǤ¹"
- kor "ÇϳªÀÇ Å×ÀÌºí¿¡¼­´Â Àû¾îµµ ÇϳªÀÇ Ä®·³ÀÌ Á¸ÀçÇÏ¿©¾ß ÇÕ´Ï´Ù."
- por "Uma tabela tem que ter pelo menos uma (1) coluna"
- rum "O tabela trebuie sa aiba cel putin o coloana"
- rus "÷ ÔÁÂÌÉÃÅ ÄÏÌÖÅÎ ÂÙÔØ ËÁË ÍÉÎÉÍÕÍ ÏÄÉÎ ÓÔÏÌÂÅÃ"
- serbian "Tabela mora imati najmanje jednu kolonu"
- slo "Tabuµka musí ma» aspoò 1 pole"
- spa "Una tabla debe tener al menos 1 columna"
- swe "Tabeller måste ha minst 1 kolumn"
- ukr "ôÁÂÌÉÃÑ ÐÏ×ÉÎÎÁ ÍÁÔÉ ÈÏÞÁ ÏÄÉÎ ÓÔÏ×ÂÅÃØ"
-ER_RECORD_FILE_FULL
- cze "Tabulka '%-.192s' je pln-Bá"
- dan "Tabellen '%-.192s' er fuld"
- nla "De tabel '%-.192s' is vol"
- eng "The table '%-.192s' is full"
- jps "table '%-.192s' ‚Í‚¢‚Á‚Ï‚¢‚Å‚·",
- est "Tabel '%-.192s' on täis"
- fre "La table '%-.192s' est pleine"
- ger "Tabelle '%-.192s' ist voll"
- greek "Ï ðßíáêáò '%-.192s' åßíáé ãåìÜôïò"
- hun "A '%-.192s' tabla megtelt"
- ita "La tabella '%-.192s' e` piena"
- jpn "table '%-.192s' ¤Ï¤¤¤Ã¤Ñ¤¤¤Ç¤¹"
- kor "Å×À̺í '%-.192s'°¡ full³µ½À´Ï´Ù. "
- por "Tabela '%-.192s' está cheia"
- rum "Tabela '%-.192s' e plina"
- rus "ôÁÂÌÉÃÁ '%-.192s' ÐÅÒÅÐÏÌÎÅÎÁ"
- serbian "Tabela '%-.192s' je popunjena do kraja"
- slo "Tabuµka '%-.192s' je plná"
- spa "La tabla '%-.192s' está llena"
- swe "Tabellen '%-.192s' är full"
- ukr "ôÁÂÌÉÃÑ '%-.192s' ÚÁÐÏ×ÎÅÎÁ"
-ER_UNKNOWN_CHARACTER_SET 42000
- cze "Nezn-Bámá znaková sada: '%-.64s'"
- dan "Ukendt tegnsæt: '%-.64s'"
- nla "Onbekende character set: '%-.64s'"
- eng "Unknown character set: '%-.64s'"
- jps "character set '%-.64s' ‚̓Tƒ|[ƒg‚µ‚Ä‚¢‚Ü‚¹‚ñ",
- est "Vigane kooditabel '%-.64s'"
- fre "Jeu de caractères inconnu: '%-.64s'"
- ger "Unbekannter Zeichensatz: '%-.64s'"
- greek "Áãíùóôï character set: '%-.64s'"
- hun "Ervenytelen karakterkeszlet: '%-.64s'"
- ita "Set di caratteri '%-.64s' sconosciuto"
- jpn "character set '%-.64s' ¤Ï¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Þ¤»¤ó"
- kor "¾Ë¼ö¾ø´Â ¾ð¾î Set: '%-.64s'"
- por "Conjunto de caracteres '%-.64s' desconhecido"
- rum "Set de caractere invalid: '%-.64s'"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ËÏÄÉÒÏ×ËÁ '%-.64s'"
- serbian "Nepoznati karakter-set: '%-.64s'"
- slo "Neznáma znaková sada: '%-.64s'"
- spa "Juego de caracteres desconocido: '%-.64s'"
- swe "Okänd teckenuppsättning: '%-.64s'"
- ukr "îÅצÄÏÍÁ ËÏÄÏ×Á ÔÁÂÌÉÃÑ: '%-.64s'"
-ER_TOO_MANY_TABLES
- cze "P-Bøíli¹ mnoho tabulek, MySQL jich mù¾e mít v joinu jen %d"
- dan "For mange tabeller. MySQL kan kun bruge %d tabeller i et join"
- nla "Teveel tabellen. MySQL kan slechts %d tabellen in een join bevatten"
- eng "Too many tables; MySQL can only use %d tables in a join"
- jps "ƒe[ƒuƒ‹‚ª‘½‚·‚¬‚Ü‚·; MySQL can only use %d tables in a join",
- est "Liiga palju tabeleid. MySQL suudab JOINiga ühendada kuni %d tabelit"
- fre "Trop de tables. MySQL ne peut utiliser que %d tables dans un JOIN"
- ger "Zu viele Tabellen. MySQL kann in einem Join maximal %d Tabellen verwenden"
- greek "Ðïëý ìåãÜëïò áñéèìüò ðéíÜêùí. Ç MySQL ìðïñåß íá ÷ñçóéìïðïéÞóåé %d ðßíáêåò óå äéáäéêáóßá join"
- hun "Tul sok tabla. A MySQL csak %d tablat tud kezelni osszefuzeskor"
- ita "Troppe tabelle. MySQL puo` usare solo %d tabelle in una join"
- jpn "¥Æ¡¼¥Ö¥ë¤¬Â¿¤¹¤®¤Þ¤¹; MySQL can only use %d tables in a join"
- kor "³Ê¹« ¸¹Àº Å×À̺íÀÌ JoinµÇ¾ú½À´Ï´Ù. MySQL¿¡¼­´Â JOIN½Ã %d°³ÀÇ Å×ÀÌºí¸¸ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù."
- por "Tabelas demais. O MySQL pode usar somente %d tabelas em uma junção (JOIN)"
- rum "Prea multe tabele. MySQL nu poate folosi mai mult de %d tabele intr-un join"
- rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÔÁÂÌÉÃ. MySQL ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÔÏÌØËÏ %d ÔÁÂÌÉÃ × ÓÏÅÄÉÎÅÎÉÉ"
- serbian "Previše tabela. MySQL može upotrebiti maksimum %d tabela pri 'JOIN' operaciji"
- slo "Príli¹ mnoho tabuliek. MySQL mô¾e pou¾i» len %d v JOIN-e"
- spa "Muchas tablas. MySQL solamente puede usar %d tablas en un join"
- swe "För många tabeller. MySQL can ha högst %d tabeller i en och samma join"
- ukr "úÁÂÁÇÁÔÏ ÔÁÂÌÉÃØ. MySQL ÍÏÖÅ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÌÉÛÅ %d ÔÁÂÌÉÃØ Õ ÏÂ'¤ÄÎÁÎΦ"
-ER_TOO_MANY_FIELDS
- cze "P-Bøíli¹ mnoho polo¾ek"
- dan "For mange felter"
- nla "Te veel velden"
- eng "Too many columns"
- jps "column ‚ª‘½‚·‚¬‚Ü‚·",
- est "Liiga palju tulpasid"
- fre "Trop de champs"
- ger "Zu viele Felder"
- greek "Ðïëý ìåãÜëïò áñéèìüò ðåäßùí"
- hun "Tul sok mezo"
- ita "Troppi campi"
- jpn "column ¤¬Â¿¤¹¤®¤Þ¤¹"
- kor "Ä®·³ÀÌ ³Ê¹« ¸¹½À´Ï´Ù."
- por "Colunas demais"
- rum "Prea multe coloane"
- rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÓÔÏÌÂÃÏ×"
- serbian "Previše kolona"
- slo "Príli¹ mnoho polí"
- spa "Muchos campos"
- swe "För många fält"
- ukr "úÁÂÁÇÁÔÏ ÓÔÏ×Âæ×"
-ER_TOO_BIG_ROWSIZE 42000
- cze "-BØádek je pøíli¹ velký. Maximální velikost øádku, nepoèítaje polo¾ky blob, je %ld. Musíte zmìnit nìkteré polo¾ky na blob"
- dan "For store poster. Max post størrelse, uden BLOB's, er %ld. Du må lave nogle felter til BLOB's"
- nla "Rij-grootte is groter dan toegestaan. Maximale rij grootte, blobs niet meegeteld, is %ld. U dient sommige velden in blobs te veranderen."
- eng "Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some columns to TEXT or BLOBs"
- jps "row size ‚ª‘å‚«‚·‚¬‚Ü‚·. BLOB ‚ðŠÜ‚Ü‚È‚¢ê‡‚Ì row size ‚ÌÅ‘å‚Í %ld ‚Å‚·. ‚¢‚­‚‚©‚Ì field ‚ð BLOB ‚É•Ï‚¦‚Ä‚­‚¾‚³‚¢.",
- est "Liiga pikk kirje. Kirje maksimumpikkus arvestamata BLOB-tüüpi välju on %ld. Muuda mõned väljad BLOB-tüüpi väljadeks"
- fre "Ligne trop grande. Le taille maximale d'une ligne, sauf les BLOBs, est %ld. Changez le type de quelques colonnes en BLOB"
- ger "Zeilenlänge zu groß. Die maximale Zeilenlänge für den verwendeten Tabellentyp (ohne BLOB-Felder) beträgt %ld. Einige Felder müssen in BLOB oder TEXT umgewandelt werden"
- greek "Ðïëý ìåãÜëï ìÝãåèïò åããñáöÞò. Ôï ìÝãéóôï ìÝãåèïò åããñáöÞò, ÷ùñßò íá õðïëïãßæïíôáé ôá blobs, åßíáé %ld. ÐñÝðåé íá ïñßóåôå êÜðïéá ðåäßá óáí blobs"
- hun "Tul nagy sormeret. A maximalis sormeret (nem szamolva a blob objektumokat) %ld. Nehany mezot meg kell valtoztatnia"
- ita "Riga troppo grande. La massima grandezza di una riga, non contando i BLOB, e` %ld. Devi cambiare alcuni campi in BLOB"
- jpn "row size ¤¬Â礭¤¹¤®¤Þ¤¹. BLOB ¤ò´Þ¤Þ¤Ê¤¤¾ì¹ç¤Î row size ¤ÎºÇÂç¤Ï %ld ¤Ç¤¹. ¤¤¤¯¤Ä¤«¤Î field ¤ò BLOB ¤ËÊѤ¨¤Æ¤¯¤À¤µ¤¤."
- kor "³Ê¹« Å« row »çÀÌÁîÀÔ´Ï´Ù. BLOB¸¦ °è»êÇÏÁö ¾Ê°í ÃÖ´ë row »çÀÌÁî´Â %ldÀÔ´Ï´Ù. ¾ó¸¶°£ÀÇ ÇʵåµéÀ» BLOB·Î ¹Ù²Ù¼Å¾ß °Ú±º¿ä.."
- por "Tamanho de linha grande demais. O máximo tamanho de linha, não contando BLOBs, é %ld. Você tem que mudar alguns campos para BLOBs"
- rum "Marimea liniei (row) prea mare. Marimea maxima a liniei, excluzind BLOB-urile este de %ld. Trebuie sa schimbati unele cimpuri in BLOB-uri"
- rus "óÌÉÛËÏÍ ÂÏÌØÛÏÊ ÒÁÚÍÅÒ ÚÁÐÉÓÉ. íÁËÓÉÍÁÌØÎÙÊ ÒÁÚÍÅÒ ÓÔÒÏËÉ, ÉÓËÌÀÞÁÑ ÐÏÌÑ BLOB, - %ld. ÷ÏÚÍÏÖÎÏ, ×ÁÍ ÓÌÅÄÕÅÔ ÉÚÍÅÎÉÔØ ÔÉÐ ÎÅËÏÔÏÒÙÈ ÐÏÌÅÊ ÎÁ BLOB"
- serbian "Prevelik slog. Maksimalna velièina sloga, ne raèunajuæi BLOB polja, je %ld. Trebali bi da promenite tip nekih polja u BLOB"
- slo "Riadok je príli¹ veµký. Maximálna veµkos» riadku, okrem 'BLOB', je %ld. Musíte zmeni» niektoré polo¾ky na BLOB"
- spa "Tamaño de línea muy grande. Máximo tamaño de línea, no contando blob, es %ld. Tu tienes que cambiar algunos campos para blob"
- swe "För stor total radlängd. Den högst tillåtna radlängden, förutom BLOBs, är %ld. Ändra några av dina fält till BLOB"
- ukr "úÁÄÏ×ÇÁ ÓÔÒÏËÁ. îÁʦÌØÛÏÀ ÄÏ×ÖÉÎÏÀ ÓÔÒÏËÉ, ÎÅ ÒÁÈÕÀÞÉ BLOB, ¤ %ld. ÷ÁÍ ÐÏÔÒ¦ÂÎÏ ÐÒÉ×ÅÓÔÉ ÄÅÑ˦ ÓÔÏ×Âæ ÄÏ ÔÉÐÕ BLOB"
-ER_STACK_OVERRUN
- cze "P-Bøeteèení zásobníku threadu: pou¾ito %ld z %ld. Pou¾ijte 'mysqld -O thread_stack=#' k zadání vìt¹ího zásobníku"
- dan "Thread stack brugt: Brugt: %ld af en %ld stak. Brug 'mysqld -O thread_stack=#' for at allokere en større stak om nødvendigt"
- nla "Thread stapel overrun: Gebruikte: %ld van een %ld stack. Gebruik 'mysqld -O thread_stack=#' om een grotere stapel te definieren (indien noodzakelijk)."
- eng "Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed"
- jps "Thread stack overrun: Used: %ld of a %ld stack. ƒXƒ^ƒbƒN—̈æ‚𑽂­‚Ƃ肽‚¢ê‡A'mysqld -O thread_stack=#' ‚ÆŽw’肵‚Ä‚­‚¾‚³‚¢",
- fre "Débordement de la pile des tâches (Thread stack). Utilisées: %ld pour une pile de %ld. Essayez 'mysqld -O thread_stack=#' pour indiquer une plus grande valeur"
- ger "Thread-Stack-Überlauf. Benutzt: %ld von %ld Stack. 'mysqld -O thread_stack=#' verwenden, um bei Bedarf einen größeren Stack anzulegen"
- greek "Stack overrun óôï thread: Used: %ld of a %ld stack. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå 'mysqld -O thread_stack=#' ãéá íá ïñßóåôå Ýíá ìåãáëýôåñï stack áí ÷ñåéÜæåôáé"
- hun "Thread verem tullepes: Used: %ld of a %ld stack. Hasznalja a 'mysqld -O thread_stack=#' nagyobb verem definialasahoz"
- ita "Thread stack overrun: Usati: %ld di uno stack di %ld. Usa 'mysqld -O thread_stack=#' per specificare uno stack piu` grande."
- jpn "Thread stack overrun: Used: %ld of a %ld stack. ¥¹¥¿¥Ã¥¯Îΰè¤ò¿¤¯¤È¤ê¤¿¤¤¾ì¹ç¡¢'mysqld -O thread_stack=#' ¤È»ØÄꤷ¤Æ¤¯¤À¤µ¤¤"
- kor "¾²·¹µå ½ºÅÃÀÌ ³ÑÃƽÀ´Ï´Ù. »ç¿ë: %ld°³ ½ºÅÃ: %ld°³. ¸¸¾à ÇÊ¿ä½Ã ´õÅ« ½ºÅÃÀ» ¿øÇÒ¶§¿¡´Â 'mysqld -O thread_stack=#' ¸¦ Á¤ÀÇÇϼ¼¿ä"
- por "Estouro da pilha do 'thread'. Usados %ld de uma pilha de %ld. Use 'mysqld -O thread_stack=#' para especificar uma pilha maior, se necessário"
- rum "Stack-ul thread-ului a fost depasit (prea mic): Folositi: %ld intr-un stack de %ld. Folositi 'mysqld -O thread_stack=#' ca sa specifici un stack mai mare"
- rus "óÔÅË ÐÏÔÏËÏ× ÐÅÒÅÐÏÌÎÅÎ: ÉÓÐÏÌØÚÏ×ÁÎÏ: %ld ÉÚ %ld ÓÔÅËÁ. ðÒÉÍÅÎÑÊÔÅ 'mysqld -O thread_stack=#' ÄÌÑ ÕËÁÚÁÎÉÑ ÂÏÌØÛÅÇÏ ÒÁÚÍÅÒÁ ÓÔÅËÁ, ÅÓÌÉ ÎÅÏÂÈÏÄÉÍÏ"
- serbian "Prepisivanje thread stack-a: Upotrebljeno: %ld od %ld stack memorije. Upotrebite 'mysqld -O thread_stack=#' da navedete veæi stack ako je potrebno"
- slo "Preteèenie zásobníku vlákna: pou¾ité: %ld z %ld. Pou¾ite 'mysqld -O thread_stack=#' k zadaniu väè¹ieho zásobníka"
- spa "Sobrecarga de la pila de thread: Usada: %ld de una %ld pila. Use 'mysqld -O thread_stack=#' para especificar una mayor pila si necesario"
- swe "Trådstacken tog slut: Har använt %ld av %ld bytes. Använd 'mysqld -O thread_stack=#' ifall du behöver en större stack"
- ukr "óÔÅË Ç¦ÌÏË ÐÅÒÅÐÏ×ÎÅÎÏ: ÷ÉËÏÒÉÓÔÁÎÏ: %ld Ú %ld. ÷ÉËÏÒÉÓÔÏ×ÕÊÔÅ 'mysqld -O thread_stack=#' ÁÂÉ ÚÁÚÎÁÞÉÔÉ Â¦ÌØÛÉÊ ÓÔÅË, ÑËÝÏ ÎÅÏÂȦÄÎÏ"
-ER_WRONG_OUTER_JOIN 42000
- cze "V OUTER JOIN byl nalezen k-Bøí¾ový odkaz. Provìøte ON podmínky"
- dan "Krydsreferencer fundet i OUTER JOIN; check dine ON conditions"
- nla "Gekruiste afhankelijkheid gevonden in OUTER JOIN. Controleer uw ON-conditions"
- eng "Cross dependency found in OUTER JOIN; examine your ON conditions"
- est "Ristsõltuvus OUTER JOIN klauslis. Kontrolli oma ON tingimusi"
- fre "Dépendance croisée dans une clause OUTER JOIN. Vérifiez la condition ON"
- ger "OUTER JOIN enthält fehlerhafte Abhängigkeiten. In ON verwendete Bedingungen überprüfen"
- greek "Cross dependency âñÝèçêå óå OUTER JOIN. Ðáñáêáëþ åîåôÜóôå ôéò óõíèÞêåò ðïõ èÝóáôå óôï ON"
- hun "Keresztfuggoseg van az OUTER JOIN-ban. Ellenorizze az ON felteteleket"
- ita "Trovata una dipendenza incrociata nella OUTER JOIN. Controlla le condizioni ON"
- por "Dependência cruzada encontrada em junção externa (OUTER JOIN); examine as condições utilizadas nas cláusulas 'ON'"
- rum "Dependinta incrucisata (cross dependency) gasita in OUTER JOIN. Examinati conditiile ON"
- rus "÷ OUTER JOIN ÏÂÎÁÒÕÖÅÎÁ ÐÅÒÅËÒÅÓÔÎÁÑ ÚÁ×ÉÓÉÍÏÓÔØ. ÷ÎÉÍÁÔÅÌØÎÏ ÐÒÏÁÎÁÌÉÚÉÒÕÊÔÅ Ó×ÏÉ ÕÓÌÏ×ÉÑ ON"
- serbian "Unakrsna zavisnost pronaðena u komandi 'OUTER JOIN'. Istražite vaše 'ON' uslove"
- slo "V OUTER JOIN bol nájdený krí¾ový odkaz. Skontrolujte podmienky ON"
- spa "Dependencia cruzada encontrada en OUTER JOIN. Examine su condición ON"
- swe "Felaktigt referens i OUTER JOIN. Kontrollera ON-uttrycket"
- ukr "ðÅÒÅÈÒÅÓÎÁ ÚÁÌÅÖΦÓÔØ Õ OUTER JOIN. ðÅÒÅצÒÔÅ ÕÍÏ×Õ ON"
-ER_NULL_COLUMN_IN_INDEX 42000
- eng "Table handler doesn't support NULL in given index. Please change column '%-.192s' to be NOT NULL or use another handler"
- swe "Tabell hanteraren kan inte indexera NULL kolumner för den givna index typen. Ändra '%-.192s' till NOT NULL eller använd en annan hanterare"
-ER_CANT_FIND_UDF
- cze "Nemohu na-Bèíst funkci '%-.192s'"
- dan "Kan ikke læse funktionen '%-.192s'"
- nla "Kan functie '%-.192s' niet laden"
- eng "Can't load function '%-.192s'"
- jps "function '%-.192s' ‚ð ƒ[ƒh‚Å‚«‚Ü‚¹‚ñ",
- est "Ei suuda avada funktsiooni '%-.192s'"
- fre "Imposible de charger la fonction '%-.192s'"
- ger "Kann Funktion '%-.192s' nicht laden"
- greek "Äåí åßíáé äõíáôÞ ç äéáäéêáóßá load ãéá ôç óõíÜñôçóç '%-.192s'"
- hun "A(z) '%-.192s' fuggveny nem toltheto be"
- ita "Impossibile caricare la funzione '%-.192s'"
- jpn "function '%-.192s' ¤ò ¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó"
- kor "'%-.192s' ÇÔ¼ö¸¦ ·ÎµåÇÏÁö ¸øÇß½À´Ï´Ù."
- por "Não pode carregar a função '%-.192s'"
- rum "Nu pot incarca functia '%-.192s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÇÒÕÚÉÔØ ÆÕÎËÃÉÀ '%-.192s'"
- serbian "Ne mogu da uèitam funkciju '%-.192s'"
- slo "Nemô¾em naèíta» funkciu '%-.192s'"
- spa "No puedo cargar función '%-.192s'"
- swe "Kan inte ladda funktionen '%-.192s'"
- ukr "îÅ ÍÏÖÕ ÚÁ×ÁÎÔÁÖÉÔÉ ÆÕÎËæÀ '%-.192s'"
-ER_CANT_INITIALIZE_UDF
- cze "Nemohu inicializovat funkci '%-.192s'; %-.80s"
- dan "Kan ikke starte funktionen '%-.192s'; %-.80s"
- nla "Kan functie '%-.192s' niet initialiseren; %-.80s"
- eng "Can't initialize function '%-.192s'; %-.80s"
- jps "function '%-.192s' ‚ð‰Šú‰»‚Å‚«‚Ü‚¹‚ñ; %-.80s",
- est "Ei suuda algväärtustada funktsiooni '%-.192s'; %-.80s"
- fre "Impossible d'initialiser la fonction '%-.192s'; %-.80s"
- ger "Kann Funktion '%-.192s' nicht initialisieren: %-.80s"
- greek "Äåí åßíáé äõíáôÞ ç Ýíáñîç ôçò óõíÜñôçóçò '%-.192s'; %-.80s"
- hun "A(z) '%-.192s' fuggveny nem inicializalhato; %-.80s"
- ita "Impossibile inizializzare la funzione '%-.192s'; %-.80s"
- jpn "function '%-.192s' ¤ò½é´ü²½¤Ç¤­¤Þ¤»¤ó; %-.80s"
- kor "'%-.192s' ÇÔ¼ö¸¦ ÃʱâÈ­ ÇÏÁö ¸øÇß½À´Ï´Ù.; %-.80s"
- por "Não pode inicializar a função '%-.192s' - '%-.80s'"
- rum "Nu pot initializa functia '%-.192s'; %-.80s"
- rus "îÅ×ÏÚÍÏÖÎÏ ÉÎÉÃÉÁÌÉÚÉÒÏ×ÁÔØ ÆÕÎËÃÉÀ '%-.192s'; %-.80s"
- serbian "Ne mogu da inicijalizujem funkciju '%-.192s'; %-.80s"
- slo "Nemô¾em inicializova» funkciu '%-.192s'; %-.80s"
- spa "No puedo inicializar función '%-.192s'; %-.80s"
- swe "Kan inte initialisera funktionen '%-.192s'; '%-.80s'"
- ukr "îÅ ÍÏÖÕ ¦Î¦Ã¦Á̦ÚÕ×ÁÔÉ ÆÕÎËæÀ '%-.192s'; %-.80s"
-ER_UDF_NO_PATHS
- cze "Pro sd-Bílenou knihovnu nejsou povoleny cesty"
- dan "Angivelse af sti ikke tilladt for delt bibliotek"
- nla "Geen pad toegestaan voor shared library"
- eng "No paths allowed for shared library"
- jps "shared library ‚ւ̃pƒX‚ª’Ê‚Á‚Ä‚¢‚Ü‚¹‚ñ",
- est "Teegi nimes ei tohi olla kataloogi"
- fre "Chemin interdit pour les bibliothèques partagées"
- ger "Keine Pfade gestattet für Shared Library"
- greek "Äåí âñÝèçêáí paths ãéá ôçí shared library"
- hun "Nincs ut a megosztott konyvtarakhoz (shared library)"
- ita "Non sono ammessi path per le librerie condivisa"
- jpn "shared library ¤Ø¤Î¥Ñ¥¹¤¬Ä̤äƤ¤¤Þ¤»¤ó"
- kor "°øÀ¯ ¶óÀ̹ö·¯¸®¸¦ À§ÇÑ Æнº°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù."
- por "Não há caminhos (paths) permitidos para biblioteca compartilhada"
- rum "Nici un paths nu e permis pentru o librarie shared"
- rus "îÅÄÏÐÕÓÔÉÍÏ ÕËÁÚÙ×ÁÔØ ÐÕÔÉ ÄÌÑ ÄÉÎÁÍÉÞÅÓËÉÈ ÂÉÂÌÉÏÔÅË"
- serbian "Ne postoje dozvoljene putanje do share-ovane biblioteke"
- slo "Neprípustné ¾iadne cesty k zdieµanej kni¾nici"
- spa "No pasos permitidos para librarias conjugadas"
- swe "Man får inte ange sökväg för dynamiska bibliotek"
- ukr "îÅ ÄÏÚ×ÏÌÅÎÏ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÐÕÔ¦ ÄÌÑ ÒÏÚĦÌÀ×ÁÎÉÈ Â¦Â̦ÏÔÅË"
-ER_UDF_EXISTS
- cze "Funkce '%-.192s' ji-B¾ existuje"
- dan "Funktionen '%-.192s' findes allerede"
- nla "Functie '%-.192s' bestaat reeds"
- eng "Function '%-.192s' already exists"
- jps "Function '%-.192s' ‚ÍŠù‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚·",
- est "Funktsioon '%-.192s' juba eksisteerib"
- fre "La fonction '%-.192s' existe déjà"
- ger "Funktion '%-.192s' existiert schon"
- greek "Ç óõíÜñôçóç '%-.192s' õðÜñ÷åé Þäç"
- hun "A '%-.192s' fuggveny mar letezik"
- ita "La funzione '%-.192s' esiste gia`"
- jpn "Function '%-.192s' ¤Ï´û¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤¹"
- kor "'%-.192s' ÇÔ¼ö´Â ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù."
- por "Função '%-.192s' já existe"
- rum "Functia '%-.192s' exista deja"
- rus "æÕÎËÃÉÑ '%-.192s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Funkcija '%-.192s' veæ postoji"
- slo "Funkcia '%-.192s' u¾ existuje"
- spa "Función '%-.192s' ya existe"
- swe "Funktionen '%-.192s' finns redan"
- ukr "æÕÎËÃ¦Ñ '%-.192s' ×ÖÅ ¦ÓÎÕ¤"
-ER_CANT_OPEN_LIBRARY
- cze "Nemohu otev-Bøít sdílenou knihovnu '%-.192s' (errno: %d %-.128s)"
- dan "Kan ikke åbne delt bibliotek '%-.192s' (errno: %d %-.128s)"
- nla "Kan shared library '%-.192s' niet openen (Errcode: %d %-.128s)"
- eng "Can't open shared library '%-.192s' (errno: %d %-.128s)"
- jps "shared library '%-.192s' ‚ðŠJ‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d %-.128s)",
- est "Ei suuda avada jagatud teeki '%-.192s' (veakood: %d %-.128s)"
- fre "Impossible d'ouvrir la bibliothèque partagée '%-.192s' (errno: %d %-.128s)"
- ger "Kann Shared Library '%-.192s' nicht öffnen (Fehler: %d %-.128s)"
- greek "Äåí åßíáé äõíáôÞ ç áíÜãíùóç ôçò shared library '%-.192s' (êùäéêüò ëÜèïõò: %d %-.128s)"
- hun "A(z) '%-.192s' megosztott konyvtar nem hasznalhato (hibakod: %d %-.128s)"
- ita "Impossibile aprire la libreria condivisa '%-.192s' (errno: %d %-.128s)"
- jpn "shared library '%-.192s' ¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d %-.128s)"
- kor "'%-.192s' °øÀ¯ ¶óÀ̹ö·¯¸®¸¦ ¿­¼ö ¾ø½À´Ï´Ù.(¿¡·¯¹øÈ£: %d %-.128s)"
- nor "Can't open shared library '%-.192s' (errno: %d %-.128s)"
- norwegian-ny "Can't open shared library '%-.192s' (errno: %d %-.128s)"
- pol "Can't open shared library '%-.192s' (errno: %d %-.128s)"
- por "Não pode abrir biblioteca compartilhada '%-.192s' (erro no. %d '%-.128s')"
- rum "Nu pot deschide libraria shared '%-.192s' (Eroare: %d %-.128s)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÄÉÎÁÍÉÞÅÓËÕÀ ÂÉÂÌÉÏÔÅËÕ '%-.192s' (ÏÛÉÂËÁ: %d %-.128s)"
- serbian "Ne mogu da otvorim share-ovanu biblioteku '%-.192s' (errno: %d %-.128s)"
- slo "Nemô¾em otvori» zdieµanú kni¾nicu '%-.192s' (chybový kód: %d %-.128s)"
- spa "No puedo abrir libraria conjugada '%-.192s' (errno: %d %-.128s)"
- swe "Kan inte öppna det dynamiska biblioteket '%-.192s' (Felkod: %d %-.128s)"
- ukr "îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÒÏÚĦÌÀ×ÁÎÕ Â¦Â̦ÏÔÅËÕ '%-.192s' (ÐÏÍÉÌËÁ: %d %-.128s)"
-ER_CANT_FIND_DL_ENTRY
- cze "Nemohu naj-Bít funkci '%-.128s' v knihovnì"
- dan "Kan ikke finde funktionen '%-.128s' i bibliotek"
- nla "Kan functie '%-.128s' niet in library vinden"
- eng "Can't find symbol '%-.128s' in library"
- jps "function '%-.128s' ‚ðƒ‰ƒCƒuƒ‰ƒŠ[’†‚ÉŒ©•t‚¯‚鎖‚ª‚Å‚«‚Ü‚¹‚ñ",
- est "Ei leia funktsiooni '%-.128s' antud teegis"
- fre "Impossible de trouver la fonction '%-.128s' dans la bibliothèque"
- ger "Kann Funktion '%-.128s' in der Library nicht finden"
- greek "Äåí åßíáé äõíáôÞ ç áíåýñåóç ôçò óõíÜñôçóçò '%-.128s' óôçí âéâëéïèÞêç"
- hun "A(z) '%-.128s' fuggveny nem talalhato a konyvtarban"
- ita "Impossibile trovare la funzione '%-.128s' nella libreria"
- jpn "function '%-.128s' ¤ò¥é¥¤¥Ö¥é¥ê¡¼Ãæ¤Ë¸«ÉÕ¤±¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó"
- kor "¶óÀ̹ö·¯¸®¿¡¼­ '%-.128s' ÇÔ¼ö¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù."
- por "Não pode encontrar a função '%-.128s' na biblioteca"
- rum "Nu pot gasi functia '%-.128s' in libraria"
- rus "îÅ×ÏÚÍÏÖÎÏ ÏÔÙÓËÁÔØ ÓÉÍ×ÏÌ '%-.128s' × ÂÉÂÌÉÏÔÅËÅ"
- serbian "Ne mogu da pronadjem funkciju '%-.128s' u biblioteci"
- slo "Nemô¾em nájs» funkciu '%-.128s' v kni¾nici"
- spa "No puedo encontrar función '%-.128s' en libraria"
- swe "Hittar inte funktionen '%-.128s' in det dynamiska biblioteket"
- ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ ÆÕÎËæÀ '%-.128s' Õ Â¦Â̦ÏÔÅæ"
-ER_FUNCTION_NOT_DEFINED
- cze "Funkce '%-.192s' nen-Bí definována"
- dan "Funktionen '%-.192s' er ikke defineret"
- nla "Functie '%-.192s' is niet gedefinieerd"
- eng "Function '%-.192s' is not defined"
- jps "Function '%-.192s' ‚Í’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "Funktsioon '%-.192s' ei ole defineeritud"
- fre "La fonction '%-.192s' n'est pas définie"
- ger "Funktion '%-.192s' ist nicht definiert"
- greek "Ç óõíÜñôçóç '%-.192s' äåí Ý÷åé ïñéóèåß"
- hun "A '%-.192s' fuggveny nem definialt"
- ita "La funzione '%-.192s' non e` definita"
- jpn "Function '%-.192s' ¤ÏÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "'%-.192s' ÇÔ¼ö°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù."
- por "Função '%-.192s' não está definida"
- rum "Functia '%-.192s' nu e definita"
- rus "æÕÎËÃÉÑ '%-.192s' ÎÅ ÏÐÒÅÄÅÌÅÎÁ"
- serbian "Funkcija '%-.192s' nije definisana"
- slo "Funkcia '%-.192s' nie je definovaná"
- spa "Función '%-.192s' no está definida"
- swe "Funktionen '%-.192s' är inte definierad"
- ukr "æÕÎËæÀ '%-.192s' ÎÅ ×ÉÚÎÁÞÅÎÏ"
-ER_HOST_IS_BLOCKED
- cze "Stroj '%-.64s' je zablokov-Bán kvùli mnoha chybám pøi pøipojování. Odblokujete pou¾itím 'mysqladmin flush-hosts'"
- dan "Værten '%-.64s' er blokeret på grund af mange fejlforespørgsler. Lås op med 'mysqladmin flush-hosts'"
- nla "Host '%-.64s' is geblokkeeerd vanwege te veel verbindings fouten. Deblokkeer met 'mysqladmin flush-hosts'"
- eng "Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'"
- jps "Host '%-.64s' ‚Í many connection error ‚Ì‚½‚ßA‹‘”Û‚³‚ê‚Ü‚µ‚½. 'mysqladmin flush-hosts' ‚ʼn𜂵‚Ä‚­‚¾‚³‚¢",
- est "Masin '%-.64s' on blokeeritud hulgaliste ühendusvigade tõttu. Blokeeringu saab tühistada 'mysqladmin flush-hosts' käsuga"
- fre "L'hôte '%-.64s' est bloqué à cause d'un trop grand nombre d'erreur de connexion. Débloquer le par 'mysqladmin flush-hosts'"
- ger "Host '%-.64s' blockiert wegen zu vieler Verbindungsfehler. Aufheben der Blockierung mit 'mysqladmin flush-hosts'"
- greek "Ï õðïëïãéóôÞò '%-.64s' Ý÷åé áðïêëåéóèåß ëüãù ðïëëáðëþí ëáèþí óýíäåóçò. ÐñïóðáèÞóôå íá äéïñþóåôå ìå 'mysqladmin flush-hosts'"
- hun "A '%-.64s' host blokkolodott, tul sok kapcsolodasi hiba miatt. Hasznalja a 'mysqladmin flush-hosts' parancsot"
- ita "Sistema '%-.64s' bloccato a causa di troppi errori di connessione. Per sbloccarlo: 'mysqladmin flush-hosts'"
- jpn "Host '%-.64s' ¤Ï many connection error ¤Î¤¿¤á¡¢µñÈݤµ¤ì¤Þ¤·¤¿. 'mysqladmin flush-hosts' ¤Ç²ò½ü¤·¤Æ¤¯¤À¤µ¤¤"
- kor "³Ê¹« ¸¹Àº ¿¬°á¿À·ù·Î ÀÎÇÏ¿© È£½ºÆ® '%-.64s'´Â ºí¶ôµÇ¾ú½À´Ï´Ù. 'mysqladmin flush-hosts'¸¦ ÀÌ¿ëÇÏ¿© ºí¶ôÀ» ÇØÁ¦Çϼ¼¿ä"
- por "'Host' '%-.64s' está bloqueado devido a muitos erros de conexão. Desbloqueie com 'mysqladmin flush-hosts'"
- rum "Host-ul '%-.64s' e blocat din cauza multelor erori de conectie. Poti deploca folosind 'mysqladmin flush-hosts'"
- rus "èÏÓÔ '%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎ ÉÚ-ÚÁ ÓÌÉÛËÏÍ ÂÏÌØÛÏÇÏ ËÏÌÉÞÅÓÔ×Á ÏÛÉÂÏË ÓÏÅÄÉÎÅÎÉÑ. òÁÚÂÌÏËÉÒÏ×ÁÔØ ÅÇÏ ÍÏÖÎÏ Ó ÐÏÍÏÝØÀ 'mysqladmin flush-hosts'"
- serbian "Host '%-.64s' je blokiran zbog previše grešaka u konekciji. Možete ga odblokirati pomoæu komande 'mysqladmin flush-hosts'"
- spa "Servidor '%-.64s' está bloqueado por muchos errores de conexión. Desbloquear con 'mysqladmin flush-hosts'"
- swe "Denna dator, '%-.64s', är blockerad pga många felaktig paket. Gör 'mysqladmin flush-hosts' för att ta bort alla blockeringarna"
- ukr "èÏÓÔ '%-.64s' ÚÁÂÌÏËÏ×ÁÎÏ Ú ÐÒÉÞÉÎÉ ×ÅÌÉËϧ ˦ÌØËÏÓÔ¦ ÐÏÍÉÌÏË Ú'¤ÄÎÁÎÎÑ. äÌÑ ÒÏÚÂÌÏËÕ×ÁÎÎÑ ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ 'mysqladmin flush-hosts'"
-ER_HOST_NOT_PRIVILEGED
- cze "Stroj '%-.64s' nem-Bá povoleno se k tomuto MySQL serveru pøipojit"
- dan "Værten '%-.64s' kan ikke tilkoble denne MySQL-server"
- nla "Het is host '%-.64s' is niet toegestaan verbinding te maken met deze MySQL server"
- eng "Host '%-.64s' is not allowed to connect to this MySQL server"
- jps "Host '%-.64s' ‚Í MySQL server ‚ÉÚ‘±‚ð‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "Masinal '%-.64s' puudub ligipääs sellele MySQL serverile"
- fre "Le hôte '%-.64s' n'est pas authorisé à se connecter à ce serveur MySQL"
- ger "Host '%-.64s' hat keine Berechtigung, sich mit diesem MySQL-Server zu verbinden"
- greek "Ï õðïëïãéóôÞò '%-.64s' äåí Ý÷åé äéêáßùìá óýíäåóçò ìå ôïí MySQL server"
- hun "A '%-.64s' host szamara nem engedelyezett a kapcsolodas ehhez a MySQL szerverhez"
- ita "Al sistema '%-.64s' non e` consentita la connessione a questo server MySQL"
- jpn "Host '%-.64s' ¤Ï MySQL server ¤ËÀܳ¤òµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "'%-.64s' È£½ºÆ®´Â ÀÌ MySQL¼­¹ö¿¡ Á¢¼ÓÇÒ Çã°¡¸¦ ¹ÞÁö ¸øÇß½À´Ï´Ù."
- por "'Host' '%-.64s' não tem permissão para se conectar com este servidor MySQL"
- rum "Host-ul '%-.64s' nu este permis a se conecta la aceste server MySQL"
- rus "èÏÓÔÕ '%-.64s' ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÐÏÄËÌÀÞÁÔØÓÑ Ë ÜÔÏÍÕ ÓÅÒ×ÅÒÕ MySQL"
- serbian "Host-u '%-.64s' nije dozvoljeno da se konektuje na ovaj MySQL server"
- spa "Servidor '%-.64s' no está permitido para conectar con este servidor MySQL"
- swe "Denna dator, '%-.64s', har inte privileger att använda denna MySQL server"
- ukr "èÏÓÔÕ '%-.64s' ÎÅ ÄÏ×ÏÌÅÎÏ Ú×'ÑÚÕ×ÁÔÉÓØ Ú ÃÉÍ ÓÅÒ×ÅÒÏÍ MySQL"
-ER_PASSWORD_ANONYMOUS_USER 42000
- cze "Pou-B¾íváte MySQL jako anonymní u¾ivatel a anonymní u¾ivatelé nemají povoleno mìnit hesla"
- dan "Du bruger MySQL som anonym bruger. Anonyme brugere må ikke ændre adgangskoder"
- nla "U gebruikt MySQL als anonieme gebruiker en deze mogen geen wachtwoorden wijzigen"
- eng "You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords"
- jps "MySQL ‚ð anonymous users ‚ÅŽg—p‚µ‚Ä‚¢‚éó‘Ô‚Å‚ÍAƒpƒXƒ[ƒh‚Ì•ÏX‚Í‚Å‚«‚Ü‚¹‚ñ",
- est "Te kasutate MySQL-i anonüümse kasutajana, kelledel pole parooli muutmise õigust"
- fre "Vous utilisez un utilisateur anonyme et les utilisateurs anonymes ne sont pas autorisés à changer les mots de passe"
- ger "Sie benutzen MySQL als anonymer Benutzer und dürfen daher keine Passwörter ändern"
- greek "×ñçóéìïðïéåßôå ôçí MySQL óáí anonymous user êáé Ýôóé äåí ìðïñåßôå íá áëëÜîåôå ôá passwords Üëëùí ÷ñçóôþí"
- hun "Nevtelen (anonymous) felhasznalokent nem negedelyezett a jelszovaltoztatas"
- ita "Impossibile cambiare la password usando MySQL come utente anonimo"
- jpn "MySQL ¤ò anonymous users ¤Ç»ÈÍѤ·¤Æ¤¤¤ë¾õÂ֤Ǥϡ¢¥Ñ¥¹¥ï¡¼¥É¤ÎÊѹ¹¤Ï¤Ç¤­¤Þ¤»¤ó"
- kor "´ç½ÅÀº MySQL¼­¹ö¿¡ À͸íÀÇ »ç¿ëÀÚ·Î Á¢¼ÓÀ» Çϼ̽À´Ï´Ù.À͸íÀÇ »ç¿ëÀÚ´Â ¾ÏÈ£¸¦ º¯°æÇÒ ¼ö ¾ø½À´Ï´Ù."
- por "Você está usando o MySQL como usuário anônimo e usuários anônimos não têm permissão para mudar senhas"
- rum "Dumneavoastra folositi MySQL ca un utilizator anonim si utilizatorii anonimi nu au voie sa schime parolele"
- rus "÷Ù ÉÓÐÏÌØÚÕÅÔÅ MySQL ÏÔ ÉÍÅÎÉ ÁÎÏÎÉÍÎÏÇÏ ÐÏÌØÚÏ×ÁÔÅÌÑ, Á ÁÎÏÎÉÍÎÙÍ ÐÏÌØÚÏ×ÁÔÅÌÑÍ ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÍÅÎÑÔØ ÐÁÒÏÌÉ"
- serbian "Vi koristite MySQL kao anonimni korisnik a anonimnim korisnicima nije dozvoljeno da menjaju lozinke"
- spa "Tu estás usando MySQL como un usuario anonimo y usuarios anonimos no tienen permiso para cambiar las claves"
- swe "Du använder MySQL som en anonym användare och som sådan får du inte ändra ditt lösenord"
- ukr "÷É ×ÉËÏÒÉÓÔÏ×Õ¤ÔÅ MySQL ÑË ÁÎÏΦÍÎÉÊ ËÏÒÉÓÔÕ×ÁÞ, ÔÏÍÕ ×ÁÍ ÎÅ ÄÏÚ×ÏÌÅÎÏ ÚͦÎÀ×ÁÔÉ ÐÁÒÏ̦"
-ER_PASSWORD_NOT_ALLOWED 42000
- cze "Na zm-Bìnu hesel ostatním musíte mít právo provést update tabulek v databázi mysql"
- dan "Du skal have tilladelse til at opdatere tabeller i MySQL databasen for at ændre andres adgangskoder"
- nla "U moet tabel update priveleges hebben in de mysql database om wachtwoorden voor anderen te mogen wijzigen"
- eng "You must have privileges to update tables in the mysql database to be able to change passwords for others"
- jps "‘¼‚̃†[ƒU[‚̃pƒXƒ[ƒh‚ð•ÏX‚·‚邽‚ß‚É‚Í, mysql ƒf[ƒ^ƒx[ƒX‚ɑ΂µ‚Ä update ‚Ì‹–‰Â‚ª‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ.",
- est "Teiste paroolide muutmiseks on nõutav tabelite muutmisõigus 'mysql' andmebaasis"
- fre "Vous devez avoir le privilège update sur les tables de la base de donnée mysql pour pouvoir changer les mots de passe des autres"
- ger "Sie benötigen die Berechtigung zum Aktualisieren von Tabellen in der Datenbank 'mysql', um die Passwörter anderer Benutzer ändern zu können"
- greek "ÐñÝðåé íá Ý÷åôå äéêáßùìá äéüñèùóçò ðéíÜêùí (update) óôç âÜóç äåäïìÝíùí mysql ãéá íá ìðïñåßôå íá áëëÜîåôå ôá passwords Üëëùí ÷ñçóôþí"
- hun "Onnek tabla-update joggal kell rendelkeznie a mysql adatbazisban masok jelszavanak megvaltoztatasahoz"
- ita "E` necessario il privilegio di update sulle tabelle del database mysql per cambiare le password per gli altri utenti"
- jpn "¾¤Î¥æ¡¼¥¶¡¼¤Î¥Ñ¥¹¥ï¡¼¥É¤òÊѹ¹¤¹¤ë¤¿¤á¤Ë¤Ï, mysql ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ËÂФ·¤Æ update ¤Îµö²Ä¤¬¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó."
- kor "´ç½ÅÀº ´Ù¸¥»ç¿ëÀÚµéÀÇ ¾ÏÈ£¸¦ º¯°æÇÒ ¼ö ÀÖµµ·Ï µ¥ÀÌŸº£À̽º º¯°æ±ÇÇÑÀ» °¡Á®¾ß ÇÕ´Ï´Ù."
- por "Você deve ter privilégios para atualizar tabelas no banco de dados mysql para ser capaz de mudar a senha de outros"
- rum "Trebuie sa aveti privilegii sa actualizati tabelele in bazele de date mysql ca sa puteti sa schimati parolele altora"
- rus "äÌÑ ÔÏÇÏ ÞÔÏÂÙ ÉÚÍÅÎÑÔØ ÐÁÒÏÌÉ ÄÒÕÇÉÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ, Õ ×ÁÓ ÄÏÌÖÎÙ ÂÙÔØ ÐÒÉ×ÉÌÅÇÉÉ ÎÁ ÉÚÍÅÎÅÎÉÅ ÔÁÂÌÉÃ × ÂÁÚÅ ÄÁÎÎÙÈ mysql"
- serbian "Morate imati privilegije da možete da update-ujete odreðene tabele ako želite da menjate lozinke za druge korisnike"
- spa "Tu debes de tener permiso para actualizar tablas en la base de datos mysql para cambiar las claves para otros"
- swe "För att ändra lösenord för andra måste du ha rättigheter att uppdatera mysql-databasen"
- ukr "÷É ÐÏ×ÉΦ ÍÁÔÉ ÐÒÁ×Ï ÎÁ ÏÎÏ×ÌÅÎÎÑ ÔÁÂÌÉÃØ Õ ÂÁÚ¦ ÄÁÎÎÉÈ mysql, ÁÂÉ ÍÁÔÉ ÍÏÖÌÉצÓÔØ ÚͦÎÀ×ÁÔÉ ÐÁÒÏÌØ ¦ÎÛÉÍ"
-ER_PASSWORD_NO_MATCH 42000
- cze "V tabulce user nen-Bí ¾ádný odpovídající øádek"
- dan "Kan ikke finde nogen tilsvarende poster i bruger tabellen"
- nla "Kan geen enkele passende rij vinden in de gebruikers tabel"
- eng "Can't find any matching row in the user table"
- est "Ei leia vastavat kirjet kasutajate tabelis"
- fre "Impossible de trouver un enregistrement correspondant dans la table user"
- ger "Kann keinen passenden Datensatz in Tabelle 'user' finden"
- greek "Äåí åßíáé äõíáôÞ ç áíåýñåóç ôçò áíôßóôïé÷çò åããñáöÞò óôïí ðßíáêá ôùí ÷ñçóôþí"
- hun "Nincs megegyezo sor a user tablaban"
- ita "Impossibile trovare la riga corrispondente nella tabella user"
- kor "»ç¿ëÀÚ Å×ÀÌºí¿¡¼­ ÀÏÄ¡ÇÏ´Â °ÍÀ» ãÀ» ¼ö ¾øÀ¾´Ï´Ù."
- por "Não pode encontrar nenhuma linha que combine na tabela usuário (user table)"
- rum "Nu pot gasi nici o linie corespunzatoare in tabela utilizatorului"
- rus "îÅ×ÏÚÍÏÖÎÏ ÏÔÙÓËÁÔØ ÐÏÄÈÏÄÑÝÕÀ ÚÁÐÉÓØ × ÔÁÂÌÉÃÅ ÐÏÌØÚÏ×ÁÔÅÌÅÊ"
- serbian "Ne mogu da pronaðem odgovarajuæi slog u 'user' tabeli"
- spa "No puedo encontrar una línea correponsdiente en la tabla user"
- swe "Hittade inte användaren i 'user'-tabellen"
- ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ ×¦ÄÐÏצÄÎÉÈ ÚÁÐÉÓ¦× Õ ÔÁÂÌÉæ ËÏÒÉÓÔÕ×ÁÞÁ"
-ER_UPDATE_INFO
- cze "Nalezen-Bých øádkù: %ld Zmìnìno: %ld Varování: %ld"
- dan "Poster fundet: %ld Ændret: %ld Advarsler: %ld"
- nla "Passende rijen: %ld Gewijzigd: %ld Waarschuwingen: %ld"
- eng "Rows matched: %ld Changed: %ld Warnings: %ld"
- jps "ˆê’v”(Rows matched): %ld •ÏX: %ld Warnings: %ld",
- est "Sobinud kirjeid: %ld Muudetud: %ld Hoiatusi: %ld"
- fre "Enregistrements correspondants: %ld Modifiés: %ld Warnings: %ld"
- ger "Datensätze gefunden: %ld Geändert: %ld Warnungen: %ld"
- hun "Megegyezo sorok szama: %ld Valtozott: %ld Warnings: %ld"
- ita "Rows riconosciute: %ld Cambiate: %ld Warnings: %ld"
- jpn "°ìÃ׿ô(Rows matched): %ld Êѹ¹: %ld Warnings: %ld"
- kor "ÀÏÄ¡ÇÏ´Â Rows : %ld°³ º¯°æµÊ: %ld°³ °æ°í: %ld°³"
- por "Linhas que combinaram: %ld - Alteradas: %ld - Avisos: %ld"
- rum "Linii identificate (matched): %ld Schimbate: %ld Atentionari (warnings): %ld"
- rus "óÏ×ÐÁÌÏ ÚÁÐÉÓÅÊ: %ld éÚÍÅÎÅÎÏ: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld"
- serbian "Odgovarajuæih slogova: %ld Promenjeno: %ld Upozorenja: %ld"
- spa "Líneas correspondientes: %ld Cambiadas: %ld Avisos: %ld"
- swe "Rader: %ld Uppdaterade: %ld Varningar: %ld"
- ukr "úÁÐÉÓ¦× ×¦ÄÐÏצÄÁ¤: %ld úͦÎÅÎÏ: %ld úÁÓÔÅÒÅÖÅÎØ: %ld"
-ER_CANT_CREATE_THREAD
- cze "Nemohu vytvo-Bøit nový thread (errno %d). Pokud je je¹tì nìjaká volná pamì», podívejte se do manuálu na èást o chybách specifických pro jednotlivé operaèní systémy"
- dan "Kan ikke danne en ny tråd (fejl nr. %d). Hvis computeren ikke er løbet tør for hukommelse, kan du se i brugervejledningen for en mulig operativ-system - afhængig fejl"
- nla "Kan geen nieuwe thread aanmaken (Errcode: %d). Indien er geen tekort aan geheugen is kunt u de handleiding consulteren over een mogelijke OS afhankelijke fout"
- eng "Can't create a new thread (errno %d); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug"
- jps "V‹K‚ɃXƒŒƒbƒh‚ªì‚ê‚Ü‚¹‚ñ‚Å‚µ‚½ (errno %d). ‚à‚µÅ‘åŽg—p‹–‰Âƒƒ‚ƒŠ[”‚ð‰z‚¦‚Ä‚¢‚È‚¢‚̂ɃGƒ‰[‚ª”­¶‚µ‚Ä‚¢‚é‚È‚ç, ƒ}ƒjƒ…ƒAƒ‹‚Ì’†‚©‚ç 'possible OS-dependent bug' ‚Æ‚¢‚¤•¶Žš‚ð’T‚µ‚Ä‚­‚Ý‚Ä‚¾‚³‚¢.",
- est "Ei suuda luua uut lõime (veakood %d). Kui mälu ei ole otsas, on tõenäoliselt tegemist operatsioonisüsteemispetsiifilise veaga"
- fre "Impossible de créer une nouvelle tâche (errno %d). S'il reste de la mémoire libre, consultez le manual pour trouver un éventuel bug dépendant de l'OS"
- ger "Kann keinen neuen Thread erzeugen (Fehler: %d). Sollte noch Speicher verfügbar sein, bitte im Handbuch wegen möglicher Fehler im Betriebssystem nachschlagen"
- hun "Uj thread letrehozasa nem lehetseges (Hibakod: %d). Amenyiben van meg szabad memoria, olvassa el a kezikonyv operacios rendszerfuggo hibalehetosegekrol szolo reszet"
- ita "Impossibile creare un nuovo thread (errno %d). Se non ci sono problemi di memoria disponibile puoi consultare il manuale per controllare possibili problemi dipendenti dal SO"
- jpn "¿·µ¬¤Ë¥¹¥ì¥Ã¥É¤¬ºî¤ì¤Þ¤»¤ó¤Ç¤·¤¿ (errno %d). ¤â¤·ºÇÂç»ÈÍѵö²Ä¥á¥â¥ê¡¼¿ô¤ò±Û¤¨¤Æ¤¤¤Ê¤¤¤Î¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Æ¤¤¤ë¤Ê¤é, ¥Þ¥Ë¥å¥¢¥ë¤ÎÃ椫¤é 'possible OS-dependent bug' ¤È¤¤¤¦Ê¸»ú¤òõ¤·¤Æ¤¯¤ß¤Æ¤À¤µ¤¤."
- kor "»õ·Î¿î ¾²·¹µå¸¦ ¸¸µé ¼ö ¾ø½À´Ï´Ù.(¿¡·¯¹øÈ£ %d). ¸¸¾à ¿©À¯¸Þ¸ð¸®°¡ ÀÖ´Ù¸é OS-dependent¹ö±× ÀÇ ¸Þ´º¾ó ºÎºÐÀ» ã¾Æº¸½Ã¿À."
- nor "Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug"
- norwegian-ny "Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug"
- pol "Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug"
- por "Não pode criar uma nova 'thread' (erro no. %d). Se você não estiver sem memória disponível, você pode consultar o manual sobre um possível 'bug' dependente do sistema operacional"
- rum "Nu pot crea un thread nou (Eroare %d). Daca mai aveti memorie disponibila in sistem, puteti consulta manualul - ar putea exista un potential bug in legatura cu sistemul de operare"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÎÏ×ÙÊ ÐÏÔÏË (ÏÛÉÂËÁ %d). åÓÌÉ ÜÔÏ ÎÅ ÓÉÔÕÁÃÉÑ, Ó×ÑÚÁÎÎÁÑ Ó ÎÅÈ×ÁÔËÏÊ ÐÁÍÑÔÉ, ÔÏ ×ÁÍ ÓÌÅÄÕÅÔ ÉÚÕÞÉÔØ ÄÏËÕÍÅÎÔÁÃÉÀ ÎÁ ÐÒÅÄÍÅÔ ÏÐÉÓÁÎÉÑ ×ÏÚÍÏÖÎÏÊ ÏÛÉÂËÉ ÒÁÂÏÔÙ × ËÏÎËÒÅÔÎÏÊ ïó"
- serbian "Ne mogu da kreiram novi thread (errno %d). Ako imate još slobodne memorije, trebali biste da pogledate u priruèniku da li je ovo specifièna greška vašeg operativnog sistema"
- spa "No puedo crear un nuevo thread (errno %d). Si tu está con falta de memoria disponible, tu puedes consultar el Manual para posibles problemas con SO"
- swe "Kan inte skapa en ny tråd (errno %d)"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÎÏ×Õ Ç¦ÌËÕ (ÐÏÍÉÌËÁ %d). ñËÝÏ ×É ÎÅ ×ÉËÏÒÉÓÔÁÌÉ ÕÓÀ ÐÁÍ'ÑÔØ, ÔÏ ÐÒÏÞÉÔÁÊÔÅ ÄÏËÕÍÅÎÔÁæÀ ÄÏ ×ÁÛϧ ïó - ÍÏÖÌÉ×Ï ÃÅ ÐÏÍÉÌËÁ ïó"
-ER_WRONG_VALUE_COUNT_ON_ROW 21S01
- cze "Po-Bèet sloupcù neodpovídá poètu hodnot na øádku %ld"
- dan "Kolonne antallet stemmer ikke overens med antallet af værdier i post %ld"
- nla "Kolom aantal komt niet overeen met waarde aantal in rij %ld"
- eng "Column count doesn't match value count at row %ld"
- est "Tulpade hulk erineb väärtuste hulgast real %ld"
- ger "Anzahl der Felder stimmt nicht mit der Anzahl der Werte in Zeile %ld überein"
- hun "Az oszlopban talalhato ertek nem egyezik meg a %ld sorban szamitott ertekkel"
- ita "Il numero delle colonne non corrisponde al conteggio alla riga %ld"
- kor "Row %ld¿¡¼­ Ä®·³ Ä«¿îÆ®¿Í value Ä«¿îÅÍ¿Í ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù."
- por "Contagem de colunas não confere com a contagem de valores na linha %ld"
- rum "Numarul de coloane nu corespunde cu numarul de valori la linia %ld"
- rus "ëÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ× ÎÅ ÓÏ×ÐÁÄÁÅÔ Ó ËÏÌÉÞÅÓÔ×ÏÍ ÚÎÁÞÅÎÉÊ × ÚÁÐÉÓÉ %ld"
- serbian "Broj kolona ne odgovara broju vrednosti u slogu %ld"
- spa "El número de columnas no corresponde al número en la línea %ld"
- swe "Antalet kolumner motsvarar inte antalet värden på rad: %ld"
- ukr "ë¦ÌØ˦ÓÔØ ÓÔÏ×ÂÃ¦× ÎÅ ÓЦ×ÐÁÄÁ¤ Ú Ë¦ÌØ˦ÓÔÀ ÚÎÁÞÅÎØ Õ ÓÔÒÏæ %ld"
-ER_CANT_REOPEN_TABLE
- cze "Nemohu znovuotev-Bøít tabulku: '%-.192s"
- dan "Kan ikke genåbne tabel '%-.192s"
- nla "Kan tabel niet opnieuw openen: '%-.192s"
- eng "Can't reopen table: '%-.192s'"
- est "Ei suuda taasavada tabelit '%-.192s'"
- fre "Impossible de réouvrir la table: '%-.192s"
- ger "Kann Tabelle'%-.192s' nicht erneut öffnen"
- hun "Nem lehet ujra-megnyitni a tablat: '%-.192s"
- ita "Impossibile riaprire la tabella: '%-.192s'"
- kor "Å×À̺íÀ» ´Ù½Ã ¿­¼ö ¾ø±º¿ä: '%-.192s"
- nor "Can't reopen table: '%-.192s"
- norwegian-ny "Can't reopen table: '%-.192s"
- pol "Can't reopen table: '%-.192s"
- por "Não pode reabrir a tabela '%-.192s"
- rum "Nu pot redeschide tabela: '%-.192s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÎÏ×Ï ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ '%-.192s'"
- serbian "Ne mogu da ponovo otvorim tabelu '%-.192s'"
- slo "Can't reopen table: '%-.192s"
- spa "No puedo reabrir tabla: '%-.192s"
- swe "Kunde inte stänga och öppna tabell '%-.192s"
- ukr "îÅ ÍÏÖÕ ÐÅÒÅצÄËÒÉÔÉ ÔÁÂÌÉÃÀ: '%-.192s'"
-ER_INVALID_USE_OF_NULL 22004
- cze "Neplatn-Bé u¾ití hodnoty NULL"
- dan "Forkert brug af nulværdi (NULL)"
- nla "Foutief gebruik van de NULL waarde"
- eng "Invalid use of NULL value"
- jps "NULL ’l‚ÌŽg—p•û–@‚ª•s“KØ‚Å‚·",
- est "NULL väärtuse väärkasutus"
- fre "Utilisation incorrecte de la valeur NULL"
- ger "Unerlaubte Verwendung eines NULL-Werts"
- hun "A NULL ervenytelen hasznalata"
- ita "Uso scorretto del valore NULL"
- jpn "NULL ÃͤλÈÍÑÊýË¡¤¬ÉÔŬÀڤǤ¹"
- kor "NULL °ªÀ» À߸ø »ç¿ëÇϼ̱º¿ä..."
- por "Uso inválido do valor NULL"
- rum "Folosirea unei value NULL e invalida"
- rus "îÅÐÒÁ×ÉÌØÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ×ÅÌÉÞÉÎÙ NULL"
- serbian "Pogrešna upotreba vrednosti NULL"
- spa "Invalido uso de valor NULL"
- swe "Felaktig använding av NULL"
- ukr "èÉÂÎÅ ×ÉËÏÒÉÓÔÁÎÎÑ ÚÎÁÞÅÎÎÑ NULL"
-ER_REGEXP_ERROR 42000
- cze "Regul-Bární výraz vrátil chybu '%-.64s'"
- dan "Fik fejl '%-.64s' fra regexp"
- nla "Fout '%-.64s' ontvangen van regexp"
- eng "Got error '%-.64s' from regexp"
- est "regexp tagastas vea '%-.64s'"
- fre "Erreur '%-.64s' provenant de regexp"
- ger "regexp lieferte Fehler '%-.64s'"
- hun "'%-.64s' hiba a regularis kifejezes hasznalata soran (regexp)"
- ita "Errore '%-.64s' da regexp"
- kor "regexp¿¡¼­ '%-.64s'°¡ ³µ½À´Ï´Ù."
- por "Obteve erro '%-.64s' em regexp"
- rum "Eroarea '%-.64s' obtinuta din expresia regulara (regexp)"
- rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ '%-.64s' ÏÔ ÒÅÇÕÌÑÒÎÏÇÏ ×ÙÒÁÖÅÎÉÑ"
- serbian "Funkcija regexp je vratila grešku '%-.64s'"
- spa "Obtenido error '%-.64s' de regexp"
- swe "Fick fel '%-.64s' från REGEXP"
- ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ '%-.64s' ×¦Ä ÒÅÇÕÌÑÒÎÏÇÏ ×ÉÒÁÚÕ"
-ER_MIX_OF_GROUP_FUNC_AND_FIELDS 42000
- cze "Pokud nen-Bí ¾ádná GROUP BY klauzule, není dovoleno souèasné pou¾ití GROUP polo¾ek (MIN(),MAX(),COUNT()...) s ne GROUP polo¾kami"
- dan "Sammenblanding af GROUP kolonner (MIN(),MAX(),COUNT()...) uden GROUP kolonner er ikke tilladt, hvis der ikke er noget GROUP BY prædikat"
- nla "Het mixen van GROUP kolommen (MIN(),MAX(),COUNT()...) met no-GROUP kolommen is foutief indien er geen GROUP BY clausule is"
- eng "Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause"
- est "GROUP tulpade (MIN(),MAX(),COUNT()...) kooskasutamine tavaliste tulpadega ilma GROUP BY klauslita ei ole lubatud"
- fre "Mélanger les colonnes GROUP (MIN(),MAX(),COUNT()...) avec des colonnes normales est interdit s'il n'y a pas de clause GROUP BY"
- ger "Das Vermischen von GROUP-Feldern (MIN(),MAX(),COUNT()...) mit Nicht-GROUP-Feldern ist nicht zulässig, wenn keine GROUP-BY-Klausel vorhanden ist"
- hun "A GROUP mezok (MIN(),MAX(),COUNT()...) kevert hasznalata nem lehetseges GROUP BY hivatkozas nelkul"
- ita "Il mescolare funzioni di aggregazione (MIN(),MAX(),COUNT()...) e non e` illegale se non c'e` una clausula GROUP BY"
- kor "Mixing of GROUP Ä®·³s (MIN(),MAX(),COUNT(),...) with no GROUP Ä®·³s is illegal if there is no GROUP BY clause"
- por "Mistura de colunas agrupadas (com MIN(), MAX(), COUNT(), ...) com colunas não agrupadas é ilegal, se não existir uma cláusula de agrupamento (cláusula GROUP BY)"
- rum "Amestecarea de coloane GROUP (MIN(),MAX(),COUNT()...) fara coloane GROUP este ilegala daca nu exista o clauza GROUP BY"
- rus "ïÄÎÏ×ÒÅÍÅÎÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÓÇÒÕÐÐÉÒÏ×ÁÎÎÙÈ (GROUP) ÓÔÏÌÂÃÏ× (MIN(),MAX(),COUNT(),...) Ó ÎÅÓÇÒÕÐÐÉÒÏ×ÁÎÎÙÍÉ ÓÔÏÌÂÃÁÍÉ Ñ×ÌÑÅÔÓÑ ÎÅËÏÒÒÅËÔÎÙÍ, ÅÓÌÉ × ×ÙÒÁÖÅÎÉÉ ÅÓÔØ GROUP BY"
- serbian "Upotreba agregatnih funkcija (MIN(),MAX(),COUNT()...) bez 'GROUP' kolona je pogrešna ako ne postoji 'GROUP BY' iskaz"
- spa "Mezcla de columnas GROUP (MIN(),MAX(),COUNT()...) con no GROUP columnas es ilegal si no hat la clausula GROUP BY"
- swe "Man får ha både GROUP-kolumner (MIN(),MAX(),COUNT()...) och fält i en fråga om man inte har en GROUP BY-del"
- ukr "úͦÛÕ×ÁÎÎÑ GROUP ÓÔÏ×ÂÃ¦× (MIN(),MAX(),COUNT()...) Ú ÎÅ GROUP ÓÔÏ×ÂÃÑÍÉ ¤ ÚÁÂÏÒÏÎÅÎÉÍ, ÑËÝÏ ÎÅ ÍÁ¤ GROUP BY"
-ER_NONEXISTING_GRANT 42000
- cze "Neexistuje odpov-Bídající grant pro u¾ivatele '%-.48s' na stroji '%-.64s'"
- dan "Denne tilladelse findes ikke for brugeren '%-.48s' på vært '%-.64s'"
- nla "Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.48s' op host '%-.64s'"
- eng "There is no such grant defined for user '%-.48s' on host '%-.64s'"
- jps "ƒ†[ƒU[ '%-.48s' (ƒzƒXƒg '%-.64s' ‚̃†[ƒU[) ‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "Sellist õigust ei ole defineeritud kasutajale '%-.48s' masinast '%-.64s'"
- fre "Un tel droit n'est pas défini pour l'utilisateur '%-.48s' sur l'hôte '%-.64s'"
- ger "Für Benutzer '%-.48s' auf Host '%-.64s' gibt es keine solche Berechtigung"
- hun "A '%-.48s' felhasznalonak nincs ilyen joga a '%-.64s' host-on"
- ita "GRANT non definita per l'utente '%-.48s' dalla macchina '%-.64s'"
- jpn "¥æ¡¼¥¶¡¼ '%-.48s' (¥Û¥¹¥È '%-.64s' ¤Î¥æ¡¼¥¶¡¼) ¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "»ç¿ëÀÚ '%-.48s' (È£½ºÆ® '%-.64s')¸¦ À§ÇÏ¿© Á¤ÀÇµÈ ±×·± ½ÂÀÎÀº ¾ø½À´Ï´Ù."
- por "Não existe tal permissão (grant) definida para o usuário '%-.48s' no 'host' '%-.64s'"
- rum "Nu exista un astfel de grant definit pentru utilzatorul '%-.48s' de pe host-ul '%-.64s'"
- rus "ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s' ÎÁ ÈÏÓÔÅ '%-.64s'"
- serbian "Ne postoji odobrenje za pristup korisniku '%-.48s' na host-u '%-.64s'"
- spa "No existe permiso definido para usuario '%-.48s' en el servidor '%-.64s'"
- swe "Det finns inget privilegium definierat för användare '%-.48s' på '%-.64s'"
- ukr "ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.48s' Ú ÈÏÓÔÕ '%-.64s'"
-ER_TABLEACCESS_DENIED_ERROR 42000
- cze "%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.48s'@'%-.64s' pro tabulku '%-.192s'"
- dan "%-.16s-kommandoen er ikke tilladt for brugeren '%-.48s'@'%-.64s' for tabellen '%-.192s'"
- nla "%-.16s commando geweigerd voor gebruiker: '%-.48s'@'%-.64s' voor tabel '%-.192s'"
- eng "%-.16s command denied to user '%-.48s'@'%-.64s' for table '%-.192s'"
- jps "ƒRƒ}ƒ“ƒh %-.16s ‚Í ƒ†[ƒU[ '%-.48s'@'%-.64s' ,ƒe[ƒuƒ‹ '%-.192s' ‚ɑ΂µ‚Ä‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "%-.16s käsk ei ole lubatud kasutajale '%-.48s'@'%-.64s' tabelis '%-.192s'"
- fre "La commande '%-.16s' est interdite à l'utilisateur: '%-.48s'@'@%-.64s' sur la table '%-.192s'"
- ger "%-.16s Befehl nicht erlaubt für Benutzer '%-.48s'@'%-.64s' auf Tabelle '%-.192s'"
- hun "%-.16s parancs a '%-.48s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.192s' tablaban"
- ita "Comando %-.16s negato per l'utente: '%-.48s'@'%-.64s' sulla tabella '%-.192s'"
- jpn "¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.48s'@'%-.64s' ,¥Æ¡¼¥Ö¥ë '%-.192s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.48s'@'%-.64s' for Å×À̺í '%-.192s'"
- por "Comando '%-.16s' negado para o usuário '%-.48s'@'%-.64s' na tabela '%-.192s'"
- rum "Comanda %-.16s interzisa utilizatorului: '%-.48s'@'%-.64s' pentru tabela '%-.192s'"
- rus "ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.48s'@'%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.192s'"
- serbian "%-.16s komanda zabranjena za korisnika '%-.48s'@'%-.64s' za tabelu '%-.192s'"
- spa "%-.16s comando negado para usuario: '%-.48s'@'%-.64s' para tabla '%-.192s'"
- swe "%-.16s ej tillåtet för '%-.48s'@'%-.64s' för tabell '%-.192s'"
- ukr "%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.48s'@'%-.64s' Õ ÔÁÂÌÉæ '%-.192s'"
-ER_COLUMNACCESS_DENIED_ERROR 42000
- cze "%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.48s'@'%-.64s' pro sloupec '%-.192s' v tabulce '%-.192s'"
- dan "%-.16s-kommandoen er ikke tilladt for brugeren '%-.48s'@'%-.64s' for kolonne '%-.192s' in tabellen '%-.192s'"
- nla "%-.16s commando geweigerd voor gebruiker: '%-.48s'@'%-.64s' voor kolom '%-.192s' in tabel '%-.192s'"
- eng "%-.16s command denied to user '%-.48s'@'%-.64s' for column '%-.192s' in table '%-.192s'"
- jps "ƒRƒ}ƒ“ƒh %-.16s ‚Í ƒ†[ƒU[ '%-.48s'@'%-.64s'\n ƒJƒ‰ƒ€ '%-.192s' ƒe[ƒuƒ‹ '%-.192s' ‚ɑ΂µ‚Ä‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "%-.16s käsk ei ole lubatud kasutajale '%-.48s'@'%-.64s' tulbale '%-.192s' tabelis '%-.192s'"
- fre "La commande '%-.16s' est interdite à l'utilisateur: '%-.48s'@'@%-.64s' sur la colonne '%-.192s' de la table '%-.192s'"
- ger "%-.16s Befehl nicht erlaubt für Benutzer '%-.48s'@'%-.64s' und Feld '%-.192s' in Tabelle '%-.192s'"
- hun "%-.16s parancs a '%-.48s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.192s' mezo eseten a '%-.192s' tablaban"
- ita "Comando %-.16s negato per l'utente: '%-.48s'@'%-.64s' sulla colonna '%-.192s' della tabella '%-.192s'"
- jpn "¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.48s'@'%-.64s'\n ¥«¥é¥à '%-.192s' ¥Æ¡¼¥Ö¥ë '%-.192s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.48s'@'%-.64s' for Ä®·³ '%-.192s' in Å×À̺í '%-.192s'"
- por "Comando '%-.16s' negado para o usuário '%-.48s'@'%-.64s' na coluna '%-.192s', na tabela '%-.192s'"
- rum "Comanda %-.16s interzisa utilizatorului: '%-.48s'@'%-.64s' pentru coloana '%-.192s' in tabela '%-.192s'"
- rus "ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.48s'@'%-.64s' ÄÌÑ ÓÔÏÌÂÃÁ '%-.192s' × ÔÁÂÌÉÃÅ '%-.192s'"
- serbian "%-.16s komanda zabranjena za korisnika '%-.48s'@'%-.64s' za kolonu '%-.192s' iz tabele '%-.192s'"
- spa "%-.16s comando negado para usuario: '%-.48s'@'%-.64s' para columna '%-.192s' en la tabla '%-.192s'"
- swe "%-.16s ej tillåtet för '%-.48s'@'%-.64s' för kolumn '%-.192s' i tabell '%-.192s'"
- ukr "%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.48s'@'%-.64s' ÄÌÑ ÓÔÏ×ÂÃÑ '%-.192s' Õ ÔÁÂÌÉæ '%-.192s'"
-ER_ILLEGAL_GRANT_FOR_TABLE 42000
- cze "Neplatn-Bý pøíkaz GRANT/REVOKE. Prosím, pøeètìte si v manuálu, jaká privilegia je mo¾né pou¾ít."
- dan "Forkert GRANT/REVOKE kommando. Se i brugervejledningen hvilke privilegier der kan specificeres."
- nla "Foutief GRANT/REVOKE commando. Raadpleeg de handleiding welke priveleges gebruikt kunnen worden."
- eng "Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used"
- est "Vigane GRANT/REVOKE käsk. Tutvu kasutajajuhendiga"
- fre "Commande GRANT/REVOKE incorrecte. Consultez le manuel."
- ger "Unzulässiger GRANT- oder REVOKE-Befehl. Verfügbare Berechtigungen sind im Handbuch aufgeführt"
- greek "Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used."
- hun "Ervenytelen GRANT/REVOKE parancs. Kerem, nezze meg a kezikonyvben, milyen jogok lehetsegesek"
- ita "Comando GRANT/REVOKE illegale. Prego consultare il manuale per sapere quali privilegi possono essere usati."
- jpn "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
- kor "À߸øµÈ GRANT/REVOKE ¸í·É. ¾î¶² ±Ç¸®¿Í ½ÂÀÎÀÌ »ç¿ëµÇ¾î Áú ¼ö ÀÖ´ÂÁö ¸Þ´º¾óÀ» º¸½Ã¿À."
- nor "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
- norwegian-ny "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
- pol "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
- por "Comando GRANT/REVOKE ilegal. Por favor consulte no manual quais privilégios podem ser usados."
- rum "Comanda GRANT/REVOKE ilegala. Consultati manualul in privinta privilegiilor ce pot fi folosite."
- rus "îÅ×ÅÒÎÁÑ ËÏÍÁÎÄÁ GRANT ÉÌÉ REVOKE. ïÂÒÁÔÉÔÅÓØ Ë ÄÏËÕÍÅÎÔÁÃÉÉ, ÞÔÏÂÙ ×ÙÑÓÎÉÔØ, ËÁËÉÅ ÐÒÉ×ÉÌÅÇÉÉ ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ"
- serbian "Pogrešna 'GRANT' odnosno 'REVOKE' komanda. Molim Vas pogledajte u priruèniku koje vrednosti mogu biti upotrebljene."
- slo "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
- spa "Ilegal comando GRANT/REVOKE. Por favor consulte el manual para cuales permisos pueden ser usados."
- swe "Felaktigt GRANT-privilegium använt"
- ukr "èÉÂÎÁ GRANT/REVOKE ËÏÍÁÎÄÁ; ÐÒÏÞÉÔÁÊÔÅ ÄÏËÕÍÅÎÔÁæÀ ÓÔÏÓÏ×ÎÏ ÔÏÇÏ, Ñ˦ ÐÒÁ×Á ÍÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ"
-ER_GRANT_WRONG_HOST_OR_USER 42000
- cze "Argument p-Bøíkazu GRANT u¾ivatel nebo stroj je pøíli¹ dlouhý"
- dan "Værts- eller brugernavn for langt til GRANT"
- nla "De host of gebruiker parameter voor GRANT is te lang"
- eng "The host or user argument to GRANT is too long"
- est "Masina või kasutaja nimi GRANT lauses on liiga pikk"
- fre "L'hôte ou l'utilisateur donné en argument à GRANT est trop long"
- ger "Das Host- oder User-Argument für GRANT ist zu lang"
- hun "A host vagy felhasznalo argumentuma tul hosszu a GRANT parancsban"
- ita "L'argomento host o utente per la GRANT e` troppo lungo"
- kor "½ÂÀÎ(GRANT)À» À§ÇÏ¿© »ç¿ëÇÑ »ç¿ëÀÚ³ª È£½ºÆ®ÀÇ °ªµéÀÌ ³Ê¹« ±é´Ï´Ù."
- por "Argumento de 'host' ou de usuário para o GRANT é longo demais"
- rum "Argumentul host-ului sau utilizatorului pentru GRANT e prea lung"
- rus "óÌÉÛËÏÍ ÄÌÉÎÎÏÅ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ/ÈÏÓÔÁ ÄÌÑ GRANT"
- serbian "Argument 'host' ili 'korisnik' prosleðen komandi 'GRANT' je predugaèak"
- spa "El argumento para servidor o usuario para GRANT es demasiado grande"
- swe "Felaktigt maskinnamn eller användarnamn använt med GRANT"
- ukr "áÒÇÕÍÅÎÔ host ÁÂÏ user ÄÌÑ GRANT ÚÁÄÏ×ÇÉÊ"
-ER_NO_SUCH_TABLE 42S02
- cze "Tabulka '%-.192s.%-.192s' neexistuje"
- dan "Tabellen '%-.192s.%-.192s' eksisterer ikke"
- nla "Tabel '%-.192s.%-.192s' bestaat niet"
- eng "Table '%-.192s.%-.192s' doesn't exist"
- est "Tabelit '%-.192s.%-.192s' ei eksisteeri"
- fre "La table '%-.192s.%-.192s' n'existe pas"
- ger "Tabelle '%-.192s.%-.192s' existiert nicht"
- hun "A '%-.192s.%-.192s' tabla nem letezik"
- ita "La tabella '%-.192s.%-.192s' non esiste"
- jpn "Table '%-.192s.%-.192s' doesn't exist"
- kor "Å×À̺í '%-.192s.%-.192s' ´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
- nor "Table '%-.192s.%-.192s' doesn't exist"
- norwegian-ny "Table '%-.192s.%-.192s' doesn't exist"
- pol "Table '%-.192s.%-.192s' doesn't exist"
- por "Tabela '%-.192s.%-.192s' não existe"
- rum "Tabela '%-.192s.%-.192s' nu exista"
- rus "ôÁÂÌÉÃÁ '%-.192s.%-.192s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Tabela '%-.192s.%-.192s' ne postoji"
- slo "Table '%-.192s.%-.192s' doesn't exist"
- spa "Tabla '%-.192s.%-.192s' no existe"
- swe "Det finns ingen tabell som heter '%-.192s.%-.192s'"
- ukr "ôÁÂÌÉÃÑ '%-.192s.%-.192s' ÎÅ ¦ÓÎÕ¤"
-ER_NONEXISTING_TABLE_GRANT 42000
- cze "Neexistuje odpov-Bídající grant pro u¾ivatele '%-.48s' na stroji '%-.64s' pro tabulku '%-.192s'"
- dan "Denne tilladelse eksisterer ikke for brugeren '%-.48s' på vært '%-.64s' for tabellen '%-.192s'"
- nla "Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.48s' op host '%-.64s' op tabel '%-.192s'"
- eng "There is no such grant defined for user '%-.48s' on host '%-.64s' on table '%-.192s'"
- est "Sellist õigust ei ole defineeritud kasutajale '%-.48s' masinast '%-.64s' tabelile '%-.192s'"
- fre "Un tel droit n'est pas défini pour l'utilisateur '%-.48s' sur l'hôte '%-.64s' sur la table '%-.192s'"
- ger "Eine solche Berechtigung ist für User '%-.48s' auf Host '%-.64s' an Tabelle '%-.192s' nicht definiert"
- hun "A '%-.48s' felhasznalo szamara a '%-.64s' host '%-.192s' tablajaban ez a parancs nem engedelyezett"
- ita "GRANT non definita per l'utente '%-.48s' dalla macchina '%-.64s' sulla tabella '%-.192s'"
- kor "»ç¿ëÀÚ '%-.48s'(È£½ºÆ® '%-.64s')´Â Å×À̺í '%-.192s'¸¦ »ç¿ëÇϱâ À§ÇÏ¿© Á¤ÀÇµÈ ½ÂÀÎÀº ¾ø½À´Ï´Ù. "
- por "Não existe tal permissão (grant) definido para o usuário '%-.48s' no 'host' '%-.64s', na tabela '%-.192s'"
- rum "Nu exista un astfel de privilegiu (grant) definit pentru utilizatorul '%-.48s' de pe host-ul '%-.64s' pentru tabela '%-.192s'"
- rus "ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s' ÎÁ ËÏÍÐØÀÔÅÒÅ '%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.192s'"
- serbian "Ne postoji odobrenje za pristup korisniku '%-.48s' na host-u '%-.64s' tabeli '%-.192s'"
- spa "No existe tal permiso definido para usuario '%-.48s' en el servidor '%-.64s' en la tabla '%-.192s'"
- swe "Det finns inget privilegium definierat för användare '%-.48s' på '%-.64s' för tabell '%-.192s'"
- ukr "ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.48s' Ú ÈÏÓÔÕ '%-.64s' ÄÌÑ ÔÁÂÌÉæ '%-.192s'"
-ER_NOT_ALLOWED_COMMAND 42000
- cze "Pou-B¾itý pøíkaz není v této verzi MySQL povolen"
- dan "Den brugte kommando er ikke tilladt med denne udgave af MySQL"
- nla "Het used commando is niet toegestaan in deze MySQL versie"
- eng "The used command is not allowed with this MySQL version"
- est "Antud käsk ei ole lubatud käesolevas MySQL versioonis"
- fre "Cette commande n'existe pas dans cette version de MySQL"
- ger "Der verwendete Befehl ist in dieser MySQL-Version nicht zulässig"
- hun "A hasznalt parancs nem engedelyezett ebben a MySQL verzioban"
- ita "Il comando utilizzato non e` supportato in questa versione di MySQL"
- kor "»ç¿ëµÈ ¸í·ÉÀº ÇöÀçÀÇ MySQL ¹öÁ¯¿¡¼­´Â ÀÌ¿ëµÇÁö ¾Ê½À´Ï´Ù."
- por "Comando usado não é permitido para esta versão do MySQL"
- rum "Comanda folosita nu este permisa pentru aceasta versiune de MySQL"
- rus "üÔÁ ËÏÍÁÎÄÁ ÎÅ ÄÏÐÕÓËÁÅÔÓÑ × ÄÁÎÎÏÊ ×ÅÒÓÉÉ MySQL"
- serbian "Upotrebljena komanda nije dozvoljena sa ovom verzijom MySQL servera"
- spa "El comando usado no es permitido con esta versión de MySQL"
- swe "Du kan inte använda detta kommando med denna MySQL version"
- ukr "÷ÉËÏÒÉÓÔÏ×Õ×ÁÎÁ ËÏÍÁÎÄÁ ÎÅ ÄÏÚ×ÏÌÅÎÁ Õ Ã¦Ê ×ÅÒÓ¦§ MySQL"
-ER_SYNTAX_ERROR 42000
- cze "Va-B¹e syntaxe je nìjaká divná"
- dan "Der er en fejl i SQL syntaksen"
- nla "Er is iets fout in de gebruikte syntax"
- eng "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use"
- est "Viga SQL süntaksis"
- fre "Erreur de syntaxe"
- ger "Fehler in der SQL-Syntax. Bitte die korrekte Syntax im Handbuch nachschlagen"
- greek "You have an error in your SQL syntax"
- hun "Szintaktikai hiba"
- ita "Errore di sintassi nella query SQL"
- jpn "Something is wrong in your syntax"
- kor "SQL ±¸¹®¿¡ ¿À·ù°¡ ÀÖ½À´Ï´Ù."
- nor "Something is wrong in your syntax"
- norwegian-ny "Something is wrong in your syntax"
- pol "Something is wrong in your syntax"
- por "Você tem um erro de sintaxe no seu SQL"
- rum "Aveti o eroare in sintaxa RSQL"
- rus "õ ×ÁÓ ÏÛÉÂËÁ × ÚÁÐÒÏÓÅ. éÚÕÞÉÔÅ ÄÏËÕÍÅÎÔÁÃÉÀ ÐÏ ÉÓÐÏÌØÚÕÅÍÏÊ ×ÅÒÓÉÉ MySQL ÎÁ ÐÒÅÄÍÅÔ ËÏÒÒÅËÔÎÏÇÏ ÓÉÎÔÁËÓÉÓÁ"
- serbian "Imate grešku u vašoj SQL sintaksi"
- slo "Something is wrong in your syntax"
- spa "Algo está equivocado en su sintax"
- swe "Du har något fel i din syntax"
- ukr "õ ×ÁÓ ÐÏÍÉÌËÁ Õ ÓÉÎÔÁËÓÉÓ¦ SQL"
-ER_DELAYED_CANT_CHANGE_LOCK
- cze "Zpo-B¾dìný insert threadu nebyl schopen získat po¾adovaný zámek pro tabulku %-.192s"
- dan "Forsinket indsættelse tråden (delayed insert thread) kunne ikke opnå lås på tabellen %-.192s"
- nla "'Delayed insert' thread kon de aangevraagde 'lock' niet krijgen voor tabel %-.192s"
- eng "Delayed insert thread couldn't get requested lock for table %-.192s"
- est "INSERT DELAYED lõim ei suutnud saada soovitud lukku tabelile %-.192s"
- fre "La tâche 'delayed insert' n'a pas pu obtenir le verrou démandé sur la table %-.192s"
- ger "Verzögerter (DELAYED) Einfüge-Thread konnte die angeforderte Sperre für Tabelle '%-.192s' nicht erhalten"
- hun "A kesleltetett beillesztes (delayed insert) thread nem kapott zatolast a %-.192s tablahoz"
- ita "Il thread di inserimento ritardato non riesce ad ottenere il lock per la tabella %-.192s"
- kor "Áö¿¬µÈ insert ¾²·¹µå°¡ Å×À̺í %-.192sÀÇ ¿ä±¸µÈ ¶ôÅ·À» ó¸®ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù."
- por "'Thread' de inserção retardada (atrasada) pois não conseguiu obter a trava solicitada para tabela '%-.192s'"
- rum "Thread-ul pentru inserarea aminata nu a putut obtine lacatul (lock) pentru tabela %-.192s"
- rus "ðÏÔÏË, ÏÂÓÌÕÖÉ×ÁÀÝÉÊ ÏÔÌÏÖÅÎÎÕÀ ×ÓÔÁ×ËÕ (delayed insert), ÎÅ ÓÍÏÇ ÐÏÌÕÞÉÔØ ÚÁÐÒÁÛÉ×ÁÅÍÕÀ ÂÌÏËÉÒÏ×ËÕ ÎÁ ÔÁÂÌÉÃÕ %-.192s"
- serbian "Prolongirani 'INSERT' thread nije mogao da dobije traženo zakljuèavanje tabele '%-.192s'"
- spa "Thread de inserción retarda no pudiendo bloquear para la tabla %-.192s"
- swe "DELAYED INSERT-tråden kunde inte låsa tabell '%-.192s'"
- ukr "ç¦ÌËÁ ÄÌÑ INSERT DELAYED ÎÅ ÍÏÖÅ ÏÔÒÉÍÁÔÉ ÂÌÏËÕ×ÁÎÎÑ ÄÌÑ ÔÁÂÌÉæ %-.192s"
-ER_TOO_MANY_DELAYED_THREADS
- cze "P-Bøíli¹ mnoho zpo¾dìných threadù"
- dan "For mange slettede tråde (threads) i brug"
- nla "Te veel 'delayed' threads in gebruik"
- eng "Too many delayed threads in use"
- est "Liiga palju DELAYED lõimesid kasutusel"
- fre "Trop de tâche 'delayed' en cours"
- ger "Zu viele verzögerte (DELAYED) Threads in Verwendung"
- hun "Tul sok kesletetett thread (delayed)"
- ita "Troppi threads ritardati in uso"
- kor "³Ê¹« ¸¹Àº Áö¿¬ ¾²·¹µå¸¦ »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù."
- por "Excesso de 'threads' retardadas (atrasadas) em uso"
- rum "Prea multe threaduri aminate care sint in uz"
- rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÐÏÔÏËÏ×, ÏÂÓÌÕÖÉ×ÁÀÝÉÈ ÏÔÌÏÖÅÎÎÕÀ ×ÓÔÁ×ËÕ (delayed insert)"
- serbian "Previše prolongiranih thread-ova je u upotrebi"
- spa "Muchos threads retardados en uso"
- swe "Det finns redan 'max_delayed_threads' trådar i använding"
- ukr "úÁÂÁÇÁÔÏ ÚÁÔÒÉÍÁÎÉÈ Ç¦ÌÏË ×ÉËÏÒÉÓÔÏ×Õ¤ÔØÓÑ"
-ER_ABORTING_CONNECTION 08S01
- cze "Zru-B¹eno spojení %ld do databáze: '%-.192s' u¾ivatel: '%-.48s' (%-.64s)"
- dan "Afbrudt forbindelse %ld til database: '%-.192s' bruger: '%-.48s' (%-.64s)"
- nla "Afgebroken verbinding %ld naar db: '%-.192s' gebruiker: '%-.48s' (%-.64s)"
- eng "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
- est "Ühendus katkestatud %ld andmebaasile: '%-.192s' kasutajale: '%-.48s' (%-.64s)"
- fre "Connection %ld avortée vers la bd: '%-.192s' utilisateur: '%-.48s' (%-.64s)"
- ger "Abbruch der Verbindung %ld zur Datenbank '%-.192s'. Benutzer: '%-.48s' (%-.64s)"
- hun "Megszakitott kapcsolat %ld db: '%-.192s' adatbazishoz, felhasznalo: '%-.48s' (%-.64s)"
- ita "Interrotta la connessione %ld al db: '%-.192s' utente: '%-.48s' (%-.64s)"
- jpn "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
- kor "µ¥ÀÌŸº£À̽º Á¢¼ÓÀ» À§ÇÑ ¿¬°á %ld°¡ Áß´ÜµÊ : '%-.192s' »ç¿ëÀÚ: '%-.48s' (%-.64s)"
- nor "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
- norwegian-ny "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
- pol "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
- por "Conexão %ld abortou para o banco de dados '%-.192s' - usuário '%-.48s' (%-.64s)"
- rum "Conectie terminata %ld la baza de date: '%-.192s' utilizator: '%-.48s' (%-.64s)"
- rus "ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.192s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s' (%-.64s)"
- serbian "Prekinuta konekcija broj %ld ka bazi: '%-.192s' korisnik je bio: '%-.48s' (%-.64s)"
- slo "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
- spa "Conexión abortada %ld para db: '%-.192s' usuario: '%-.48s' (%-.64s)"
- swe "Avbröt länken för tråd %ld till db '%-.192s', användare '%-.48s' (%-.64s)"
- ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.192s' ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s' (%-.64s)"
-ER_NET_PACKET_TOO_LARGE 08S01
- cze "Zji-B¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'"
- dan "Modtog en datapakke som var større end 'max_allowed_packet'"
- nla "Groter pakket ontvangen dan 'max_allowed_packet'"
- eng "Got a packet bigger than 'max_allowed_packet' bytes"
- est "Saabus suurem pakett kui lubatud 'max_allowed_packet' muutujaga"
- fre "Paquet plus grand que 'max_allowed_packet' reçu"
- ger "Empfangenes Paket ist größer als 'max_allowed_packet' Bytes"
- hun "A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'max_allowed_packet'"
- ita "Ricevuto un pacchetto piu` grande di 'max_allowed_packet'"
- kor "'max_allowed_packet'º¸´Ù ´õÅ« ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù."
- por "Obteve um pacote maior do que a taxa máxima de pacotes definida (max_allowed_packet)"
- rum "Un packet mai mare decit 'max_allowed_packet' a fost primit"
- rus "ðÏÌÕÞÅÎÎÙÊ ÐÁËÅÔ ÂÏÌØÛÅ, ÞÅÍ 'max_allowed_packet'"
- serbian "Primio sam mrežni paket veæi od definisane vrednosti 'max_allowed_packet'"
- spa "Obtenido un paquete mayor que 'max_allowed_packet'"
- swe "Kommunkationspaketet är större än 'max_allowed_packet'"
- ukr "ïÔÒÉÍÁÎÏ ÐÁËÅÔ Â¦ÌØÛÉÊ Î¦Ö max_allowed_packet"
-ER_NET_READ_ERROR_FROM_PIPE 08S01
- cze "Zji-B¹tìna chyba pøi ètení z roury spojení"
- dan "Fik læsefejl fra forbindelse (connection pipe)"
- nla "Kreeg leesfout van de verbindings pipe"
- eng "Got a read error from the connection pipe"
- est "Viga ühendustoru lugemisel"
- fre "Erreur de lecture reçue du pipe de connexion"
- ger "Lese-Fehler bei einer Verbindungs-Pipe"
- hun "Olvasasi hiba a kapcsolat soran"
- ita "Rilevato un errore di lettura dalla pipe di connessione"
- kor "¿¬°á ÆÄÀÌÇÁ·ÎºÎÅÍ ¿¡·¯°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù."
- por "Obteve um erro de leitura no 'pipe' da conexão"
- rum "Eroare la citire din cauza lui 'connection pipe'"
- rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ ÞÔÅÎÉÑ ÏÔ ÐÏÔÏËÁ ÓÏÅÄÉÎÅÎÉÑ (connection pipe)"
- serbian "Greška pri èitanju podataka sa pipe-a"
- spa "Obtenido un error de lectura de la conexión pipe"
- swe "Fick läsfel från klienten vid läsning från 'PIPE'"
- ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ ÞÉÔÁÎÎÑ Ú ËÏÍÕΦËÁæÊÎÏÇÏ ËÁÎÁÌÕ"
-ER_NET_FCNTL_ERROR 08S01
- cze "Zji-B¹tìna chyba fcntl()"
- dan "Fik fejlmeddelelse fra fcntl()"
- nla "Kreeg fout van fcntl()"
- eng "Got an error from fcntl()"
- est "fcntl() tagastas vea"
- fre "Erreur reçue de fcntl() "
- ger "fcntl() lieferte einen Fehler"
- hun "Hiba a fcntl() fuggvenyben"
- ita "Rilevato un errore da fcntl()"
- kor "fcntl() ÇÔ¼ö·ÎºÎÅÍ ¿¡·¯°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù."
- por "Obteve um erro em fcntl()"
- rum "Eroare obtinuta de la fcntl()"
- rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ ÏÔ fcntl()"
- serbian "Greška pri izvršavanju funkcije fcntl()"
- spa "Obtenido un error de fcntl()"
- swe "Fick fatalt fel från 'fcntl()'"
- ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËËÕ ×¦Ä fcntl()"
-ER_NET_PACKETS_OUT_OF_ORDER 08S01
- cze "P-Bøíchozí packety v chybném poøadí"
- dan "Modtog ikke datapakker i korrekt rækkefølge"
- nla "Pakketten in verkeerde volgorde ontvangen"
- eng "Got packets out of order"
- est "Paketid saabusid vales järjekorras"
- fre "Paquets reçus dans le désordre"
- ger "Pakete nicht in der richtigen Reihenfolge empfangen"
- hun "Helytelen sorrendben erkezett adatcsomagok"
- ita "Ricevuti pacchetti non in ordine"
- kor "¼ø¼­°¡ ¸ÂÁö¾Ê´Â ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù."
- por "Obteve pacotes fora de ordem"
- rum "Packets care nu sint ordonati au fost gasiti"
- rus "ðÁËÅÔÙ ÐÏÌÕÞÅÎÙ × ÎÅ×ÅÒÎÏÍ ÐÏÒÑÄËÅ"
- serbian "Primio sam mrežne pakete van reda"
- spa "Obtenido paquetes desordenados"
- swe "Kommunikationspaketen kom i fel ordning"
- ukr "ïÔÒÉÍÁÎÏ ÐÁËÅÔÉ Õ ÎÅÎÁÌÅÖÎÏÍÕ ÐÏÒÑÄËÕ"
-ER_NET_UNCOMPRESS_ERROR 08S01
- cze "Nemohu rozkomprimovat komunika-Bèní packet"
- dan "Kunne ikke dekomprimere kommunikations-pakke (communication packet)"
- nla "Communicatiepakket kon niet worden gedecomprimeerd"
- eng "Couldn't uncompress communication packet"
- est "Viga andmepaketi lahtipakkimisel"
- fre "Impossible de décompresser le paquet reçu"
- ger "Kommunikationspaket lässt sich nicht entpacken"
- hun "A kommunikacios adatcsomagok nem tomorithetok ki"
- ita "Impossibile scompattare i pacchetti di comunicazione"
- kor "Åë½Å ÆÐŶÀÇ ¾ÐÃàÇØÁ¦¸¦ ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù."
- por "Não conseguiu descomprimir pacote de comunicação"
- rum "Nu s-a putut decompresa pachetul de comunicatie (communication packet)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÒÁÓÐÁËÏ×ÁÔØ ÐÁËÅÔ, ÐÏÌÕÞÅÎÎÙÊ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ"
- serbian "Ne mogu da dekompresujem mrežne pakete"
- spa "No puedo descomprimir paquetes de comunicación"
- swe "Kunde inte packa up kommunikationspaketet"
- ukr "îÅ ÍÏÖÕ ÄÅËÏÍÐÒÅÓÕ×ÁÔÉ ËÏÍÕΦËÁæÊÎÉÊ ÐÁËÅÔ"
-ER_NET_READ_ERROR 08S01
- cze "Zji-B¹tìna chyba pøi ètení komunikaèního packetu"
- dan "Fik fejlmeddelelse ved læsning af kommunikations-pakker (communication packets)"
- nla "Fout bij het lezen van communicatiepakketten"
- eng "Got an error reading communication packets"
- est "Viga andmepaketi lugemisel"
- fre "Erreur de lecture des paquets reçus"
- ger "Fehler beim Lesen eines Kommunikationspakets"
- hun "HIba a kommunikacios adatcsomagok olvasasa soran"
- ita "Rilevato un errore ricevendo i pacchetti di comunicazione"
- kor "Åë½Å ÆÐŶÀ» Àд Áß ¿À·ù°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù."
- por "Obteve um erro na leitura de pacotes de comunicação"
- rum "Eroare obtinuta citind pachetele de comunicatie (communication packets)"
- rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ × ÐÒÏÃÅÓÓÅ ÐÏÌÕÞÅÎÉÑ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ "
- serbian "Greška pri primanju mrežnih paketa"
- spa "Obtenido un error leyendo paquetes de comunicación"
- swe "Fick ett fel vid läsning från klienten"
- ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ ÞÉÔÁÎÎÑ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×"
-ER_NET_READ_INTERRUPTED 08S01
- cze "Zji-B¹tìn timeout pøi ètení komunikaèního packetu"
- dan "Timeout-fejl ved læsning af kommunukations-pakker (communication packets)"
- nla "Timeout bij het lezen van communicatiepakketten"
- eng "Got timeout reading communication packets"
- est "Kontrollaja ületamine andmepakettide lugemisel"
- fre "Timeout en lecture des paquets reçus"
- ger "Zeitüberschreitung beim Lesen eines Kommunikationspakets"
- hun "Idotullepes a kommunikacios adatcsomagok olvasasa soran"
- ita "Rilevato un timeout ricevendo i pacchetti di comunicazione"
- kor "Åë½Å ÆÐŶÀ» Àд Áß timeoutÀÌ ¹ß»ýÇÏ¿´½À´Ï´Ù."
- por "Obteve expiração de tempo (timeout) na leitura de pacotes de comunicação"
- rum "Timeout obtinut citind pachetele de comunicatie (communication packets)"
- rus "ðÏÌÕÞÅÎ ÔÁÊÍÁÕÔ ÏÖÉÄÁÎÉÑ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ "
- serbian "Vremenski limit za èitanje mrežnih paketa je istekao"
- spa "Obtenido timeout leyendo paquetes de comunicación"
- swe "Fick 'timeout' vid läsning från klienten"
- ukr "ïÔÒÉÍÁÎÏ ÚÁÔÒÉÍËÕ ÞÉÔÁÎÎÑ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×"
-ER_NET_ERROR_ON_WRITE 08S01
- cze "Zji-B¹tìna chyba pøi zápisu komunikaèního packetu"
- dan "Fik fejlmeddelelse ved skrivning af kommunukations-pakker (communication packets)"
- nla "Fout bij het schrijven van communicatiepakketten"
- eng "Got an error writing communication packets"
- est "Viga andmepaketi kirjutamisel"
- fre "Erreur d'écriture des paquets envoyés"
- ger "Fehler beim Schreiben eines Kommunikationspakets"
- hun "Hiba a kommunikacios csomagok irasa soran"
- ita "Rilevato un errore inviando i pacchetti di comunicazione"
- kor "Åë½Å ÆÐŶÀ» ±â·ÏÇÏ´Â Áß ¿À·ù°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù."
- por "Obteve um erro na escrita de pacotes de comunicação"
- rum "Eroare in scrierea pachetelor de comunicatie (communication packets)"
- rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ ÐÒÉ ÐÅÒÅÄÁÞÅ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ "
- serbian "Greška pri slanju mrežnih paketa"
- spa "Obtenido un error de escribiendo paquetes de comunicación"
- swe "Fick ett fel vid skrivning till klienten"
- ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ ÚÁÐÉÓÕ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×"
-ER_NET_WRITE_INTERRUPTED 08S01
- cze "Zji-B¹tìn timeout pøi zápisu komunikaèního packetu"
- dan "Timeout-fejl ved skrivning af kommunukations-pakker (communication packets)"
- nla "Timeout bij het schrijven van communicatiepakketten"
- eng "Got timeout writing communication packets"
- est "Kontrollaja ületamine andmepakettide kirjutamisel"
- fre "Timeout d'écriture des paquets envoyés"
- ger "Zeitüberschreitung beim Schreiben eines Kommunikationspakets"
- hun "Idotullepes a kommunikacios csomagok irasa soran"
- ita "Rilevato un timeout inviando i pacchetti di comunicazione"
- kor "Åë½Å ÆÐÆÂÀ» ±â·ÏÇÏ´Â Áß timeoutÀÌ ¹ß»ýÇÏ¿´½À´Ï´Ù."
- por "Obteve expiração de tempo ('timeout') na escrita de pacotes de comunicação"
- rum "Timeout obtinut scriind pachetele de comunicatie (communication packets)"
- rus "ðÏÌÕÞÅÎ ÔÁÊÍÁÕÔ × ÐÒÏÃÅÓÓÅ ÐÅÒÅÄÁÞÉ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ "
- serbian "Vremenski limit za slanje mrežnih paketa je istekao"
- spa "Obtenido timeout escribiendo paquetes de comunicación"
- swe "Fick 'timeout' vid skrivning till klienten"
- ukr "ïÔÒÉÍÁÎÏ ÚÁÔÒÉÍËÕ ÚÁÐÉÓÕ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×"
-ER_TOO_LONG_STRING 42000
- cze "V-Býsledný øetìzec je del¹í ne¾ 'max_allowed_packet'"
- dan "Strengen med resultater er større end 'max_allowed_packet'"
- nla "Resultaat string is langer dan 'max_allowed_packet'"
- eng "Result string is longer than 'max_allowed_packet' bytes"
- est "Tulemus on pikem kui lubatud 'max_allowed_packet' muutujaga"
- fre "La chaîne résultat est plus grande que 'max_allowed_packet'"
- ger "Ergebnis-String ist länger als 'max_allowed_packet' Bytes"
- hun "Ez eredmeny sztring nagyobb, mint a lehetseges maximum: 'max_allowed_packet'"
- ita "La stringa di risposta e` piu` lunga di 'max_allowed_packet'"
- por "'String' resultante é mais longa do que 'max_allowed_packet'"
- rum "Sirul rezultat este mai lung decit 'max_allowed_packet'"
- rus "òÅÚÕÌØÔÉÒÕÀÝÁÑ ÓÔÒÏËÁ ÂÏÌØÛÅ, ÞÅÍ 'max_allowed_packet'"
- serbian "Rezultujuèi string je duži nego što to dozvoljava parametar servera 'max_allowed_packet'"
- spa "La string resultante es mayor que max_allowed_packet"
- swe "Resultatsträngen är längre än max_allowed_packet"
- ukr "óÔÒÏËÁ ÒÅÚÕÌØÔÁÔÕ ÄÏ×ÛÁ Î¦Ö max_allowed_packet"
-ER_TABLE_CANT_HANDLE_BLOB 42000
- cze "Typ pou-B¾ité tabulky nepodporuje BLOB/TEXT sloupce"
- dan "Denne tabeltype understøtter ikke brug af BLOB og TEXT kolonner"
- nla "Het gebruikte tabel type ondersteunt geen BLOB/TEXT kolommen"
- eng "The used table type doesn't support BLOB/TEXT columns"
- est "Valitud tabelitüüp ei toeta BLOB/TEXT tüüpi välju"
- fre "Ce type de table ne supporte pas les colonnes BLOB/TEXT"
- ger "Der verwendete Tabellentyp unterstützt keine BLOB- und TEXT-Felder"
- hun "A hasznalt tabla tipus nem tamogatja a BLOB/TEXT mezoket"
- ita "Il tipo di tabella usata non supporta colonne di tipo BLOB/TEXT"
- por "Tipo de tabela usado não permite colunas BLOB/TEXT"
- rum "Tipul de tabela folosit nu suporta coloane de tip BLOB/TEXT"
- rus "éÓÐÏÌØÚÕÅÍÁÑ ÔÁÂÌÉÃÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÔÉÐÙ BLOB/TEXT"
- serbian "Iskorišteni tip tabele ne podržava kolone tipa 'BLOB' odnosno 'TEXT'"
- spa "El tipo de tabla usada no permite soporte para columnas BLOB/TEXT"
- swe "Den använda tabelltypen kan inte hantera BLOB/TEXT-kolumner"
- ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ BLOB/TEXT ÓÔÏ×Âæ"
-ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 42000
- cze "Typ pou-B¾ité tabulky nepodporuje AUTO_INCREMENT sloupce"
- dan "Denne tabeltype understøtter ikke brug af AUTO_INCREMENT kolonner"
- nla "Het gebruikte tabel type ondersteunt geen AUTO_INCREMENT kolommen"
- eng "The used table type doesn't support AUTO_INCREMENT columns"
- est "Valitud tabelitüüp ei toeta AUTO_INCREMENT tüüpi välju"
- fre "Ce type de table ne supporte pas les colonnes AUTO_INCREMENT"
- ger "Der verwendete Tabellentyp unterstützt keine AUTO_INCREMENT-Felder"
- hun "A hasznalt tabla tipus nem tamogatja az AUTO_INCREMENT tipusu mezoket"
- ita "Il tipo di tabella usata non supporta colonne di tipo AUTO_INCREMENT"
- por "Tipo de tabela usado não permite colunas AUTO_INCREMENT"
- rum "Tipul de tabela folosit nu suporta coloane de tip AUTO_INCREMENT"
- rus "éÓÐÏÌØÚÕÅÍÁÑ ÔÁÂÌÉÃÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ Á×ÔÏÉÎËÒÅÍÅÎÔÎÙÅ ÓÔÏÌÂÃÙ"
- serbian "Iskorišteni tip tabele ne podržava kolone tipa 'AUTO_INCREMENT'"
- spa "El tipo de tabla usada no permite soporte para columnas AUTO_INCREMENT"
- swe "Den använda tabelltypen kan inte hantera AUTO_INCREMENT-kolumner"
- ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ AUTO_INCREMENT ÓÔÏ×Âæ"
-ER_DELAYED_INSERT_TABLE_LOCKED
- cze "INSERT DELAYED nen-Bí mo¾no s tabulkou '%-.192s' pou¾ít, proto¾e je zamèená pomocí LOCK TABLES"
- dan "INSERT DELAYED kan ikke bruges med tabellen '%-.192s', fordi tabellen er låst med LOCK TABLES"
- nla "INSERT DELAYED kan niet worden gebruikt bij table '%-.192s', vanwege een 'lock met LOCK TABLES"
- eng "INSERT DELAYED can't be used with table '%-.192s' because it is locked with LOCK TABLES"
- est "INSERT DELAYED ei saa kasutada tabeli '%-.192s' peal, kuna see on lukustatud LOCK TABLES käsuga"
- fre "INSERT DELAYED ne peut être utilisé avec la table '%-.192s', car elle est verrouée avec LOCK TABLES"
- ger "INSERT DELAYED kann für Tabelle '%-.192s' nicht verwendet werden, da sie mit LOCK TABLES gesperrt ist"
- greek "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
- hun "Az INSERT DELAYED nem hasznalhato a '%-.192s' tablahoz, mert a tabla zarolt (LOCK TABLES)"
- ita "L'inserimento ritardato (INSERT DELAYED) non puo` essere usato con la tabella '%-.192s', perche` soggetta a lock da 'LOCK TABLES'"
- jpn "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
- kor "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
- nor "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
- norwegian-ny "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
- pol "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
- por "INSERT DELAYED não pode ser usado com a tabela '%-.192s', porque ela está travada com LOCK TABLES"
- rum "INSERT DELAYED nu poate fi folosit cu tabela '%-.192s', deoarece este locked folosing LOCK TABLES"
- rus "îÅÌØÚÑ ÉÓÐÏÌØÚÏ×ÁÔØ INSERT DELAYED ÄÌÑ ÔÁÂÌÉÃÙ '%-.192s', ÐÏÔÏÍÕ ÞÔÏ ÏÎÁ ÚÁÂÌÏËÉÒÏ×ÁÎÁ Ó ÐÏÍÏÝØÀ LOCK TABLES"
- serbian "Komanda 'INSERT DELAYED' ne može biti iskorištena u tabeli '%-.192s', zbog toga što je zakljuèana komandom 'LOCK TABLES'"
- slo "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
- spa "INSERT DELAYED no puede ser usado con tablas '%-.192s', porque esta bloqueada con LOCK TABLES"
- swe "INSERT DELAYED kan inte användas med tabell '%-.192s', emedan den är låst med LOCK TABLES"
- ukr "INSERT DELAYED ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÏ Ú ÔÁÂÌÉÃÅÀ '%-.192s', ÔÏÍÕ ÝÏ §§ ÚÁÂÌÏËÏ×ÁÎÏ Ú LOCK TABLES"
-ER_WRONG_COLUMN_NAME 42000
- cze "Nespr-Bávné jméno sloupce '%-.100s'"
- dan "Forkert kolonnenavn '%-.100s'"
- nla "Incorrecte kolom naam '%-.100s'"
- eng "Incorrect column name '%-.100s'"
- est "Vigane tulba nimi '%-.100s'"
- fre "Nom de colonne '%-.100s' incorrect"
- ger "Falscher Spaltenname '%-.100s'"
- hun "Ervenytelen mezonev: '%-.100s'"
- ita "Nome colonna '%-.100s' non corretto"
- por "Nome de coluna '%-.100s' incorreto"
- rum "Nume increct de coloana '%-.100s'"
- rus "îÅ×ÅÒÎÏÅ ÉÍÑ ÓÔÏÌÂÃÁ '%-.100s'"
- serbian "Pogrešno ime kolone '%-.100s'"
- spa "Incorrecto nombre de columna '%-.100s'"
- swe "Felaktigt kolumnnamn '%-.100s'"
- ukr "îÅצÒÎÅ ¦Í'Ñ ÓÔÏ×ÂÃÑ '%-.100s'"
-ER_WRONG_KEY_COLUMN 42000
- cze "Handler pou-B¾ité tabulky neumí indexovat sloupce '%-.192s'"
- dan "Den brugte tabeltype kan ikke indeksere kolonnen '%-.192s'"
- nla "De gebruikte tabel 'handler' kan kolom '%-.192s' niet indexeren"
- eng "The used storage engine can't index column '%-.192s'"
- est "Tabelihandler ei oska indekseerida tulpa '%-.192s'"
- fre "Le handler de la table ne peut indexé la colonne '%-.192s'"
- ger "Die verwendete Speicher-Engine kann die Spalte '%-.192s' nicht indizieren"
- greek "The used table handler can't index column '%-.192s'"
- hun "A hasznalt tablakezelo nem tudja a '%-.192s' mezot indexelni"
- ita "Il gestore delle tabelle non puo` indicizzare la colonna '%-.192s'"
- jpn "The used table handler can't index column '%-.192s'"
- kor "The used table handler can't index column '%-.192s'"
- nor "The used table handler can't index column '%-.192s'"
- norwegian-ny "The used table handler can't index column '%-.192s'"
- pol "The used table handler can't index column '%-.192s'"
- por "O manipulador de tabela usado não pode indexar a coluna '%-.192s'"
- rum "Handler-ul tabelei folosite nu poate indexa coloana '%-.192s'"
- rus "éÓÐÏÌØÚÏ×ÁÎÎÙÊ ÏÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÍÏÖÅÔ ÐÒÏÉÎÄÅËÓÉÒÏ×ÁÔØ ÓÔÏÌÂÅà '%-.192s'"
- serbian "Handler tabele ne može da indeksira kolonu '%-.192s'"
- slo "The used table handler can't index column '%-.192s'"
- spa "El manipulador de tabla usado no puede indexar columna '%-.192s'"
- swe "Den använda tabelltypen kan inte indexera kolumn '%-.192s'"
- ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ×ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ÎÅ ÍÏÖÅ ¦ÎÄÅËÓÕ×ÁÔÉ ÓÔÏ×ÂÅÃØ '%-.192s'"
-ER_WRONG_MRG_TABLE
- cze "V-B¹echny tabulky v MERGE tabulce nejsou definovány stejnì"
- dan "Tabellerne i MERGE er ikke defineret ens"
- nla "Niet alle tabellen in de MERGE tabel hebben identieke gedefinities"
- eng "Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist"
- est "Kõik tabelid MERGE tabeli määratluses ei ole identsed"
- fre "Toutes les tables de la table de type MERGE n'ont pas la même définition"
- ger "Nicht alle Tabellen in der MERGE-Tabelle sind gleich definiert"
- hun "A MERGE tablaban talalhato tablak definicioja nem azonos"
- ita "Non tutte le tabelle nella tabella di MERGE sono definite in maniera identica"
- jpn "All tables in the MERGE table are not defined identically"
- kor "All tables in the MERGE table are not defined identically"
- nor "All tables in the MERGE table are not defined identically"
- norwegian-ny "All tables in the MERGE table are not defined identically"
- pol "All tables in the MERGE table are not defined identically"
- por "Todas as tabelas contidas na tabela fundida (MERGE) não estão definidas identicamente"
- rum "Toate tabelele din tabela MERGE nu sint definite identic"
- rus "îÅ ×ÓÅ ÔÁÂÌÉÃÙ × MERGE ÏÐÒÅÄÅÌÅÎÙ ÏÄÉÎÁËÏ×Ï"
- serbian "Tabele iskorištene u 'MERGE' tabeli nisu definisane na isti naèin"
- slo "All tables in the MERGE table are not defined identically"
- spa "Todas las tablas en la MERGE tabla no estan definidas identicamente"
- swe "Tabellerna i MERGE-tabellen är inte identiskt definierade"
- ukr "ôÁÂÌÉæ Õ MERGE TABLE ÍÁÀÔØ Ò¦ÚÎÕ ÓÔÒÕËÔÕÒÕ"
-ER_DUP_UNIQUE 23000
- cze "Kv-Bùli unique constraintu nemozu zapsat do tabulky '%-.192s'"
- dan "Kan ikke skrive til tabellen '%-.192s' fordi det vil bryde CONSTRAINT regler"
- nla "Kan niet opslaan naar table '%-.192s' vanwege 'unique' beperking"
- eng "Can't write, because of unique constraint, to table '%-.192s'"
- est "Ei suuda kirjutada tabelisse '%-.192s', kuna see rikub ühesuse kitsendust"
- fre "Écriture impossible à cause d'un index UNIQUE sur la table '%-.192s'"
- ger "Schreiben in Tabelle '%-.192s' nicht möglich wegen einer Eindeutigkeitsbeschränkung (unique constraint)"
- hun "A '%-.192s' nem irhato, az egyedi mezok miatt"
- ita "Impossibile scrivere nella tabella '%-.192s' per limitazione di unicita`"
- por "Não pode gravar, devido à restrição UNIQUE, na tabela '%-.192s'"
- rum "Nu pot scrie pe hard-drive, din cauza constraintului unic (unique constraint) pentru tabela '%-.192s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÐÉÓÁÔØ × ÔÁÂÌÉÃÕ '%-.192s' ÉÚ-ÚÁ ÏÇÒÁÎÉÞÅÎÉÊ ÕÎÉËÁÌØÎÏÇÏ ËÌÀÞÁ"
- serbian "Zbog provere jedinstvenosti ne mogu da upišem podatke u tabelu '%-.192s'"
- spa "No puedo escribir, debido al único constraint, para tabla '%-.192s'"
- swe "Kan inte skriva till tabell '%-.192s'; UNIQUE-test"
- ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ ÄÏ ÔÁÂÌÉæ '%-.192s', Ú ÐÒÉÞÉÎÉ ×ÉÍÏÇ ÕΦËÁÌØÎÏÓÔ¦"
-ER_BLOB_KEY_WITHOUT_LENGTH 42000
- cze "BLOB sloupec '%-.192s' je pou-B¾it ve specifikaci klíèe bez délky"
- dan "BLOB kolonnen '%-.192s' brugt i nøglespecifikation uden nøglelængde"
- nla "BLOB kolom '%-.192s' gebruikt in zoeksleutel specificatie zonder zoeksleutel lengte"
- eng "BLOB/TEXT column '%-.192s' used in key specification without a key length"
- est "BLOB-tüüpi tulp '%-.192s' on kasutusel võtmes ilma pikkust määratlemata"
- fre "La colonne '%-.192s' de type BLOB est utilisée dans une définition d'index sans longueur d'index"
- ger "BLOB- oder TEXT-Spalte '%-.192s' wird in der Schlüsseldefinition ohne Schlüssellängenangabe verwendet"
- greek "BLOB column '%-.192s' used in key specification without a key length"
- hun "BLOB mezo '%-.192s' hasznalt a mezo specifikacioban, a mezohossz megadasa nelkul"
- ita "La colonna '%-.192s' di tipo BLOB e` usata in una chiave senza specificarne la lunghezza"
- jpn "BLOB column '%-.192s' used in key specification without a key length"
- kor "BLOB column '%-.192s' used in key specification without a key length"
- nor "BLOB column '%-.192s' used in key specification without a key length"
- norwegian-ny "BLOB column '%-.192s' used in key specification without a key length"
- pol "BLOB column '%-.192s' used in key specification without a key length"
- por "Coluna BLOB '%-.192s' usada na especificação de chave sem o comprimento da chave"
- rum "Coloana BLOB '%-.192s' este folosita in specificarea unei chei fara ca o lungime de cheie sa fie folosita"
- rus "óÔÏÌÂÅÃ ÔÉÐÁ BLOB '%-.192s' ÂÙÌ ÕËÁÚÁÎ × ÏÐÒÅÄÅÌÅÎÉÉ ËÌÀÞÁ ÂÅÚ ÕËÁÚÁÎÉÑ ÄÌÉÎÙ ËÌÀÞÁ"
- serbian "BLOB kolona '%-.192s' je upotrebljena u specifikaciji kljuèa bez navoðenja dužine kljuèa"
- slo "BLOB column '%-.192s' used in key specification without a key length"
- spa "Columna BLOB column '%-.192s' usada en especificación de clave sin tamaño de la clave"
- swe "Du har inte angett någon nyckellängd för BLOB '%-.192s'"
- ukr "óÔÏ×ÂÅÃØ BLOB '%-.192s' ×ÉËÏÒÉÓÔÁÎÏ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ ÂÅÚ ×ËÁÚÁÎÎÑ ÄÏ×ÖÉÎÉ ËÌÀÞÁ"
-ER_PRIMARY_CANT_HAVE_NULL 42000
- cze "V-B¹echny èásti primárního klíèe musejí být NOT NULL; pokud potøebujete NULL, pou¾ijte UNIQUE"
- dan "Alle dele af en PRIMARY KEY skal være NOT NULL; Hvis du skal bruge NULL i nøglen, brug UNIQUE istedet"
- nla "Alle delen van een PRIMARY KEY moeten NOT NULL zijn; Indien u NULL in een zoeksleutel nodig heeft kunt u UNIQUE gebruiken"
- eng "All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead"
- est "Kõik PRIMARY KEY peavad olema määratletud NOT NULL piiranguga; vajadusel kasuta UNIQUE tüüpi võtit"
- fre "Toutes les parties d'un index PRIMARY KEY doivent être NOT NULL; Si vous avez besoin d'un NULL dans l'index, utilisez un index UNIQUE"
- ger "Alle Teile eines PRIMARY KEY müssen als NOT NULL definiert sein. Wenn NULL in einem Schlüssel benötigt wird, muss ein UNIQUE-Schlüssel verwendet werden"
- hun "Az elsodleges kulcs teljes egeszeben csak NOT NULL tipusu lehet; Ha NULL mezot szeretne a kulcskent, hasznalja inkabb a UNIQUE-ot"
- ita "Tutte le parti di una chiave primaria devono essere dichiarate NOT NULL; se necessitano valori NULL nelle chiavi utilizzare UNIQUE"
- por "Todas as partes de uma chave primária devem ser não-nulas. Se você precisou usar um valor nulo (NULL) em uma chave, use a cláusula UNIQUE em seu lugar"
- rum "Toate partile unei chei primare (PRIMARY KEY) trebuie sa fie NOT NULL; Daca aveti nevoie de NULL in vreo cheie, folositi UNIQUE in schimb"
- rus "÷ÓÅ ÞÁÓÔÉ ÐÅÒ×ÉÞÎÏÇÏ ËÌÀÞÁ (PRIMARY KEY) ÄÏÌÖÎÙ ÂÙÔØ ÏÐÒÅÄÅÌÅÎÙ ËÁË NOT NULL; åÓÌÉ ×ÁÍ ÎÕÖÎÁ ÐÏÄÄÅÒÖËÁ ×ÅÌÉÞÉÎ NULL × ËÌÀÞÅ, ×ÏÓÐÏÌØÚÕÊÔÅÓØ ÉÎÄÅËÓÏÍ UNIQUE"
- serbian "Svi delovi primarnog kljuèa moraju biti razlièiti od NULL; Ako Vam ipak treba NULL vrednost u kljuèu, upotrebite 'UNIQUE'"
- spa "Todas las partes de un PRIMARY KEY deben ser NOT NULL; Si necesitas NULL en una clave, use UNIQUE"
- swe "Alla delar av en PRIMARY KEY måste vara NOT NULL; Om du vill ha en nyckel med NULL, använd UNIQUE istället"
- ukr "õÓ¦ ÞÁÓÔÉÎÉ PRIMARY KEY ÐÏ×ÉÎΦ ÂÕÔÉ NOT NULL; ñËÝÏ ×É ÐÏÔÒÅÂÕ¤ÔÅ NULL Õ ËÌÀÞ¦, ÓËÏÒÉÓÔÁÊÔÅÓÑ UNIQUE"
-ER_TOO_MANY_ROWS 42000
- cze "V-Býsledek obsahuje více ne¾ jeden øádek"
- dan "Resultatet bestod af mere end een række"
- nla "Resultaat bevatte meer dan een rij"
- eng "Result consisted of more than one row"
- est "Tulemis oli rohkem kui üks kirje"
- fre "Le résultat contient plus d'un enregistrement"
- ger "Ergebnis besteht aus mehr als einer Zeile"
- hun "Az eredmeny tobb, mint egy sort tartalmaz"
- ita "Il risultato consiste di piu` di una riga"
- por "O resultado consistiu em mais do que uma linha"
- rum "Resultatul constista din mai multe linii"
- rus "÷ ÒÅÚÕÌØÔÁÔÅ ×ÏÚ×ÒÁÝÅÎÁ ÂÏÌÅÅ ÞÅÍ ÏÄÎÁ ÓÔÒÏËÁ"
- serbian "Rezultat je saèinjen od više slogova"
- spa "Resultado compuesto de mas que una línea"
- swe "Resultet bestod av mera än en rad"
- ukr "òÅÚÕÌØÔÁÔ ÚÎÁÈÏÄÉÔØÓÑ Õ Â¦ÌØÛÅ Î¦Ö ÏÄÎ¦Ê ÓÔÒÏæ"
-ER_REQUIRES_PRIMARY_KEY 42000
- cze "Tento typ tabulky vy-B¾aduje primární klíè"
- dan "Denne tabeltype kræver en primærnøgle"
- nla "Dit tabel type heeft een primaire zoeksleutel nodig"
- eng "This table type requires a primary key"
- est "Antud tabelitüüp nõuab primaarset võtit"
- fre "Ce type de table nécessite une clé primaire (PRIMARY KEY)"
- ger "Dieser Tabellentyp benötigt einen Primärschlüssel (PRIMARY KEY)"
- hun "Az adott tablatipushoz elsodleges kulcs hasznalata kotelezo"
- ita "Questo tipo di tabella richiede una chiave primaria"
- por "Este tipo de tabela requer uma chave primária"
- rum "Aceast tip de tabela are nevoie de o cheie primara"
- rus "üÔÏÔ ÔÉÐ ÔÁÂÌÉÃÙ ÔÒÅÂÕÅÔ ÏÐÒÅÄÅÌÅÎÉÑ ÐÅÒ×ÉÞÎÏÇÏ ËÌÀÞÁ"
- serbian "Ovaj tip tabele zahteva da imate definisan primarni kljuè"
- spa "Este tipo de tabla necesita de una primary key"
- swe "Denna tabelltyp kräver en PRIMARY KEY"
- ukr "ãÅÊ ÔÉÐ ÔÁÂÌÉæ ÐÏÔÒÅÂÕ¤ ÐÅÒ×ÉÎÎÏÇÏ ËÌÀÞÁ"
-ER_NO_RAID_COMPILED
- cze "Tato verze MySQL nen-Bí zkompilována s podporou RAID"
- dan "Denne udgave af MySQL er ikke oversat med understøttelse af RAID"
- nla "Deze versie van MySQL is niet gecompileerd met RAID ondersteuning"
- eng "This version of MySQL is not compiled with RAID support"
- est "Antud MySQL versioon on kompileeritud ilma RAID toeta"
- fre "Cette version de MySQL n'est pas compilée avec le support RAID"
- ger "Diese MySQL-Version ist nicht mit RAID-Unterstützung kompiliert"
- hun "Ezen leforditott MySQL verzio nem tartalmaz RAID support-ot"
- ita "Questa versione di MYSQL non e` compilata con il supporto RAID"
- por "Esta versão do MySQL não foi compilada com suporte a RAID"
- rum "Aceasta versiune de MySQL, nu a fost compilata cu suport pentru RAID"
- rus "üÔÁ ×ÅÒÓÉÑ MySQL ÓËÏÍÐÉÌÉÒÏ×ÁÎÁ ÂÅÚ ÐÏÄÄÅÒÖËÉ RAID"
- serbian "Ova verzija MySQL servera nije kompajlirana sa podrškom za RAID ureðaje"
- spa "Esta versión de MySQL no es compilada con soporte RAID"
- swe "Denna version av MySQL är inte kompilerad med RAID"
- ukr "ãÑ ×ÅÒÓ¦Ñ MySQL ÎÅ ÚËÏÍЦÌØÏ×ÁÎÁ Ú Ð¦ÄÔÒÉÍËÏÀ RAID"
-ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE
- cze "Update tabulky bez WHERE s kl-Bíèem není v módu bezpeèných update dovoleno"
- dan "Du bruger sikker opdaterings modus ('safe update mode') og du forsøgte at opdatere en tabel uden en WHERE klausul, der gør brug af et KEY felt"
- nla "U gebruikt 'safe update mode' en u probeerde een tabel te updaten zonder een WHERE met een KEY kolom"
- eng "You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column"
- est "Katse muuta tabelit turvalises rezhiimis ilma WHERE klauslita"
- fre "Vous êtes en mode 'safe update' et vous essayez de faire un UPDATE sans clause WHERE utilisant un index"
- ger "MySQL läuft im sicheren Aktualisierungsmodus (safe update mode). Sie haben versucht, eine Tabelle zu aktualisieren, ohne in der WHERE-Klausel ein KEY-Feld anzugeben"
- hun "On a biztonsagos update modot hasznalja, es WHERE that uses a KEY column"
- ita "In modalita` 'safe update' si e` cercato di aggiornare una tabella senza clausola WHERE su una chiave"
- por "Você está usando modo de atualização seguro e tentou atualizar uma tabela sem uma cláusula WHERE que use uma coluna chave"
- rus "÷Ù ÒÁÂÏÔÁÅÔÅ × ÒÅÖÉÍÅ ÂÅÚÏÐÁÓÎÙÈ ÏÂÎÏ×ÌÅÎÉÊ (safe update mode) É ÐÏÐÒÏÂÏ×ÁÌÉ ÉÚÍÅÎÉÔØ ÔÁÂÌÉÃÕ ÂÅÚ ÉÓÐÏÌØÚÏ×ÁÎÉÑ ËÌÀÞÅ×ÏÇÏ ÓÔÏÌÂÃÁ × ÞÁÓÔÉ WHERE"
- serbian "Vi koristite safe update mod servera, a probali ste da promenite podatke bez 'WHERE' komande koja koristi kolonu kljuèa"
- spa "Tu estás usando modo de actualización segura y tentado actualizar una tabla sin un WHERE que usa una KEY columna"
- swe "Du använder 'säker uppdateringsmod' och försökte uppdatera en tabell utan en WHERE-sats som använder sig av en nyckel"
- ukr "÷É Õ ÒÅÖÉͦ ÂÅÚÐÅÞÎÏÇÏ ÏÎÏ×ÌÅÎÎÑ ÔÁ ÎÁÍÁÇÁ¤ÔÅÓØ ÏÎÏ×ÉÔÉ ÔÁÂÌÉÃÀ ÂÅÚ ÏÐÅÒÁÔÏÒÁ WHERE, ÝÏ ×ÉËÏÒÉÓÔÏ×Õ¤ KEY ÓÔÏ×ÂÅÃØ"
-ER_KEY_DOES_NOT_EXITS 42000 S1009
- cze "Kl-Bíè '%-.192s' v tabulce '%-.192s' neexistuje"
- dan "Nøglen '%-.192s' eksisterer ikke i tabellen '%-.192s'"
- nla "Zoeksleutel '%-.192s' bestaat niet in tabel '%-.192s'"
- eng "Key '%-.192s' doesn't exist in table '%-.192s'"
- est "Võti '%-.192s' ei eksisteeri tabelis '%-.192s'"
- fre "L'index '%-.192s' n'existe pas sur la table '%-.192s'"
- ger "Schlüssel '%-.192s' existiert in der Tabelle '%-.192s' nicht"
- hun "A '%-.192s' kulcs nem letezik a '%-.192s' tablaban"
- ita "La chiave '%-.192s' non esiste nella tabella '%-.192s'"
- por "Chave '%-.192s' não existe na tabela '%-.192s'"
- rus "ëÌÀÞ '%-.192s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ × ÔÁÂÌÉÃÅ '%-.192s'"
- serbian "Kljuè '%-.192s' ne postoji u tabeli '%-.192s'"
- spa "Clave '%-.192s' no existe en la tabla '%-.192s'"
- swe "Nyckel '%-.192s' finns inte in tabell '%-.192s'"
- ukr "ëÌÀÞ '%-.192s' ÎÅ ¦ÓÎÕ¤ × ÔÁÂÌÉæ '%-.192s'"
-ER_CHECK_NO_SUCH_TABLE 42000
- cze "Nemohu otev-Bøít tabulku"
- dan "Kan ikke åbne tabellen"
- nla "Kan tabel niet openen"
- eng "Can't open table"
- est "Ei suuda avada tabelit"
- fre "Impossible d'ouvrir la table"
- ger "Kann Tabelle nicht öffnen"
- hun "Nem tudom megnyitni a tablat"
- ita "Impossibile aprire la tabella"
- por "Não pode abrir a tabela"
- rus "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ"
- serbian "Ne mogu da otvorim tabelu"
- spa "No puedo abrir tabla"
- swe "Kan inte öppna tabellen"
- ukr "îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÔÁÂÌÉÃÀ"
-ER_CHECK_NOT_IMPLEMENTED 42000
- cze "Handler tabulky nepodporuje %s"
- dan "Denne tabeltype understøtter ikke %s"
- nla "De 'handler' voor de tabel ondersteund geen %s"
- eng "The storage engine for the table doesn't support %s"
- est "Antud tabelitüüp ei toeta %s käske"
- fre "Ce type de table ne supporte pas les %s"
- ger "Die Speicher-Engine für diese Tabelle unterstützt kein %s"
- greek "The handler for the table doesn't support %s"
- hun "A tabla kezeloje (handler) nem tamogatja az %s"
- ita "Il gestore per la tabella non supporta il %s"
- jpn "The handler for the table doesn't support %s"
- kor "The handler for the table doesn't support %s"
- nor "The handler for the table doesn't support %s"
- norwegian-ny "The handler for the table doesn't support %s"
- pol "The handler for the table doesn't support %s"
- por "O manipulador de tabela não suporta %s"
- rum "The handler for the table doesn't support %s"
- rus "ïÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÜÔÏÇÏ: %s"
- serbian "Handler za ovu tabelu ne dozvoljava %s komande"
- slo "The handler for the table doesn't support %s"
- spa "El manipulador de la tabla no permite soporte para %s"
- swe "Tabellhanteraren för denna tabell kan inte göra %s"
- ukr "÷ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕÅ %s"
-ER_CANT_DO_THIS_DURING_AN_TRANSACTION 25000
- cze "Proveden-Bí tohoto pøíkazu není v transakci dovoleno"
- dan "Du må ikke bruge denne kommando i en transaktion"
- nla "Het is u niet toegestaan dit commando uit te voeren binnen een transactie"
- eng "You are not allowed to execute this command in a transaction"
- est "Seda käsku ei saa kasutada transaktsiooni sees"
- fre "Vous n'êtes pas autorisé à exécute cette commande dans une transaction"
- ger "Sie dürfen diesen Befehl nicht in einer Transaktion ausführen"
- hun "Az On szamara nem engedelyezett a parancs vegrehajtasa a tranzakcioban"
- ita "Non puoi eseguire questo comando in una transazione"
- por "Não lhe é permitido executar este comando em uma transação"
- rus "÷ÁÍ ÎÅ ÒÁÚÒÅÛÅÎÏ ×ÙÐÏÌÎÑÔØ ÜÔÕ ËÏÍÁÎÄÕ × ÔÒÁÎÚÁËÃÉÉ"
- serbian "Nije Vam dozvoljeno da izvršite ovu komandu u transakciji"
- spa "No tienes el permiso para ejecutar este comando en una transición"
- swe "Du får inte utföra detta kommando i en transaktion"
- ukr "÷ÁÍ ÎÅ ÄÏÚ×ÏÌÅÎÏ ×ÉËÏÎÕ×ÁÔÉ ÃÀ ËÏÍÁÎÄÕ × ÔÒÁÎÚÁËæ§"
-ER_ERROR_DURING_COMMIT
- cze "Chyba %d p-Bøi COMMIT"
- dan "Modtog fejl %d mens kommandoen COMMIT blev udført"
- nla "Kreeg fout %d tijdens COMMIT"
- eng "Got error %d during COMMIT"
- est "Viga %d käsu COMMIT täitmisel"
- fre "Erreur %d lors du COMMIT"
- ger "Fehler %d beim COMMIT"
- hun "%d hiba a COMMIT vegrehajtasa soran"
- ita "Rilevato l'errore %d durante il COMMIT"
- por "Obteve erro %d durante COMMIT"
- rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ COMMIT"
- serbian "Greška %d za vreme izvršavanja komande 'COMMIT'"
- spa "Obtenido error %d durante COMMIT"
- swe "Fick fel %d vid COMMIT"
- ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ COMMIT"
-ER_ERROR_DURING_ROLLBACK
- cze "Chyba %d p-Bøi ROLLBACK"
- dan "Modtog fejl %d mens kommandoen ROLLBACK blev udført"
- nla "Kreeg fout %d tijdens ROLLBACK"
- eng "Got error %d during ROLLBACK"
- est "Viga %d käsu ROLLBACK täitmisel"
- fre "Erreur %d lors du ROLLBACK"
- ger "Fehler %d beim ROLLBACK"
- hun "%d hiba a ROLLBACK vegrehajtasa soran"
- ita "Rilevato l'errore %d durante il ROLLBACK"
- por "Obteve erro %d durante ROLLBACK"
- rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ ROLLBACK"
- serbian "Greška %d za vreme izvršavanja komande 'ROLLBACK'"
- spa "Obtenido error %d durante ROLLBACK"
- swe "Fick fel %d vid ROLLBACK"
- ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ ROLLBACK"
-ER_ERROR_DURING_FLUSH_LOGS
- cze "Chyba %d p-Bøi FLUSH_LOGS"
- dan "Modtog fejl %d mens kommandoen FLUSH_LOGS blev udført"
- nla "Kreeg fout %d tijdens FLUSH_LOGS"
- eng "Got error %d during FLUSH_LOGS"
- est "Viga %d käsu FLUSH_LOGS täitmisel"
- fre "Erreur %d lors du FLUSH_LOGS"
- ger "Fehler %d bei FLUSH_LOGS"
- hun "%d hiba a FLUSH_LOGS vegrehajtasa soran"
- ita "Rilevato l'errore %d durante il FLUSH_LOGS"
- por "Obteve erro %d durante FLUSH_LOGS"
- rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ FLUSH_LOGS"
- serbian "Greška %d za vreme izvršavanja komande 'FLUSH_LOGS'"
- spa "Obtenido error %d durante FLUSH_LOGS"
- swe "Fick fel %d vid FLUSH_LOGS"
- ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ FLUSH_LOGS"
-ER_ERROR_DURING_CHECKPOINT
- cze "Chyba %d p-Bøi CHECKPOINT"
- dan "Modtog fejl %d mens kommandoen CHECKPOINT blev udført"
- nla "Kreeg fout %d tijdens CHECKPOINT"
- eng "Got error %d during CHECKPOINT"
- est "Viga %d käsu CHECKPOINT täitmisel"
- fre "Erreur %d lors du CHECKPOINT"
- ger "Fehler %d bei CHECKPOINT"
- hun "%d hiba a CHECKPOINT vegrehajtasa soran"
- ita "Rilevato l'errore %d durante il CHECKPOINT"
- por "Obteve erro %d durante CHECKPOINT"
- rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ CHECKPOINT"
- serbian "Greška %d za vreme izvršavanja komande 'CHECKPOINT'"
- spa "Obtenido error %d durante CHECKPOINT"
- swe "Fick fel %d vid CHECKPOINT"
- ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ CHECKPOINT"
-ER_NEW_ABORTING_CONNECTION 08S01
- cze "Spojen-Bí %ld do databáze: '%-.192s' u¾ivatel: '%-.48s' stroj: '%-.64s' (%-.64s) bylo pøeru¹eno"
- dan "Afbrød forbindelsen %ld til databasen '%-.192s' bruger: '%-.48s' vært: '%-.64s' (%-.64s)"
- nla "Afgebroken verbinding %ld naar db: '%-.192s' gebruiker: '%-.48s' host: '%-.64s' (%-.64s)"
- eng "Aborted connection %ld to db: '%-.192s' user: '%-.48s' host: '%-.64s' (%-.64s)"
- est "Ühendus katkestatud %ld andmebaas: '%-.192s' kasutaja: '%-.48s' masin: '%-.64s' (%-.64s)"
- fre "Connection %ld avortée vers la bd: '%-.192s' utilisateur: '%-.48s' hôte: '%-.64s' (%-.64s)"
- ger "Abbruch der Verbindung %ld zur Datenbank '%-.192s'. Benutzer: '%-.48s', Host: '%-.64s' (%-.64s)"
- ita "Interrotta la connessione %ld al db: ''%-.192s' utente: '%-.48s' host: '%-.64s' (%-.64s)"
- por "Conexão %ld abortada para banco de dados '%-.192s' - usuário '%-.48s' - 'host' '%-.64s' ('%-.64s')"
- rus "ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.192s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s' Ó ÈÏÓÔÁ '%-.64s' (%-.64s)"
- serbian "Prekinuta konekcija broj %ld ka bazi: '%-.192s' korisnik je bio: '%-.48s' a host: '%-.64s' (%-.64s)"
- spa "Abortada conexión %ld para db: '%-.192s' usuario: '%-.48s' servidor: '%-.64s' (%-.64s)"
- swe "Avbröt länken för tråd %ld till db '%-.192s', användare '%-.48s', host '%-.64s' (%-.64s)"
- ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.192s' ËÏÒÉÓÔÕ×ÁÞ: '%-.48s' ÈÏÓÔ: '%-.64s' (%-.64s)"
-ER_DUMP_NOT_IMPLEMENTED
- cze "Handler tabulky nepodporuje bin-Bární dump"
- dan "Denne tabeltype unserstøtter ikke binært tabeldump"
- nla "De 'handler' voor de tabel ondersteund geen binaire tabel dump"
- eng "The storage engine for the table does not support binary table dump"
- fre "Ce type de table ne supporte pas les copies binaires"
- ger "Die Speicher-Engine für die Tabelle unterstützt keinen binären Tabellen-Dump"
- ita "Il gestore per la tabella non supporta il dump binario"
- jpn "The handler for the table does not support binary table dump"
- por "O manipulador de tabela não suporta 'dump' binário de tabela"
- rum "The handler for the table does not support binary table dump"
- rus "ïÂÒÁÂÏÔÞÉË ÜÔÏÊ ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ Ä×ÏÉÞÎÏÇÏ ÓÏÈÒÁÎÅÎÉÑ ÏÂÒÁÚÁ ÔÁÂÌÉÃÙ (dump)"
- serbian "Handler tabele ne podržava binarni dump tabele"
- spa "El manipulador de tabla no soporta dump para tabla binaria"
- swe "Tabellhanteraren klarar inte en binär kopiering av tabellen"
- ukr "ãÅÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ ¦ÎÁÒÎÕ ÐÅÒÅÄÁÞÕ ÔÁÂÌÉæ"
-ER_FLUSH_MASTER_BINLOG_CLOSED
- eng "Binlog closed, cannot RESET MASTER"
- ger "Binlog geschlossen. Kann RESET MASTER nicht ausführen"
- por "Binlog fechado. Não pode fazer RESET MASTER"
- rus "ä×ÏÉÞÎÙÊ ÖÕÒÎÁÌ ÏÂÎÏ×ÌÅÎÉÑ ÚÁËÒÙÔ, ÎÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ RESET MASTER"
- serbian "Binarni log file zatvoren, ne mogu da izvršim komandu 'RESET MASTER'"
- ukr "òÅÐ̦ËÁæÊÎÉÊ ÌÏÇ ÚÁËÒÉÔÏ, ÎÅ ÍÏÖÕ ×ÉËÏÎÁÔÉ RESET MASTER"
-ER_INDEX_REBUILD
- cze "P-Bøebudování indexu dumpnuté tabulky '%-.192s' nebylo úspì¹né"
- dan "Kunne ikke genopbygge indekset for den dumpede tabel '%-.192s'"
- nla "Gefaald tijdens heropbouw index van gedumpte tabel '%-.192s'"
- eng "Failed rebuilding the index of dumped table '%-.192s'"
- fre "La reconstruction de l'index de la table copiée '%-.192s' a échoué"
- ger "Neuerstellung des Index der Dump-Tabelle '%-.192s' fehlgeschlagen"
- greek "Failed rebuilding the index of dumped table '%-.192s'"
- hun "Failed rebuilding the index of dumped table '%-.192s'"
- ita "Fallita la ricostruzione dell'indice della tabella copiata '%-.192s'"
- por "Falhou na reconstrução do índice da tabela 'dumped' '%-.192s'"
- rus "ïÛÉÂËÁ ÐÅÒÅÓÔÒÏÊËÉ ÉÎÄÅËÓÁ ÓÏÈÒÁÎÅÎÎÏÊ ÔÁÂÌÉÃÙ '%-.192s'"
- serbian "Izgradnja indeksa dump-ovane tabele '%-.192s' nije uspela"
- spa "Falla reconstruyendo el indice de la tabla dumped '%-.192s'"
- ukr "îÅ×ÄÁÌŠצÄÎÏ×ÌÅÎÎÑ ¦ÎÄÅËÓÁ ÐÅÒÅÄÁÎϧ ÔÁÂÌÉæ '%-.192s'"
-ER_MASTER
- cze "Chyba masteru: '%-.64s'"
- dan "Fejl fra master: '%-.64s'"
- nla "Fout van master: '%-.64s'"
- eng "Error from master: '%-.64s'"
- fre "Erreur reçue du maître: '%-.64s'"
- ger "Fehler vom Master: '%-.64s'"
- ita "Errore dal master: '%-.64s"
- por "Erro no 'master' '%-.64s'"
- rus "ïÛÉÂËÁ ÏÔ ÇÏÌÏ×ÎÏÇÏ ÓÅÒ×ÅÒÁ: '%-.64s'"
- serbian "Greška iz glavnog servera '%-.64s' u klasteru"
- spa "Error del master: '%-.64s'"
- swe "Fick en master: '%-.64s'"
- ukr "ðÏÍÉÌËÁ ×¦Ä ÇÏÌÏ×ÎÏÇÏ: '%-.64s'"
-ER_MASTER_NET_READ 08S01
- cze "S-Bí»ová chyba pøi ètení z masteru"
- dan "Netværksfejl ved læsning fra master"
- nla "Net fout tijdens lezen van master"
- eng "Net error reading from master"
- fre "Erreur de lecture réseau reçue du maître"
- ger "Netzfehler beim Lesen vom Master"
- ita "Errore di rete durante la ricezione dal master"
- por "Erro de rede lendo do 'master'"
- rus "÷ÏÚÎÉËÌÁ ÏÛÉÂËÁ ÞÔÅÎÉÑ × ÐÒÏÃÅÓÓÅ ËÏÍÍÕÎÉËÁÃÉÉ Ó ÇÏÌÏ×ÎÙÍ ÓÅÒ×ÅÒÏÍ"
- serbian "Greška u primanju mrežnih paketa sa glavnog servera u klasteru"
- spa "Error de red leyendo del master"
- swe "Fick nätverksfel vid läsning från master"
- ukr "íÅÒÅÖÅ×Á ÐÏÍÉÌËÁ ÞÉÔÁÎÎÑ ×¦Ä ÇÏÌÏ×ÎÏÇÏ"
-ER_MASTER_NET_WRITE 08S01
- cze "S-Bí»ová chyba pøi zápisu na master"
- dan "Netværksfejl ved skrivning til master"
- nla "Net fout tijdens schrijven naar master"
- eng "Net error writing to master"
- fre "Erreur d'écriture réseau reçue du maître"
- ger "Netzfehler beim Schreiben zum Master"
- ita "Errore di rete durante l'invio al master"
- por "Erro de rede gravando no 'master'"
- rus "÷ÏÚÎÉËÌÁ ÏÛÉÂËÁ ÚÁÐÉÓÉ × ÐÒÏÃÅÓÓÅ ËÏÍÍÕÎÉËÁÃÉÉ Ó ÇÏÌÏ×ÎÙÍ ÓÅÒ×ÅÒÏÍ"
- serbian "Greška u slanju mrežnih paketa na glavni server u klasteru"
- spa "Error de red escribiendo para el master"
- swe "Fick nätverksfel vid skrivning till master"
- ukr "íÅÒÅÖÅ×Á ÐÏÍÉÌËÁ ÚÁÐÉÓÕ ÄÏ ÇÏÌÏ×ÎÏÇÏ"
-ER_FT_MATCHING_KEY_NOT_FOUND
- cze "-B®ádný sloupec nemá vytvoøen fulltextový index"
- dan "Kan ikke finde en FULLTEXT nøgle som svarer til kolonne listen"
- nla "Kan geen FULLTEXT index vinden passend bij de kolom lijst"
- eng "Can't find FULLTEXT index matching the column list"
- est "Ei suutnud leida FULLTEXT indeksit, mis kattuks kasutatud tulpadega"
- fre "Impossible de trouver un index FULLTEXT correspondant à cette liste de colonnes"
- ger "Kann keinen FULLTEXT-Index finden, der der Feldliste entspricht"
- ita "Impossibile trovare un indice FULLTEXT che corrisponda all'elenco delle colonne"
- por "Não pode encontrar um índice para o texto todo que combine com a lista de colunas"
- rus "îÅ×ÏÚÍÏÖÎÏ ÏÔÙÓËÁÔØ ÐÏÌÎÏÔÅËÓÔÏ×ÙÊ (FULLTEXT) ÉÎÄÅËÓ, ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ÓÐÉÓËÕ ÓÔÏÌÂÃÏ×"
- serbian "Ne mogu da pronaðem 'FULLTEXT' indeks koli odgovara listi kolona"
- spa "No puedo encontrar índice FULLTEXT correspondiendo a la lista de columnas"
- swe "Hittar inte ett FULLTEXT-index i kolumnlistan"
- ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ FULLTEXT ¦ÎÄÅËÓ, ÝÏ ×¦ÄÐÏצÄÁ¤ ÐÅÒÅ̦ËÕ ÓÔÏ×Âæ×"
-ER_LOCK_OR_ACTIVE_TRANSACTION
- cze "Nemohu prov-Bést zadaný pøíkaz, proto¾e existují aktivní zamèené tabulky nebo aktivní transakce"
- dan "Kan ikke udføre den givne kommando fordi der findes aktive, låste tabeller eller fordi der udføres en transaktion"
- nla "Kan het gegeven commando niet uitvoeren, want u heeft actieve gelockte tabellen of een actieve transactie"
- eng "Can't execute the given command because you have active locked tables or an active transaction"
- est "Ei suuda täita antud käsku kuna on aktiivseid lukke või käimasolev transaktsioon"
- fre "Impossible d'exécuter la commande car vous avez des tables verrouillées ou une transaction active"
- ger "Kann den angegebenen Befehl wegen einer aktiven Tabellensperre oder einer aktiven Transaktion nicht ausführen"
- ita "Impossibile eseguire il comando richiesto: tabelle sotto lock o transazione in atto"
- por "Não pode executar o comando dado porque você tem tabelas ativas travadas ou uma transação ativa"
- rus "îÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ ÕËÁÚÁÎÎÕÀ ËÏÍÁÎÄÕ, ÐÏÓËÏÌØËÕ Õ ×ÁÓ ÐÒÉÓÕÔÓÔ×ÕÀÔ ÁËÔÉ×ÎÏ ÚÁÂÌÏËÉÒÏ×ÁÎÎÙÅ ÔÁÂÌÉÃÁ ÉÌÉ ÏÔËÒÙÔÁÑ ÔÒÁÎÚÁËÃÉÑ"
- serbian "Ne mogu da izvršim datu komandu zbog toga što su tabele zakljuèane ili je transakcija u toku"
- spa "No puedo ejecutar el comando dado porque tienes tablas bloqueadas o una transición activa"
- swe "Kan inte utföra kommandot emedan du har en låst tabell eller an aktiv transaktion"
- ukr "îÅ ÍÏÖÕ ×ÉËÏÎÁÔÉ ÐÏÄÁÎÕ ËÏÍÁÎÄÕ ÔÏÍÕ, ÝÏ ÔÁÂÌÉÃÑ ÚÁÂÌÏËÏ×ÁÎÁ ÁÂÏ ×ÉËÏÎÕ¤ÔØÓÑ ÔÒÁÎÚÁËæÑ"
-ER_UNKNOWN_SYSTEM_VARIABLE
- cze "Nezn-Bámá systémová promìnná '%-.64s'"
- dan "Ukendt systemvariabel '%-.64s'"
- nla "Onbekende systeem variabele '%-.64s'"
- eng "Unknown system variable '%-.64s'"
- est "Tundmatu süsteemne muutuja '%-.64s'"
- fre "Variable système '%-.64s' inconnue"
- ger "Unbekannte Systemvariable '%-.64s'"
- ita "Variabile di sistema '%-.64s' sconosciuta"
- por "Variável de sistema '%-.64s' desconhecida"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ÓÉÓÔÅÍÎÁÑ ÐÅÒÅÍÅÎÎÁÑ '%-.64s'"
- serbian "Nepoznata sistemska promenljiva '%-.64s'"
- spa "Desconocida variable de sistema '%-.64s'"
- swe "Okänd systemvariabel: '%-.64s'"
- ukr "îÅצÄÏÍÁ ÓÉÓÔÅÍÎÁ ÚͦÎÎÁ '%-.64s'"
-ER_CRASHED_ON_USAGE
- cze "Tabulka '%-.192s' je ozna-Bèena jako poru¹ená a mìla by být opravena"
- dan "Tabellen '%-.192s' er markeret med fejl og bør repareres"
- nla "Tabel '%-.192s' staat als gecrashed gemarkeerd en dient te worden gerepareerd"
- eng "Table '%-.192s' is marked as crashed and should be repaired"
- est "Tabel '%-.192s' on märgitud vigaseks ja tuleb parandada"
- fre "La table '%-.192s' est marquée 'crashed' et devrait être réparée"
- ger "Tabelle '%-.192s' ist als defekt markiert und sollte repariert werden"
- ita "La tabella '%-.192s' e` segnalata come corrotta e deve essere riparata"
- por "Tabela '%-.192s' está marcada como danificada e deve ser reparada"
- rus "ôÁÂÌÉÃÁ '%-.192s' ÐÏÍÅÞÅÎÁ ËÁË ÉÓÐÏÒÞÅÎÎÁÑ É ÄÏÌÖÎÁ ÐÒÏÊÔÉ ÐÒÏ×ÅÒËÕ É ÒÅÍÏÎÔ"
- serbian "Tabela '%-.192s' je markirana kao ošteæena i trebala bi biti popravljena"
- spa "Tabla '%-.192s' está marcada como crashed y debe ser reparada"
- swe "Tabell '%-.192s' är trasig och bör repareras med REPAIR TABLE"
- ukr "ôÁÂÌÉÃÀ '%-.192s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ §§ ÐÏÔÒ¦ÂÎÏ ×¦ÄÎÏ×ÉÔÉ"
-ER_CRASHED_ON_REPAIR
- cze "Tabulka '%-.192s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila"
- dan "Tabellen '%-.192s' er markeret med fejl og sidste (automatiske?) REPAIR fejlede"
- nla "Tabel '%-.192s' staat als gecrashed gemarkeerd en de laatste (automatische?) reparatie poging mislukte"
- eng "Table '%-.192s' is marked as crashed and last (automatic?) repair failed"
- est "Tabel '%-.192s' on märgitud vigaseks ja viimane (automaatne?) parandus ebaõnnestus"
- fre "La table '%-.192s' est marquée 'crashed' et le dernier 'repair' a échoué"
- ger "Tabelle '%-.192s' ist als defekt markiert und der letzte (automatische?) Reparaturversuch schlug fehl"
- ita "La tabella '%-.192s' e` segnalata come corrotta e l'ultima ricostruzione (automatica?) e` fallita"
- por "Tabela '%-.192s' está marcada como danificada e a última reparação (automática?) falhou"
- rus "ôÁÂÌÉÃÁ '%-.192s' ÐÏÍÅÞÅÎÁ ËÁË ÉÓÐÏÒÞÅÎÎÁÑ É ÐÏÓÌÅÄÎÉÊ (Á×ÔÏÍÁÔÉÞÅÓËÉÊ?) ÒÅÍÏÎÔ ÎÅ ÂÙÌ ÕÓÐÅÛÎÙÍ"
- serbian "Tabela '%-.192s' je markirana kao ošteæena, a zadnja (automatska?) popravka je bila neuspela"
- spa "Tabla '%-.192s' está marcada como crashed y la última reparación (automactica?) falló"
- swe "Tabell '%-.192s' är trasig och senast (automatiska?) reparation misslyckades"
- ukr "ôÁÂÌÉÃÀ '%-.192s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ ÏÓÔÁÎΤ (Á×ÔÏÍÁÔÉÞÎÅ?) צÄÎÏ×ÌÅÎÎÑ ÎÅ ×ÄÁÌÏÓÑ"
-ER_WARNING_NOT_COMPLETE_ROLLBACK
- dan "Advarsel: Visse data i tabeller der ikke understøtter transaktioner kunne ikke tilbagestilles"
- nla "Waarschuwing: Roll back mislukt voor sommige buiten transacties gewijzigde tabellen"
- eng "Some non-transactional changed tables couldn't be rolled back"
- est "Hoiatus: mõnesid transaktsioone mittetoetavaid tabeleid ei suudetud tagasi kerida"
- fre "Attention: certaines tables ne supportant pas les transactions ont été changées et elles ne pourront pas être restituées"
- ger "Änderungen an einigen nicht transaktionalen Tabellen konnten nicht zurückgerollt werden"
- ita "Attenzione: Alcune delle modifiche alle tabelle non transazionali non possono essere ripristinate (roll back impossibile)"
- por "Aviso: Algumas tabelas não-transacionais alteradas não puderam ser reconstituídas (rolled back)"
- rus "÷ÎÉÍÁÎÉÅ: ÐÏ ÎÅËÏÔÏÒÙÍ ÉÚÍÅÎÅÎÎÙÍ ÎÅÔÒÁÎÚÁËÃÉÏÎÎÙÍ ÔÁÂÌÉÃÁÍ ÎÅ×ÏÚÍÏÖÎÏ ÂÕÄÅÔ ÐÒÏÉÚ×ÅÓÔÉ ÏÔËÁÔ ÔÒÁÎÚÁËÃÉÉ"
- serbian "Upozorenje: Neke izmenjene tabele ne podržavaju komandu 'ROLLBACK'"
- spa "Aviso: Algunas tablas no transancionales no pueden tener rolled back"
- swe "Warning: Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK"
- ukr "úÁÓÔÅÒÅÖÅÎÎÑ: äÅÑ˦ ÎÅÔÒÁÎÚÁËæÊΦ ÚͦÎÉ ÔÁÂÌÉÃØ ÎÅ ÍÏÖÎÁ ÂÕÄÅ ÐÏ×ÅÒÎÕÔÉ"
-ER_TRANS_CACHE_FULL
- dan "Fler-udtryks transaktion krævede mere plads en 'max_binlog_cache_size' bytes. Forhøj værdien af denne variabel og prøv igen"
- nla "Multi-statement transactie vereist meer dan 'max_binlog_cache_size' bytes opslag. Verhoog deze mysqld variabele en probeer opnieuw"
- eng "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again"
- est "Mitme lausendiga transaktsioon nõudis rohkem ruumi kui lubatud 'max_binlog_cache_size' muutujaga. Suurenda muutuja väärtust ja proovi uuesti"
- fre "Cette transaction à commandes multiples nécessite plus de 'max_binlog_cache_size' octets de stockage, augmentez cette variable de mysqld et réessayez"
- ger "Transaktionen, die aus mehreren Befehlen bestehen, benötigten mehr als 'max_binlog_cache_size' Bytes an Speicher. Btte vergrössern Sie diese Server-Variable versuchen Sie es noch einmal"
- ita "La transazione a comandi multipli (multi-statement) ha richiesto piu` di 'max_binlog_cache_size' bytes di disco: aumentare questa variabile di mysqld e riprovare"
- por "Transações multi-declaradas (multi-statement transactions) requeriram mais do que o valor limite (max_binlog_cache_size) de bytes para armazenagem. Aumente o valor desta variável do mysqld e tente novamente"
- rus "ôÒÁÎÚÁËÃÉÉ, ×ËÌÀÞÁÀÝÅÊ ÂÏÌØÛÏÅ ËÏÌÉÞÅÓÔ×Ï ËÏÍÁÎÄ, ÐÏÔÒÅÂÏ×ÁÌÏÓØ ÂÏÌÅÅ ÞÅÍ 'max_binlog_cache_size' ÂÁÊÔ. õ×ÅÌÉÞØÔÅ ÜÔÕ ÐÅÒÅÍÅÎÎÕÀ ÓÅÒ×ÅÒÁ mysqld É ÐÏÐÒÏÂÕÊÔÅ ÅÝÅ ÒÁÚ"
- spa "Multipla transición necesita mas que 'max_binlog_cache_size' bytes de almacenamiento. Aumente esta variable mysqld y tente de nuevo"
- swe "Transaktionen krävde mera än 'max_binlog_cache_size' minne. Öka denna mysqld-variabel och försök på nytt"
- ukr "ôÒÁÎÚÁËÃ¦Ñ Ú ÂÁÇÁÔØÍÁ ×ÉÒÁÚÁÍÉ ×ÉÍÁÇÁ¤ ¦ÌØÛÅ Î¦Ö 'max_binlog_cache_size' ÂÁÊÔ¦× ÄÌÑ ÚÂÅÒ¦ÇÁÎÎÑ. ú¦ÌØÛÔÅ ÃÀ ÚͦÎÎÕ mysqld ÔÁ ÓÐÒÏÂÕÊÔÅ ÚÎÏ×Õ"
-ER_SLAVE_MUST_STOP
- dan "Denne handling kunne ikke udføres med kørende slave, brug først kommandoen STOP SLAVE"
- nla "Deze operatie kan niet worden uitgevoerd met een actieve slave, doe eerst STOP SLAVE"
- eng "This operation cannot be performed with a running slave; run STOP SLAVE first"
- fre "Cette opération ne peut être réalisée avec un esclave actif, faites STOP SLAVE d'abord"
- ger "Diese Operation kann bei einem aktiven Slave nicht durchgeführt werden. Bitte zuerst STOP SLAVE ausführen"
- ita "Questa operazione non puo' essere eseguita con un database 'slave' che gira, lanciare prima STOP SLAVE"
- por "Esta operação não pode ser realizada com um 'slave' em execução. Execute STOP SLAVE primeiro"
- rus "üÔÕ ÏÐÅÒÁÃÉÀ ÎÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ ÐÒÉ ÒÁÂÏÔÁÀÝÅÍ ÐÏÔÏËÅ ÐÏÄÞÉÎÅÎÎÏÇÏ ÓÅÒ×ÅÒÁ. óÎÁÞÁÌÁ ×ÙÐÏÌÎÉÔÅ STOP SLAVE"
- serbian "Ova operacija ne može biti izvršena dok je aktivan podreðeni server. Zadajte prvo komandu 'STOP SLAVE' da zaustavite podreðeni server."
- spa "Esta operación no puede ser hecha con el esclavo funcionando, primero use STOP SLAVE"
- swe "Denna operation kan inte göras under replikering; Gör STOP SLAVE först"
- ukr "ïÐÅÒÁÃ¦Ñ ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÎÁÎÁ Ú ÚÁÐÕÝÅÎÉÍ Ð¦ÄÌÅÇÌÉÍ, ÓÐÏÞÁÔËÕ ×ÉËÏÎÁÊÔÅ STOP SLAVE"
-ER_SLAVE_NOT_RUNNING
- dan "Denne handling kræver en kørende slave. Konfigurer en slave og brug kommandoen START SLAVE"
- nla "Deze operatie vereist een actieve slave, configureer slave en doe dan START SLAVE"
- eng "This operation requires a running slave; configure slave and do START SLAVE"
- fre "Cette opération nécessite un esclave actif, configurez les esclaves et faites START SLAVE"
- ger "Diese Operation benötigt einen aktiven Slave. Bitte Slave konfigurieren und mittels START SLAVE aktivieren"
- ita "Questa operaione richiede un database 'slave', configurarlo ed eseguire START SLAVE"
- por "Esta operação requer um 'slave' em execução. Configure o 'slave' e execute START SLAVE"
- rus "äÌÑ ÜÔÏÊ ÏÐÅÒÁÃÉÉ ÔÒÅÂÕÅÔÓÑ ÒÁÂÏÔÁÀÝÉÊ ÐÏÄÞÉÎÅÎÎÙÊ ÓÅÒ×ÅÒ. óÎÁÞÁÌÁ ×ÙÐÏÌÎÉÔÅ START SLAVE"
- serbian "Ova operacija zahteva da je aktivan podreðeni server. Konfigurišite prvo podreðeni server i onda izvršite komandu 'START SLAVE'"
- spa "Esta operación necesita el esclavo funcionando, configure esclavo y haga el START SLAVE"
- swe "Denna operation kan endast göras under replikering; Konfigurera slaven och gör START SLAVE"
- ukr "ïÐÅÒÁÃ¦Ñ ×ÉÍÁÇÁ¤ ÚÁÐÕÝÅÎÏÇÏ Ð¦ÄÌÅÇÌÏÇÏ, ÚËÏÎƦÇÕÒÕÊÔŠЦÄÌÅÇÌÏÇÏ ÔÁ ×ÉËÏÎÁÊÔÅ START SLAVE"
-ER_BAD_SLAVE
- dan "Denne server er ikke konfigureret som slave. Ret in config-filen eller brug kommandoen CHANGE MASTER TO"
- nla "De server is niet geconfigureerd als slave, fix in configuratie bestand of met CHANGE MASTER TO"
- eng "The server is not configured as slave; fix in config file or with CHANGE MASTER TO"
- fre "Le server n'est pas configuré comme un esclave, changez le fichier de configuration ou utilisez CHANGE MASTER TO"
- ger "Der Server ist nicht als Slave konfiguriert. Bitte in der Konfigurationsdatei oder mittels CHANGE MASTER TO beheben"
- ita "Il server non e' configurato come 'slave', correggere il file di configurazione cambiando CHANGE MASTER TO"
- por "O servidor não está configurado como 'slave'. Acerte o arquivo de configuração ou use CHANGE MASTER TO"
- rus "üÔÏÔ ÓÅÒ×ÅÒ ÎÅ ÎÁÓÔÒÏÅÎ ËÁË ÐÏÄÞÉÎÅÎÎÙÊ. ÷ÎÅÓÉÔÅ ÉÓÐÒÁ×ÌÅÎÉÑ × ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÍ ÆÁÊÌÅ ÉÌÉ Ó ÐÏÍÏÝØÀ CHANGE MASTER TO"
- serbian "Server nije konfigurisan kao podreðeni server, ispravite konfiguracioni file ili na njemu izvršite komandu 'CHANGE MASTER TO'"
- spa "El servidor no está configurado como esclavo, edite el archivo config file o con CHANGE MASTER TO"
- swe "Servern är inte konfigurerade som en replikationsslav. Ändra konfigurationsfilen eller gör CHANGE MASTER TO"
- ukr "óÅÒ×ÅÒ ÎÅ ÚËÏÎƦÇÕÒÏ×ÁÎÏ ÑË Ð¦ÄÌÅÇÌÉÊ, ×ÉÐÒÁ×ÔÅ ÃÅ Õ ÆÁÊ̦ ËÏÎƦÇÕÒÁæ§ ÁÂÏ Ú CHANGE MASTER TO"
-ER_MASTER_INFO
- eng "Could not initialize master info structure; more error messages can be found in the MySQL error log"
- fre "Impossible d'initialiser les structures d'information de maître, vous trouverez des messages d'erreur supplémentaires dans le journal des erreurs de MySQL"
- ger "Konnte Master-Info-Struktur nicht initialisieren. Weitere Fehlermeldungen können im MySQL-Error-Log eingesehen werden"
- serbian "Nisam mogao da inicijalizujem informacionu strukturu glavnog servera, proverite da li imam privilegije potrebne za pristup file-u 'master.info'"
- swe "Kunde inte initialisera replikationsstrukturerna. See MySQL fel fil för mera information"
-ER_SLAVE_THREAD
- dan "Kunne ikke danne en slave-tråd; check systemressourcerne"
- nla "Kon slave thread niet aanmaken, controleer systeem resources"
- eng "Could not create slave thread; check system resources"
- fre "Impossible de créer une tâche esclave, vérifiez les ressources système"
- ger "Konnte Slave-Thread nicht starten. Bitte System-Ressourcen überprüfen"
- ita "Impossibile creare il thread 'slave', controllare le risorse di sistema"
- por "Não conseguiu criar 'thread' de 'slave'. Verifique os recursos do sistema"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÐÏÔÏË ÐÏÄÞÉÎÅÎÎÏÇÏ ÓÅÒ×ÅÒÁ. ðÒÏ×ÅÒØÔÅ ÓÉÓÔÅÍÎÙÅ ÒÅÓÕÒÓÙ"
- serbian "Nisam mogao da startujem thread za podreðeni server, proverite sistemske resurse"
- spa "No puedo crear el thread esclavo, verifique recursos del sistema"
- swe "Kunde inte starta en tråd för replikering"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ Ð¦ÄÌÅÇÌÕ Ç¦ÌËÕ, ÐÅÒÅצÒÔÅ ÓÉÓÔÅÍΦ ÒÅÓÕÒÓÉ"
-ER_TOO_MANY_USER_CONNECTIONS 42000
- dan "Brugeren %-.64s har allerede mere end 'max_user_connections' aktive forbindelser"
- nla "Gebruiker %-.64s heeft reeds meer dan 'max_user_connections' actieve verbindingen"
- eng "User %-.64s already has more than 'max_user_connections' active connections"
- est "Kasutajal %-.64s on juba rohkem ühendusi kui lubatud 'max_user_connections' muutujaga"
- fre "L'utilisateur %-.64s possède déjà plus de 'max_user_connections' connexions actives"
- ger "Benutzer '%-.64s' hat mehr als 'max_user_connections' aktive Verbindungen"
- ita "L'utente %-.64s ha gia' piu' di 'max_user_connections' connessioni attive"
- por "Usuário '%-.64s' já possui mais que o valor máximo de conexões (max_user_connections) ativas"
- rus "õ ÐÏÌØÚÏ×ÁÔÅÌÑ %-.64s ÕÖÅ ÂÏÌØÛÅ ÞÅÍ 'max_user_connections' ÁËÔÉ×ÎÙÈ ÓÏÅÄÉÎÅÎÉÊ"
- serbian "Korisnik %-.64s veæ ima više aktivnih konekcija nego što je to odreðeno 'max_user_connections' promenljivom"
- spa "Usario %-.64s ya tiene mas que 'max_user_connections' conexiones activas"
- swe "Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar"
- ukr "ëÏÒÉÓÔÕ×ÁÞ %-.64s ×ÖÅ ÍÁ¤ ¦ÌØÛÅ Î¦Ö 'max_user_connections' ÁËÔÉ×ÎÉÈ Ú'¤ÄÎÁÎØ"
-ER_SET_CONSTANTS_ONLY
- dan "Du må kun bruge konstantudtryk med SET"
- nla "U mag alleen constante expressies gebruiken bij SET"
- eng "You may only use constant expressions with SET"
- est "Ainult konstantsed suurused on lubatud SET klauslis"
- fre "Seules les expressions constantes sont autorisées avec SET"
- ger "Bei SET dürfen nur konstante Ausdrücke verwendet werden"
- ita "Si possono usare solo espressioni costanti con SET"
- por "Você pode usar apenas expressões constantes com SET"
- rus "÷Ù ÍÏÖÅÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ × SET ÔÏÌØËÏ ËÏÎÓÔÁÎÔÎÙÅ ×ÙÒÁÖÅÎÉÑ"
- serbian "Možete upotrebiti samo konstantan iskaz sa komandom 'SET'"
- spa "Tu solo debes usar expresiones constantes con SET"
- swe "Man kan endast använda konstantuttryck med SET"
- ukr "íÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÌÉÛÅ ×ÉÒÁÚÉ Ú¦ ÓÔÁÌÉÍÉ Õ SET"
-ER_LOCK_WAIT_TIMEOUT
- dan "Lock wait timeout overskredet"
- nla "Lock wacht tijd overschreden"
- eng "Lock wait timeout exceeded; try restarting transaction"
- est "Kontrollaeg ületatud luku järel ootamisel; Proovi transaktsiooni otsast alata"
- fre "Timeout sur l'obtention du verrou"
- ger "Beim Warten auf eine Sperre wurde die zulässige Wartezeit überschritten. Bitte versuchen Sie, die Transaktion neu zu starten"
- ita "E' scaduto il timeout per l'attesa del lock"
- por "Tempo de espera (timeout) de travamento excedido. Tente reiniciar a transação."
- rus "ôÁÊÍÁÕÔ ÏÖÉÄÁÎÉÑ ÂÌÏËÉÒÏ×ËÉ ÉÓÔÅË; ÐÏÐÒÏÂÕÊÔÅ ÐÅÒÅÚÁÐÕÓÔÉÔØ ÔÒÁÎÚÁËÃÉÀ"
- serbian "Vremenski limit za zakljuèavanje tabele je istekao; Probajte da ponovo startujete transakciju"
- spa "Tiempo de bloqueo de espera excedido"
- swe "Fick inte ett lås i tid ; Försök att starta om transaktionen"
- ukr "úÁÔÒÉÍËÕ ÏÞ¦ËÕ×ÁÎÎÑ ÂÌÏËÕ×ÁÎÎÑ ×ÉÞÅÒÐÁÎÏ"
-ER_LOCK_TABLE_FULL
- dan "Det totale antal låse overstiger størrelsen på låse-tabellen"
- nla "Het totale aantal locks overschrijdt de lock tabel grootte"
- eng "The total number of locks exceeds the lock table size"
- est "Lukkude koguarv ületab lukutabeli suuruse"
- fre "Le nombre total de verrou dépasse la taille de la table des verrous"
- ger "Die Gesamtzahl der Sperren überschreitet die Größe der Sperrtabelle"
- ita "Il numero totale di lock e' maggiore della grandezza della tabella di lock"
- por "O número total de travamentos excede o tamanho da tabela de travamentos"
- rus "ïÂÝÅÅ ËÏÌÉÞÅÓÔ×Ï ÂÌÏËÉÒÏ×ÏË ÐÒÅ×ÙÓÉÌÏ ÒÁÚÍÅÒÙ ÔÁÂÌÉÃÙ ÂÌÏËÉÒÏ×ÏË"
- serbian "Broj totalnih zakljuèavanja tabele premašuje velièinu tabele zakljuèavanja"
- spa "El número total de bloqueos excede el tamaño de bloqueo de la tabla"
- swe "Antal lås överskrider antalet reserverade lås"
- ukr "úÁÇÁÌØÎÁ ˦ÌØ˦ÓÔØ ÂÌÏËÕ×ÁÎØ ÐÅÒÅ×ÉÝÉÌÁ ÒÏÚÍ¦Ò ÂÌÏËÕ×ÁÎØ ÄÌÑ ÔÁÂÌÉæ"
-ER_READ_ONLY_TRANSACTION 25000
- dan "Update lås kan ikke opnås under en READ UNCOMMITTED transaktion"
- nla "Update locks kunnen niet worden verkregen tijdens een READ UNCOMMITTED transactie"
- eng "Update locks cannot be acquired during a READ UNCOMMITTED transaction"
- est "Uuenduslukke ei saa kasutada READ UNCOMMITTED transaktsiooni käigus"
- fre "Un verrou en update ne peut être acquit pendant une transaction READ UNCOMMITTED"
- ger "Während einer READ-UNCOMMITTED-Transaktion können keine UPDATE-Sperren angefordert werden"
- ita "I lock di aggiornamento non possono essere acquisiti durante una transazione 'READ UNCOMMITTED'"
- por "Travamentos de atualização não podem ser obtidos durante uma transação de tipo READ UNCOMMITTED"
- rus "âÌÏËÉÒÏ×ËÉ ÏÂÎÏ×ÌÅÎÉÊ ÎÅÌØÚÑ ÐÏÌÕÞÉÔØ × ÐÒÏÃÅÓÓÅ ÞÔÅÎÉÑ ÎÅ ÐÒÉÎÑÔÏÊ (× ÒÅÖÉÍÅ READ UNCOMMITTED) ÔÒÁÎÚÁËÃÉÉ"
- serbian "Zakljuèavanja izmena ne mogu biti realizovana sve dok traje 'READ UNCOMMITTED' transakcija"
- spa "Bloqueos de actualización no pueden ser adqueridos durante una transición READ UNCOMMITTED"
- swe "Updateringslås kan inte göras när man använder READ UNCOMMITTED"
- ukr "ïÎÏ×ÉÔÉ ÂÌÏËÕ×ÁÎÎÑ ÎÅ ÍÏÖÌÉ×Ï ÎÁ ÐÒÏÔÑÚ¦ ÔÒÁÎÚÁËæ§ READ UNCOMMITTED"
-ER_DROP_DB_WITH_READ_LOCK
- dan "DROP DATABASE er ikke tilladt mens en tråd holder på globalt read lock"
- nla "DROP DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit"
- eng "DROP DATABASE not allowed while thread is holding global read lock"
- est "DROP DATABASE ei ole lubatud kui lõim omab globaalset READ lukku"
- fre "DROP DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture"
- ger "DROP DATABASE ist nicht erlaubt, solange der Thread eine globale Lesesperre hält"
- ita "DROP DATABASE non e' permesso mentre il thread ha un lock globale di lettura"
- por "DROP DATABASE não permitido enquanto uma 'thread' está mantendo um travamento global de leitura"
- rus "îÅ ÄÏÐÕÓËÁÅÔÓÑ DROP DATABASE, ÐÏËÁ ÐÏÔÏË ÄÅÒÖÉÔ ÇÌÏÂÁÌØÎÕÀ ÂÌÏËÉÒÏ×ËÕ ÞÔÅÎÉÑ"
- serbian "Komanda 'DROP DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka"
- spa "DROP DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global"
- swe "DROP DATABASE är inte tillåtet när man har ett globalt läslås"
- ukr "DROP DATABASE ÎÅ ÄÏÚ×ÏÌÅÎÏ ÄÏËÉ Ç¦ÌËÁ ÐÅÒÅÂÕ×Á¤ Ð¦Ä ÚÁÇÁÌØÎÉÍ ÂÌÏËÕ×ÁÎÎÑÍ ÞÉÔÁÎÎÑ"
-ER_CREATE_DB_WITH_READ_LOCK
- dan "CREATE DATABASE er ikke tilladt mens en tråd holder på globalt read lock"
- nla "CREATE DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit"
- eng "CREATE DATABASE not allowed while thread is holding global read lock"
- est "CREATE DATABASE ei ole lubatud kui lõim omab globaalset READ lukku"
- fre "CREATE DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture"
- ger "CREATE DATABASE ist nicht erlaubt, solange der Thread eine globale Lesesperre hält"
- ita "CREATE DATABASE non e' permesso mentre il thread ha un lock globale di lettura"
- por "CREATE DATABASE não permitido enquanto uma 'thread' está mantendo um travamento global de leitura"
- rus "îÅ ÄÏÐÕÓËÁÅÔÓÑ CREATE DATABASE, ÐÏËÁ ÐÏÔÏË ÄÅÒÖÉÔ ÇÌÏÂÁÌØÎÕÀ ÂÌÏËÉÒÏ×ËÕ ÞÔÅÎÉÑ"
- serbian "Komanda 'CREATE DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka"
- spa "CREATE DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global"
- swe "CREATE DATABASE är inte tillåtet när man har ett globalt läslås"
- ukr "CREATE DATABASE ÎÅ ÄÏÚ×ÏÌÅÎÏ ÄÏËÉ Ç¦ÌËÁ ÐÅÒÅÂÕ×Á¤ Ð¦Ä ÚÁÇÁÌØÎÉÍ ÂÌÏËÕ×ÁÎÎÑÍ ÞÉÔÁÎÎÑ"
-ER_WRONG_ARGUMENTS
- nla "Foutieve parameters voor %s"
- eng "Incorrect arguments to %s"
- est "Vigased parameetrid %s-le"
- fre "Mauvais arguments à %s"
- ger "Falsche Argumente für %s"
- ita "Argomenti errati a %s"
- por "Argumentos errados para %s"
- rus "îÅ×ÅÒÎÙÅ ÐÁÒÁÍÅÔÒÙ ÄÌÑ %s"
- serbian "Pogrešni argumenti prosleðeni na %s"
- spa "Argumentos errados para %s"
- swe "Felaktiga argument till %s"
- ukr "èÉÂÎÉÊ ÁÒÇÕÍÅÎÔ ÄÌÑ %s"
-ER_NO_PERMISSION_TO_CREATE_USER 42000
- nla "'%-.48s'@'%-.64s' mag geen nieuwe gebruikers creeren"
- eng "'%-.48s'@'%-.64s' is not allowed to create new users"
- est "Kasutajal '%-.48s'@'%-.64s' ei ole lubatud luua uusi kasutajaid"
- fre "'%-.48s'@'%-.64s' n'est pas autorisé à créer de nouveaux utilisateurs"
- ger "'%-.48s'@'%-.64s' ist nicht berechtigt, neue Benutzer hinzuzufügen"
- ita "A '%-.48s'@'%-.64s' non e' permesso creare nuovi utenti"
- por "Não é permitido a '%-.48s'@'%-.64s' criar novos usuários"
- rus "'%-.48s'@'%-.64s' ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÓÏÚÄÁ×ÁÔØ ÎÏ×ÙÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ"
- serbian "Korisniku '%-.48s'@'%-.64s' nije dozvoljeno da kreira nove korisnike"
- spa "'%-.48s`@`%-.64s` no es permitido para crear nuevos usuarios"
- swe "'%-.48s'@'%-.64s' har inte rättighet att skapa nya användare"
- ukr "ëÏÒÉÓÔÕ×ÁÞÕ '%-.48s'@'%-.64s' ÎÅ ÄÏÚ×ÏÌÅÎÏ ÓÔ×ÏÒÀ×ÁÔÉ ÎÏ×ÉÈ ËÏÒÉÓÔÕ×ÁÞ¦×"
-ER_UNION_TABLES_IN_DIFFERENT_DIR
- nla "Incorrecte tabel definitie; alle MERGE tabellen moeten tot dezelfde database behoren"
- eng "Incorrect table definition; all MERGE tables must be in the same database"
- est "Vigane tabelimääratlus; kõik MERGE tabeli liikmed peavad asuma samas andmebaasis"
- fre "Définition de table incorrecte; toutes les tables MERGE doivent être dans la même base de donnée"
- ger "Falsche Tabellendefinition. Alle MERGE-Tabellen müssen sich in derselben Datenbank befinden"
- ita "Definizione della tabella errata; tutte le tabelle di tipo MERGE devono essere nello stesso database"
- por "Definição incorreta da tabela. Todas as tabelas contidas na junção devem estar no mesmo banco de dados."
- rus "îÅ×ÅÒÎÏÅ ÏÐÒÅÄÅÌÅÎÉÅ ÔÁÂÌÉÃÙ; ÷ÓÅ ÔÁÂÌÉÃÙ × MERGE ÄÏÌÖÎÙ ÐÒÉÎÁÄÌÅÖÁÔØ ÏÄÎÏÊ É ÔÏÊ ÖÅ ÂÁÚÅ ÄÁÎÎÙÈ"
- serbian "Pogrešna definicija tabele; sve 'MERGE' tabele moraju biti u istoj bazi podataka"
- spa "Incorrecta definición de la tabla; Todas las tablas MERGE deben estar en el mismo banco de datos"
- swe "Felaktig tabelldefinition; alla tabeller i en MERGE-tabell måste vara i samma databas"
-ER_LOCK_DEADLOCK 40001
- nla "Deadlock gevonden tijdens lock-aanvraag poging; Probeer herstart van de transactie"
- eng "Deadlock found when trying to get lock; try restarting transaction"
- est "Lukustamisel tekkis tupik (deadlock); alusta transaktsiooni otsast"
- fre "Deadlock découvert en essayant d'obtenir les verrous : essayez de redémarrer la transaction"
- ger "Beim Versuch, eine Sperre anzufordern, ist ein Deadlock aufgetreten. Versuchen Sie, die Transaktion neu zu starten"
- ita "Trovato deadlock durante il lock; Provare a far ripartire la transazione"
- por "Encontrado um travamento fatal (deadlock) quando tentava obter uma trava. Tente reiniciar a transação."
- rus "÷ÏÚÎÉËÌÁ ÔÕÐÉËÏ×ÁÑ ÓÉÔÕÁÃÉÑ × ÐÒÏÃÅÓÓÅ ÐÏÌÕÞÅÎÉÑ ÂÌÏËÉÒÏ×ËÉ; ðÏÐÒÏÂÕÊÔÅ ÐÅÒÅÚÁÐÕÓÔÉÔØ ÔÒÁÎÚÁËÃÉÀ"
- serbian "Unakrsno zakljuèavanje pronaðeno kada sam pokušao da dobijem pravo na zakljuèavanje; Probajte da restartujete transakciju"
- spa "Encontrado deadlock cuando tentando obtener el bloqueo; Tente recomenzar la transición"
- swe "Fick 'DEADLOCK' vid låsförsök av block/rad. Försök att starta om transaktionen"
-ER_TABLE_CANT_HANDLE_FT
- nla "Het gebruikte tabel type ondersteund geen FULLTEXT indexen"
- eng "The used table type doesn't support FULLTEXT indexes"
- est "Antud tabelitüüp ei toeta FULLTEXT indekseid"
- fre "Le type de table utilisé ne supporte pas les index FULLTEXT"
- ger "Der verwendete Tabellentyp unterstützt keine FULLTEXT-Indizes"
- ita "La tabella usata non supporta gli indici FULLTEXT"
- por "O tipo de tabela utilizado não suporta índices de texto completo (fulltext indexes)"
- rus "éÓÐÏÌØÚÕÅÍÙÊ ÔÉÐ ÔÁÂÌÉà ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÏÌÎÏÔÅËÓÔÏ×ÙÈ ÉÎÄÅËÓÏ×"
- serbian "Upotrebljeni tip tabele ne podržava 'FULLTEXT' indekse"
- spa "El tipo de tabla usada no soporta índices FULLTEXT"
- swe "Tabelltypen har inte hantering av FULLTEXT-index"
- ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ FULLTEXT ¦ÎÄÅËÓ¦×"
-ER_CANNOT_ADD_FOREIGN
- nla "Kan foreign key beperking niet toevoegen"
- eng "Cannot add foreign key constraint"
- fre "Impossible d'ajouter des contraintes d'index externe"
- ger "Fremdschlüssel-Beschränkung kann nicht hinzugefügt werden"
- ita "Impossibile aggiungere il vincolo di integrita' referenziale (foreign key constraint)"
- por "Não pode acrescentar uma restrição de chave estrangeira"
- rus "îÅ×ÏÚÍÏÖÎÏ ÄÏÂÁ×ÉÔØ ÏÇÒÁÎÉÞÅÎÉÑ ×ÎÅÛÎÅÇÏ ËÌÀÞÁ"
- serbian "Ne mogu da dodam proveru spoljnog kljuèa"
- spa "No puede adicionar clave extranjera constraint"
- swe "Kan inte lägga till 'FOREIGN KEY constraint'"
-ER_NO_REFERENCED_ROW 23000
- nla "Kan onderliggende rij niet toevoegen: foreign key beperking gefaald"
- eng "Cannot add or update a child row: a foreign key constraint fails"
- fre "Impossible d'ajouter un enregistrement fils : une constrainte externe l'empèche"
- ger "Hinzufügen oder Aktualisieren eines Kind-Datensatzes schlug aufgrund einer Fremdschlüssel-Beschränkung fehl"
- greek "Cannot add a child row: a foreign key constraint fails"
- hun "Cannot add a child row: a foreign key constraint fails"
- ita "Impossibile aggiungere la riga: un vincolo d'integrita' referenziale non e' soddisfatto"
- norwegian-ny "Cannot add a child row: a foreign key constraint fails"
- por "Não pode acrescentar uma linha filha: uma restrição de chave estrangeira falhou"
- rus "îÅ×ÏÚÍÏÖÎÏ ÄÏÂÁ×ÉÔØ ÉÌÉ ÏÂÎÏ×ÉÔØ ÄÏÞÅÒÎÀÀ ÓÔÒÏËÕ: ÐÒÏ×ÅÒËÁ ÏÇÒÁÎÉÞÅÎÉÊ ×ÎÅÛÎÅÇÏ ËÌÀÞÁ ÎÅ ×ÙÐÏÌÎÑÅÔÓÑ"
- spa "No puede adicionar una línea hijo: falla de clave extranjera constraint"
- swe "FOREIGN KEY-konflikt: Kan inte skriva barn"
-ER_ROW_IS_REFERENCED 23000
- eng "Cannot delete or update a parent row: a foreign key constraint fails"
- fre "Impossible de supprimer un enregistrement père : une constrainte externe l'empèche"
- ger "Löschen oder Aktualisieren eines Eltern-Datensatzes schlug aufgrund einer Fremdschlüssel-Beschränkung fehl"
- greek "Cannot delete a parent row: a foreign key constraint fails"
- hun "Cannot delete a parent row: a foreign key constraint fails"
- ita "Impossibile cancellare la riga: un vincolo d'integrita' referenziale non e' soddisfatto"
- por "Não pode apagar uma linha pai: uma restrição de chave estrangeira falhou"
- rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÉÌÉ ÏÂÎÏ×ÉÔØ ÒÏÄÉÔÅÌØÓËÕÀ ÓÔÒÏËÕ: ÐÒÏ×ÅÒËÁ ÏÇÒÁÎÉÞÅÎÉÊ ×ÎÅÛÎÅÇÏ ËÌÀÞÁ ÎÅ ×ÙÐÏÌÎÑÅÔÓÑ"
- serbian "Ne mogu da izbrišem roditeljski slog: provera spoljnog kljuèa je neuspela"
- spa "No puede deletar una línea padre: falla de clave extranjera constraint"
- swe "FOREIGN KEY-konflikt: Kan inte radera fader"
-ER_CONNECT_TO_MASTER 08S01
- nla "Fout bij opbouwen verbinding naar master: %-.128s"
- eng "Error connecting to master: %-.128s"
- ger "Fehler bei der Verbindung zum Master: %-.128s"
- ita "Errore durante la connessione al master: %-.128s"
- por "Erro conectando com o master: %-.128s"
- rus "ïÛÉÂËÁ ÓÏÅÄÉÎÅÎÉÑ Ó ÇÏÌÏ×ÎÙÍ ÓÅÒ×ÅÒÏÍ: %-.128s"
- spa "Error de coneccion a master: %-.128s"
- swe "Fick fel vid anslutning till master: %-.128s"
-ER_QUERY_ON_MASTER
- nla "Fout bij uitvoeren query op master: %-.128s"
- eng "Error running query on master: %-.128s"
- ger "Beim Ausführen einer Abfrage auf dem Master trat ein Fehler auf: %-.128s"
- ita "Errore eseguendo una query sul master: %-.128s"
- por "Erro rodando consulta no master: %-.128s"
- rus "ïÛÉÂËÁ ×ÙÐÏÌÎÅÎÉÑ ÚÁÐÒÏÓÁ ÎÁ ÇÏÌÏ×ÎÏÍ ÓÅÒ×ÅÒÅ: %-.128s"
- spa "Error executando el query en master: %-.128s"
- swe "Fick fel vid utförande av command på mastern: %-.128s"
-ER_ERROR_WHEN_EXECUTING_COMMAND
- nla "Fout tijdens uitvoeren van commando %s: %-.128s"
- eng "Error when executing command %s: %-.128s"
- est "Viga käsu %s täitmisel: %-.128s"
- ger "Fehler beim Ausführen des Befehls %s: %-.128s"
- ita "Errore durante l'esecuzione del comando %s: %-.128s"
- por "Erro quando executando comando %s: %-.128s"
- rus "ïÛÉÂËÁ ÐÒÉ ×ÙÐÏÌÎÅÎÉÉ ËÏÍÁÎÄÙ %s: %-.128s"
- serbian "Greška pri izvršavanju komande %s: %-.128s"
- spa "Error de %s: %-.128s"
- swe "Fick fel vid utförande av %s: %-.128s"
-ER_WRONG_USAGE
- nla "Foutief gebruik van %s en %s"
- eng "Incorrect usage of %s and %s"
- est "Vigane %s ja %s kasutus"
- ger "Falsche Verwendung von %s und %s"
- ita "Uso errato di %s e %s"
- por "Uso errado de %s e %s"
- rus "îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ %s É %s"
- serbian "Pogrešna upotreba %s i %s"
- spa "Equivocado uso de %s y %s"
- swe "Felaktig använding av %s and %s"
- ukr "Wrong usage of %s and %s"
-ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 21000
- nla "De gebruikte SELECT commando's hebben een verschillend aantal kolommen"
- eng "The used SELECT statements have a different number of columns"
- est "Tulpade arv kasutatud SELECT lausetes ei kattu"
- ger "Die verwendeten SELECT-Befehle liefern unterschiedliche Anzahlen von Feldern zurück"
- ita "La SELECT utilizzata ha un numero di colonne differente"
- por "Os comandos SELECT usados têm diferente número de colunas"
- rus "éÓÐÏÌØÚÏ×ÁÎÎÙÅ ÏÐÅÒÁÔÏÒÙ ×ÙÂÏÒËÉ (SELECT) ÄÁÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×"
- serbian "Upotrebljene 'SELECT' komande adresiraju razlièit broj kolona"
- spa "El comando SELECT usado tiene diferente número de columnas"
- swe "SELECT-kommandona har olika antal kolumner"
-ER_CANT_UPDATE_WITH_READLOCK
- nla "Kan de query niet uitvoeren vanwege een conflicterende read lock"
- eng "Can't execute the query because you have a conflicting read lock"
- est "Ei suuda täita päringut konfliktse luku tõttu"
- ger "Augrund eines READ-LOCK-Konflikts kann die Abfrage nicht ausgeführt werden"
- ita "Impossibile eseguire la query perche' c'e' un conflitto con in lock di lettura"
- por "Não posso executar a consulta porque você tem um conflito de travamento de leitura"
- rus "îÅ×ÏÚÍÏÖÎÏ ÉÓÐÏÌÎÉÔØ ÚÁÐÒÏÓ, ÐÏÓËÏÌØËÕ Õ ×ÁÓ ÕÓÔÁÎÏ×ÌÅÎÙ ËÏÎÆÌÉËÔÕÀÝÉÅ ÂÌÏËÉÒÏ×ËÉ ÞÔÅÎÉÑ"
- serbian "Ne mogu da izvršim upit zbog toga što imate zakljuèavanja èitanja podataka u konfliktu"
- spa "No puedo ejecutar el query porque usted tiene conflicto de traba de lectura"
- swe "Kan inte utföra kommandot emedan du har ett READ-lås"
-ER_MIXING_NOT_ALLOWED
- nla "Het combineren van transactionele en niet-transactionele tabellen is uitgeschakeld."
- eng "Mixing of transactional and non-transactional tables is disabled"
- est "Transaktsioone toetavate ning mittetoetavate tabelite kooskasutamine ei ole lubatud"
- ger "Die gleichzeitige Verwendung von Tabellen mit und ohne Transaktionsunterstützung ist deaktiviert"
- ita "E' disabilitata la possibilita' di mischiare tabelle transazionali e non-transazionali"
- por "Mistura de tabelas transacional e não-transacional está desabilitada"
- rus "éÓÐÏÌØÚÏ×ÁÎÉÅ ÔÒÁÎÚÁËÃÉÏÎÎÙÈ ÔÁÂÌÉà ÎÁÒÑÄÕ Ó ÎÅÔÒÁÎÚÁËÃÉÏÎÎÙÍÉ ÚÁÐÒÅÝÅÎÏ"
- serbian "Mešanje tabela koje podržavaju transakcije i onih koje ne podržavaju transakcije je iskljuèeno"
- spa "Mezla de transancional y no-transancional tablas está deshabilitada"
- swe "Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat"
-ER_DUP_ARGUMENT
- nla "Optie '%s' tweemaal gebruikt in opdracht"
- eng "Option '%s' used twice in statement"
- est "Määrangut '%s' on lauses kasutatud topelt"
- ger "Option '%s' wird im Befehl zweimal verwendet"
- ita "L'opzione '%s' e' stata usata due volte nel comando"
- por "Opção '%s' usada duas vezes no comando"
- rus "ïÐÃÉÑ '%s' Ä×ÁÖÄÙ ÉÓÐÏÌØÚÏ×ÁÎÁ × ×ÙÒÁÖÅÎÉÉ"
- spa "Opción '%s' usada dos veces en el comando"
- swe "Option '%s' användes två gånger"
-ER_USER_LIMIT_REACHED 42000
- nla "Gebruiker '%-.64s' heeft het maximale gebruik van de '%s' faciliteit overschreden (huidige waarde: %ld)"
- eng "User '%-.64s' has exceeded the '%s' resource (current value: %ld)"
- ger "Benutzer '%-.64s' hat die Ressourcenbeschränkung '%s' überschritten (aktueller Wert: %ld)"
- ita "L'utente '%-.64s' ha ecceduto la risorsa '%s' (valore corrente: %ld)"
- por "Usuário '%-.64s' tem excedido o '%s' recurso (atual valor: %ld)"
- rus "ðÏÌØÚÏ×ÁÔÅÌØ '%-.64s' ÐÒÅ×ÙÓÉÌ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÒÅÓÕÒÓÁ '%s' (ÔÅËÕÝÅÅ ÚÎÁÞÅÎÉÅ: %ld)"
- spa "Usuario '%-.64s' ha excedido el recurso '%s' (actual valor: %ld)"
- swe "Användare '%-.64s' har överskridit '%s' (nuvarande värde: %ld)"
-ER_SPECIFIC_ACCESS_DENIED_ERROR 42000
- nla "Toegang geweigerd. U moet het %-.128s privilege hebben voor deze operatie"
- eng "Access denied; you need the %-.128s privilege for this operation"
- ger "Kein Zugriff. Hierfür wird die Berechtigung %-.128s benötigt"
- ita "Accesso non consentito. Serve il privilegio %-.128s per questa operazione"
- por "Acesso negado. Você precisa o privilégio %-.128s para essa operação"
- rus "÷ ÄÏÓÔÕÐÅ ÏÔËÁÚÁÎÏ. ÷ÁÍ ÎÕÖÎÙ ÐÒÉ×ÉÌÅÇÉÉ %-.128s ÄÌÑ ÜÔÏÊ ÏÐÅÒÁÃÉÉ"
- spa "Acceso negado. Usted necesita el privilegio %-.128s para esta operación"
- swe "Du har inte privlegiet '%-.128s' som behövs för denna operation"
- ukr "Access denied. You need the %-.128s privilege for this operation"
-ER_LOCAL_VARIABLE
- nla "Variabele '%-.64s' is SESSION en kan niet worden gebruikt met SET GLOBAL"
- eng "Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL"
- ger "Variable '%-.64s' ist eine lokale Variable und kann nicht mit SET GLOBAL verändert werden"
- ita "La variabile '%-.64s' e' una variabile locale ( SESSION ) e non puo' essere cambiata usando SET GLOBAL"
- por "Variável '%-.64s' é uma SESSION variável e não pode ser usada com SET GLOBAL"
- rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' Ñ×ÌÑÅÔÓÑ ÐÏÔÏËÏ×ÏÊ (SESSION) ÐÅÒÅÍÅÎÎÏÊ É ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÚÍÅÎÅÎÁ Ó ÐÏÍÏÝØÀ SET GLOBAL"
- spa "Variable '%-.64s' es una SESSION variable y no puede ser usada con SET GLOBAL"
- swe "Variabel '%-.64s' är en SESSION variabel och kan inte ändrad med SET GLOBAL"
-ER_GLOBAL_VARIABLE
- nla "Variabele '%-.64s' is GLOBAL en dient te worden gewijzigd met SET GLOBAL"
- eng "Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL"
- ger "Variable '%-.64s' ist eine globale Variable und muss mit SET GLOBAL verändert werden"
- ita "La variabile '%-.64s' e' una variabile globale ( GLOBAL ) e deve essere cambiata usando SET GLOBAL"
- por "Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL"
- rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' Ñ×ÌÑÅÔÓÑ ÇÌÏÂÁÌØÎÏÊ (GLOBAL) ÐÅÒÅÍÅÎÎÏÊ, É ÅÅ ÓÌÅÄÕÅÔ ÉÚÍÅÎÑÔØ Ó ÐÏÍÏÝØÀ SET GLOBAL"
- spa "Variable '%-.64s' es una GLOBAL variable y no puede ser configurada con SET GLOBAL"
- swe "Variabel '%-.64s' är en GLOBAL variabel och bör sättas med SET GLOBAL"
-ER_NO_DEFAULT 42000
- nla "Variabele '%-.64s' heeft geen standaard waarde"
- eng "Variable '%-.64s' doesn't have a default value"
- ger "Variable '%-.64s' hat keinen Vorgabewert"
- ita "La variabile '%-.64s' non ha un valore di default"
- por "Variável '%-.64s' não tem um valor padrão"
- rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÎÅ ÉÍÅÅÔ ÚÎÁÞÅÎÉÑ ÐÏ ÕÍÏÌÞÁÎÉÀ"
- spa "Variable '%-.64s' no tiene un valor patrón"
- swe "Variabel '%-.64s' har inte ett DEFAULT-värde"
-ER_WRONG_VALUE_FOR_VAR 42000
- nla "Variabele '%-.64s' kan niet worden gewijzigd naar de waarde '%-.200s'"
- eng "Variable '%-.64s' can't be set to the value of '%-.200s'"
- ger "Variable '%-.64s' kann nicht auf '%-.200s' gesetzt werden"
- ita "Alla variabile '%-.64s' non puo' essere assegato il valore '%-.200s'"
- por "Variável '%-.64s' não pode ser configurada para o valor de '%-.200s'"
- rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÕÓÔÁÎÏ×ÌÅÎÁ × ÚÎÁÞÅÎÉÅ '%-.200s'"
- spa "Variable '%-.64s' no puede ser configurada para el valor de '%-.200s'"
- swe "Variabel '%-.64s' kan inte sättas till '%-.200s'"
-ER_WRONG_TYPE_FOR_VAR 42000
- nla "Foutief argumenttype voor variabele '%-.64s'"
- eng "Incorrect argument type to variable '%-.64s'"
- ger "Falscher Argumenttyp für Variable '%-.64s'"
- ita "Tipo di valore errato per la variabile '%-.64s'"
- por "Tipo errado de argumento para variável '%-.64s'"
- rus "îÅ×ÅÒÎÙÊ ÔÉÐ ÁÒÇÕÍÅÎÔÁ ÄÌÑ ÐÅÒÅÍÅÎÎÏÊ '%-.64s'"
- spa "Tipo de argumento equivocado para variable '%-.64s'"
- swe "Fel typ av argument till variabel '%-.64s'"
-ER_VAR_CANT_BE_READ
- nla "Variabele '%-.64s' kan alleen worden gewijzigd, niet gelezen"
- eng "Variable '%-.64s' can only be set, not read"
- ger "Variable '%-.64s' kann nur verändert, nicht gelesen werden"
- ita "Alla variabile '%-.64s' e' di sola scrittura quindi puo' essere solo assegnato un valore, non letto"
- por "Variável '%-.64s' somente pode ser configurada, não lida"
- rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÍÏÖÅÔ ÂÙÔØ ÔÏÌØËÏ ÕÓÔÁÎÏ×ÌÅÎÁ, ÎÏ ÎÅ ÓÞÉÔÁÎÁ"
- spa "Variable '%-.64s' solamente puede ser configurada, no leída"
- swe "Variabeln '%-.64s' kan endast sättas, inte läsas"
-ER_CANT_USE_OPTION_HERE 42000
- nla "Foutieve toepassing/plaatsing van '%s'"
- eng "Incorrect usage/placement of '%s'"
- ger "Falsche Verwendung oder Platzierung von '%s'"
- ita "Uso/posizione di '%s' sbagliato"
- por "Errado uso/colocação de '%s'"
- rus "îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÉÌÉ × ÎÅ×ÅÒÎÏÍ ÍÅÓÔÅ ÕËÁÚÁÎ '%s'"
- spa "Equivocado uso/colocación de '%s'"
- swe "Fel använding/placering av '%s'"
-ER_NOT_SUPPORTED_YET 42000
- nla "Deze versie van MySQL ondersteunt nog geen '%s'"
- eng "This version of MySQL doesn't yet support '%s'"
- ger "Diese MySQL-Version unterstützt '%s' nicht"
- ita "Questa versione di MySQL non supporta ancora '%s'"
- por "Esta versão de MySQL não suporta ainda '%s'"
- rus "üÔÁ ×ÅÒÓÉÑ MySQL ÐÏËÁ ÅÝÅ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ '%s'"
- spa "Esta versión de MySQL no soporta todavia '%s'"
- swe "Denna version av MySQL kan ännu inte utföra '%s'"
-ER_MASTER_FATAL_ERROR_READING_BINLOG
- nla "Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log"
- eng "Got fatal error %d from master when reading data from binary log: '%-.128s'"
- ger "Schwerer Fehler %d: '%-.128s vom Master beim Lesen des binären Logs"
- ita "Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario"
- por "Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log"
- rus "ðÏÌÕÞÅÎÁ ÎÅÉÓÐÒÁ×ÉÍÁÑ ÏÛÉÂËÁ %d: '%-.128s' ÏÔ ÇÏÌÏ×ÎÏÇÏ ÓÅÒ×ÅÒÁ × ÐÒÏÃÅÓÓÅ ×ÙÂÏÒËÉ ÄÁÎÎÙÈ ÉÚ Ä×ÏÉÞÎÏÇÏ ÖÕÒÎÁÌÁ"
- spa "Recibió fatal error %d: '%-.128s' del master cuando leyendo datos del binary log"
- swe "Fick fatalt fel %d: '%-.128s' från master vid läsning av binärloggen"
-ER_SLAVE_IGNORED_TABLE
- eng "Slave SQL thread ignored the query because of replicate-*-table rules"
- ger "Slave-SQL-Thread hat die Abfrage aufgrund von replicate-*-table-Regeln ignoriert"
- nla "Slave SQL thread negeerde de query vanwege replicate-*-table opties"
- por "Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela"
- spa "Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla"
- swe "Slav SQL tråden ignorerade frågan pga en replicate-*-table regel"
-ER_INCORRECT_GLOBAL_LOCAL_VAR
- eng "Variable '%-.192s' is a %s variable"
- serbian "Promenljiva '%-.192s' je %s promenljiva"
- ger "Variable '%-.192s' ist eine %s-Variable"
- nla "Variabele '%-.192s' is geen %s variabele"
- spa "Variable '%-.192s' es una %s variable"
- swe "Variabel '%-.192s' är av typ %s"
-ER_WRONG_FK_DEF 42000
- eng "Incorrect foreign key definition for '%-.192s': %s"
- ger "Falsche Fremdschlüssel-Definition für '%-.192s': %s"
- nla "Incorrecte foreign key definitie voor '%-.192s': %s"
- por "Definição errada da chave estrangeira para '%-.192s': %s"
- spa "Equivocada definición de llave extranjera para '%-.192s': %s"
- swe "Felaktig FOREIGN KEY-definition för '%-.192s': %s"
-ER_KEY_REF_DO_NOT_MATCH_TABLE_REF
- eng "Key reference and table reference don't match"
- ger "Schlüssel- und Tabellenverweis passen nicht zusammen"
- nla "Sleutel- en tabelreferentie komen niet overeen"
- por "Referência da chave e referência da tabela não coincidem"
- spa "Referencia de llave y referencia de tabla no coinciden"
- swe "Nyckelreferensen och tabellreferensen stämmer inte överens"
-ER_OPERAND_COLUMNS 21000
- eng "Operand should contain %d column(s)"
- ger "Operand sollte %d Spalte(n) enthalten"
- nla "Operand behoort %d kolommen te bevatten"
- rus "ïÐÅÒÁÎÄ ÄÏÌÖÅÎ ÓÏÄÅÒÖÁÔØ %d ËÏÌÏÎÏË"
- spa "Operando debe tener %d columna(s)"
- ukr "ïÐÅÒÁÎÄ ÍÁ¤ ÓËÌÁÄÁÔÉÓÑ Ú %d ÓÔÏ×Âæ×"
-ER_SUBQUERY_NO_1_ROW 21000
- eng "Subquery returns more than 1 row"
- ger "Unterabfrage lieferte mehr als einen Datensatz zurück"
- nla "Subquery retourneert meer dan 1 rij"
- por "Subconsulta retorna mais que 1 registro"
- rus "ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÊ ÚÁÐÉÓÉ"
- spa "Subconsulta retorna mas que 1 línea"
- swe "Subquery returnerade mer än 1 rad"
- ukr "ð¦ÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ¦ÌØÛ ÎiÖ 1 ÚÁÐÉÓ"
-ER_UNKNOWN_STMT_HANDLER
- dan "Unknown prepared statement handler (%.*s) given to %s"
- eng "Unknown prepared statement handler (%.*s) given to %s"
- ger "Unbekannter Prepared-Statement-Handler (%.*s) für %s angegeben"
- nla "Onebekende prepared statement handler (%.*s) voor %s aangegeven"
- por "Desconhecido manipulador de declaração preparado (%.*s) determinado para %s"
- spa "Desconocido preparado comando handler (%.*s) dado para %s"
- swe "Okänd PREPARED STATEMENT id (%.*s) var given till %s"
- ukr "Unknown prepared statement handler (%.*s) given to %s"
-ER_CORRUPT_HELP_DB
- eng "Help database is corrupt or does not exist"
- ger "Die Hilfe-Datenbank ist beschädigt oder existiert nicht"
- nla "Help database is beschadigd of bestaat niet"
- por "Banco de dado de ajuda corrupto ou não existente"
- spa "Base de datos Help está corrupto o no existe"
- swe "Hjälpdatabasen finns inte eller är skadad"
-ER_CYCLIC_REFERENCE
- eng "Cyclic reference on subqueries"
- ger "Zyklischer Verweis in Unterabfragen"
- nla "Cyclische verwijzing in subqueries"
- por "Referência cíclica em subconsultas"
- rus "ãÉËÌÉÞÅÓËÁÑ ÓÓÙÌËÁ ÎÁ ÐÏÄÚÁÐÒÏÓ"
- spa "Cíclica referencia en subconsultas"
- swe "Cyklisk referens i subqueries"
- ukr "ãÉË̦ÞÎÅ ÐÏÓÉÌÁÎÎÑ ÎÁ ЦÄÚÁÐÉÔ"
-ER_AUTO_CONVERT
- eng "Converting column '%s' from %s to %s"
- ger "Feld '%s' wird von %s nach %s umgewandelt"
- nla "Veld '%s' wordt van %s naar %s geconverteerd"
- por "Convertendo coluna '%s' de %s para %s"
- rus "ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ÐÏÌÑ '%s' ÉÚ %s × %s"
- spa "Convirtiendo columna '%s' de %s para %s"
- swe "Konvertar kolumn '%s' från %s till %s"
- ukr "ðÅÒÅÔ×ÏÒÅÎÎÑ ÓÔÏ×ÂÃÁ '%s' Ú %s Õ %s"
-ER_ILLEGAL_REFERENCE 42S22
- eng "Reference '%-.64s' not supported (%s)"
- ger "Verweis '%-.64s' wird nicht unterstützt (%s)"
- nla "Verwijzing '%-.64s' niet ondersteund (%s)"
- por "Referência '%-.64s' não suportada (%s)"
- rus "óÓÙÌËÁ '%-.64s' ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ (%s)"
- spa "Referencia '%-.64s' no soportada (%s)"
- swe "Referens '%-.64s' stöds inte (%s)"
- ukr "ðÏÓÉÌÁÎÎÑ '%-.64s' ÎÅ ÐiÄÔÒÉÍÕÅÔÓÑ (%s)"
-ER_DERIVED_MUST_HAVE_ALIAS 42000
- eng "Every derived table must have its own alias"
- ger "Für jede abgeleitete Tabelle muss ein eigener Alias angegeben werden"
- nla "Voor elke afgeleide tabel moet een unieke alias worden gebruikt"
- por "Cada tabela derivada deve ter seu próprio alias"
- spa "Cada tabla derivada debe tener su propio alias"
- swe "Varje 'derived table' måste ha sitt eget alias"
-ER_SELECT_REDUCED 01000
- eng "Select %u was reduced during optimization"
- ger "Select %u wurde während der Optimierung reduziert"
- nla "Select %u werd geredureerd tijdens optimtalisatie"
- por "Select %u foi reduzido durante otimização"
- rus "Select %u ÂÙÌ ÕÐÒÁÚÄÎÅÎ × ÐÒÏÃÅÓÓÅ ÏÐÔÉÍÉÚÁÃÉÉ"
- spa "Select %u fué reducido durante optimización"
- swe "Select %u reducerades vid optimiering"
- ukr "Select %u was ÓËÁÓÏ×ÁÎÏ ÐÒÉ ÏÐÔÉÍiÚÁÃii"
-ER_TABLENAME_NOT_ALLOWED_HERE 42000
- eng "Table '%-.192s' from one of the SELECTs cannot be used in %-.32s"
- ger "Tabelle '%-.192s', die in einem der SELECT-Befehle verwendet wurde, kann nicht in %-.32s verwendet werden"
- nla "Tabel '%-.192s' uit een van de SELECTS kan niet in %-.32s gebruikt worden"
- por "Tabela '%-.192s' de um dos SELECTs não pode ser usada em %-.32s"
- spa "Tabla '%-.192s' de uno de los SELECT no puede ser usada en %-.32s"
- swe "Tabell '%-.192s' från en SELECT kan inte användas i %-.32s"
-ER_NOT_SUPPORTED_AUTH_MODE 08004
- eng "Client does not support authentication protocol requested by server; consider upgrading MySQL client"
- ger "Client unterstützt das vom Server erwartete Authentifizierungsprotokoll nicht. Bitte aktualisieren Sie Ihren MySQL-Client"
- nla "Client ondersteunt het door de server verwachtte authenticatieprotocol niet. Overweeg een nieuwere MySQL client te gebruiken"
- por "Cliente não suporta o protocolo de autenticação exigido pelo servidor; considere a atualização do cliente MySQL"
- spa "Cliente no soporta protocolo de autenticación solicitado por el servidor; considere actualizar el cliente MySQL"
- swe "Klienten stöder inte autentiseringsprotokollet som begärts av servern; överväg uppgradering av klientprogrammet."
-ER_SPATIAL_CANT_HAVE_NULL 42000
- eng "All parts of a SPATIAL index must be NOT NULL"
- ger "Alle Teile eines SPATIAL-Index müssen als NOT NULL deklariert sein"
- nla "Alle delete van een SPATIAL index dienen als NOT NULL gedeclareerd te worden"
- por "Todas as partes de uma SPATIAL index devem ser NOT NULL"
- spa "Todas las partes de una SPATIAL index deben ser NOT NULL"
- swe "Alla delar av en SPATIAL index måste vara NOT NULL"
-ER_COLLATION_CHARSET_MISMATCH 42000
- eng "COLLATION '%s' is not valid for CHARACTER SET '%s'"
- ger "COLLATION '%s' ist für CHARACTER SET '%s' ungültig"
- nla "COLLATION '%s' is niet geldig voor CHARACTER SET '%s'"
- por "COLLATION '%s' não é válida para CHARACTER SET '%s'"
- spa "COLLATION '%s' no es válido para CHARACTER SET '%s'"
- swe "COLLATION '%s' är inte tillåtet för CHARACTER SET '%s'"
-ER_SLAVE_WAS_RUNNING
- eng "Slave is already running"
- ger "Slave läuft bereits"
- nla "Slave is reeds actief"
- por "O slave já está rodando"
- spa "Slave ya está funcionando"
- swe "Slaven har redan startat"
-ER_SLAVE_WAS_NOT_RUNNING
- eng "Slave already has been stopped"
- ger "Slave wurde bereits angehalten"
- nla "Slave is reeds gestopt"
- por "O slave já está parado"
- spa "Slave ya fué parado"
- swe "Slaven har redan stoppat"
-ER_TOO_BIG_FOR_UNCOMPRESS
- eng "Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)"
- ger "Unkomprimierte Daten sind zu groß. Die maximale Größe beträgt %d (wahrscheinlich wurde die Länge der unkomprimierten Daten beschädigt)"
- nla "Ongecomprimeerder data is te groot; de maximum lengte is %d (waarschijnlijk, de lengte van de gecomprimeerde data was beschadigd)"
- por "Tamanho muito grande dos dados des comprimidos. O máximo tamanho é %d. (provavelmente, o comprimento dos dados descomprimidos está corrupto)"
- spa "Tamaño demasiado grande para datos descomprimidos. El máximo tamaño es %d. (probablemente, extensión de datos descomprimidos fué corrompida)"
-ER_ZLIB_Z_MEM_ERROR
- eng "ZLIB: Not enough memory"
- ger "ZLIB: Nicht genug Speicher"
- nla "ZLIB: Onvoldoende geheugen"
- por "ZLIB: Não suficiente memória disponível"
- spa "Z_MEM_ERROR: No suficiente memoria para zlib"
-ER_ZLIB_Z_BUF_ERROR
- eng "ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)"
- ger "ZLIB: Im Ausgabepuffer ist nicht genug Platz vorhanden (wahrscheinlich wurde die Länge der unkomprimierten Daten beschädigt)"
- nla "ZLIB: Onvoldoende ruimte in uitgaande buffer (waarschijnlijk, de lengte van de ongecomprimeerde data was beschadigd)"
- por "ZLIB: Não suficiente espaço no buffer emissor (provavelmente, o comprimento dos dados descomprimidos está corrupto)"
- spa "Z_BUF_ERROR: No suficiente espacio en el búfer de salida para zlib (probablemente, extensión de datos descomprimidos fué corrompida)"
-ER_ZLIB_Z_DATA_ERROR
- eng "ZLIB: Input data corrupted"
- ger "ZLIB: Eingabedaten beschädigt"
- nla "ZLIB: Invoer data beschadigd"
- por "ZLIB: Dados de entrada está corrupto"
- spa "ZLIB: Dato de entrada fué corrompido para zlib"
-ER_CUT_VALUE_GROUP_CONCAT
- eng "%d line(s) were cut by GROUP_CONCAT()"
- ger "%d Zeile(n) durch GROUP_CONCAT() abgeschnitten"
- nla "%d regel(s) door GROUP_CONCAT() ingekort"
- por "%d linha(s) foram cortada(s) por GROUP_CONCAT()"
- spa "%d línea(s) fue(fueron) cortadas por group_concat()"
- swe "%d rad(er) kapades av group_concat()"
- ukr "%d line(s) was(were) cut by group_concat()"
-ER_WARN_TOO_FEW_RECORDS 01000
- eng "Row %ld doesn't contain data for all columns"
- ger "Zeile %ld enthält nicht für alle Felder Daten"
- nla "Rij %ld bevat niet de data voor alle kolommen"
- por "Conta de registro é menor que a conta de coluna na linha %ld"
- spa "Línea %ld no contiene datos para todas las columnas"
-ER_WARN_TOO_MANY_RECORDS 01000
- eng "Row %ld was truncated; it contained more data than there were input columns"
- ger "Zeile %ld gekürzt, die Zeile enthielt mehr Daten, als es Eingabefelder gibt"
- nla "Regel %ld ingekort, bevatte meer data dan invoer kolommen"
- por "Conta de registro é maior que a conta de coluna na linha %ld"
- spa "Línea %ld fué truncada; La misma contine mas datos que las que existen en las columnas de entrada"
-ER_WARN_NULL_TO_NOTNULL 22004
- eng "Column set to default value; NULL supplied to NOT NULL column '%s' at row %ld"
- ger "Feld auf Vorgabewert gesetzt, da NULL für NOT-NULL-Feld '%s' in Zeile %ld angegeben"
- por "Dado truncado, NULL fornecido para NOT NULL coluna '%s' na linha %ld"
- spa "Datos truncado, NULL suministrado para NOT NULL columna '%s' en la línea %ld"
-ER_WARN_DATA_OUT_OF_RANGE 22003
- eng "Out of range value for column '%s' at row %ld"
-WARN_DATA_TRUNCATED 01000
- eng "Data truncated for column '%s' at row %ld"
- ger "Daten abgeschnitten für Feld '%s' in Zeile %ld"
- por "Dado truncado para coluna '%s' na linha %ld"
- spa "Datos truncados para columna '%s' en la línea %ld"
-ER_WARN_USING_OTHER_HANDLER
- eng "Using storage engine %s for table '%s'"
- ger "Für Tabelle '%s' wird Speicher-Engine %s benutzt"
- por "Usando engine de armazenamento %s para tabela '%s'"
- spa "Usando motor de almacenamiento %s para tabla '%s'"
- swe "Använder handler %s för tabell '%s'"
-ER_CANT_AGGREGATE_2COLLATIONS
- eng "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'"
- ger "Unerlaubte Mischung von Sortierreihenfolgen (%s, %s) und (%s, %s) für Operation '%s'"
- por "Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'"
- spa "Ilegal mezcla de collations (%s,%s) y (%s,%s) para operación '%s'"
-ER_DROP_USER
- eng "Cannot drop one or more of the requested users"
- ger "Kann einen oder mehrere der angegebenen Benutzer nicht löschen"
-ER_REVOKE_GRANTS
- eng "Can't revoke all privileges for one or more of the requested users"
- ger "Kann nicht alle Berechtigungen widerrufen, die für einen oder mehrere Benutzer gewährt wurden"
- por "Não pode revocar todos os privilégios, grant para um ou mais dos usuários pedidos"
- spa "No puede revocar todos los privilegios, derecho para uno o mas de los usuarios solicitados"
-ER_CANT_AGGREGATE_3COLLATIONS
- eng "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'"
- ger "Unerlaubte Mischung von Sortierreihenfolgen (%s, %s), (%s, %s), (%s, %s) für Operation '%s'"
- por "Ilegal combinação de collations (%s,%s), (%s,%s), (%s,%s) para operação '%s'"
- spa "Ilegal mezcla de collations (%s,%s), (%s,%s), (%s,%s) para operación '%s'"
-ER_CANT_AGGREGATE_NCOLLATIONS
- eng "Illegal mix of collations for operation '%s'"
- ger "Unerlaubte Mischung von Sortierreihenfolgen für Operation '%s'"
- por "Ilegal combinação de collations para operação '%s'"
- spa "Ilegal mezcla de collations para operación '%s'"
-ER_VARIABLE_IS_NOT_STRUCT
- eng "Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)"
- ger "Variable '%-.64s' ist keine Variablen-Komponente (kann nicht als XXXX.variablen_name verwendet werden)"
- por "Variável '%-.64s' não é uma variável componente (Não pode ser usada como XXXX.variável_nome)"
- spa "Variable '%-.64s' no es una variable componente (No puede ser usada como XXXX.variable_name)"
-ER_UNKNOWN_COLLATION
- eng "Unknown collation: '%-.64s'"
- ger "Unbekannte Sortierreihenfolge: '%-.64s'"
- por "Collation desconhecida: '%-.64s'"
- spa "Collation desconocida: '%-.64s'"
-ER_SLAVE_IGNORED_SSL_PARAMS
- eng "SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started"
- ger "SSL-Parameter in CHANGE MASTER werden ignoriert, weil dieser MySQL-Slave ohne SSL-Unterstützung kompiliert wurde. Sie können aber später verwendet werden, wenn ein MySQL-Slave mit SSL gestartet wird"
- por "SSL parâmetros em CHANGE MASTER são ignorados porque este escravo MySQL foi compilado sem o SSL suporte. Os mesmos podem ser usados mais tarde quando o escravo MySQL com SSL seja iniciado."
- spa "Parametros SSL en CHANGE MASTER son ignorados porque este slave MySQL fue compilado sin soporte SSL; pueden ser usados despues cuando el slave MySQL con SSL sea inicializado"
-ER_SERVER_IS_IN_SECURE_AUTH_MODE
- eng "Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format"
- ger "Server läuft im Modus --secure-auth, aber '%s'@'%s' hat ein Passwort im alten Format. Bitte Passwort ins neue Format ändern"
- por "Servidor está rodando em --secure-auth modo, porêm '%s'@'%s' tem senha no formato antigo; por favor troque a senha para o novo formato"
- rus "óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s'@'%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ"
- spa "Servidor está rodando en modo --secure-auth, pero '%s'@'%s' tiene clave en el antiguo formato; por favor cambie la clave para el nuevo formato"
-ER_WARN_FIELD_RESOLVED
- eng "Field or reference '%-.192s%s%-.192s%s%-.192s' of SELECT #%d was resolved in SELECT #%d"
- ger "Feld oder Verweis '%-.192s%s%-.192s%s%-.192s' im SELECT-Befehl Nr. %d wurde im SELECT-Befehl Nr. %d aufgelöst"
- por "Campo ou referência '%-.192s%s%-.192s%s%-.192s' de SELECT #%d foi resolvido em SELECT #%d"
- rus "ðÏÌÅ ÉÌÉ ÓÓÙÌËÁ '%-.192s%s%-.192s%s%-.192s' ÉÚ SELECTÁ #%d ÂÙÌÁ ÎÁÊÄÅÎÁ × SELECTÅ #%d"
- spa "Campo o referencia '%-.192s%s%-.192s%s%-.192s' de SELECT #%d fue resolvido en SELECT #%d"
- ukr "óÔÏ×ÂÅÃØ ÁÂÏ ÐÏÓÉÌÁÎÎÑ '%-.192s%s%-.192s%s%-.192s' ¦Ú SELECTÕ #%d ÂÕÌÏ ÚÎÁÊÄÅÎÅ Õ SELECT¦ #%d"
-ER_BAD_SLAVE_UNTIL_COND
- eng "Incorrect parameter or combination of parameters for START SLAVE UNTIL"
- ger "Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL"
- por "Parâmetro ou combinação de parâmetros errado para START SLAVE UNTIL"
- spa "Parametro equivocado o combinación de parametros para START SLAVE UNTIL"
-ER_MISSING_SKIP_SLAVE
- eng "It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you will get problems if you get an unexpected slave's mysqld restart"
- ger "Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn ein Slave-Server unerwartet neu startet"
- por "É recomendado para rodar com --skip-slave-start quando fazendo replicação passo-por-passo com START SLAVE UNTIL, de outra forma você não está seguro em caso de inesperada reinicialição do mysqld escravo"
- spa "Es recomendado rodar con --skip-slave-start cuando haciendo replicación step-by-step con START SLAVE UNTIL, a menos que usted no esté seguro en caso de inesperada reinicialización del mysqld slave"
-ER_UNTIL_COND_IGNORED
- eng "SQL thread is not to be started so UNTIL options are ignored"
- ger "SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert"
- por "Thread SQL não pode ser inicializado tal que opções UNTIL são ignoradas"
- spa "SQL thread no es inicializado tal que opciones UNTIL son ignoradas"
-ER_WRONG_NAME_FOR_INDEX 42000
- eng "Incorrect index name '%-.100s'"
- ger "Falscher Indexname '%-.100s'"
- por "Incorreto nome de índice '%-.100s'"
- spa "Nombre de índice incorrecto '%-.100s'"
- swe "Felaktigt index namn '%-.100s'"
-ER_WRONG_NAME_FOR_CATALOG 42000
- eng "Incorrect catalog name '%-.100s'"
- ger "Falscher Katalogname '%-.100s'"
- por "Incorreto nome de catálogo '%-.100s'"
- spa "Nombre de catalog incorrecto '%-.100s'"
- swe "Felaktigt katalog namn '%-.100s'"
-ER_WARN_QC_RESIZE
- eng "Query cache failed to set size %lu; new query cache size is %lu"
- ger "Änderung der Query-Cache-Größe auf %lu fehlgeschlagen; neue Query-Cache-Größe ist %lu"
- por "Falha em Query cache para configurar tamanho %lu, novo tamanho de query cache é %lu"
- rus "ëÅÛ ÚÁÐÒÏÓÏ× ÎÅ ÍÏÖÅÔ ÕÓÔÁÎÏ×ÉÔØ ÒÁÚÍÅÒ %lu, ÎÏ×ÙÊ ÒÁÚÍÅÒ ËÅÛÁ ÚÐÒÏÓÏ× - %lu"
- spa "Query cache fallada para configurar tamaño %lu, nuevo tamaño de query cache es %lu"
- swe "Storleken av "Query cache" kunde inte sättas till %lu, ny storlek är %lu"
- ukr "ëÅÛ ÚÁÐÉÔ¦× ÎÅÓÐÒÏÍÏÖÅÎ ×ÓÔÁÎÏ×ÉÔÉ ÒÏÚÍ¦Ò %lu, ÎÏ×ÉÊ ÒÏÚÍ¦Ò ËÅÛÁ ÚÁÐÉÔ¦× - %lu"
-ER_BAD_FT_COLUMN
- eng "Column '%-.192s' cannot be part of FULLTEXT index"
- ger "Feld '%-.192s' kann nicht Teil eines FULLTEXT-Index sein"
- por "Coluna '%-.192s' não pode ser parte de índice FULLTEXT"
- spa "Columna '%-.192s' no puede ser parte de FULLTEXT index"
- swe "Kolumn '%-.192s' kan inte vara del av ett FULLTEXT index"
-ER_UNKNOWN_KEY_CACHE
- eng "Unknown key cache '%-.100s'"
- ger "Unbekannter Schlüssel-Cache '%-.100s'"
- por "Key cache desconhecida '%-.100s'"
- spa "Desconocida key cache '%-.100s'"
- swe "Okänd nyckel cache '%-.100s'"
-ER_WARN_HOSTNAME_WONT_WORK
- eng "MySQL is started in --skip-name-resolve mode; you must restart it without this switch for this grant to work"
- ger "MySQL wurde mit --skip-name-resolve gestartet. Diese Option darf nicht verwendet werden, damit diese Rechtevergabe möglich ist"
- por "MySQL foi inicializado em modo --skip-name-resolve. Você necesita reincializá-lo sem esta opção para este grant funcionar"
- spa "MySQL esta inicializado en modo --skip-name-resolve. Usted necesita reinicializarlo sin esta opción para este derecho funcionar"
-ER_UNKNOWN_STORAGE_ENGINE 42000
- eng "Unknown table engine '%s'"
- ger "Unbekannte Speicher-Engine '%s'"
- por "Motor de tabela desconhecido '%s'"
- spa "Desconocido motor de tabla '%s'"
-# When using this error code, use ER(ER_WARN_DEPRECATED_SYNTAX_WITH_VER)
-# for the message string. See, for example, code in mysql_priv.h.
-ER_WARN_DEPRECATED_SYNTAX
- eng "'%s' is deprecated and will be removed in a future release. Please use %s instead"
- ger "'%s' ist veraltet. Bitte benutzen Sie '%s'"
- por "'%s' é desatualizado. Use '%s' em seu lugar"
- spa "'%s' está desaprobado, use '%s' en su lugar"
-ER_NON_UPDATABLE_TABLE
- eng "The target table %-.100s of the %s is not updatable"
- ger "Die Zieltabelle %-.100s von %s ist nicht aktualisierbar"
- por "A tabela destino %-.100s do %s não é atualizável"
- rus "ôÁÂÌÉÃÁ %-.100s × %s ÎÅ ÍÏÖÅÔ ÉÚÍÅÎÑÔÓÑ"
- spa "La tabla destino %-.100s del %s no es actualizable"
- swe "Tabell %-.100s använd med '%s' är inte uppdateringsbar"
- ukr "ôÁÂÌÉÃÑ %-.100s Õ %s ÎÅ ÍÏÖÅ ÏÎÏ×ÌÀ×ÁÔÉÓØ"
-ER_FEATURE_DISABLED
- eng "The '%s' feature is disabled; you need MySQL built with '%s' to have it working"
- ger "Das Feature '%s' ist ausgeschaltet, Sie müssen MySQL mit '%s' übersetzen, damit es verfügbar ist"
- por "O recurso '%s' foi desativado; você necessita MySQL construído com '%s' para ter isto funcionando"
- spa "El recurso '%s' fue deshabilitado; usted necesita construir MySQL con '%s' para tener eso funcionando"
- swe "'%s' är inte aktiverad; För att aktivera detta måste du bygga om MySQL med '%s' definerad"
-ER_OPTION_PREVENTS_STATEMENT
- eng "The MySQL server is running with the %s option so it cannot execute this statement"
- ger "Der MySQL-Server läuft mit der Option %s und kann diese Anweisung deswegen nicht ausführen"
- por "O servidor MySQL está rodando com a opção %s razão pela qual não pode executar esse commando"
- spa "El servidor MySQL está rodando con la opción %s tal que no puede ejecutar este comando"
- swe "MySQL är startad med %s. Pga av detta kan du inte använda detta kommando"
-ER_DUPLICATED_VALUE_IN_TYPE
- eng "Column '%-.100s' has duplicated value '%-.64s' in %s"
- ger "Feld '%-.100s' hat doppelten Wert '%-.64s' in %s"
- por "Coluna '%-.100s' tem valor duplicado '%-.64s' em %s"
- spa "Columna '%-.100s' tiene valor doblado '%-.64s' en %s"
-ER_TRUNCATED_WRONG_VALUE 22007
- eng "Truncated incorrect %-.32s value: '%-.128s'"
- ger "Falscher %-.32s-Wert gekürzt: '%-.128s'"
- por "Truncado errado %-.32s valor: '%-.128s'"
- spa "Equivocado truncado %-.32s valor: '%-.128s'"
-ER_TOO_MUCH_AUTO_TIMESTAMP_COLS
- eng "Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
- ger "Fehlerhafte Tabellendefinition. Es kann nur eine einzige TIMESTAMP-Spalte mit CURRENT_TIMESTAMP als DEFAULT oder in einer ON-UPDATE-Klausel geben"
- por "Incorreta definição de tabela; Pode ter somente uma coluna TIMESTAMP com CURRENT_TIMESTAMP em DEFAULT ou ON UPDATE cláusula"
- spa "Incorrecta definición de tabla; Solamente debe haber una columna TIMESTAMP con CURRENT_TIMESTAMP en DEFAULT o ON UPDATE cláusula"
-ER_INVALID_ON_UPDATE
- eng "Invalid ON UPDATE clause for '%-.192s' column"
- ger "Ungültige ON-UPDATE-Klausel für Spalte '%-.192s'"
- por "Inválida cláusula ON UPDATE para campo '%-.192s'"
- spa "Inválido ON UPDATE cláusula para campo '%-.192s'"
-ER_UNSUPPORTED_PS
- eng "This command is not supported in the prepared statement protocol yet"
- ger "Dieser Befehl wird im Protokoll für vorbereitete Anweisungen noch nicht unterstützt"
-ER_GET_ERRMSG
- dan "Modtog fejl %d '%-.100s' fra %s"
- eng "Got error %d '%-.100s' from %s"
- ger "Fehler %d '%-.100s' von %s"
- nor "Mottok feil %d '%-.100s' fa %s"
- norwegian-ny "Mottok feil %d '%-.100s' fra %s"
-ER_GET_TEMPORARY_ERRMSG
- dan "Modtog temporary fejl %d '%-.100s' fra %s"
- eng "Got temporary error %d '%-.100s' from %s"
- ger "Temporärer Fehler %d '%-.100s' von %s"
- nor "Mottok temporary feil %d '%-.100s' fra %s"
- norwegian-ny "Mottok temporary feil %d '%-.100s' fra %s"
-ER_UNKNOWN_TIME_ZONE
- eng "Unknown or incorrect time zone: '%-.64s'"
- ger "Unbekannte oder falsche Zeitzone: '%-.64s'"
-ER_WARN_INVALID_TIMESTAMP
- eng "Invalid TIMESTAMP value in column '%s' at row %ld"
- ger "Ungültiger TIMESTAMP-Wert in Feld '%s', Zeile %ld"
-ER_INVALID_CHARACTER_STRING
- eng "Invalid %s character string: '%.64s'"
- ger "Ungültiger %s-Zeichen-String: '%.64s'"
-ER_WARN_ALLOWED_PACKET_OVERFLOWED
- eng "Result of %s() was larger than max_allowed_packet (%ld) - truncated"
- ger "Ergebnis von %s() war größer als max_allowed_packet (%ld) Bytes und wurde deshalb gekürzt"
-ER_CONFLICTING_DECLARATIONS
- eng "Conflicting declarations: '%s%s' and '%s%s'"
- ger "Widersprüchliche Deklarationen: '%s%s' und '%s%s'"
-ER_SP_NO_RECURSIVE_CREATE 2F003
- eng "Can't create a %s from within another stored routine"
- ger "Kann kein %s innerhalb einer anderen gespeicherten Routine erzeugen"
-ER_SP_ALREADY_EXISTS 42000
- eng "%s %s already exists"
- ger "%s %s existiert bereits"
-ER_SP_DOES_NOT_EXIST 42000
- eng "%s %s does not exist"
- ger "%s %s existiert nicht"
-ER_SP_DROP_FAILED
- eng "Failed to DROP %s %s"
- ger "DROP %s %s ist fehlgeschlagen"
-ER_SP_STORE_FAILED
- eng "Failed to CREATE %s %s"
- ger "CREATE %s %s ist fehlgeschlagen"
-ER_SP_LILABEL_MISMATCH 42000
- eng "%s with no matching label: %s"
- ger "%s ohne passende Marke: %s"
-ER_SP_LABEL_REDEFINE 42000
- eng "Redefining label %s"
- ger "Neudefinition der Marke %s"
-ER_SP_LABEL_MISMATCH 42000
- eng "End-label %s without match"
- ger "Ende-Marke %s ohne zugehörigen Anfang"
-ER_SP_UNINIT_VAR 01000
- eng "Referring to uninitialized variable %s"
- ger "Zugriff auf nichtinitialisierte Variable %s"
-ER_SP_BADSELECT 0A000
- eng "PROCEDURE %s can't return a result set in the given context"
- ger "PROCEDURE %s kann im gegebenen Kontext keine Ergebnismenge zurückgeben"
-ER_SP_BADRETURN 42000
- eng "RETURN is only allowed in a FUNCTION"
- ger "RETURN ist nur innerhalb einer FUNCTION erlaubt"
-ER_SP_BADSTATEMENT 0A000
- eng "%s is not allowed in stored procedures"
- ger "%s ist in gespeicherten Prozeduren nicht erlaubt"
-ER_UPDATE_LOG_DEPRECATED_IGNORED 42000
- eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored. This option will be removed in MySQL 5.6."
- ger "Das Update-Log ist veraltet und wurde durch das Binär-Log ersetzt. SET SQL_LOG_UPDATE wird ignoriert. Diese Option wird in MySQL 5.6 entfernt."
-ER_UPDATE_LOG_DEPRECATED_TRANSLATED 42000
- eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN. This option will be removed in MySQL 5.6."
- ger "Das Update-Log ist veraltet und wurde durch das Binär-Log ersetzt. SET SQL_LOG_UPDATE wurde in SET SQL_LOG_BIN übersetzt. Diese Option wird in MySQL 5.6 entfernt."
-ER_QUERY_INTERRUPTED 70100
- eng "Query execution was interrupted"
- ger "Ausführung der Abfrage wurde unterbrochen"
-ER_SP_WRONG_NO_OF_ARGS 42000
- eng "Incorrect number of arguments for %s %s; expected %u, got %u"
- ger "Falsche Anzahl von Argumenten für %s %s; erwarte %u, erhalte %u"
-ER_SP_COND_MISMATCH 42000
- eng "Undefined CONDITION: %s"
- ger "Undefinierte CONDITION: %s"
-ER_SP_NORETURN 42000
- eng "No RETURN found in FUNCTION %s"
- ger "Kein RETURN in FUNCTION %s gefunden"
-ER_SP_NORETURNEND 2F005
- eng "FUNCTION %s ended without RETURN"
- ger "FUNCTION %s endete ohne RETURN"
-ER_SP_BAD_CURSOR_QUERY 42000
- eng "Cursor statement must be a SELECT"
- ger "Cursor-Anweisung muss ein SELECT sein"
-ER_SP_BAD_CURSOR_SELECT 42000
- eng "Cursor SELECT must not have INTO"
- ger "Cursor-SELECT darf kein INTO haben"
-ER_SP_CURSOR_MISMATCH 42000
- eng "Undefined CURSOR: %s"
- ger "Undefinierter CURSOR: %s"
-ER_SP_CURSOR_ALREADY_OPEN 24000
- eng "Cursor is already open"
- ger "Cursor ist schon geöffnet"
-ER_SP_CURSOR_NOT_OPEN 24000
- eng "Cursor is not open"
- ger "Cursor ist nicht geöffnet"
-ER_SP_UNDECLARED_VAR 42000
- eng "Undeclared variable: %s"
- ger "Nicht deklarierte Variable: %s"
-ER_SP_WRONG_NO_OF_FETCH_ARGS
- eng "Incorrect number of FETCH variables"
- ger "Falsche Anzahl von FETCH-Variablen"
-ER_SP_FETCH_NO_DATA 02000
- eng "No data - zero rows fetched, selected, or processed"
- ger "Keine Daten - null Zeilen geholt (fetch), ausgewählt oder verarbeitet"
-ER_SP_DUP_PARAM 42000
- eng "Duplicate parameter: %s"
- ger "Doppelter Parameter: %s"
-ER_SP_DUP_VAR 42000
- eng "Duplicate variable: %s"
- ger "Doppelte Variable: %s"
-ER_SP_DUP_COND 42000
- eng "Duplicate condition: %s"
- ger "Doppelte Bedingung: %s"
-ER_SP_DUP_CURS 42000
- eng "Duplicate cursor: %s"
- ger "Doppelter Cursor: %s"
-ER_SP_CANT_ALTER
- eng "Failed to ALTER %s %s"
- ger "ALTER %s %s fehlgeschlagen"
-ER_SP_SUBSELECT_NYI 0A000
- eng "Subquery value not supported"
- ger "Subquery-Wert wird nicht unterstützt"
-ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 0A000
- eng "%s is not allowed in stored function or trigger"
- ger "%s ist in gespeicherten Funktionen und in Triggern nicht erlaubt"
-ER_SP_VARCOND_AFTER_CURSHNDLR 42000
- eng "Variable or condition declaration after cursor or handler declaration"
- ger "Deklaration einer Variablen oder einer Bedingung nach der Deklaration eines Cursors oder eines Handlers"
-ER_SP_CURSOR_AFTER_HANDLER 42000
- eng "Cursor declaration after handler declaration"
- ger "Deklaration eines Cursors nach der Deklaration eines Handlers"
-ER_SP_CASE_NOT_FOUND 20000
- eng "Case not found for CASE statement"
- ger "Fall für CASE-Anweisung nicht gefunden"
-ER_FPARSER_TOO_BIG_FILE
- eng "Configuration file '%-.192s' is too big"
- ger "Konfigurationsdatei '%-.192s' ist zu groß"
- rus "óÌÉÛËÏÍ ÂÏÌØÛÏÊ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÙÊ ÆÁÊÌ '%-.192s'"
- ukr "úÁÎÁÄÔÏ ×ÅÌÉËÉÊ ËÏÎƦÇÕÒÁæÊÎÉÊ ÆÁÊÌ '%-.192s'"
-ER_FPARSER_BAD_HEADER
- eng "Malformed file type header in file '%-.192s'"
- ger "Nicht wohlgeformter Dateityp-Header in Datei '%-.192s'"
- rus "îÅ×ÅÒÎÙÊ ÚÁÇÏÌÏ×ÏË ÔÉÐÁ ÆÁÊÌÁ '%-.192s'"
- ukr "îÅצÒÎÉÊ ÚÁÇÏÌÏ×ÏË ÔÉÐÕ Õ ÆÁÊ̦ '%-.192s'"
-ER_FPARSER_EOF_IN_COMMENT
- eng "Unexpected end of file while parsing comment '%-.200s'"
- ger "Unerwartetes Dateiende beim Parsen des Kommentars '%-.200s'"
- rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ × ËÏÍÅÎÔÁÒÉÉ '%-.200s'"
- ukr "îÅÓÐÏĦ×ÁÎÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ Õ ËÏÍÅÎÔÁÒ¦ '%-.200s'"
-ER_FPARSER_ERROR_IN_PARAMETER
- eng "Error while parsing parameter '%-.192s' (line: '%-.192s')"
- ger "Fehler beim Parsen des Parameters '%-.192s' (Zeile: '%-.192s')"
- rus "ïÛÉÂËÁ ÐÒÉ ÒÁÓÐÏÚÎÁ×ÁÎÉÉ ÐÁÒÁÍÅÔÒÁ '%-.192s' (ÓÔÒÏËÁ: '%-.192s')"
- ukr "ðÏÍÉÌËÁ × ÒÏÓЦÚÎÁ×ÁÎΦ ÐÁÒÁÍÅÔÒÕ '%-.192s' (ÒÑÄÏË: '%-.192s')"
-ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER
- eng "Unexpected end of file while skipping unknown parameter '%-.192s'"
- ger "Unerwartetes Dateiende beim Überspringen des unbekannten Parameters '%-.192s'"
- rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ ÐÒÉ ÐÒÏÐÕÓËÅ ÎÅÉÚ×ÅÓÔÎÏÇÏ ÐÁÒÁÍÅÔÒÁ '%-.192s'"
- ukr "îÅÓÐÏĦ×ÁÎÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ Õ ÓÐÒϦ ÐÒÏÍÉÎÕÔÉ ÎÅצÄÏÍÉÊ ÐÁÒÁÍÅÔÒ '%-.192s'"
-ER_VIEW_NO_EXPLAIN
- eng "EXPLAIN/SHOW can not be issued; lacking privileges for underlying table"
- ger "EXPLAIN/SHOW kann nicht verlangt werden. Rechte für zugrunde liegende Tabelle fehlen"
- rus "EXPLAIN/SHOW ÎÅ ÍÏÖÅÔ ÂÙÔØ ×ÙÐÏÌÎÅÎÎÏ; ÎÅÄÏÓÔÁÔÏÞÎÏ ÐÒÁ× ÎÁ ÔÁËÂÌÉÃÙ ÚÁÐÒÏÓÁ"
- ukr "EXPLAIN/SHOW ÎÅ ÍÏÖÅ ÂÕÔÉ ×¦ËÏÎÁÎÏ; ÎÅÍÁ¤ ÐÒÁ× ÎÁ ÔÉÂÌÉæ ÚÁÐÉÔÕ"
-ER_FRM_UNKNOWN_TYPE
- eng "File '%-.192s' has unknown type '%-.64s' in its header"
- ger "Datei '%-.192s' hat unbekannten Typ '%-.64s' im Header"
- rus "æÁÊÌ '%-.192s' ÓÏÄÅÒÖÉÔ ÎÅÉÚ×ÅÓÔÎÙÊ ÔÉÐ '%-.64s' × ÚÁÇÏÌÏ×ËÅ"
- ukr "æÁÊÌ '%-.192s' ÍÁ¤ ÎÅצÄÏÍÉÊ ÔÉÐ '%-.64s' Õ ÚÁÇÏÌÏ×ËÕ"
-ER_WRONG_OBJECT
- eng "'%-.192s.%-.192s' is not %s"
- ger "'%-.192s.%-.192s' ist nicht %s"
- rus "'%-.192s.%-.192s' - ÎÅ %s"
- ukr "'%-.192s.%-.192s' ÎÅ ¤ %s"
-ER_NONUPDATEABLE_COLUMN
- eng "Column '%-.192s' is not updatable"
- ger "Feld '%-.192s' ist nicht aktualisierbar"
- rus "óÔÏÌÂÅà '%-.192s' ÎÅ ÏÂÎÏ×ÌÑÅÍÙÊ"
- ukr "óÔÏ×ÂÅÃØ '%-.192s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÚÍÉÎÅÎÉÊ"
-ER_VIEW_SELECT_DERIVED
- eng "View's SELECT contains a subquery in the FROM clause"
- ger "SELECT der View enthält eine Subquery in der FROM-Klausel"
- rus "View SELECT ÓÏÄÅÒÖÉÔ ÐÏÄÚÁÐÒÏÓ × ËÏÎÓÔÒÕËÃÉÉ FROM"
- ukr "View SELECT ÍÁ¤ ЦÄÚÁÐÉÔ Õ ËÏÎÓÔÒÕËæ§ FROM"
-ER_VIEW_SELECT_CLAUSE
- eng "View's SELECT contains a '%s' clause"
- ger "SELECT der View enthält eine '%s'-Klausel"
- rus "View SELECT ÓÏÄÅÒÖÉÔ ËÏÎÓÔÒÕËÃÉÀ '%s'"
- ukr "View SELECT ÍÁ¤ ËÏÎÓÔÒÕËæÀ '%s'"
-ER_VIEW_SELECT_VARIABLE
- eng "View's SELECT contains a variable or parameter"
- ger "SELECT der View enthält eine Variable oder einen Parameter"
- rus "View SELECT ÓÏÄÅÒÖÉÔ ÐÅÒÅÍÅÎÎÕÀ ÉÌÉ ÐÁÒÁÍÅÔÒ"
- ukr "View SELECT ÍÁ¤ ÚÍÉÎÎÕ ÁÂÏ ÐÁÒÁÍÅÔÅÒ"
-ER_VIEW_SELECT_TMPTABLE
- eng "View's SELECT refers to a temporary table '%-.192s'"
- ger "SELECT der View verweist auf eine temporäre Tabelle '%-.192s'"
- rus "View SELECT ÓÏÄÅÒÖÉÔ ÓÓÙÌËÕ ÎÁ ×ÒÅÍÅÎÎÕÀ ÔÁÂÌÉÃÕ '%-.192s'"
- ukr "View SELECT ×ÉËÏÒÉÓÔÏ×Õ¤ ÔÉÍÞÁÓÏ×Õ ÔÁÂÌÉÃÀ '%-.192s'"
-ER_VIEW_WRONG_LIST
- eng "View's SELECT and view's field list have different column counts"
- ger "SELECT- und Feldliste der Views haben unterschiedliche Anzahlen von Spalten"
- rus "View SELECT É ÓÐÉÓÏË ÐÏÌÅÊ view ÉÍÅÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×"
- ukr "View SELECT ¦ ÐÅÒÅÌ¦Ë ÓÔÏ×ÂÃ¦× view ÍÁÀÔØ Ò¦ÚÎÕ Ë¦ÌØ˦ÓÔØ ÓËÏ×Âæ×"
-ER_WARN_VIEW_MERGE
- eng "View merge algorithm can't be used here for now (assumed undefined algorithm)"
- ger "View-Merge-Algorithmus kann hier momentan nicht verwendet werden (undefinierter Algorithmus wird angenommen)"
- rus "áÌÇÏÒÉÔÍ ÓÌÉÑÎÉÑ view ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ÓÅÊÞÁÓ (ÁÌÇÏÒÉÔÍ ÂÕÄÅÔ ÎÅÏÐÅÒÅÄÅÌÅÎÎÙÍ)"
- ukr "áÌÇÏÒÉÔÍ ÚÌÉ×ÁÎÎÑ view ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÉÊ ÚÁÒÁÚ (ÁÌÇÏÒÉÔÍ ÂÕÄÅ ÎÅ×ÉÚÎÁÞÅÎÉÊ)"
-ER_WARN_VIEW_WITHOUT_KEY
- eng "View being updated does not have complete key of underlying table in it"
- ger "Die aktualisierte View enthält nicht den vollständigen Schlüssel der zugrunde liegenden Tabelle"
- rus "ïÂÎÏ×ÌÑÅÍÙÊ view ÎÅ ÓÏÄÅÒÖÉÔ ËÌÀÞÁ ÉÓÐÏÌØÚÏ×ÁÎÎÙÈ(ÏÊ) × ÎÅÍ ÔÁÂÌÉÃ(Ù)"
- ukr "View, ÝÏ ÏÎÏ×ÌÀÅÔØÓÑ, ΊͦÓÔÉÔØ ÐÏ×ÎÏÇÏ ËÌÀÞÁ ÔÁÂÌÉæ(Ø), ÝÏ ×ÉËÏÒ¦ÓÔÁÎÁ × ÎØÀÏÍÕ"
-ER_VIEW_INVALID
- eng "View '%-.192s.%-.192s' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them"
-ER_SP_NO_DROP_SP
- eng "Can't drop or alter a %s from within another stored routine"
- ger "Kann eine %s nicht von innerhalb einer anderen gespeicherten Routine löschen oder ändern"
-ER_SP_GOTO_IN_HNDLR
- eng "GOTO is not allowed in a stored procedure handler"
- ger "GOTO ist im Handler einer gespeicherten Prozedur nicht erlaubt"
-ER_TRG_ALREADY_EXISTS
- eng "Trigger already exists"
- ger "Trigger existiert bereits"
-ER_TRG_DOES_NOT_EXIST
- eng "Trigger does not exist"
- ger "Trigger existiert nicht"
-ER_TRG_ON_VIEW_OR_TEMP_TABLE
- eng "Trigger's '%-.192s' is view or temporary table"
- ger "'%-.192s' des Triggers ist View oder temporäre Tabelle"
-ER_TRG_CANT_CHANGE_ROW
- eng "Updating of %s row is not allowed in %strigger"
- ger "Aktualisieren einer %s-Zeile ist in einem %s-Trigger nicht erlaubt"
-ER_TRG_NO_SUCH_ROW_IN_TRG
- eng "There is no %s row in %s trigger"
- ger "Es gibt keine %s-Zeile im %s-Trigger"
-ER_NO_DEFAULT_FOR_FIELD
- eng "Field '%-.192s' doesn't have a default value"
- ger "Feld '%-.192s' hat keinen Vorgabewert"
-ER_DIVISION_BY_ZERO 22012
- eng "Division by 0"
- ger "Division durch 0"
-ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
- eng "Incorrect %-.32s value: '%-.128s' for column '%.192s' at row %ld"
- ger "Falscher %-.32s-Wert: '%-.128s' für Feld '%.192s' in Zeile %ld"
-ER_ILLEGAL_VALUE_FOR_TYPE 22007
- eng "Illegal %s '%-.192s' value found during parsing"
- ger "Nicht zulässiger %s-Wert '%-.192s' beim Parsen gefunden"
-ER_VIEW_NONUPD_CHECK
- eng "CHECK OPTION on non-updatable view '%-.192s.%-.192s'"
- ger "CHECK OPTION auf nicht-aktualisierbarem View '%-.192s.%-.192s'"
- rus "CHECK OPTION ÄÌÑ ÎÅÏÂÎÏ×ÌÑÅÍÏÇÏ VIEW '%-.192s.%-.192s'"
- ukr "CHECK OPTION ÄÌÑ VIEW '%-.192s.%-.192s' ÝÏ ÎÅ ÍÏÖÅ ÂÕÔÉ ÏÎÏ×ÌÅÎÎÉÍ"
-ER_VIEW_CHECK_FAILED
- eng "CHECK OPTION failed '%-.192s.%-.192s'"
- ger "CHECK OPTION fehlgeschlagen: '%-.192s.%-.192s'"
- rus "ÐÒÏ×ÅÒËÁ CHECK OPTION ÄÌÑ VIEW '%-.192s.%-.192s' ÐÒÏ×ÁÌÉÌÁÓØ"
- ukr "ðÅÒÅצÒËÁ CHECK OPTION ÄÌÑ VIEW '%-.192s.%-.192s' ÎÅ ÐÒÏÊÛÌÁ"
-ER_PROCACCESS_DENIED_ERROR 42000
- eng "%-.16s command denied to user '%-.48s'@'%-.64s' for routine '%-.192s'"
- ger "Befehl %-.16s nicht zulässig für Benutzer '%-.48s'@'%-.64s' in Routine '%-.192s'"
-ER_RELAY_LOG_FAIL
- eng "Failed purging old relay logs: %s"
- ger "Bereinigen alter Relais-Logs fehlgeschlagen: %s"
-ER_PASSWD_LENGTH
- eng "Password hash should be a %d-digit hexadecimal number"
- ger "Passwort-Hash sollte eine Hexdaezimalzahl mit %d Stellen sein"
-ER_UNKNOWN_TARGET_BINLOG
- eng "Target log not found in binlog index"
- ger "Ziel-Log im Binlog-Index nicht gefunden"
-ER_IO_ERR_LOG_INDEX_READ
- eng "I/O error reading log index file"
- ger "Fehler beim Lesen der Log-Index-Datei"
-ER_BINLOG_PURGE_PROHIBITED
- eng "Server configuration does not permit binlog purge"
- ger "Server-Konfiguration erlaubt keine Binlog-Bereinigung"
-ER_FSEEK_FAIL
- eng "Failed on fseek()"
- ger "fseek() fehlgeschlagen"
-ER_BINLOG_PURGE_FATAL_ERR
- eng "Fatal error during log purge"
- ger "Schwerwiegender Fehler bei der Log-Bereinigung"
-ER_LOG_IN_USE
- eng "A purgeable log is in use, will not purge"
- ger "Ein zu bereinigendes Log wird gerade benutzt, daher keine Bereinigung"
-ER_LOG_PURGE_UNKNOWN_ERR
- eng "Unknown error during log purge"
- ger "Unbekannter Fehler bei Log-Bereinigung"
-ER_RELAY_LOG_INIT
- eng "Failed initializing relay log position: %s"
- ger "Initialisierung der Relais-Log-Position fehlgeschlagen: %s"
-ER_NO_BINARY_LOGGING
- eng "You are not using binary logging"
- ger "Sie verwenden keine Binärlogs"
-ER_RESERVED_SYNTAX
- eng "The '%-.64s' syntax is reserved for purposes internal to the MySQL server"
- ger "Die Schreibweise '%-.64s' ist für interne Zwecke des MySQL-Servers reserviert"
-ER_WSAS_FAILED
- eng "WSAStartup Failed"
- ger "WSAStartup fehlgeschlagen"
-ER_DIFF_GROUPS_PROC
- eng "Can't handle procedures with different groups yet"
- ger "Kann Prozeduren mit unterschiedlichen Gruppen noch nicht verarbeiten"
-ER_NO_GROUP_FOR_PROC
- eng "Select must have a group with this procedure"
- ger "SELECT muss bei dieser Prozedur ein GROUP BY haben"
-ER_ORDER_WITH_PROC
- eng "Can't use ORDER clause with this procedure"
- ger "Kann bei dieser Prozedur keine ORDER-BY-Klausel verwenden"
-ER_LOGGING_PROHIBIT_CHANGING_OF
- eng "Binary logging and replication forbid changing the global server %s"
- ger "Binärlogs und Replikation verhindern Wechsel des globalen Servers %s"
-ER_NO_FILE_MAPPING
- eng "Can't map file: %-.200s, errno: %d"
- ger "Kann Datei nicht abbilden: %-.200s, Fehler: %d"
-ER_WRONG_MAGIC
- eng "Wrong magic in %-.64s"
- ger "Falsche magische Zahlen in %-.64s"
-ER_PS_MANY_PARAM
- eng "Prepared statement contains too many placeholders"
- ger "Vorbereitete Anweisung enthält zu viele Platzhalter"
-ER_KEY_PART_0
- eng "Key part '%-.192s' length cannot be 0"
- ger "Länge des Schlüsselteils '%-.192s' kann nicht 0 sein"
-ER_VIEW_CHECKSUM
- eng "View text checksum failed"
- ger "View-Text-Prüfsumme fehlgeschlagen"
- rus "ðÒÏ×ÅÒËÁ ËÏÎÔÒÏÌØÎÏÊ ÓÕÍÍÙ ÔÅËÓÔÁ VIEW ÐÒÏ×ÁÌÉÌÁÓØ"
- ukr "ðÅÒÅצÒËÁ ËÏÎÔÒÏÌØÎϧ ÓÕÍÉ ÔÅËÓÔÕ VIEW ÎÅ ÐÒÏÊÛÌÁ"
-ER_VIEW_MULTIUPDATE
- eng "Can not modify more than one base table through a join view '%-.192s.%-.192s'"
- ger "Kann nicht mehr als eine Basistabelle über Join-View '%-.192s.%-.192s' ändern"
- rus "îÅÌØÚÑ ÉÚÍÅÎÉÔØ ÂÏÌØÛÅ ÞÅÍ ÏÄÎÕ ÂÁÚÏ×ÕÀ ÔÁÂÌÉÃÕ ÉÓÐÏÌØÚÕÑ ÍÎÏÇÏÔÁÂÌÉÞÎÙÊ VIEW '%-.192s.%-.192s'"
- ukr "îÅÍÏÖÌÉ×Ï ÏÎÏ×ÉÔÉ Â¦ÌØÛ ÎÉÖ ÏÄÎÕ ÂÁÚÏ×Õ ÔÁÂÌÉÃÀ ×ÙËÏÒÉÓÔÏ×ÕÀÞÉ VIEW '%-.192s.%-.192s', ÝÏ Í¦ÓÔ¦ÔØ ÄÅ˦ÌØËÁ ÔÁÂÌÉÃØ"
-ER_VIEW_NO_INSERT_FIELD_LIST
- eng "Can not insert into join view '%-.192s.%-.192s' without fields list"
- ger "Kann nicht ohne Feldliste in Join-View '%-.192s.%-.192s' einfügen"
- rus "îÅÌØÚÑ ×ÓÔÁ×ÌÑÔØ ÚÁÐÉÓÉ × ÍÎÏÇÏÔÁÂÌÉÞÎÙÊ VIEW '%-.192s.%-.192s' ÂÅÚ ÓÐÉÓËÁ ÐÏÌÅÊ"
- ukr "îÅÍÏÖÌÉ×Ï ÕÓÔÁ×ÉÔÉ ÒÑÄËÉ Õ VIEW '%-.192s.%-.192s', ÝÏ Í¦ÓÔÉÔØ ÄÅ˦ÌØËÁ ÔÁÂÌÉÃØ, ÂÅÚ ÓÐÉÓËÕ ÓÔÏ×Âæ×"
-ER_VIEW_DELETE_MERGE_VIEW
- eng "Can not delete from join view '%-.192s.%-.192s'"
- ger "Kann nicht aus Join-View '%-.192s.%-.192s' löschen"
- rus "îÅÌØÚÑ ÕÄÁÌÑÔØ ÉÚ ÍÎÏÇÏÔÁÂÌÉÞÎÏÇÏ VIEW '%-.192s.%-.192s'"
- ukr "îÅÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÒÑÄËÉ Õ VIEW '%-.192s.%-.192s', ÝÏ Í¦ÓÔÉÔØ ÄÅ˦ÌØËÁ ÔÁÂÌÉÃØ"
-ER_CANNOT_USER
- eng "Operation %s failed for %.256s"
- ger "Operation %s schlug fehl für %.256s"
- norwegian-ny "Operation %s failed for '%.256s'"
-ER_XAER_NOTA XAE04
- eng "XAER_NOTA: Unknown XID"
- ger "XAER_NOTA: Unbekannte XID"
-ER_XAER_INVAL XAE05
- eng "XAER_INVAL: Invalid arguments (or unsupported command)"
- ger "XAER_INVAL: Ungültige Argumente (oder nicht unterstützter Befehl)"
-ER_XAER_RMFAIL XAE07
- eng "XAER_RMFAIL: The command cannot be executed when global transaction is in the %.64s state"
- ger "XAER_RMFAIL: DEr Befehl kann nicht ausgeführt werden, wenn die globale Transaktion im Zustand %.64s ist"
- rus "XAER_RMFAIL: ÜÔÕ ËÏÍÁÎÄÕ ÎÅÌØÚÑ ×ÙÐÏÌÎÑÔØ ËÏÇÄÁ ÇÌÏÂÁÌØÎÁÑ ÔÒÁÎÚÁËÃÉÑ ÎÁÈÏÄÉÔÓÑ × ÓÏÓÔÏÑÎÉÉ '%.64s'"
-ER_XAER_OUTSIDE XAE09
- eng "XAER_OUTSIDE: Some work is done outside global transaction"
- ger "XAER_OUTSIDE: Einige Arbeiten werden außerhalb der globalen Transaktion verrichtet"
-ER_XAER_RMERR XAE03
- eng "XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency"
- ger "XAER_RMERR: Schwerwiegender Fehler im Transaktionszweig - prüfen Sie Ihre Daten auf Konsistenz"
-ER_XA_RBROLLBACK XA100
- eng "XA_RBROLLBACK: Transaction branch was rolled back"
- ger "XA_RBROLLBACK: Transaktionszweig wurde zurückgerollt"
-ER_NONEXISTING_PROC_GRANT 42000
- eng "There is no such grant defined for user '%-.48s' on host '%-.64s' on routine '%-.192s'"
- ger "Es gibt diese Berechtigung für Benutzer '%-.48s' auf Host '%-.64s' für Routine '%-.192s' nicht"
-ER_PROC_AUTO_GRANT_FAIL
- eng "Failed to grant EXECUTE and ALTER ROUTINE privileges"
- ger "Gewährung von EXECUTE- und ALTER-ROUTINE-Rechten fehlgeschlagen"
-ER_PROC_AUTO_REVOKE_FAIL
- eng "Failed to revoke all privileges to dropped routine"
- ger "Rücknahme aller Rechte für die gelöschte Routine fehlgeschlagen"
-ER_DATA_TOO_LONG 22001
- eng "Data too long for column '%s' at row %ld"
- ger "Daten zu lang für Feld '%s' in Zeile %ld"
-ER_SP_BAD_SQLSTATE 42000
- eng "Bad SQLSTATE: '%s'"
- ger "Ungültiger SQLSTATE: '%s'"
-ER_STARTUP
- eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d %s"
- ger "%s: bereit für Verbindungen.\nVersion: '%s' Socket: '%s' Port: %d %s"
-ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR
- eng "Can't load value from file with fixed size rows to variable"
- ger "Kann Wert aus Datei mit Zeilen fester Größe nicht in Variable laden"
-ER_CANT_CREATE_USER_WITH_GRANT 42000
- eng "You are not allowed to create a user with GRANT"
- ger "Sie dürfen keinen Benutzer mit GRANT anlegen"
-ER_WRONG_VALUE_FOR_TYPE
- eng "Incorrect %-.32s value: '%-.128s' for function %-.32s"
- ger "Falscher %-.32s-Wert: '%-.128s' für Funktion %-.32s"
-ER_TABLE_DEF_CHANGED
- eng "Table definition has changed, please retry transaction"
- ger "Tabellendefinition wurde geändert, bitte starten Sie die Transaktion neu"
-ER_SP_DUP_HANDLER 42000
- eng "Duplicate handler declared in the same block"
- ger "Doppelter Handler im selben Block deklariert"
-ER_SP_NOT_VAR_ARG 42000
- eng "OUT or INOUT argument %d for routine %s is not a variable or NEW pseudo-variable in BEFORE trigger"
- ger "OUT- oder INOUT-Argument %d für Routine %s ist keine Variable"
-ER_SP_NO_RETSET 0A000
- eng "Not allowed to return a result set from a %s"
- ger "Rückgabe einer Ergebnismenge aus einer %s ist nicht erlaubt"
-ER_CANT_CREATE_GEOMETRY_OBJECT 22003
- eng "Cannot get geometry object from data you send to the GEOMETRY field"
- ger "Kann kein Geometrieobjekt aus den Daten machen, die Sie dem GEOMETRY-Feld übergeben haben"
-ER_FAILED_ROUTINE_BREAK_BINLOG
- eng "A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes"
- ger "Eine Routine, die weder NO SQL noch READS SQL DATA in der Deklaration hat, schlug fehl und Binärlogging ist aktiv. Wenn Nicht-Transaktions-Tabellen aktualisiert wurden, enthält das Binärlog ihre Änderungen nicht"
-ER_BINLOG_UNSAFE_ROUTINE
- eng "This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)"
- ger "Diese Routine hat weder DETERMINISTIC, NO SQL noch READS SQL DATA in der Deklaration und Binärlogging ist aktiv (*vielleicht* sollten Sie die weniger sichere Variable log_bin_trust_routine_creators verwenden)"
-ER_BINLOG_CREATE_ROUTINE_NEED_SUPER
- eng "You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)"
- ger "Sie haben keine SUPER-Berechtigung und Binärlogging ist aktiv (*vielleicht* sollten Sie die weniger sichere Variable log_bin_trust_routine_creators verwenden)"
-ER_EXEC_STMT_WITH_OPEN_CURSOR
- eng "You can't execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it."
- ger "Sie können keine vorbereitete Anweisung ausführen, die mit einem geöffneten Cursor verknüpft ist. Setzen Sie die Anweisung zurück, um sie neu auszuführen"
-ER_STMT_HAS_NO_OPEN_CURSOR
- eng "The statement (%lu) has no open cursor."
- ger "Die Anweisung (%lu) hat keinen geöffneten Cursor"
-ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
- eng "Explicit or implicit commit is not allowed in stored function or trigger."
- ger "Explizites oder implizites Commit ist in gespeicherten Funktionen und in Triggern nicht erlaubt"
-ER_NO_DEFAULT_FOR_VIEW_FIELD
- eng "Field of view '%-.192s.%-.192s' underlying table doesn't have a default value"
- ger "Ein Feld der dem View '%-.192s.%-.192s' zugrundeliegenden Tabelle hat keinen Vorgabewert"
-ER_SP_NO_RECURSION
- eng "Recursive stored functions and triggers are not allowed."
- ger "Rekursive gespeicherte Routinen und Triggers sind nicht erlaubt"
-ER_TOO_BIG_SCALE 42000 S1009
- eng "Too big scale %d specified for column '%-.192s'. Maximum is %lu."
- ger "Zu großer Skalierungsfaktor %d für Feld '%-.192s' angegeben. Maximum ist %lu"
-ER_TOO_BIG_PRECISION 42000 S1009
- eng "Too big precision %d specified for column '%-.192s'. Maximum is %lu."
- ger "Zu große Genauigkeit %d für Feld '%-.192s' angegeben. Maximum ist %lu"
-ER_M_BIGGER_THAN_D 42000 S1009
- eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s')."
- ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.192s')"
-ER_WRONG_LOCK_OF_SYSTEM_TABLE
- eng "You can't combine write-locking of system tables with other tables or lock types"
- ger "Sie können Schreibsperren auf der Systemtabelle nicht mit anderen Tabellen kombinieren"
-ER_CONNECT_TO_FOREIGN_DATA_SOURCE
- eng "Unable to connect to foreign data source: %.64s"
- ger "Kann nicht mit Fremddatenquelle verbinden: %.64s"
-ER_QUERY_ON_FOREIGN_DATA_SOURCE
- eng "There was a problem processing the query on the foreign data source. Data source error: %-.64s"
- ger "Bei der Verarbeitung der Abfrage ist in der Fremddatenquelle ein Problem aufgetreten. Datenquellenfehlermeldung: %-.64s"
-ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST
- eng "The foreign data source you are trying to reference does not exist. Data source error: %-.64s"
- ger "Die Fremddatenquelle, auf die Sie zugreifen wollen, existiert nicht. Datenquellenfehlermeldung: %-.64s"
-ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE
- eng "Can't create federated table. The data source connection string '%-.64s' is not in the correct format"
- ger "Kann föderierte Tabelle nicht erzeugen. Der Datenquellen-Verbindungsstring '%-.64s' hat kein korrektes Format"
-ER_FOREIGN_DATA_STRING_INVALID
- eng "The data source connection string '%-.64s' is not in the correct format"
- ger "Der Datenquellen-Verbindungsstring '%-.64s' hat kein korrektes Format"
-ER_CANT_CREATE_FEDERATED_TABLE
- eng "Can't create federated table. Foreign data src error: %-.64s"
- ger "Kann föderierte Tabelle nicht erzeugen. Fremddatenquellenfehlermeldung: %-.64s"
-ER_TRG_IN_WRONG_SCHEMA
- eng "Trigger in wrong schema"
- ger "Trigger im falschen Schema"
-ER_STACK_OVERRUN_NEED_MORE
- eng "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use 'mysqld -O thread_stack=#' to specify a bigger stack."
- ger "Thread-Stack-Überlauf: %ld Bytes eines %ld-Byte-Stacks in Verwendung, und %ld Bytes benötigt. Verwenden Sie 'mysqld -O thread_stack=#', um einen größeren Stack anzugeben"
-ER_TOO_LONG_BODY 42000 S1009
- eng "Routine body for '%-.100s' is too long"
- ger "Routinen-Body für '%-.100s' ist zu lang"
-ER_WARN_CANT_DROP_DEFAULT_KEYCACHE
- eng "Cannot drop default keycache"
- ger "Der vorgabemäßige Schlüssel-Cache kann nicht gelöscht werden"
-ER_TOO_BIG_DISPLAYWIDTH 42000 S1009
- eng "Display width out of range for column '%-.192s' (max = %lu)"
- ger "Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%-.192s' (Maximum: %lu)"
-ER_XAER_DUPID XAE08
- eng "XAER_DUPID: The XID already exists"
- ger "XAER_DUPID: Die XID existiert bereits"
-ER_DATETIME_FUNCTION_OVERFLOW 22008
- eng "Datetime function: %-.32s field overflow"
- ger "Datetime-Funktion: %-.32s Feldüberlauf"
-ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
- eng "Can't update table '%-.192s' in stored function/trigger because it is already used by statement which invoked this stored function/trigger."
- ger "Kann Tabelle '%-.192s' in gespeicherter Funktion oder Trigger nicht aktualisieren, weil sie bereits von der Anweisung verwendet wird, die diese gespeicherte Funktion oder den Trigger aufrief"
-ER_VIEW_PREVENT_UPDATE
- eng "The definition of table '%-.192s' prevents operation %.192s on table '%-.192s'."
- ger "Die Definition der Tabelle '%-.192s' verhindert die Operation %.192s auf Tabelle '%-.192s'"
-ER_PS_NO_RECURSION
- eng "The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner"
- ger "Die vorbereitete Anweisung enthält einen Aufruf einer gespeicherten Routine, die auf eben dieselbe Anweisung verweist. Es ist nicht erlaubt, eine vorbereitete Anweisung in solch rekursiver Weise auszuführen"
-ER_SP_CANT_SET_AUTOCOMMIT
- eng "Not allowed to set autocommit from a stored function or trigger"
- ger "Es ist nicht erlaubt, innerhalb einer gespeicherten Funktion oder eines Triggers AUTOCOMMIT zu setzen"
-ER_MALFORMED_DEFINER
- eng "Definer is not fully qualified"
- ger "Definierer des View ist nicht vollständig spezifiziert"
-ER_VIEW_FRM_NO_USER
- eng "View '%-.192s'.'%-.192s' has no definer information (old table format). Current user is used as definer. Please recreate the view!"
- ger "View '%-.192s'.'%-.192s' hat keine Definierer-Information (altes Tabellenformat). Der aktuelle Benutzer wird als Definierer verwendet. Bitte erstellen Sie den View neu"
-ER_VIEW_OTHER_USER
- eng "You need the SUPER privilege for creation view with '%-.192s'@'%-.192s' definer"
- ger "Sie brauchen die SUPER-Berechtigung, um einen View mit dem Definierer '%-.192s'@'%-.192s' zu erzeugen"
-ER_NO_SUCH_USER
- eng "The user specified as a definer ('%-.64s'@'%-.64s') does not exist"
-ER_FORBID_SCHEMA_CHANGE
- eng "Changing schema from '%-.192s' to '%-.192s' is not allowed."
- ger "Wechsel des Schemas von '%-.192s' auf '%-.192s' ist nicht erlaubt"
-ER_ROW_IS_REFERENCED_2 23000
- eng "Cannot delete or update a parent row: a foreign key constraint fails (%.192s)"
- ger "Kann Eltern-Zeile nicht löschen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl (%.192s)"
-ER_NO_REFERENCED_ROW_2 23000
- eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)"
- ger "Kann Kind-Zeile nicht hinzufügen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl (%.192s)"
-ER_SP_BAD_VAR_SHADOW 42000
- eng "Variable '%-.64s' must be quoted with `...`, or renamed"
- ger "Variable '%-.64s' muss mit `...` geschützt oder aber umbenannt werden"
-ER_TRG_NO_DEFINER
- eng "No definer attribute for trigger '%-.192s'.'%-.192s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger."
- ger "Kein Definierer-Attribut für Trigger '%-.192s'.'%-.192s'. Der Trigger wird mit der Autorisierung des Aufrufers aktiviert, der möglicherweise keine zureichenden Berechtigungen hat. Bitte legen Sie den Trigger neu an."
-ER_OLD_FILE_FORMAT
- eng "'%-.192s' has an old format, you should re-create the '%s' object(s)"
- ger "'%-.192s' hat altes Format, Sie sollten die '%s'-Objekt(e) neu erzeugen"
-ER_SP_RECURSION_LIMIT
- eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.192s"
- ger "Rekursionsgrenze %d (durch Variable max_sp_recursion_depth gegeben) wurde für Routine %.192s überschritten"
-ER_SP_PROC_TABLE_CORRUPT
- eng "Failed to load routine %-.192s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)"
- ger "Routine %-.192s konnte nicht geladen werden. Die Tabelle mysql.proc fehlt, ist beschädigt, oder enthält fehlerhaften Daten (interner Code: %d)"
-ER_SP_WRONG_NAME 42000
- eng "Incorrect routine name '%-.192s'"
- ger "Ungültiger Routinenname '%-.192s'"
-ER_TABLE_NEEDS_UPGRADE
- eng "Table upgrade required. Please do \"REPAIR TABLE `%-.32s`\" or dump/reload to fix it!"
- ger "Tabellenaktualisierung erforderlich. Bitte zum Reparieren \"REPAIR TABLE `%-.32s`\" eingeben!"
-ER_SP_NO_AGGREGATE 42000
- eng "AGGREGATE is not supported for stored functions"
- ger "AGGREGATE wird bei gespeicherten Funktionen nicht unterstützt"
-ER_MAX_PREPARED_STMT_COUNT_REACHED 42000
- eng "Can't create more than max_prepared_stmt_count statements (current value: %lu)"
- ger "Kann nicht mehr Anweisungen als max_prepared_stmt_count erzeugen (aktueller Wert: %lu)"
-ER_VIEW_RECURSIVE
- eng "`%-.192s`.`%-.192s` contains view recursion"
- ger "`%-.192s`.`%-.192s` enthält View-Rekursion"
-ER_NON_GROUPING_FIELD_USED 42000
- eng "non-grouping field '%-.192s' is used in %-.64s clause"
- ger "In der %-.192s-Klausel wird das die Nicht-Gruppierungsspalte '%-.64s' verwendet"
-ER_TABLE_CANT_HANDLE_SPKEYS
- eng "The used table type doesn't support SPATIAL indexes"
- ger "Der verwendete Tabellentyp unterstützt keine SPATIAL-Indizes"
-ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
- eng "Triggers can not be created on system tables"
- ger "Trigger können nicht auf Systemtabellen erzeugt werden"
-ER_REMOVED_SPACES
- eng "Leading spaces are removed from name '%s'"
- ger "Führende Leerzeichen werden aus dem Namen '%s' entfernt"
-ER_AUTOINC_READ_FAILED
- eng "Failed to read auto-increment value from storage engine"
- ger "Lesen des Autoincrement-Werts von der Speicher-Engine fehlgeschlagen"
-ER_USERNAME
- eng "user name"
- ger "Benutzername"
-ER_HOSTNAME
- eng "host name"
- ger "Hostname"
-ER_WRONG_STRING_LENGTH
- eng "String '%-.70s' is too long for %s (should be no longer than %d)"
- ger "String '%-.70s' ist zu lang für %s (sollte nicht länger sein als %d)"
-ER_NON_INSERTABLE_TABLE
- eng "The target table %-.100s of the %s is not insertable-into"
- ger "Die Zieltabelle %-.100s von %s ist nicht einfügbar"
-ER_ADMIN_WRONG_MRG_TABLE
- eng "Table '%-.64s' is differently defined or of non-MyISAM type or doesn't exist"
-ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT
- eng "Too high level of nesting for select"
-ER_NAME_BECOMES_EMPTY
- eng "Name '%-.64s' has become ''"
-ER_AMBIGUOUS_FIELD_TERM
- eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY"
-ER_FOREIGN_SERVER_EXISTS
- eng "The foreign server, %s, you are trying to create already exists."
-ER_FOREIGN_SERVER_DOESNT_EXIST
- eng "The foreign server name you are trying to reference does not exist. Data source error: %-.64s"
- ger "Die externe Verbindung, auf die Sie zugreifen wollen, existiert nicht. Datenquellenfehlermeldung: %-.64s"
-ER_ILLEGAL_HA_CREATE_OPTION
- eng "Table storage engine '%-.64s' does not support the create option '%.64s'"
- ger "Speicher-Engine '%-.64s' der Tabelle unterstützt die Option '%.64s' nicht"
-ER_PARTITION_REQUIRES_VALUES_ERROR
- eng "Syntax error: %-.64s PARTITIONING requires definition of VALUES %-.64s for each partition"
- ger "Fehler in der SQL-Syntax: %-.64s-PARTITIONierung erfordert Definition von VALUES %-.64s für jede Partition"
- swe "Syntaxfel: %-.64s PARTITIONering kräver definition av VALUES %-.64s för varje partition"
-ER_PARTITION_WRONG_VALUES_ERROR
- eng "Only %-.64s PARTITIONING can use VALUES %-.64s in partition definition"
- ger "Nur %-.64s-PARTITIONierung kann VALUES %-.64s in der Partitionsdefinition verwenden"
- swe "Endast %-.64s partitionering kan använda VALUES %-.64s i definition av partitionen"
-ER_PARTITION_MAXVALUE_ERROR
- eng "MAXVALUE can only be used in last partition definition"
- ger "MAXVALUE kann nur für die Definition der letzten Partition verwendet werden"
- swe "MAXVALUE kan bara användas i definitionen av den sista partitionen"
-ER_PARTITION_SUBPARTITION_ERROR
- eng "Subpartitions can only be hash partitions and by key"
- ger "Unterpartitionen dürfen nur HASH- oder KEY-Partitionen sein"
- swe "Subpartitioner kan bara vara hash och key partitioner"
-ER_PARTITION_SUBPART_MIX_ERROR
- eng "Must define subpartitions on all partitions if on one partition"
- ger "Unterpartitionen können nur Hash- oder Key-Partitionen sein"
- swe "Subpartitioner måste definieras på alla partitioner om på en"
-ER_PARTITION_WRONG_NO_PART_ERROR
- eng "Wrong number of partitions defined, mismatch with previous setting"
- ger "Falsche Anzahl von Partitionen definiert, stimmt nicht mit vorherigen Einstellungen überein"
- swe "Antal partitioner definierade och antal partitioner är inte lika"
-ER_PARTITION_WRONG_NO_SUBPART_ERROR
- eng "Wrong number of subpartitions defined, mismatch with previous setting"
- ger "Falsche Anzahl von Unterpartitionen definiert, stimmt nicht mit vorherigen Einstellungen überein"
- swe "Antal subpartitioner definierade och antal subpartitioner är inte lika"
-ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
- eng "Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed"
- ger "Konstante oder Random-Ausdrücke in (Unter-)Partitionsfunktionen sind nicht erlaubt"
- swe "Konstanta uttryck eller slumpmässiga uttryck är inte tillåtna (sub)partitioneringsfunktioner"
-ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR
- eng "Expression in RANGE/LIST VALUES must be constant"
- ger "Ausdrücke in RANGE/LIST VALUES müssen konstant sein"
- swe "Uttryck i RANGE/LIST VALUES måste vara ett konstant uttryck"
-ER_FIELD_NOT_FOUND_PART_ERROR
- eng "Field in list of fields for partition function not found in table"
- ger "Felder in der Feldliste der Partitionierungsfunktion wurden in der Tabelle nicht gefunden"
- swe "Fält i listan av fält för partitionering med key inte funnen i tabellen"
-ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR
- eng "List of fields is only allowed in KEY partitions"
- ger "Eine Feldliste ist nur in KEY-Partitionen erlaubt"
- swe "En lista av fält är endast tillåtet för KEY partitioner"
-ER_INCONSISTENT_PARTITION_INFO_ERROR
- eng "The partition info in the frm file is not consistent with what can be written into the frm file"
- ger "Die Partitionierungsinformationen in der frm-Datei stimmen nicht mit dem überein, was in die frm-Datei geschrieben werden kann"
- swe "Partitioneringsinformationen i frm-filen är inte konsistent med vad som kan skrivas i frm-filen"
-ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
- eng "The %-.192s function returns the wrong type"
- ger "Die %-.192s-Funktion gibt einen falschen Typ zurück"
- swe "%-.192s-funktionen returnerar felaktig typ"
-ER_PARTITIONS_MUST_BE_DEFINED_ERROR
- eng "For %-.64s partitions each partition must be defined"
- ger "Für %-.64s-Partitionen muss jede Partition definiert sein"
- swe "För %-.64s partitionering så måste varje partition definieras"
-ER_RANGE_NOT_INCREASING_ERROR
- eng "VALUES LESS THAN value must be strictly increasing for each partition"
- ger "Werte in VALUES LESS THAN müssen für jede Partition strikt aufsteigend sein"
- swe "Värden i VALUES LESS THAN måste vara strikt växande för varje partition"
-ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR
- eng "VALUES value must be of same type as partition function"
- ger "VALUES-Werte müssen vom selben Typ wie die Partitionierungsfunktion sein"
- swe "Värden i VALUES måste vara av samma typ som partitioneringsfunktionen"
-ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR
- eng "Multiple definition of same constant in list partitioning"
- ger "Mehrfachdefinition derselben Konstante bei Listen-Partitionierung"
- swe "Multipel definition av samma konstant i list partitionering"
-ER_PARTITION_ENTRY_ERROR
- eng "Partitioning can not be used stand-alone in query"
- ger "Partitionierung kann in einer Abfrage nicht alleinstehend benutzt werden"
- swe "Partitioneringssyntax kan inte användas på egen hand i en SQL-fråga"
-ER_MIX_HANDLER_ERROR
- eng "The mix of handlers in the partitions is not allowed in this version of MySQL"
- ger "Das Vermischen von Handlern in Partitionen ist in dieser Version von MySQL nicht erlaubt"
- swe "Denna mix av lagringsmotorer är inte tillåten i denna version av MySQL"
-ER_PARTITION_NOT_DEFINED_ERROR
- eng "For the partitioned engine it is necessary to define all %-.64s"
- ger "Für die partitionierte Engine müssen alle %-.64s definiert sein"
- swe "För partitioneringsmotorn så är det nödvändigt att definiera alla %-.64s"
-ER_TOO_MANY_PARTITIONS_ERROR
- eng "Too many partitions (including subpartitions) were defined"
- ger "Es wurden zu vielen Partitionen (einschließlich Unterpartitionen) definiert"
- swe "För många partitioner (inkluderande subpartitioner) definierades"
-ER_SUBPARTITION_ERROR
- eng "It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning"
- ger "RANGE/LIST-Partitionierung kann bei Unterpartitionen nur zusammen mit HASH/KEY-Partitionierung verwendet werden"
- swe "Det är endast möjligt att blanda RANGE/LIST partitionering med HASH/KEY partitionering för subpartitionering"
-ER_CANT_CREATE_HANDLER_FILE
- eng "Failed to create specific handler file"
- ger "Erzeugen einer spezifischen Handler-Datei fehlgeschlagen"
- swe "Misslyckades med att skapa specifik fil i lagringsmotor"
-ER_BLOB_FIELD_IN_PART_FUNC_ERROR
- eng "A BLOB field is not allowed in partition function"
- ger "In der Partitionierungsfunktion sind BLOB-Spalten nicht erlaubt"
- swe "Ett BLOB-fält är inte tillåtet i partitioneringsfunktioner"
-ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF
- eng "A %-.192s must include all columns in the table's partitioning function"
-ER_NO_PARTS_ERROR
- eng "Number of %-.64s = 0 is not an allowed value"
- ger "Eine Anzahl von %-.64s = 0 ist kein erlaubter Wert"
- swe "Antal %-.64s = 0 är inte ett tillåten värde"
-ER_PARTITION_MGMT_ON_NONPARTITIONED
- eng "Partition management on a not partitioned table is not possible"
- ger "Partitionsverwaltung einer nicht partitionierten Tabelle ist nicht möglich"
- swe "Partitioneringskommando på en opartitionerad tabell är inte möjligt"
-ER_FOREIGN_KEY_ON_PARTITIONED
- eng "Foreign key clause is not yet supported in conjunction with partitioning"
- ger "Fremdschlüssel-Beschränkungen sind im Zusammenhang mit Partitionierung nicht zulässig"
- swe "Foreign key klausul är inte ännu implementerad i kombination med partitionering"
-ER_DROP_PARTITION_NON_EXISTENT
- eng "Error in list of partitions to %-.64s"
- ger "Fehler in der Partitionsliste bei %-.64s"
- swe "Fel i listan av partitioner att %-.64s"
-ER_DROP_LAST_PARTITION
- eng "Cannot remove all partitions, use DROP TABLE instead"
- ger "Es lassen sich nicht sämtliche Partitionen löschen, benutzen Sie statt dessen DROP TABLE"
- swe "Det är inte tillåtet att ta bort alla partitioner, använd DROP TABLE istället"
-ER_COALESCE_ONLY_ON_HASH_PARTITION
- eng "COALESCE PARTITION can only be used on HASH/KEY partitions"
- ger "COALESCE PARTITION kann nur auf HASH- oder KEY-Partitionen benutzt werden"
- swe "COALESCE PARTITION kan bara användas på HASH/KEY partitioner"
-ER_REORG_HASH_ONLY_ON_SAME_NO
- eng "REORGANIZE PARTITION can only be used to reorganize partitions not to change their numbers"
- ger "REORGANIZE PARTITION kann nur zur Reorganisation von Partitionen verwendet werden, nicht, um ihre Nummern zu ändern"
- swe "REORGANIZE PARTITION kan bara användas för att omorganisera partitioner, inte för att ändra deras antal"
-ER_REORG_NO_PARAM_ERROR
- eng "REORGANIZE PARTITION without parameters can only be used on auto-partitioned tables using HASH PARTITIONs"
- ger "REORGANIZE PARTITION ohne Parameter kann nur für auto-partitionierte Tabellen verwendet werden, die HASH-Partitionierung benutzen"
- swe "REORGANIZE PARTITION utan parametrar kan bara användas på auto-partitionerade tabeller som använder HASH partitionering"
-ER_ONLY_ON_RANGE_LIST_PARTITION
- eng "%-.64s PARTITION can only be used on RANGE/LIST partitions"
- ger "%-.64s PARTITION kann nur für RANGE- oder LIST-Partitionen verwendet werden"
- swe "%-.64s PARTITION kan bara användas på RANGE/LIST-partitioner"
-ER_ADD_PARTITION_SUBPART_ERROR
- eng "Trying to Add partition(s) with wrong number of subpartitions"
- ger "Es wurde versucht, eine oder mehrere Partitionen mit der falschen Anzahl von Unterpartitionen hinzuzufügen"
- swe "ADD PARTITION med fel antal subpartitioner"
-ER_ADD_PARTITION_NO_NEW_PARTITION
- eng "At least one partition must be added"
- ger "Es muss zumindest eine Partition hinzugefügt werden"
- swe "Åtminstone en partition måste läggas till vid ADD PARTITION"
-ER_COALESCE_PARTITION_NO_PARTITION
- eng "At least one partition must be coalesced"
- ger "Zumindest eine Partition muss mit COALESCE PARTITION zusammengefügt werden"
- swe "Åtminstone en partition måste slås ihop vid COALESCE PARTITION"
-ER_REORG_PARTITION_NOT_EXIST
- eng "More partitions to reorganize than there are partitions"
- ger "Es wurde versucht, mehr Partitionen als vorhanden zu reorganisieren"
- swe "Fler partitioner att reorganisera än det finns partitioner"
-ER_SAME_NAME_PARTITION
- eng "Duplicate partition name %-.192s"
- ger "Doppelter Partitionsname: %-.192s"
- swe "Duplicerat partitionsnamn %-.192s"
-ER_NO_BINLOG_ERROR
- eng "It is not allowed to shut off binlog on this command"
- ger "Es es nicht erlaubt, bei diesem Befehl binlog abzuschalten"
- swe "Det är inte tillåtet att stänga av binlog på detta kommando"
-ER_CONSECUTIVE_REORG_PARTITIONS
- eng "When reorganizing a set of partitions they must be in consecutive order"
- ger "Bei der Reorganisation eines Satzes von Partitionen müssen diese in geordneter Reihenfolge vorliegen"
- swe "När ett antal partitioner omorganiseras måste de vara i konsekutiv ordning"
-ER_REORG_OUTSIDE_RANGE
- eng "Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range"
- ger "Die Reorganisation von RANGE-Partitionen kann Gesamtbereiche nicht verändern, mit Ausnahme der letzten Partition, die den Bereich erweitern kann"
- swe "Reorganisering av rangepartitioner kan inte ändra den totala intervallet utom för den sista partitionen där intervallet kan utökas"
-ER_PARTITION_FUNCTION_FAILURE
- eng "Partition function not supported in this version for this handler"
- ger "Partitionsfunktion in dieser Version dieses Handlers nicht unterstützt"
-ER_PART_STATE_ERROR
- eng "Partition state cannot be defined from CREATE/ALTER TABLE"
- ger "Partitionszustand kann nicht von CREATE oder ALTER TABLE aus definiert werden"
- swe "Partition state kan inte definieras från CREATE/ALTER TABLE"
-ER_LIMITED_PART_RANGE
- eng "The %-.64s handler only supports 32 bit integers in VALUES"
- ger "Der Handler %-.64s unterstützt in VALUES nur 32-Bit-Integers"
- swe "%-.64s stödjer endast 32 bitar i integers i VALUES"
-ER_PLUGIN_IS_NOT_LOADED
- eng "Plugin '%-.192s' is not loaded"
- ger "Plugin '%-.192s' ist nicht geladen"
-ER_WRONG_VALUE
- eng "Incorrect %-.32s value: '%-.128s'"
- ger "Falscher %-.32s-Wert: '%-.128s'"
-ER_NO_PARTITION_FOR_GIVEN_VALUE
- eng "Table has no partition for value %-.64s"
- ger "Tabelle hat für den Wert %-.64s keine Partition"
-ER_FILEGROUP_OPTION_ONLY_ONCE
- eng "It is not allowed to specify %s more than once"
- ger "%s darf nicht mehr als einmal angegegeben werden"
-ER_CREATE_FILEGROUP_FAILED
- eng "Failed to create %s"
- ger "Anlegen von %s fehlgeschlagen"
-ER_DROP_FILEGROUP_FAILED
- eng "Failed to drop %s"
- ger "Löschen (drop) von %s fehlgeschlagen"
-ER_TABLESPACE_AUTO_EXTEND_ERROR
- eng "The handler doesn't support autoextend of tablespaces"
- ger "Der Handler unterstützt keine automatische Erweiterung (Autoextend) von Tablespaces"
-ER_WRONG_SIZE_NUMBER
- eng "A size parameter was incorrectly specified, either number or on the form 10M"
- ger "Ein Größen-Parameter wurde unkorrekt angegeben, muss entweder Zahl sein oder im Format 10M"
-ER_SIZE_OVERFLOW_ERROR
- eng "The size number was correct but we don't allow the digit part to be more than 2 billion"
- ger "Die Zahl für die Größe war korrekt, aber der Zahlanteil darf nicht größer als 2 Milliarden sein"
-ER_ALTER_FILEGROUP_FAILED
- eng "Failed to alter: %s"
- ger "Änderung von %s fehlgeschlagen"
-ER_BINLOG_ROW_LOGGING_FAILED
- eng "Writing one row to the row-based binary log failed"
- ger "Schreiben einer Zeilen ins zeilenbasierte Binärlog fehlgeschlagen"
-ER_BINLOG_ROW_WRONG_TABLE_DEF
- eng "Table definition on master and slave does not match: %s"
- ger "Tabellendefinition auf Master und Slave stimmt nicht überein: %s"
-ER_BINLOG_ROW_RBR_TO_SBR
- eng "Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events"
- ger "Slave, die mit --log-slave-updates laufen, müssen zeilenbasiertes Loggen verwenden, um zeilenbasierte Binärlog-Ereignisse loggen zu können"
-ER_EVENT_ALREADY_EXISTS
- eng "Event '%-.192s' already exists"
- ger "Event '%-.192s' existiert bereits"
-ER_EVENT_STORE_FAILED
- eng "Failed to store event %s. Error code %d from storage engine."
- ger "Speichern von Event %s fehlgeschlagen. Fehlercode der Speicher-Engine: %d"
-ER_EVENT_DOES_NOT_EXIST
- eng "Unknown event '%-.192s'"
- ger "Unbekanntes Event '%-.192s'"
-ER_EVENT_CANT_ALTER
- eng "Failed to alter event '%-.192s'"
- ger "Ändern des Events '%-.192s' fehlgeschlagen"
-ER_EVENT_DROP_FAILED
- eng "Failed to drop %s"
- ger "Löschen von %s fehlgeschlagen"
-ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG
- eng "INTERVAL is either not positive or too big"
- ger "INTERVAL ist entweder nicht positiv oder zu groß"
-ER_EVENT_ENDS_BEFORE_STARTS
- eng "ENDS is either invalid or before STARTS"
- ger "ENDS ist entweder ungültig oder liegt vor STARTS"
-ER_EVENT_EXEC_TIME_IN_THE_PAST
- eng "Event execution time is in the past. Event has been disabled"
-ER_EVENT_OPEN_TABLE_FAILED
- eng "Failed to open mysql.event"
- ger "Öffnen von mysql.event fehlgeschlagen"
-ER_EVENT_NEITHER_M_EXPR_NOR_M_AT
- eng "No datetime expression provided"
- ger "Kein DATETIME-Ausdruck angegeben"
-ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
- eng "Column count of mysql.%s is wrong. Expected %d, found %d. The table is probably corrupted"
- ger "Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d gefunden. Tabelle ist wahrscheinlich beschädigt"
-ER_CANNOT_LOAD_FROM_TABLE
- eng "Cannot load from mysql.%s. The table is probably corrupted"
- ger "Kann mysql.%s nicht einlesen. Tabelle ist wahrscheinlich beschädigt"
-ER_EVENT_CANNOT_DELETE
- eng "Failed to delete the event from mysql.event"
- ger "Löschen des Events aus mysql.event fehlgeschlagen"
-ER_EVENT_COMPILE_ERROR
- eng "Error during compilation of event's body"
- ger "Fehler beim Kompilieren des Event-Bodys"
-ER_EVENT_SAME_NAME
- eng "Same old and new event name"
- ger "Alter und neuer Event-Name sind gleich"
-ER_EVENT_DATA_TOO_LONG
- eng "Data for column '%s' too long"
- ger "Daten der Spalte '%s' zu lang"
-ER_DROP_INDEX_FK
- eng "Cannot drop index '%-.192s': needed in a foreign key constraint"
- ger "Kann Index '%-.192s' nicht löschen: wird für einen Fremdschlüssel benötigt"
-# When using this error message, use the ER_WARN_DEPRECATED_SYNTAX error
-# code. See, for example, code in mysql_priv.h.
-ER_WARN_DEPRECATED_SYNTAX_WITH_VER
- eng "The syntax '%s' is deprecated and will be removed in MySQL %s. Please use %s instead"
- ger "Die Syntax '%s' ist veraltet und wird in MySQL %s entfernt. Bitte benutzen Sie statt dessen %s"
-ER_CANT_WRITE_LOCK_LOG_TABLE
- eng "You can't write-lock a log table. Only read access is possible"
- ger "Eine Log-Tabelle kann nicht schreibgesperrt werden. Es ist ohnehin nur Lesezugriff möglich"
-ER_CANT_LOCK_LOG_TABLE
- eng "You can't use locks with log tables."
- ger "Log-Tabellen können nicht mit normalen Lesesperren gesperrt werden. Verwenden Sie statt dessen READ LOCAL"
-ER_FOREIGN_DUPLICATE_KEY 23000 S1009
- eng "Upholding foreign key constraints for table '%.192s', entry '%-.192s', key %d would lead to a duplicate entry"
- ger "Aufrechterhalten der Fremdschlüssel-Constraints für Tabelle '%.192s', Eintrag '%-.192s', Schlüssel %d würde zu einem doppelten Eintrag führen"
-ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE
- eng "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use mysql_upgrade to fix this error."
- ger "Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d erhalten. Erzeugt mit MySQL %d, jetzt unter %d. Bitte benutzen Sie mysql_upgrade, um den Fehler zu beheben"
-ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR
- eng "Cannot switch out of the row-based binary log format when the session has open temporary tables"
- ger "Kann nicht aus dem zeilenbasierten Binärlog-Format herauswechseln, wenn die Sitzung offene temporäre Tabellen hat"
-ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT
- eng "Cannot change the binary logging format inside a stored function or trigger"
- ger "Das Binärlog-Format kann innerhalb einer gespeicherten Funktion oder eines Triggers nicht geändert werden"
-ER_NDB_CANT_SWITCH_BINLOG_FORMAT
- eng "The NDB cluster engine does not support changing the binlog format on the fly yet"
- ger "Die Speicher-Engine NDB Cluster unterstützt das Ändern des Binärlog-Formats zur Laufzeit noch nicht"
-ER_PARTITION_NO_TEMPORARY
- eng "Cannot create temporary table with partitions"
- ger "Anlegen temporärer Tabellen mit Partitionen nicht möglich"
-ER_PARTITION_CONST_DOMAIN_ERROR
- eng "Partition constant is out of partition function domain"
- ger "Partitionskonstante liegt außerhalb der Partitionsfunktionsdomäne"
- swe "Partitionskonstanten är utanför partitioneringsfunktionens domän"
-ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
- eng "This partition function is not allowed"
- ger "Diese Partitionierungsfunktion ist nicht erlaubt"
- swe "Denna partitioneringsfunktion är inte tillåten"
-ER_DDL_LOG_ERROR
- eng "Error in DDL log"
- ger "Fehler im DDL-Log"
-ER_NULL_IN_VALUES_LESS_THAN
- eng "Not allowed to use NULL value in VALUES LESS THAN"
- ger "In VALUES LESS THAN dürfen keine NULL-Werte verwendet werden"
- swe "Det är inte tillåtet att använda NULL-värden i VALUES LESS THAN"
-ER_WRONG_PARTITION_NAME
- eng "Incorrect partition name"
- ger "Falscher Partitionsname"
- swe "Felaktigt partitionsnamn"
-ER_CANT_CHANGE_TX_ISOLATION 25001
- eng "Transaction isolation level can't be changed while a transaction is in progress"
- ger "Transaktionsisolationsebene kann während einer laufenden Transaktion nicht geändert werden"
-ER_DUP_ENTRY_AUTOINCREMENT_CASE
- eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.192s' for key '%-.192s'"
- ger "ALTER TABLE führt zur Neusequenzierung von auto_increment, wodurch der doppelte Eintrag '%-.192s' für Schlüssel '%-.192s' auftritt"
-ER_EVENT_MODIFY_QUEUE_ERROR
- eng "Internal scheduler error %d"
- ger "Interner Scheduler-Fehler %d"
-ER_EVENT_SET_VAR_ERROR
- eng "Error during starting/stopping of the scheduler. Error code %u"
- ger "Fehler während des Startens oder Anhalten des Schedulers. Fehlercode %u"
-ER_PARTITION_MERGE_ERROR
- eng "Engine cannot be used in partitioned tables"
- ger "Engine kann in partitionierten Tabellen nicht verwendet werden"
- swe "Engine inte användas i en partitionerad tabell"
-ER_CANT_ACTIVATE_LOG
- eng "Cannot activate '%-.64s' log"
- ger "Kann Logdatei '%-.64s' nicht aktivieren"
-ER_RBR_NOT_AVAILABLE
- eng "The server was not built with row-based replication"
-ER_BASE64_DECODE_ERROR
- eng "Decoding of base64 string failed"
- swe "Avkodning av base64 sträng misslyckades"
- ger "Der Server hat keine zeilenbasierte Replikation"
-ER_EVENT_RECURSION_FORBIDDEN
- eng "Recursion of EVENT DDL statements is forbidden when body is present"
- ger "Rekursivität von EVENT-DDL-Anweisungen ist unzulässig wenn ein Hauptteil (Body) existiert"
-ER_EVENTS_DB_ERROR
- eng "Cannot proceed because system tables used by Event Scheduler were found damaged at server start"
- ger "Kann nicht weitermachen, weil die Tabellen, die von Events verwendet werden, beim Serverstart als beschädigt markiert wurden"
-ER_ONLY_INTEGERS_ALLOWED
- eng "Only integers allowed as number here"
- ger "An dieser Stelle sind nur Ganzzahlen zulässig"
-ER_UNSUPORTED_LOG_ENGINE
- eng "This storage engine cannot be used for log tables""
- ger "Diese Speicher-Engine kann für Logtabellen nicht verwendet werden"
-ER_BAD_LOG_STATEMENT
- eng "You cannot '%s' a log table if logging is enabled"
- ger "Sie können eine Logtabelle nicht '%s', wenn Loggen angeschaltet ist"
-ER_CANT_RENAME_LOG_TABLE
- eng "Cannot rename '%s'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to '%s'"
- ger "Kann '%s' nicht umbenennen. Wenn Loggen angeschaltet ist, müssen beim Umbenennen zu/von einer Logtabelle zwei Tabellen angegeben werden: die Logtabelle zu einer Archivtabelle und eine weitere Tabelle zurück zu '%s'"
-ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 42000
- eng "Incorrect parameter count in the call to native function '%-.192s'"
- ger "Falsche Anzahl von Parametern beim Aufruf der nativen Funktion '%-.192s'"
-ER_WRONG_PARAMETERS_TO_NATIVE_FCT 42000
- eng "Incorrect parameters in the call to native function '%-.192s'"
- ger "Falscher Parameter beim Aufruf der nativen Funktion '%-.192s'"
-ER_WRONG_PARAMETERS_TO_STORED_FCT 42000
- eng "Incorrect parameters in the call to stored function '%-.192s'"
- ger "Falsche Parameter beim Aufruf der gespeicherten Funktion '%-.192s'"
-ER_NATIVE_FCT_NAME_COLLISION
- eng "This function '%-.192s' has the same name as a native function"
- ger "Die Funktion '%-.192s' hat denselben Namen wie eine native Funktion"
-# When using this error message, use the ER_DUP_ENTRY error code. See, for
-# example, code in handler.cc.
-ER_DUP_ENTRY_WITH_KEY_NAME 23000 S1009
- cze "Zvojen-Bý klíè '%-.64s' (èíslo klíèe '%-.192s')"
- dan "Ens værdier '%-.64s' for indeks '%-.192s'"
- nla "Dubbele ingang '%-.64s' voor zoeksleutel '%-.192s'"
- eng "Duplicate entry '%-.64s' for key '%-.192s'"
- jps "'%-.64s' ‚Í key '%-.192s' ‚É‚¨‚¢‚Äd•¡‚µ‚Ä‚¢‚Ü‚·",
- est "Kattuv väärtus '%-.64s' võtmele '%-.192s'"
- fre "Duplicata du champ '%-.64s' pour la clef '%-.192s'"
- ger "Doppelter Eintrag '%-.64s' für Schlüssel '%-.192s'"
- greek "ÄéðëÞ åããñáöÞ '%-.64s' ãéá ôï êëåéäß '%-.192s'"
- hun "Duplikalt bejegyzes '%-.64s' a '%-.192s' kulcs szerint."
- ita "Valore duplicato '%-.64s' per la chiave '%-.192s'"
- jpn "'%-.64s' ¤Ï key '%-.192s' ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
- kor "Áߺ¹µÈ ÀÔ·Â °ª '%-.64s': key '%-.192s'"
- nor "Like verdier '%-.64s' for nøkkel '%-.192s'"
- norwegian-ny "Like verdiar '%-.64s' for nykkel '%-.192s'"
- pol "Powtórzone wyst?pienie '%-.64s' dla klucza '%-.192s'"
- por "Entrada '%-.64s' duplicada para a chave '%-.192s'"
- rum "Cimpul '%-.64s' e duplicat pentru cheia '%-.192s'"
- rus "äÕÂÌÉÒÕÀÝÁÑÓÑ ÚÁÐÉÓØ '%-.64s' ÐÏ ËÌÀÞÕ '%-.192s'"
- serbian "Dupliran unos '%-.64s' za kljuè '%-.192s'"
- slo "Opakovaný kµúè '%-.64s' (èíslo kµúèa '%-.192s')"
- spa "Entrada duplicada '%-.64s' para la clave '%-.192s'"
- swe "Dubbel nyckel '%-.64s' för nyckel '%-.192s'"
- ukr "äÕÂÌÀÀÞÉÊ ÚÁÐÉÓ '%-.64s' ÄÌÑ ËÌÀÞÁ '%-.192s'"
-ER_BINLOG_PURGE_EMFILE
- eng "Too many files opened, please execute the command again"
- ger "Zu viele offene Dateien, bitte führen Sie den Befehl noch einmal aus"
-ER_EVENT_CANNOT_CREATE_IN_THE_PAST
- eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation."
-ER_EVENT_CANNOT_ALTER_IN_THE_PAST
- eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation."
-ER_SLAVE_INCIDENT
- eng "The incident %s occured on the master. Message: %-.64s"
-ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT
- eng "Table has no partition for some existing values"
-ER_BINLOG_UNSAFE_STATEMENT
- eng "Statement may not be safe to log in statement format."
- swe "Detta är inte säkert att logga i statement-format."
-ER_SLAVE_FATAL_ERROR
- eng "Fatal error: %s"
-ER_SLAVE_RELAY_LOG_READ_FAILURE
- eng "Relay log read failure: %s"
-ER_SLAVE_RELAY_LOG_WRITE_FAILURE
- eng "Relay log write failure: %s"
-ER_SLAVE_CREATE_EVENT_FAILURE
- eng "Failed to create %s"
-ER_SLAVE_MASTER_COM_FAILURE
- eng "Master command %s failed: %s"
-ER_BINLOG_LOGGING_IMPOSSIBLE
- eng "Binary logging not possible. Message: %s"
-
-ER_VIEW_NO_CREATION_CTX
- eng "View `%-.64s`.`%-.64s` has no creation context"
-ER_VIEW_INVALID_CREATION_CTX
- eng "Creation context of view `%-.64s`.`%-.64s' is invalid"
-
-ER_SR_INVALID_CREATION_CTX
- eng "Creation context of stored routine `%-.64s`.`%-.64s` is invalid"
-
-ER_TRG_CORRUPTED_FILE
- eng "Corrupted TRG file for table `%-.64s`.`%-.64s`"
-ER_TRG_NO_CREATION_CTX
- eng "Triggers for table `%-.64s`.`%-.64s` have no creation context"
-ER_TRG_INVALID_CREATION_CTX
- eng "Trigger creation context of table `%-.64s`.`%-.64s` is invalid"
-
-ER_EVENT_INVALID_CREATION_CTX
- eng "Creation context of event `%-.64s`.`%-.64s` is invalid"
-
-ER_TRG_CANT_OPEN_TABLE
- eng "Cannot open table for trigger `%-.64s`.`%-.64s`"
-
-ER_CANT_CREATE_SROUTINE
- eng "Cannot create stored routine `%-.64s`. Check warnings"
-ER_SLAVE_AMBIGOUS_EXEC_MODE
- eng "Ambiguous slave modes combination. %s"
-
-ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT
- eng "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement."
-ER_SLAVE_CORRUPT_EVENT
- eng "Corrupted replication event was detected"
-
-ER_LOAD_DATA_INVALID_COLUMN
- eng "Invalid column reference (%-.64s) in LOAD DATA"
-
-ER_LOG_PURGE_NO_FILE
- eng "Being purged log %s was not found"
-
-ER_XA_RBTIMEOUT XA106
- eng "XA_RBTIMEOUT: Transaction branch was rolled back: took too long"
-
-ER_XA_RBDEADLOCK XA102
- eng "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected"
-
-ER_NEED_REPREPARE
- eng "Prepared statement needs to be re-prepared"
-
-ER_DELAYED_NOT_SUPPORTED
- eng "DELAYED option not supported for table '%-.192s'"
-
-WARN_NO_MASTER_INFO
- eng "The master info structure does not exist"
-
-WARN_OPTION_IGNORED
- eng "<%-.64s> option ignored"
-
-WARN_PLUGIN_DELETE_BUILTIN
- eng "Built-in plugins cannot be deleted"
-
-WARN_PLUGIN_BUSY
- eng "Plugin is busy and will be uninstalled on shutdown"
-
-ER_VARIABLE_IS_READONLY
- eng "%s variable '%s' is read-only. Use SET %s to assign the value"
-
-ER_WARN_ENGINE_TRANSACTION_ROLLBACK
- eng "Storage engine %s does not support rollback for this statement. Transaction rolled back and must be restarted"
-
-ER_SLAVE_HEARTBEAT_FAILURE
- eng "Unexpected master's heartbeat data: %s"
-ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
- eng "The requested value for the heartbeat period %s %s"
-
-ER_NDB_REPLICATION_SCHEMA_ERROR
- eng "Bad schema for mysql.ndb_replication table. Message: %-.64s"
-ER_CONFLICT_FN_PARSE_ERROR
- eng "Error in parsing conflict function. Message: %-.64s"
-ER_EXCEPTIONS_WRITE_ERROR
- eng "Write to exceptions table failed. Message: %-.128s""
-
-ER_TOO_LONG_TABLE_COMMENT
- eng "Comment for table '%-.64s' is too long (max = %lu)"
- por "Comentário para a tabela '%-.64s' é longo demais (max = %lu)"
-
-ER_TOO_LONG_FIELD_COMMENT
- eng "Comment for field '%-.64s' is too long (max = %lu)"
- por "Comentário para o campo '%-.64s' é longo demais (max = %lu)"
-
-ER_FUNC_INEXISTENT_NAME_COLLISION 42000
- eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual"
-
-# When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in
-# mysql_priv.h with the new maximal additional length for explain_filename.
-ER_DATABASE_NAME
- eng "Database"
- swe "Databas"
-ER_TABLE_NAME
- eng "Table"
- swe "Tabell"
-ER_PARTITION_NAME
- eng "Partition"
- swe "Partition"
-ER_SUBPARTITION_NAME
- eng "Subpartition"
- swe "Subpartition"
-ER_TEMPORARY_NAME
- eng "Temporary"
- swe "Temporär"
-ER_RENAMED_NAME
- eng "Renamed"
- swe "Namnändrad"
-ER_TOO_MANY_CONCURRENT_TRXS
- eng "Too many active concurrent transactions"
-
-WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED
- eng "Non-ASCII separator arguments are not fully supported"
-
-ER_DEBUG_SYNC_TIMEOUT
- eng "debug sync point wait timed out"
- ger "Debug Sync Point Wartezeit überschritten"
-ER_DEBUG_SYNC_HIT_LIMIT
- eng "debug sync point hit limit reached"
- ger "Debug Sync Point Hit Limit erreicht"
diff --git a/sql/slave.cc b/sql/slave.cc
index 96319de5427..8568a119fe8 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -24,22 +24,33 @@
replication slave.
*/
-#include "mysql_priv.h"
-
-#include <mysql.h>
-#include <myisam.h>
+#include "sql_priv.h"
+#include "my_global.h"
#include "slave.h"
+#include "sql_parse.h" // execute_init_command
+#include "sql_table.h" // mysql_rm_table
#include "rpl_mi.h"
#include "rpl_rli.h"
#include "sql_repl.h"
#include "rpl_filter.h"
#include "repl_failsafe.h"
+#include "transaction.h"
#include <thr_alarm.h>
#include <my_dir.h>
#include <sql_common.h>
#include <errmsg.h>
#include <mysqld_error.h>
#include <mysys_err.h>
+#include "rpl_handler.h"
+#include <signal.h>
+#include <mysql.h>
+#include <myisam.h>
+
+#include "sql_base.h" // close_thread_tables
+#include "tztime.h" // struct Time_zone
+#include "log_event.h" // Rotate_log_event,
+ // Create_file_log_event,
+ // Format_description_log_event
#ifdef HAVE_REPLICATION
@@ -49,6 +60,10 @@
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
#define MAX_SLAVE_RETRY_PAUSE 5
+/*
+ a parameter of sql_slave_killed() to defer the killed status
+*/
+#define SLAVE_WAIT_GROUP_DONE 60
bool use_slave_mask = 0;
MY_BITMAP slave_error_mask;
char slave_skip_error_names[SHOW_VAR_FUNC_BUFF_SIZE];
@@ -68,7 +83,8 @@ ulonglong relay_log_space_limit = 0;
*/
int disconnect_slave_event_count = 0, abort_slave_event_count = 0;
-int events_till_abort = -1;
+
+static pthread_key(Master_info*, RPL_MASTER_INFO);
enum enum_slave_reconnect_actions
{
@@ -138,15 +154,12 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi,
bool reconnect, bool suppress_warnings);
static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
void* thread_killed_arg);
-static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
-static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
- const char* table_name, bool overwrite);
static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi);
static Log_event* next_event(Relay_log_info* rli);
static int queue_event(Master_info* mi,const char* buf,ulong event_len);
static int terminate_slave_thread(THD *thd,
- pthread_mutex_t *term_lock,
- pthread_cond_t *term_cond,
+ mysql_mutex_t *term_lock,
+ mysql_cond_t *term_cond,
volatile uint *slave_running,
bool skip_lock);
static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info);
@@ -195,8 +208,8 @@ void lock_slave_threads(Master_info* mi)
DBUG_ENTER("lock_slave_threads");
//TODO: see if we can do this without dual mutex
- pthread_mutex_lock(&mi->run_lock);
- pthread_mutex_lock(&mi->rli.run_lock);
+ mysql_mutex_lock(&mi->run_lock);
+ mysql_mutex_lock(&mi->rli.run_lock);
DBUG_VOID_RETURN;
}
@@ -210,29 +223,58 @@ void unlock_slave_threads(Master_info* mi)
DBUG_ENTER("unlock_slave_threads");
//TODO: see if we can do this without dual mutex
- pthread_mutex_unlock(&mi->rli.run_lock);
- pthread_mutex_unlock(&mi->run_lock);
+ mysql_mutex_unlock(&mi->rli.run_lock);
+ mysql_mutex_unlock(&mi->run_lock);
DBUG_VOID_RETURN;
}
+#ifdef HAVE_PSI_INTERFACE
+static PSI_thread_key key_thread_slave_io, key_thread_slave_sql;
+
+static PSI_thread_info all_slave_threads[]=
+{
+ { &key_thread_slave_io, "slave_io", PSI_FLAG_GLOBAL},
+ { &key_thread_slave_sql, "slave_sql", PSI_FLAG_GLOBAL}
+};
+
+static void init_slave_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_slave_threads);
+ PSI_server->register_thread(category, all_slave_threads, count);
+}
+#endif /* HAVE_PSI_INTERFACE */
/* Initialize slave structures */
int init_slave()
{
DBUG_ENTER("init_slave");
+ int error= 0;
+
+#ifdef HAVE_PSI_INTERFACE
+ init_slave_psi_keys();
+#endif
/*
This is called when mysqld starts. Before client connections are
accepted. However bootstrap may conflict with us if it does START SLAVE.
So it's safer to take the lock.
*/
- pthread_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_active_mi);
/*
TODO: re-write this to interate through the list of files
for multi-master
*/
- active_mi= new Master_info;
+ active_mi= new Master_info(relay_log_recovery);
+
+ if (pthread_key_create(&RPL_MASTER_INFO, NULL))
+ goto err;
/*
If --slave-skip-errors=... was not used, the string value for the
@@ -251,22 +293,21 @@ int init_slave()
if (!active_mi)
{
sql_print_error("Failed to allocate memory for the master info structure");
+ error= 1;
goto err;
}
if (init_master_info(active_mi,master_info_file,relay_log_info_file,
- !master_host, (SLAVE_IO | SLAVE_SQL)))
+ 1, (SLAVE_IO | SLAVE_SQL)))
{
sql_print_error("Failed to initialize the master info structure");
+ error= 1;
goto err;
}
- if (server_id && !master_host && active_mi->host[0])
- master_host= active_mi->host;
-
/* If server id is not set, start_slave_thread() will say it */
- if (master_host && !opt_skip_slave_start)
+ if (active_mi->host[0] && !opt_skip_slave_start)
{
if (start_slave_threads(1 /* need mutex */,
0 /* no wait for start*/,
@@ -276,18 +317,69 @@ int init_slave()
SLAVE_IO | SLAVE_SQL))
{
sql_print_error("Failed to create slave threads");
+ error= 1;
goto err;
}
}
- pthread_mutex_unlock(&LOCK_active_mi);
- DBUG_RETURN(0);
err:
- pthread_mutex_unlock(&LOCK_active_mi);
- DBUG_RETURN(1);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ DBUG_RETURN(error);
}
+/*
+ Updates the master info based on the information stored in the
+ relay info and ignores relay logs previously retrieved by the IO
+ thread, which thus starts fetching again based on to the
+ group_master_log_pos and group_master_log_name. Eventually, the old
+ relay logs will be purged by the normal purge mechanism.
+
+ In the feature, we should improve this routine in order to avoid throwing
+ away logs that are safely stored in the disk. Note also that this recovery
+ routine relies on the correctness of the relay-log.info and only tolerates
+ coordinate problems in master.info.
+
+ In this function, there is no need for a mutex as the caller
+ (i.e. init_slave) already has one acquired.
+
+ Specifically, the following structures are updated:
+
+ 1 - mi->master_log_pos <-- rli->group_master_log_pos
+ 2 - mi->master_log_name <-- rli->group_master_log_name
+ 3 - It moves the relay log to the new relay log file, by
+ rli->group_relay_log_pos <-- BIN_LOG_HEADER_SIZE;
+ rli->event_relay_log_pos <-- BIN_LOG_HEADER_SIZE;
+ rli->group_relay_log_name <-- rli->relay_log.get_log_fname();
+ rli->event_relay_log_name <-- rli->relay_log.get_log_fname();
+
+ If there is an error, it returns (1), otherwise returns (0).
+ */
+int init_recovery(Master_info* mi, const char** errmsg)
+{
+ DBUG_ENTER("init_recovery");
+
+ Relay_log_info *rli= &mi->rli;
+ if (rli->group_master_log_name[0])
+ {
+ mi->master_log_pos= max(BIN_LOG_HEADER_SIZE,
+ rli->group_master_log_pos);
+ strmake(mi->master_log_name, rli->group_master_log_name,
+ sizeof(mi->master_log_name)-1);
+
+ sql_print_warning("Recovery from master pos %ld and file %s.",
+ (ulong) mi->master_log_pos, mi->master_log_name);
+
+ strmake(rli->group_relay_log_name, rli->relay_log.get_log_fname(),
+ sizeof(rli->group_relay_log_name)-1);
+ strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(),
+ sizeof(mi->rli.event_relay_log_name)-1);
+
+ rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
+ }
+ DBUG_RETURN(0);
+}
+
/**
Convert slave skip errors bitmap into a printable string.
*/
@@ -305,6 +397,9 @@ static void print_slave_skip_errors(void)
DBUG_ASSERT(sizeof(slave_skip_error_names) > MIN_ROOM);
DBUG_ASSERT(MAX_SLAVE_ERROR <= 999999); // 6 digits
+ /* Make @@slave_skip_errors show the nice human-readable value. */
+ opt_slave_skip_errors= slave_skip_error_names;
+
if (!use_slave_mask || bitmap_is_clear_all(&slave_error_mask))
{
/* purecov: begin tested */
@@ -406,7 +501,8 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
if (!mi->inited)
DBUG_RETURN(0); /* successfully do nothing */
int error,force_all = (thread_mask & SLAVE_FORCE_ALL);
- pthread_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock;
+ mysql_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock;
+ mysql_mutex_t *log_lock= mi->rli.relay_log.get_log_lock();
if (thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL))
{
@@ -418,6 +514,22 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
skip_lock)) &&
!force_all)
DBUG_RETURN(error);
+
+ mysql_mutex_lock(log_lock);
+
+ DBUG_PRINT("info",("Flushing relay log and master info file."));
+ if (current_thd)
+ thd_proc_info(current_thd, "Flushing relay log and master info files.");
+ if (flush_master_info(mi, TRUE, FALSE))
+ DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
+
+ if (my_sync(mi->rli.relay_log.get_log_file()->file, MYF(MY_WME)))
+ DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
+
+ if (my_sync(mi->fd, MYF(MY_WME)))
+ DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
+
+ mysql_mutex_unlock(log_lock);
}
if (thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL))
{
@@ -429,8 +541,21 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
skip_lock)) &&
!force_all)
DBUG_RETURN(error);
+
+ mysql_mutex_lock(log_lock);
+
+ DBUG_PRINT("info",("Flushing relay-log info file."));
+ if (current_thd)
+ thd_proc_info(current_thd, "Flushing relay-log info file.");
+ if (flush_relay_log_info(&mi->rli))
+ DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
+
+ if (my_sync(mi->rli.info_fd, MYF(MY_WME)))
+ DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
+
+ mysql_mutex_unlock(log_lock);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(0);
}
@@ -470,19 +595,19 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
*/
static int
terminate_slave_thread(THD *thd,
- pthread_mutex_t *term_lock,
- pthread_cond_t *term_cond,
+ mysql_mutex_t *term_lock,
+ mysql_cond_t *term_cond,
volatile uint *slave_running,
bool skip_lock)
{
DBUG_ENTER("terminate_slave_thread");
if (!skip_lock)
{
- pthread_mutex_lock(term_lock);
+ mysql_mutex_lock(term_lock);
}
else
{
- safe_mutex_assert_owner(term_lock);
+ mysql_mutex_assert_owner(term_lock);
}
if (!*slave_running)
{
@@ -492,7 +617,7 @@ terminate_slave_thread(THD *thd,
if run_lock (term_lock) is acquired locally then either
slave_running status is fine
*/
- pthread_mutex_unlock(term_lock);
+ mysql_mutex_unlock(term_lock);
DBUG_RETURN(0);
}
else
@@ -513,18 +638,18 @@ terminate_slave_thread(THD *thd,
int error;
DBUG_PRINT("loop", ("killing slave thread"));
- pthread_mutex_lock(&thd->LOCK_thd_data);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
#ifndef DONT_USE_THR_ALARM
/*
Error codes from pthread_kill are:
EINVAL: invalid signal number (can't happen)
ESRCH: thread already killed (can happen, should be ignored)
*/
- IF_DBUG(int err= ) pthread_kill(thd->real_id, thr_client_alarm);
+ int err __attribute__((unused))= pthread_kill(thd->real_id, thr_client_alarm);
DBUG_ASSERT(err != EINVAL);
#endif
thd->awake(THD::NOT_KILLED);
- pthread_mutex_unlock(&thd->LOCK_thd_data);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
/*
There is a small chance that slave thread might miss the first
@@ -532,25 +657,28 @@ terminate_slave_thread(THD *thd,
*/
struct timespec abstime;
set_timespec(abstime,2);
- error= pthread_cond_timedwait(term_cond, term_lock, &abstime);
+ error= mysql_cond_timedwait(term_cond, term_lock, &abstime);
DBUG_ASSERT(error == ETIMEDOUT || error == 0);
}
DBUG_ASSERT(*slave_running == 0);
if (!skip_lock)
- pthread_mutex_unlock(term_lock);
+ mysql_mutex_unlock(term_lock);
DBUG_RETURN(0);
}
-int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
- pthread_mutex_t *cond_lock,
- pthread_cond_t *start_cond,
+int start_slave_thread(
+#ifdef HAVE_PSI_INTERFACE
+ PSI_thread_key thread_key,
+#endif
+ pthread_handler h_func, mysql_mutex_t *start_lock,
+ mysql_mutex_t *cond_lock,
+ mysql_cond_t *start_cond,
volatile uint *slave_running,
volatile ulong *slave_run_id,
- Master_info* mi,
- bool high_priority)
+ Master_info* mi)
{
pthread_t th;
ulong start_id;
@@ -559,13 +687,13 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
DBUG_ASSERT(mi->inited);
if (start_lock)
- pthread_mutex_lock(start_lock);
+ mysql_mutex_lock(start_lock);
if (!server_id)
{
if (start_cond)
- pthread_cond_broadcast(start_cond);
+ mysql_cond_broadcast(start_cond);
if (start_lock)
- pthread_mutex_unlock(start_lock);
+ mysql_mutex_unlock(start_lock);
sql_print_error("Server id not set, will not start slave");
DBUG_RETURN(ER_BAD_SLAVE);
}
@@ -573,19 +701,18 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
if (*slave_running)
{
if (start_cond)
- pthread_cond_broadcast(start_cond);
+ mysql_cond_broadcast(start_cond);
if (start_lock)
- pthread_mutex_unlock(start_lock);
+ mysql_mutex_unlock(start_lock);
DBUG_RETURN(ER_SLAVE_MUST_STOP);
}
start_id= *slave_run_id;
DBUG_PRINT("info",("Creating new slave thread"));
- if (high_priority)
- my_pthread_attr_setprio(&connection_attrib,CONNECT_PRIOR);
- if (pthread_create(&th, &connection_attrib, h_func, (void*)mi))
+ if (mysql_thread_create(thread_key,
+ &th, &connection_attrib, h_func, (void*)mi))
{
if (start_lock)
- pthread_mutex_unlock(start_lock);
+ mysql_mutex_unlock(start_lock);
DBUG_RETURN(ER_SLAVE_THREAD);
}
if (start_cond && cond_lock) // caller has cond_lock
@@ -594,17 +721,29 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
while (start_id == *slave_run_id)
{
DBUG_PRINT("sleep",("Waiting for slave thread to start"));
- const char* old_msg = thd->enter_cond(start_cond,cond_lock,
- "Waiting for slave thread to start");
- pthread_cond_wait(start_cond,cond_lock);
+ const char *old_msg= thd->enter_cond(start_cond, cond_lock,
+ "Waiting for slave thread to start");
+ /*
+ It is not sufficient to test this at loop bottom. We must test
+ it after registering the mutex in enter_cond(). If the kill
+ happens after testing of thd->killed and before the mutex is
+ registered, we could otherwise go waiting though thd->killed is
+ set.
+ */
+ if (!thd->killed)
+ mysql_cond_wait(start_cond, cond_lock);
thd->exit_cond(old_msg);
- pthread_mutex_lock(cond_lock); // re-acquire it as exit_cond() released
+ mysql_mutex_lock(cond_lock); // re-acquire it as exit_cond() released
if (thd->killed)
+ {
+ if (start_lock)
+ mysql_mutex_unlock(start_lock);
DBUG_RETURN(thd->killed_errno());
+ }
}
}
if (start_lock)
- pthread_mutex_unlock(start_lock);
+ mysql_mutex_unlock(start_lock);
DBUG_RETURN(0);
}
@@ -622,8 +761,8 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
Master_info* mi, const char* master_info_fname,
const char* slave_info_fname, int thread_mask)
{
- pthread_mutex_t *lock_io=0,*lock_sql=0,*lock_cond_io=0,*lock_cond_sql=0;
- pthread_cond_t* cond_io=0,*cond_sql=0;
+ mysql_mutex_t *lock_io=0, *lock_sql=0, *lock_cond_io=0, *lock_cond_sql=0;
+ mysql_cond_t* cond_io=0, *cond_sql=0;
int error=0;
DBUG_ENTER("start_slave_threads");
@@ -641,16 +780,24 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
}
if (thread_mask & SLAVE_IO)
- error=start_slave_thread(handle_slave_io,lock_io,lock_cond_io,
- cond_io,
- &mi->slave_running, &mi->slave_run_id,
- mi, 1); //high priority, to read the most possible
+ error= start_slave_thread(
+#ifdef HAVE_PSI_INTERFACE
+ key_thread_slave_io,
+#endif
+ handle_slave_io, lock_io, lock_cond_io,
+ cond_io,
+ &mi->slave_running, &mi->slave_run_id,
+ mi);
if (!error && (thread_mask & SLAVE_SQL))
{
- error=start_slave_thread(handle_slave_sql,lock_sql,lock_cond_sql,
- cond_sql,
- &mi->rli.slave_running, &mi->rli.slave_run_id,
- mi, 0);
+ error= start_slave_thread(
+#ifdef HAVE_PSI_INTERFACE
+ key_thread_slave_sql,
+#endif
+ handle_slave_sql, lock_sql, lock_cond_sql,
+ cond_sql,
+ &mi->rli.slave_running, &mi->rli.slave_run_id,
+ mi);
if (error)
terminate_slave_threads(mi, thread_mask & SLAVE_IO, !need_slave_mutex);
}
@@ -658,17 +805,6 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
}
-#ifdef NOT_USED_YET
-static int end_slave_on_walk(Master_info* mi, uchar* /*unused*/)
-{
- DBUG_ENTER("end_slave_on_walk");
-
- end_master_info(mi);
- DBUG_RETURN(0);
-}
-#endif
-
-
/*
Release slave threads at time of executing shutdown.
@@ -687,7 +823,7 @@ void end_slave()
will make us wait until slave threads have started, and START SLAVE
returns, then we terminate them here.
*/
- pthread_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_active_mi);
if (active_mi)
{
/*
@@ -697,7 +833,7 @@ void end_slave()
*/
terminate_slave_threads(active_mi,SLAVE_FORCE_ALL);
}
- pthread_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_unlock(&LOCK_active_mi);
DBUG_VOID_RETURN;
}
@@ -712,14 +848,14 @@ void end_slave()
*/
void close_active_mi()
{
- pthread_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_active_mi);
if (active_mi)
{
end_master_info(active_mi);
delete active_mi;
active_mi= 0;
}
- pthread_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_unlock(&LOCK_active_mi);
}
static bool io_slave_killed(THD* thd, Master_info* mi)
@@ -731,9 +867,22 @@ static bool io_slave_killed(THD* thd, Master_info* mi)
DBUG_RETURN(mi->abort_slave || abort_loop || thd->killed);
}
+/**
+ The function analyzes a possible killed status and makes
+ a decision whether to accept it or not.
+ Normally upon accepting the sql thread goes to shutdown.
+ In the event of deffering decision @rli->last_event_start_time waiting
+ timer is set to force the killed status be accepted upon its expiration.
+
+ @param thd pointer to a THD instance
+ @param rli pointer to Relay_log_info instance
+ @return TRUE the killed status is recognized, FALSE a possible killed
+ status is deferred.
+*/
static bool sql_slave_killed(THD* thd, Relay_log_info* rli)
{
+ bool ret= FALSE;
DBUG_ENTER("sql_slave_killed");
DBUG_ASSERT(rli->sql_thd == thd);
@@ -748,36 +897,72 @@ static bool sql_slave_killed(THD* thd, Relay_log_info* rli)
as well.
Example: OPTION_KEEP_LOG is set if a temporary table is created or dropped.
*/
- if (rli->abort_slave && rli->is_in_group() &&
- (thd->transaction.all.modified_non_trans_table ||
- (thd->options & OPTION_KEEP_LOG)))
- DBUG_RETURN(0);
- /*
- If we are in an unsafe situation (stopping could corrupt replication),
- we give one minute to the slave SQL thread of grace before really
- terminating, in the hope that it will be able to read more events and
- the unsafe situation will soon be left. Note that this one minute starts
- from the last time anything happened in the slave SQL thread. So it's
- really one minute of idleness, we don't timeout if the slave SQL thread
- is actively working.
- */
- if (rli->last_event_start_time == 0)
- DBUG_RETURN(1);
- DBUG_PRINT("info", ("Slave SQL thread is in an unsafe situation, giving "
- "it some grace period"));
- if (difftime(time(0), rli->last_event_start_time) > 60)
+ if ((thd->transaction.all.modified_non_trans_table ||
+ (thd->variables.option_bits & OPTION_KEEP_LOG))
+ && rli->is_in_group())
{
- rli->report(ERROR_LEVEL, 0,
- "SQL thread had to stop in an unsafe situation, in "
- "the middle of applying updates to a "
- "non-transactional table without any primary key. "
- "There is a risk of duplicate updates when the slave "
- "SQL thread is restarted. Please check your tables' "
- "contents after restart.");
- DBUG_RETURN(1);
+ char msg_stopped[]=
+ "... The slave SQL is stopped, leaving the current group "
+ "of events unfinished with a non-transaction table changed. "
+ "If the group consists solely of Row-based events, you can try "
+ "restarting the slave with --slave-exec-mode=IDEMPOTENT, which "
+ "ignores duplicate key, key not found, and similar errors (see "
+ "documentation for details).";
+
+ if (rli->abort_slave)
+ {
+ DBUG_PRINT("info", ("Slave SQL thread is being stopped in the middle of"
+ " a group having updated a non-trans table, giving"
+ " it some grace period"));
+
+ /*
+ Slave sql thread shutdown in face of unfinished group modified
+ Non-trans table is handled via a timer. The slave may eventually
+ give out to complete the current group and in that case there
+ might be issues at consequent slave restart, see the error message.
+ WL#2975 offers a robust solution requiring to store the last exectuted
+ event's coordinates along with the group's coordianates
+ instead of waiting with @c last_event_start_time the timer.
+ */
+
+ if (rli->last_event_start_time == 0)
+ rli->last_event_start_time= my_time(0);
+ ret= difftime(my_time(0), rli->last_event_start_time) <=
+ SLAVE_WAIT_GROUP_DONE ? FALSE : TRUE;
+
+ DBUG_EXECUTE_IF("stop_slave_middle_group",
+ DBUG_EXECUTE_IF("incomplete_group_in_relay_log",
+ ret= TRUE;);); // time is over
+
+ if (ret == 0)
+ {
+ rli->report(WARNING_LEVEL, 0,
+ "slave SQL thread is being stopped in the middle "
+ "of applying of a group having updated a non-transaction "
+ "table; waiting for the group completion ... ");
+ }
+ else
+ {
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER(ER_SLAVE_FATAL_ERROR), msg_stopped);
+ }
+ }
+ else
+ {
+ ret= TRUE;
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, ER(ER_SLAVE_FATAL_ERROR),
+ msg_stopped);
+ }
+ }
+ else
+ {
+ ret= TRUE;
}
}
- DBUG_RETURN(0);
+ if (ret)
+ rli->last_event_start_time= 0;
+
+ DBUG_RETURN(ret);
}
@@ -870,6 +1055,115 @@ int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
DBUG_RETURN(1);
}
+int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val)
+{
+ char buf[16];
+ DBUG_ENTER("init_floatvar_from_file");
+
+
+ if (my_b_gets(f, buf, sizeof(buf)))
+ {
+ if (sscanf(buf, "%f", var) != 1)
+ DBUG_RETURN(1);
+ else
+ DBUG_RETURN(0);
+ }
+ else if (default_val != 0.0)
+ {
+ *var = default_val;
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(1);
+}
+
+
+/**
+ A master info read method
+
+ This function is called from @c init_master_info() along with
+ relatives to restore some of @c active_mi members.
+ Particularly, this function is responsible for restoring
+ IGNORE_SERVER_IDS list of servers whose events the slave is
+ going to ignore (to not log them in the relay log).
+ Items being read are supposed to be decimal output of values of a
+ type shorter or equal of @c long and separated by the single space.
+
+ @param arr @c DYNAMIC_ARRAY pointer to storage for servers id
+ @param f @c IO_CACHE pointer to the source file
+
+ @retval 0 All OK
+ @retval non-zero An error
+*/
+
+int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f)
+{
+ int ret= 0;
+ char buf[16 * (sizeof(long)*4 + 1)]; // static buffer to use most of times
+ char *buf_act= buf; // actual buffer can be dynamic if static is short
+ char *token, *last;
+ uint num_items; // number of items of `arr'
+ size_t read_size;
+ DBUG_ENTER("init_dynarray_intvar_from_file");
+
+ if ((read_size= my_b_gets(f, buf_act, sizeof(buf))) == 0)
+ {
+ return 0; // no line in master.info
+ }
+ if (read_size + 1 == sizeof(buf) && buf[sizeof(buf) - 2] != '\n')
+ {
+ /*
+ short read happend; allocate sufficient memory and make the 2nd read
+ */
+ char buf_work[(sizeof(long)*3 + 1)*16];
+ memcpy(buf_work, buf, sizeof(buf_work));
+ num_items= atoi(strtok_r(buf_work, " ", &last));
+ size_t snd_size;
+ /*
+ max size lower bound approximate estimation bases on the formula:
+ (the items number + items themselves) *
+ (decimal size + space) - 1 + `\n' + '\0'
+ */
+ size_t max_size= (1 + num_items) * (sizeof(long)*3 + 1) + 1;
+ buf_act= (char*) my_malloc(max_size, MYF(MY_WME));
+ memcpy(buf_act, buf, read_size);
+ snd_size= my_b_gets(f, buf_act + read_size, max_size - read_size);
+ if (snd_size == 0 ||
+ ((snd_size + 1 == max_size - read_size) && buf[max_size - 2] != '\n'))
+ {
+ /*
+ failure to make the 2nd read or short read again
+ */
+ ret= 1;
+ goto err;
+ }
+ }
+ token= strtok_r(buf_act, " ", &last);
+ if (token == NULL)
+ {
+ ret= 1;
+ goto err;
+ }
+ num_items= atoi(token);
+ for (uint i=0; i < num_items; i++)
+ {
+ token= strtok_r(NULL, " ", &last);
+ if (token == NULL)
+ {
+ ret= 1;
+ goto err;
+ }
+ else
+ {
+ ulong val= atol(token);
+ insert_dynamic(arr, (uchar *) &val);
+ }
+ }
+err:
+ if (buf_act != buf)
+ my_free(buf_act);
+ DBUG_RETURN(ret);
+}
+
/*
Check if the error is caused by network.
@@ -1009,6 +1303,8 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
mi->clock_diff_with_master=
(long) (time((time_t*) 0) - strtoul(master_row[0], 0, 10));
}
+ else if (check_io_slave_killed(mi->io_thd, mi, NULL))
+ goto slave_killed_err;
else if (is_network_error(mysql_errno(mysql)))
{
mi->report(WARNING_LEVEL, mysql_errno(mysql),
@@ -1055,7 +1351,7 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
(master_res= mysql_store_result(mysql)) &&
(master_row= mysql_fetch_row(master_res)))
{
- if ((::server_id == strtoul(master_row[1], 0, 10)) &&
+ if ((::server_id == (mi->master_id= strtoul(master_row[1], 0, 10))) &&
!mi->rli.replicate_same_server_id)
{
errmsg= "The slave I/O thread stops because master and slave have equal \
@@ -1069,7 +1365,9 @@ not always make sense; please check the manual before using it).";
}
else if (mysql_errno(mysql))
{
- if (is_network_error(mysql_errno(mysql)))
+ if (check_io_slave_killed(mi->io_thd, mi, NULL))
+ goto slave_killed_err;
+ else if (is_network_error(mysql_errno(mysql)))
{
mi->report(WARNING_LEVEL, mysql_errno(mysql),
"Get master SERVER_ID failed with error: %s", mysql_error(mysql));
@@ -1093,6 +1391,13 @@ maybe it is a *VERY OLD MASTER*.");
mysql_free_result(master_res);
master_res= NULL;
}
+ if (mi->master_id == 0 && mi->ignore_server_ids.elements > 0)
+ {
+ errmsg= "Slave configured with server id filtering could not detect the master server id.";
+ err_code= ER_SLAVE_FATAL_ERROR;
+ sprintf(err_buff, ER(err_code), errmsg);
+ goto err;
+ }
/*
Check that the master's global character_set_server and ours are the same.
@@ -1133,6 +1438,8 @@ be equal for the Statement-format replication to work";
goto err;
}
}
+ else if (check_io_slave_killed(mi->io_thd, mi, NULL))
+ goto slave_killed_err;
else if (is_network_error(mysql_errno(mysql)))
{
mi->report(WARNING_LEVEL, mysql_errno(mysql),
@@ -1194,6 +1501,8 @@ be equal for the Statement-format replication to work";
goto err;
}
}
+ else if (check_io_slave_killed(mi->io_thd, mi, NULL))
+ goto slave_killed_err;
else if (is_network_error(mysql_errno(mysql)))
{
mi->report(WARNING_LEVEL, mysql_errno(mysql),
@@ -1216,6 +1525,31 @@ when it try to get the value of TIME_ZONE global variable from master.";
}
}
+ if (mi->heartbeat_period != 0.0)
+ {
+ char llbuf[22];
+ const char query_format[]= "SET @master_heartbeat_period= %s";
+ char query[sizeof(query_format) - 2 + sizeof(llbuf)];
+ /*
+ the period is an ulonglong of nano-secs.
+ */
+ llstr((ulonglong) (mi->heartbeat_period*1000000000UL), llbuf);
+ sprintf(query, query_format, llbuf);
+
+ if (mysql_real_query(mysql, query, strlen(query))
+ && !check_io_slave_killed(mi->io_thd, mi, NULL))
+ {
+ errmsg= "The slave I/O thread stops because SET @master_heartbeat_period "
+ "on master failed.";
+ err_code= ER_SLAVE_FATAL_ERROR;
+ sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql));
+ mysql_free_result(mysql_store_result(mysql));
+ goto err;
+ }
+ mysql_free_result(mysql_store_result(mysql));
+ }
+
+
err:
if (errmsg)
{
@@ -1232,201 +1566,13 @@ network_err:
if (master_res)
mysql_free_result(master_res);
DBUG_RETURN(2);
-}
-
-/*
- Used by fetch_master_table (used by LOAD TABLE tblname FROM MASTER and LOAD
- DATA FROM MASTER). Drops the table (if 'overwrite' is true) and recreates it
- from the dump. Honours replication inclusion/exclusion rules.
- db must be non-zero (guarded by assertion).
-
- RETURN VALUES
- 0 success
- 1 error
-*/
-static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
- const char* table_name, bool overwrite)
-{
- ulong packet_len;
- char *query, *save_db;
- uint32 save_db_length;
- Vio* save_vio;
- HA_CHECK_OPT check_opt;
- TABLE_LIST tables;
- int error= 1;
- handler *file;
- ulonglong save_options;
- NET *net= &mysql->net;
- const char *found_semicolon= NULL;
- DBUG_ENTER("create_table_from_dump");
-
- packet_len= my_net_read(net); // read create table statement
- if (packet_len == packet_error)
- {
- my_message(ER_MASTER_NET_READ, ER(ER_MASTER_NET_READ), MYF(0));
- DBUG_RETURN(1);
- }
- if (net->read_pos[0] == 255) // error from master
- {
- char *err_msg;
- err_msg= (char*) net->read_pos + ((mysql->server_capabilities &
- CLIENT_PROTOCOL_41) ?
- 3+SQLSTATE_LENGTH+1 : 3);
- my_error(ER_MASTER, MYF(0), err_msg);
- DBUG_RETURN(1);
- }
- thd->command = COM_TABLE_DUMP;
- if (!(query = thd->strmake((char*) net->read_pos, packet_len)))
- {
- sql_print_error("create_table_from_dump: out of memory");
- my_message(ER_GET_ERRNO, "Out of memory", MYF(0));
- DBUG_RETURN(1);
- }
- thd->set_query(query, packet_len);
- thd->is_slave_error = 0;
-
- bzero((char*) &tables,sizeof(tables));
- tables.db = (char*)db;
- tables.alias= tables.table_name= (char*)table_name;
-
- /* Drop the table if 'overwrite' is true */
- if (overwrite)
- {
- if (mysql_rm_table(thd,&tables,1,0)) /* drop if exists */
- {
- sql_print_error("create_table_from_dump: failed to drop the table");
- goto err;
- }
- else
- {
- /* Clear the OK result of mysql_rm_table(). */
- thd->main_da.reset_diagnostics_area();
- }
- }
-
- /* Create the table. We do not want to log the "create table" statement */
- save_options = thd->options;
- thd->options &= ~ (OPTION_BIN_LOG);
- thd_proc_info(thd, "Creating table from master dump");
- // save old db in case we are creating in a different database
- save_db = thd->db;
- save_db_length= thd->db_length;
- thd->db = (char*)db;
- DBUG_ASSERT(thd->db != 0);
- thd->db_length= strlen(thd->db);
- /* run create table */
- mysql_parse(thd, thd->query(), packet_len, &found_semicolon);
- thd->db = save_db; // leave things the way the were before
- thd->db_length= save_db_length;
- thd->options = save_options;
-
- if (thd->is_slave_error)
- goto err; // mysql_parse took care of the error send
-
- thd_proc_info(thd, "Opening master dump table");
- thd->main_da.reset_diagnostics_area(); /* cleanup from CREATE_TABLE */
- /*
- Note: If this function starts to fail for MERGE tables,
- change the next two lines to these:
- tables.table= NULL; // was set by mysql_rm_table()
- if (!open_n_lock_single_table(thd, &tables, TL_WRITE))
- */
- tables.lock_type = TL_WRITE;
- if (!open_ltable(thd, &tables, TL_WRITE, 0))
- {
- sql_print_error("create_table_from_dump: could not open created table");
- goto err;
- }
-
- file = tables.table->file;
- thd_proc_info(thd, "Reading master dump table data");
- /* Copy the data file */
- if (file->net_read_dump(net))
- {
- my_message(ER_MASTER_NET_READ, ER(ER_MASTER_NET_READ), MYF(0));
- sql_print_error("create_table_from_dump: failed in\
- handler::net_read_dump()");
- goto err;
- }
-
- check_opt.init();
- check_opt.flags|= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK;
- thd_proc_info(thd, "Rebuilding the index on master dump table");
- /*
- We do not want repair() to spam us with messages
- just send them to the error log, and report the failure in case of
- problems.
- */
- save_vio = thd->net.vio;
- thd->net.vio = 0;
- /* Rebuild the index file from the copied data file (with REPAIR) */
- error=file->ha_repair(thd,&check_opt) != 0;
- thd->net.vio = save_vio;
- if (error)
- my_error(ER_INDEX_REBUILD, MYF(0), tables.table->s->table_name.str);
-
-err:
- close_thread_tables(thd);
- DBUG_RETURN(error);
-}
-
-
-int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
- Master_info *mi, MYSQL *mysql, bool overwrite)
-{
- int error= 1;
- const char *errmsg=0;
- bool called_connected= (mysql != NULL);
- DBUG_ENTER("fetch_master_table");
- DBUG_PRINT("enter", ("db_name: '%s' table_name: '%s'",
- db_name,table_name));
-
- if (!called_connected)
- {
- if (!(mysql = mysql_init(NULL)))
- {
- DBUG_RETURN(1);
- }
- if (connect_to_master(thd, mysql, mi))
- {
- my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql));
- /*
- We need to clear the active VIO since, theoretically, somebody
- might issue an awake() on this thread. If we are then in the
- middle of closing and destroying the VIO inside the
- mysql_close(), we will have a problem.
- */
-#ifdef SIGNAL_WITH_VIO_CLOSE
- thd->clear_active_vio();
-#endif
- mysql_close(mysql);
- DBUG_RETURN(1);
- }
- if (thd->killed)
- goto err;
- }
-
- if (request_table_dump(mysql, db_name, table_name))
- {
- error= ER_UNKNOWN_ERROR;
- errmsg= "Failed on table dump request";
- goto err;
- }
- if (create_table_from_dump(thd, mysql, db_name,
- table_name, overwrite))
- goto err; // create_table_from_dump have sent the error already
- error = 0;
-
- err:
- if (!called_connected)
- mysql_close(mysql);
- if (errmsg && thd->vio_ok())
- my_message(error, errmsg, MYF(0));
- DBUG_RETURN(test(error)); // Return 1 on error
+slave_killed_err:
+ if (master_res)
+ mysql_free_result(master_res);
+ DBUG_RETURN(2);
}
-
static bool wait_for_relay_log_space(Relay_log_info* rli)
{
bool slave_killed=0;
@@ -1435,7 +1581,7 @@ static bool wait_for_relay_log_space(Relay_log_info* rli)
THD* thd = mi->io_thd;
DBUG_ENTER("wait_for_relay_log_space");
- pthread_mutex_lock(&rli->log_space_lock);
+ mysql_mutex_lock(&rli->log_space_lock);
save_proc_info= thd->enter_cond(&rli->log_space_cond,
&rli->log_space_lock,
"\
@@ -1443,7 +1589,7 @@ Waiting for the slave SQL thread to free enough relay log space");
while (rli->log_space_limit < rli->log_space_total &&
!(slave_killed=io_slave_killed(thd,mi)) &&
!rli->ignore_log_space_limit)
- pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
+ mysql_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
thd->exit_cond(save_proc_info);
DBUG_RETURN(slave_killed);
}
@@ -1465,11 +1611,11 @@ Waiting for the slave SQL thread to free enough relay log space");
static void write_ignored_events_info_to_relay_log(THD *thd, Master_info *mi)
{
Relay_log_info *rli= &mi->rli;
- pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
+ mysql_mutex_t *log_lock= rli->relay_log.get_log_lock();
DBUG_ENTER("write_ignored_events_info_to_relay_log");
DBUG_ASSERT(thd == mi->io_thd);
- pthread_mutex_lock(log_lock);
+ mysql_mutex_lock(log_lock);
if (rli->ign_master_log_name_end[0])
{
DBUG_PRINT("info",("writing a Rotate event to track down ignored events"));
@@ -1478,7 +1624,7 @@ static void write_ignored_events_info_to_relay_log(THD *thd, Master_info *mi)
Rotate_log_event::DUP_NAME);
rli->ign_master_log_name_end[0]= 0;
/* can unlock before writing as slave SQL thd will soon see our Rotate */
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
if (likely((bool)ev))
{
ev->server_id= 0; // don't be ignored by slave SQL thread
@@ -1500,7 +1646,7 @@ static void write_ignored_events_info_to_relay_log(THD *thd, Master_info *mi)
" SHOW SLAVE STATUS may be inaccurate");
}
else
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
DBUG_VOID_RETURN;
}
@@ -1509,28 +1655,54 @@ int register_slave_on_master(MYSQL* mysql, Master_info *mi,
bool *suppress_warnings)
{
uchar buf[1024], *pos= buf;
- uint report_host_len, report_user_len=0, report_password_len=0;
+ uint report_host_len=0, report_user_len=0, report_password_len=0;
DBUG_ENTER("register_slave_on_master");
*suppress_warnings= FALSE;
- if (!report_host)
+ if (report_host)
+ report_host_len= strlen(report_host);
+ if (report_host_len > HOSTNAME_LENGTH)
+ {
+ sql_print_warning("The length of report_host is %d. "
+ "It is larger than the max length(%d), so this "
+ "slave cannot be registered to the master.",
+ report_host_len, HOSTNAME_LENGTH);
DBUG_RETURN(0);
- report_host_len= strlen(report_host);
+ }
+
if (report_user)
report_user_len= strlen(report_user);
+ if (report_user_len > USERNAME_LENGTH)
+ {
+ sql_print_warning("The length of report_user is %d. "
+ "It is larger than the max length(%d), so this "
+ "slave cannot be registered to the master.",
+ report_user_len, USERNAME_LENGTH);
+ DBUG_RETURN(0);
+ }
+
if (report_password)
report_password_len= strlen(report_password);
- /* 30 is a good safety margin */
- if (report_host_len + report_user_len + report_password_len + 30 >
- sizeof(buf))
- DBUG_RETURN(0); // safety
+ if (report_password_len > MAX_PASSWORD_LENGTH)
+ {
+ sql_print_warning("The length of report_password is %d. "
+ "It is larger than the max length(%d), so this "
+ "slave cannot be registered to the master.",
+ report_password_len, MAX_PASSWORD_LENGTH);
+ DBUG_RETURN(0);
+ }
int4store(pos, server_id); pos+= 4;
pos= net_store_data(pos, (uchar*) report_host, report_host_len);
pos= net_store_data(pos, (uchar*) report_user, report_user_len);
pos= net_store_data(pos, (uchar*) report_password, report_password_len);
int2store(pos, (uint16) report_port); pos+= 2;
- int4store(pos, rpl_recovery_rank); pos+= 4;
+ /*
+ Fake rpl_recovery_rank, which was removed in BUG#13963,
+ so that this server can register itself on old servers,
+ see BUG#49259.
+ */
+ int4store(pos, /* rpl_recovery_rank */ 0); pos+= 4;
/* The master will fill in master_id */
int4store(pos, 0); pos+= 4;
@@ -1632,8 +1804,12 @@ bool show_master_info(THD* thd, Master_info* mi)
field_list.push_back(new Item_empty_string("Last_IO_Error", 20));
field_list.push_back(new Item_return_int("Last_SQL_Errno", 4, MYSQL_TYPE_LONG));
field_list.push_back(new Item_empty_string("Last_SQL_Error", 20));
+ field_list.push_back(new Item_empty_string("Replicate_Ignore_Server_Ids",
+ FN_REFLEN));
+ field_list.push_back(new Item_return_int("Master_Server_Id", sizeof(ulong),
+ MYSQL_TYPE_LONG));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
@@ -1647,14 +1823,14 @@ bool show_master_info(THD* thd, Master_info* mi)
slave_running can be accessed without run_lock but not other
non-volotile members like mi->io_thd, which is guarded by the mutex.
*/
- pthread_mutex_lock(&mi->run_lock);
+ mysql_mutex_lock(&mi->run_lock);
protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin);
- pthread_mutex_unlock(&mi->run_lock);
+ mysql_mutex_unlock(&mi->run_lock);
- pthread_mutex_lock(&mi->data_lock);
- pthread_mutex_lock(&mi->rli.data_lock);
- pthread_mutex_lock(&mi->err_lock);
- pthread_mutex_lock(&mi->rli.err_lock);
+ mysql_mutex_lock(&mi->data_lock);
+ mysql_mutex_lock(&mi->rli.data_lock);
+ mysql_mutex_lock(&mi->err_lock);
+ mysql_mutex_lock(&mi->rli.err_lock);
protocol->store(mi->host, &my_charset_bin);
protocol->store(mi->user, &my_charset_bin);
protocol->store((uint32) mi->port);
@@ -1667,7 +1843,8 @@ bool show_master_info(THD* thd, Master_info* mi)
protocol->store((ulonglong) mi->rli.group_relay_log_pos);
protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
protocol->store(mi->slave_running == MYSQL_SLAVE_RUN_CONNECT ?
- "Yes" : "No", &my_charset_bin);
+ "Yes" : (mi->slave_running == MYSQL_SLAVE_RUN_NOT_CONNECT ?
+ "Connecting" : "No"), &my_charset_bin);
protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
protocol->store(rpl_filter->get_do_db());
protocol->store(rpl_filter->get_ignore_db());
@@ -1753,11 +1930,37 @@ bool show_master_info(THD* thd, Master_info* mi)
protocol->store(mi->rli.last_error().number);
// Last_SQL_Error
protocol->store(mi->rli.last_error().message, &my_charset_bin);
+ // Replicate_Ignore_Server_Ids
+ {
+ char buff[FN_REFLEN];
+ ulong i, cur_len;
+ for (i= 0, buff[0]= 0, cur_len= 0;
+ i < mi->ignore_server_ids.elements; i++)
+ {
+ ulong s_id, slen;
+ char sbuff[FN_REFLEN];
+ get_dynamic(&mi->ignore_server_ids, (uchar*) &s_id, i);
+ slen= sprintf(sbuff, (i==0? "%lu" : ", %lu"), s_id);
+ if (cur_len + slen + 4 > FN_REFLEN)
+ {
+ /*
+ break the loop whenever remained space could not fit
+ ellipses on the next cycle
+ */
+ sprintf(buff + cur_len, "...");
+ break;
+ }
+ cur_len += sprintf(buff + cur_len, "%s", sbuff);
+ }
+ protocol->store(buff, &my_charset_bin);
+ }
+ // Master_Server_id
+ protocol->store((uint32) mi->master_id);
- pthread_mutex_unlock(&mi->rli.err_lock);
- pthread_mutex_unlock(&mi->err_lock);
- pthread_mutex_unlock(&mi->rli.data_lock);
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->rli.err_lock);
+ mysql_mutex_unlock(&mi->err_lock);
+ mysql_mutex_unlock(&mi->rli.data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
if (my_net_write(&thd->net, (uchar*) thd->packet.ptr(), packet->length()))
DBUG_RETURN(TRUE);
@@ -1779,12 +1982,12 @@ void set_slave_thread_options(THD* thd)
when max_join_size is 4G, OPTION_BIG_SELECTS is automatically set, but
only for client threads.
*/
- ulonglong options= thd->options | OPTION_BIG_SELECTS;
+ ulonglong options= thd->variables.option_bits | OPTION_BIG_SELECTS;
if (opt_log_slave_updates)
options|= OPTION_BIN_LOG;
else
options&= ~OPTION_BIN_LOG;
- thd->options= options;
+ thd->variables.option_bits= options;
thd->variables.completion_type= 0;
DBUG_VOID_RETURN;
}
@@ -1836,9 +2039,9 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
thd->enable_slow_log= opt_log_slow_slave_statements;
set_slave_thread_options(thd);
thd->client_capabilities = CLIENT_LOCAL_FILES;
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
DBUG_EXECUTE_IF("simulate_io_slave_error_on_init",
simulate_error|= (1 << SLAVE_THD_IO););
@@ -1853,14 +2056,14 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
thd->cleanup();
DBUG_RETURN(-1);
}
- lex_start(thd);
if (thd_type == SLAVE_THD_SQL)
thd_proc_info(thd, "Waiting for the next event in relay log");
else
thd_proc_info(thd, "Waiting for master update");
- thd->version=refresh_version;
thd->set_time();
+ /* Do not use user-supplied timeout value for system threads. */
+ thd->variables.lock_wait_timeout= LONG_TIMEOUT;
DBUG_RETURN(0);
}
@@ -1896,17 +2099,22 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
}
-static int request_dump(MYSQL* mysql, Master_info* mi,
- bool *suppress_warnings)
+static int request_dump(THD *thd, MYSQL* mysql, Master_info* mi,
+ bool *suppress_warnings)
{
uchar buf[FN_REFLEN + 10];
int len;
- int binlog_flags = 0; // for now
+ ushort binlog_flags = 0; // for now
char* logname = mi->master_log_name;
DBUG_ENTER("request_dump");
*suppress_warnings= FALSE;
+ if (RUN_HOOK(binlog_relay_io,
+ before_request_transmit,
+ (thd, mi, binlog_flags)))
+ DBUG_RETURN(1);
+
// TODO if big log files: Change next to int8store()
int4store(buf, (ulong) mi->master_log_pos);
int2store(buf + 4, binlog_flags);
@@ -1925,37 +2133,7 @@ static int request_dump(MYSQL* mysql, Master_info* mi,
else
sql_print_error("Error on COM_BINLOG_DUMP: %d %s, will retry in %d secs",
mysql_errno(mysql), mysql_error(mysql),
- master_connect_retry);
- DBUG_RETURN(1);
- }
-
- DBUG_RETURN(0);
-}
-
-
-static int request_table_dump(MYSQL* mysql, const char* db, const char* table)
-{
- uchar buf[1024], *p = buf;
- DBUG_ENTER("request_table_dump");
-
- uint table_len = (uint) strlen(table);
- uint db_len = (uint) strlen(db);
- if (table_len + db_len > sizeof(buf) - 2)
- {
- sql_print_error("request_table_dump: Buffer overrun");
- DBUG_RETURN(1);
- }
-
- *p++ = db_len;
- memcpy(p, db, db_len);
- p += db_len;
- *p++ = table_len;
- memcpy(p, table, table_len);
-
- if (simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1))
- {
- sql_print_error("request_table_dump: Error sending the table dump \
-command");
+ mi->connect_retry);
DBUG_RETURN(1);
}
@@ -2039,7 +2217,7 @@ static int has_temporary_error(THD *thd)
DBUG_ENTER("has_temporary_error");
DBUG_EXECUTE_IF("all_errors_are_temporary_errors",
- if (thd->main_da.is_error())
+ if (thd->stmt_da->is_error())
{
thd->clear_error();
my_error(ER_LOCK_DEADLOCK, MYF(0));
@@ -2058,20 +2236,21 @@ static int has_temporary_error(THD *thd)
currently, InnoDB deadlock detected by InnoDB or lock
wait timeout (innodb_lock_wait_timeout exceeded
*/
- if (thd->main_da.sql_errno() == ER_LOCK_DEADLOCK ||
- thd->main_da.sql_errno() == ER_LOCK_WAIT_TIMEOUT)
+ if (thd->stmt_da->sql_errno() == ER_LOCK_DEADLOCK ||
+ thd->stmt_da->sql_errno() == ER_LOCK_WAIT_TIMEOUT)
DBUG_RETURN(1);
#ifdef HAVE_NDB_BINLOG
/*
currently temporary error set in ndbcluster
*/
- List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+ List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
MYSQL_ERROR *err;
while ((err= it++))
{
- DBUG_PRINT("info", ("has warning %d %s", err->code, err->msg));
- switch (err->code)
+ DBUG_PRINT("info", ("has condition %d %s", err->get_sql_errno(),
+ err->get_message_text()));
+ switch (err->get_sql_errno())
{
case ER_GET_TEMPORARY_ERRMSG:
DBUG_RETURN(1);
@@ -2120,8 +2299,8 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli)
ev->get_type_str(), ev->get_type_code(),
ev->server_id));
DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu",
- FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
- FLAGSTR(thd->options, OPTION_BEGIN),
+ FLAGSTR(thd->variables.option_bits, OPTION_NOT_AUTOCOMMIT),
+ FLAGSTR(thd->variables.option_bits, OPTION_BEGIN),
(ulong) rli->last_event_start_time));
/*
@@ -2157,8 +2336,8 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli)
int reason= ev->shall_skip(rli);
if (reason == Log_event::EVENT_SKIP_COUNT)
- --rli->slave_skip_counter;
- pthread_mutex_unlock(&rli->data_lock);
+ sql_slave_skip_counter= --rli->slave_skip_counter;
+ mysql_mutex_unlock(&rli->data_lock);
if (reason == Log_event::EVENT_SKIP_NOT)
exec_res= ev->apply_event(rli);
@@ -2177,7 +2356,7 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli)
"skipped because event skip counter was non-zero"
};
DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d",
- thd->options & OPTION_BEGIN ? 1 : 0,
+ test(thd->variables.option_bits & OPTION_BEGIN),
rli->get_flag(Relay_log_info::IN_STMT)));
DBUG_PRINT("skip_event", ("%s event was %s",
ev->get_type_str(), explain[reason]));
@@ -2264,7 +2443,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
event execution. But we will release it in places where we will
wait for something for example inside of next_event().
*/
- pthread_mutex_lock(&rli->data_lock);
+ mysql_mutex_lock(&rli->data_lock);
Log_event * ev = next_event(rli);
@@ -2272,7 +2451,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
if (sql_slave_killed(thd,rli))
{
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
delete ev;
DBUG_RETURN(1);
}
@@ -2295,10 +2474,31 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
error in query execution to be printed.
*/
rli->abort_slave= 1;
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
delete ev;
DBUG_RETURN(1);
}
+
+ { /**
+ The following failure injecion works in cooperation with tests
+ setting @@global.debug= 'd,incomplete_group_in_relay_log'.
+ Xid or Commit events are not executed to force the slave sql
+ read hanging if the realy log does not have any more events.
+ */
+ DBUG_EXECUTE_IF("incomplete_group_in_relay_log",
+ if ((ev->get_type_code() == XID_EVENT) ||
+ ((ev->get_type_code() == QUERY_EVENT) &&
+ strcmp("COMMIT", ((Query_log_event *) ev)->query) == 0))
+ {
+ DBUG_ASSERT(thd->transaction.all.modified_non_trans_table);
+ rli->abort_slave= 1;
+ mysql_mutex_unlock(&rli->data_lock);
+ delete ev;
+ rli->inc_event_relay_log_pos();
+ DBUG_RETURN(0);
+ };);
+ }
+
exec_res= apply_event_and_update_pos(ev, thd, rli);
/*
@@ -2356,10 +2556,10 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
/* chance for concurrent connection to get more locks */
safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
(CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);
- pthread_mutex_lock(&rli->data_lock); // because of SHOW STATUS
+ mysql_mutex_lock(&rli->data_lock); // because of SHOW STATUS
rli->trans_retries++;
rli->retried_trans++;
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
DBUG_PRINT("info", ("Slave retries transaction "
"rli->trans_retries: %lu", rli->trans_retries));
}
@@ -2387,7 +2587,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
}
DBUG_RETURN(exec_res);
}
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
rli->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_READ_FAILURE,
ER(ER_SLAVE_RELAY_LOG_READ_FAILURE), "\
Could not parse relay log event entry. The possible reasons are: the master's \
@@ -2413,7 +2613,6 @@ static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info)
return FALSE;
}
-
/**
@brief Try to reconnect slave IO thread.
@@ -2519,7 +2718,7 @@ pthread_handler_t handle_slave_io(void *arg)
mysql= NULL ;
retry_count= 0;
- pthread_mutex_lock(&mi->run_lock);
+ mysql_mutex_lock(&mi->run_lock);
/* Inform waiting threads that slave has started */
mi->slave_run_id++;
@@ -2536,23 +2735,33 @@ pthread_handler_t handle_slave_io(void *arg)
mi->clear_error();
if (init_slave_thread(thd, SLAVE_THD_IO))
{
- pthread_cond_broadcast(&mi->start_cond);
- pthread_mutex_unlock(&mi->run_lock);
+ mysql_cond_broadcast(&mi->start_cond);
+ mysql_mutex_unlock(&mi->run_lock);
sql_print_error("Failed during slave I/O thread initialization");
goto err;
}
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
threads.append(thd);
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
mi->slave_running = 1;
mi->abort_slave = 0;
- pthread_mutex_unlock(&mi->run_lock);
- pthread_cond_broadcast(&mi->start_cond);
+ mysql_mutex_unlock(&mi->run_lock);
+ mysql_cond_broadcast(&mi->start_cond);
DBUG_PRINT("master_info",("log_file_name: '%s' position: %s",
mi->master_log_name,
llstr(mi->master_log_pos,llbuff)));
+ /* This must be called before run any binlog_relay_io hooks */
+ my_pthread_setspecific_ptr(RPL_MASTER_INFO, mi);
+
+ if (RUN_HOOK(binlog_relay_io, thread_start, (thd, mi)))
+ {
+ mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER(ER_SLAVE_FATAL_ERROR), "Failed to run 'thread_start' hook");
+ goto err;
+ }
+
if (!(mi->mysql = mysql = mysql_init(NULL)))
{
mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
@@ -2602,7 +2811,7 @@ connected:
if (ret == 1)
/* Fatal error */
goto err;
-
+
if (ret == 2)
{
if (check_io_slave_killed(mi->io_thd, mi, "Slave I/O thread killed"
@@ -2652,7 +2861,7 @@ connected:
while (!io_slave_killed(thd,mi))
{
thd_proc_info(thd, "Requesting binlog dump");
- if (request_dump(mysql, mi, &suppress_warnings))
+ if (request_dump(thd, mysql, mi, &suppress_warnings))
{
sql_print_error("Failed on request_dump()");
if (check_io_slave_killed(thd, mi, "Slave I/O thread killed while \
@@ -2672,6 +2881,7 @@ requesting master dump") ||
goto err;
goto connected;
});
+ const char *event_buf;
DBUG_ASSERT(mi->last_error().number == 0);
while (!io_slave_killed(thd,mi))
@@ -2732,14 +2942,37 @@ Stopping slave I/O thread due to out-of-memory error from master");
retry_count=0; // ok event, reset retry counter
thd_proc_info(thd, "Queueing master event to the relay log");
- if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
- event_len))
+ event_buf= (const char*)mysql->net.read_pos + 1;
+ if (RUN_HOOK(binlog_relay_io, after_read_event,
+ (thd, mi,(const char*)mysql->net.read_pos + 1,
+ event_len, &event_buf, &event_len)))
+ {
+ mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER(ER_SLAVE_FATAL_ERROR),
+ "Failed to run 'after_read_event' hook");
+ goto err;
+ }
+
+ /* XXX: 'synced' should be updated by queue_event to indicate
+ whether event has been synced to disk */
+ bool synced= 0;
+ if (queue_event(mi, event_buf, event_len))
{
mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
"could not queue event from master");
goto err;
}
+
+ if (RUN_HOOK(binlog_relay_io, after_queue_event,
+ (thd, mi, event_buf, event_len, synced)))
+ {
+ mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER(ER_SLAVE_FATAL_ERROR),
+ "Failed to run 'after_queue_event' hook");
+ goto err;
+ }
+
if (flush_master_info(mi, TRUE, TRUE))
{
sql_print_error("Failed to flush master info file");
@@ -2785,7 +3018,8 @@ err:
// print the current replication position
sql_print_information("Slave I/O thread exiting, read up to log '%s', position %s",
IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
- thd->set_query(NULL, 0);
+ RUN_HOOK(binlog_relay_io, thread_stop, (thd, mi));
+ thd->reset_query();
thd->reset_db(NULL, 0);
if (mysql)
{
@@ -2805,7 +3039,7 @@ err:
}
write_ignored_events_info_to_relay_log(thd, mi);
thd_proc_info(thd, "Waiting for slave mutex on exit");
- pthread_mutex_lock(&mi->run_lock);
+ mysql_mutex_lock(&mi->run_lock);
/* Forget the relay log's format */
delete mi->rli.relay_log.description_event_for_queue;
@@ -2814,11 +3048,10 @@ err:
change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE);
DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net); // destructor will not free it, because net.vio is 0
- close_thread_tables(thd);
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
THD_CHECK_SENTRY(thd);
delete thd;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
mi->abort_slave= 0;
mi->slave_running= 0;
mi->io_thd= 0;
@@ -2827,9 +3060,9 @@ err:
is important. Otherwise a killer_thread can execute between the calls and
delete the mi structure leading to a crash! (see BUG#25306 for details)
*/
- pthread_cond_broadcast(&mi->stop_cond); // tell the world we are done
+ mysql_cond_broadcast(&mi->stop_cond); // tell the world we are done
DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5););
- pthread_mutex_unlock(&mi->run_lock);
+ mysql_mutex_unlock(&mi->run_lock);
DBUG_LEAVE; // Must match DBUG_ENTER()
my_thread_end();
@@ -2866,16 +3099,17 @@ int check_temp_dir(char* tmp_file)
/*
Check permissions to create a file.
*/
- if ((fd= my_create(tmp_file, CREATE_MODE,
- O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
+ if ((fd= mysql_file_create(key_file_misc,
+ tmp_file, CREATE_MODE,
+ O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+ MYF(MY_WME))) < 0)
DBUG_RETURN(1);
/*
Clean up.
*/
- my_close(fd, MYF(0));
- my_delete(tmp_file, MYF(0));
+ mysql_file_close(fd, MYF(0));
+ mysql_file_delete(key_file_misc, tmp_file, MYF(0));
DBUG_RETURN(0);
}
@@ -2906,7 +3140,7 @@ pthread_handler_t handle_slave_sql(void *arg)
DBUG_ENTER("handle_slave_sql");
DBUG_ASSERT(rli->inited);
- pthread_mutex_lock(&rli->run_lock);
+ mysql_mutex_lock(&rli->run_lock);
DBUG_ASSERT(!rli->slave_running);
errmsg= 0;
#ifndef DBUG_OFF
@@ -2928,8 +3162,8 @@ pthread_handler_t handle_slave_sql(void *arg)
TODO: this is currently broken - slave start and change master
will be stuck if we fail here
*/
- pthread_cond_broadcast(&rli->start_cond);
- pthread_mutex_unlock(&rli->run_lock);
+ mysql_cond_broadcast(&rli->start_cond);
+ mysql_mutex_unlock(&rli->run_lock);
rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
"Failed during slave thread initialization");
goto err;
@@ -2937,9 +3171,9 @@ pthread_handler_t handle_slave_sql(void *arg)
thd->init_for_queries();
thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
set_thd_in_use_temporary_tables(rli); // (re)set sql_thd in use for saved temp tables
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
threads.append(thd);
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
/*
We are going to set slave_running to 1. Assuming slave I/O thread is
alive and connected, this is going to make Seconds_Behind_Master be 0
@@ -2949,8 +3183,8 @@ pthread_handler_t handle_slave_sql(void *arg)
Seconds_Behind_Master grows. No big deal.
*/
rli->abort_slave = 0;
- pthread_mutex_unlock(&rli->run_lock);
- pthread_cond_broadcast(&rli->start_cond);
+ mysql_mutex_unlock(&rli->run_lock);
+ mysql_cond_broadcast(&rli->start_cond);
/*
Reset errors for a clean start (otherwise, if the master is idle, the SQL
@@ -2965,9 +3199,9 @@ pthread_handler_t handle_slave_sql(void *arg)
rli->clear_error();
//tell the I/O thread to take relay_log_space_limit into account from now on
- pthread_mutex_lock(&rli->log_space_lock);
+ mysql_mutex_lock(&rli->log_space_lock);
rli->ignore_log_space_limit= 0;
- pthread_mutex_unlock(&rli->log_space_lock);
+ mysql_mutex_unlock(&rli->log_space_lock);
rli->trans_retries= 0; // start from "no error"
DBUG_PRINT("info", ("rli->trans_retries: %lu", rli->trans_retries));
@@ -3019,19 +3253,19 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
if (check_temp_dir(rli->slave_patternload_file))
{
- rli->report(ERROR_LEVEL, thd->main_da.sql_errno(),
+ rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(),
"Unable to use slave's temporary directory %s - %s",
- slave_load_tmpdir, thd->main_da.message());
+ slave_load_tmpdir, thd->stmt_da->message());
goto err;
}
/* execute init_slave variable */
- if (sys_init_slave.value_length)
+ if (opt_init_slave.length)
{
- execute_init_command(thd, &sys_init_slave, &LOCK_sys_init_slave);
+ execute_init_command(thd, &opt_init_slave, &LOCK_sys_init_slave);
if (thd->is_slave_error)
{
- rli->report(ERROR_LEVEL, thd->main_da.sql_errno(),
+ rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(),
"Slave SQL thread aborted. Can't execute init_slave query");
goto err;
}
@@ -3041,7 +3275,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
First check until condition - probably there is nothing to execute. We
do not want to wait for next event in this case.
*/
- pthread_mutex_lock(&rli->data_lock);
+ mysql_mutex_lock(&rli->data_lock);
if (rli->slave_skip_counter)
{
strmake(saved_log_name, rli->group_relay_log_name, FN_REFLEN - 1);
@@ -3056,10 +3290,10 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
char buf[22];
sql_print_information("Slave SQL thread stopped because it reached its"
" UNTIL position %s", llstr(rli->until_pos(), buf));
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
goto err;
}
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
/* Read queries from the IO/THREAD until this thread is killed */
@@ -3098,20 +3332,20 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
if (thd->is_error())
{
- char const *const errmsg= thd->main_da.message();
+ char const *const errmsg= thd->stmt_da->message();
DBUG_PRINT("info",
- ("thd->main_da.sql_errno()=%d; rli->last_error.number=%d",
- thd->main_da.sql_errno(), last_errno));
+ ("thd->stmt_da->sql_errno()=%d; rli->last_error.number=%d",
+ thd->stmt_da->sql_errno(), last_errno));
if (last_errno == 0)
{
/*
This function is reporting an error which was not reported
while executing exec_relay_log_event().
*/
- rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), "%s", errmsg);
+ rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(), "%s", errmsg);
}
- else if (last_errno != thd->main_da.sql_errno())
+ else if (last_errno != thd->stmt_da->sql_errno())
{
/*
* An error was reported while executing exec_relay_log_event()
@@ -3120,12 +3354,12 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
* what caused the problem.
*/
sql_print_error("Slave (additional info): %s Error_code: %d",
- errmsg, thd->main_da.sql_errno());
+ errmsg, thd->stmt_da->sql_errno());
}
}
/* Print any warnings issued */
- List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+ List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
MYSQL_ERROR *err;
/*
Added controlled slave thread cancel for replication
@@ -3134,9 +3368,9 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
bool udf_error = false;
while ((err= it++))
{
- if (err->code == ER_CANT_OPEN_LIBRARY)
+ if (err->get_sql_errno() == ER_CANT_OPEN_LIBRARY)
udf_error = true;
- sql_print_warning("Slave: %s Error_code: %d",err->msg, err->code);
+ sql_print_warning("Slave: %s Error_code: %d", err->get_message_text(), err->get_sql_errno());
}
if (udf_error)
sql_print_error("Error loading user-defined library, slave SQL "
@@ -3175,12 +3409,12 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
variables is supposed to set them to 0 before terminating)).
*/
thd->catalog= 0;
- thd->set_query(NULL, 0);
+ thd->reset_query();
thd->reset_db(NULL, 0);
thd_proc_info(thd, "Waiting for slave mutex on exit");
- pthread_mutex_lock(&rli->run_lock);
+ mysql_mutex_lock(&rli->run_lock);
/* We need data_lock, at least to wake up any waiting master_pos_wait() */
- pthread_mutex_lock(&rli->data_lock);
+ mysql_mutex_lock(&rli->data_lock);
DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
/* When master_pos_wait() wakes up it will check this and terminate */
rli->slave_running= 0;
@@ -3188,9 +3422,9 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
delete rli->relay_log.description_event_for_exec;
rli->relay_log.description_event_for_exec= 0;
/* Wake up master_pos_wait() */
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions"));
- pthread_cond_broadcast(&rli->data_cond);
+ mysql_cond_broadcast(&rli->data_cond);
rli->ignore_log_space_limit= 0; /* don't need any lock */
/* we die so won't remember charset - re-update them on next thread start */
rli->cached_charset_invalidate();
@@ -3207,18 +3441,18 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
THD_CHECK_SENTRY(thd);
rli->sql_thd= 0;
set_thd_in_use_temporary_tables(rli); // (re)set sql_thd in use for saved temp tables
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
THD_CHECK_SENTRY(thd);
delete thd;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
/*
Note: the order of the broadcast and unlock calls below (first broadcast, then unlock)
is important. Otherwise a killer_thread can execute between the calls and
delete the mi structure leading to a crash! (see BUG#25306 for details)
*/
- pthread_cond_broadcast(&rli->stop_cond);
+ mysql_cond_broadcast(&rli->stop_cond);
DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5););
- pthread_mutex_unlock(&rli->run_lock); // tell the world we are done
+ mysql_mutex_unlock(&rli->run_lock); // tell the world we are done
DBUG_LEAVE; // Must match DBUG_ENTER()
my_thread_end();
@@ -3361,7 +3595,7 @@ err:
static int process_io_rotate(Master_info *mi, Rotate_log_event *rev)
{
DBUG_ENTER("process_io_rotate");
- safe_mutex_assert_owner(&mi->data_lock);
+ mysql_mutex_assert_owner(&mi->data_lock);
if (unlikely(!rev->is_valid()))
DBUG_RETURN(1);
@@ -3452,11 +3686,11 @@ static int queue_binlog_ver_1_event(Master_info *mi, const char *buf,
sql_print_error("Read invalid event from master: '%s',\
master could be corrupt but a more likely cause of this is a bug",
errmsg);
- my_free((char*) tmp_buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(tmp_buf);
DBUG_RETURN(1);
}
- pthread_mutex_lock(&mi->data_lock);
+ mysql_mutex_lock(&mi->data_lock);
ev->log_pos= mi->master_log_pos; /* 3.23 events don't contain log_pos */
switch (ev->get_type_code()) {
case STOP_EVENT:
@@ -3467,7 +3701,7 @@ static int queue_binlog_ver_1_event(Master_info *mi, const char *buf,
if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
{
delete ev;
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_RETURN(1);
}
inc_pos= 0;
@@ -3488,8 +3722,8 @@ static int queue_binlog_ver_1_event(Master_info *mi, const char *buf,
delete ev;
mi->master_log_pos += inc_pos;
DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
- pthread_mutex_unlock(&mi->data_lock);
- my_free((char*)tmp_buf, MYF(0));
+ mysql_mutex_unlock(&mi->data_lock);
+ my_free(tmp_buf);
DBUG_RETURN(error);
}
default:
@@ -3507,7 +3741,7 @@ static int queue_binlog_ver_1_event(Master_info *mi, const char *buf,
if (unlikely(rli->relay_log.append(ev)))
{
delete ev;
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_RETURN(1);
}
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
@@ -3515,7 +3749,7 @@ static int queue_binlog_ver_1_event(Master_info *mi, const char *buf,
delete ev;
mi->master_log_pos+= inc_pos;
DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_RETURN(0);
}
@@ -3540,10 +3774,10 @@ static int queue_binlog_ver_3_event(Master_info *mi, const char *buf,
sql_print_error("Read invalid event from master: '%s',\
master could be corrupt but a more likely cause of this is a bug",
errmsg);
- my_free((char*) tmp_buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(tmp_buf);
DBUG_RETURN(1);
}
- pthread_mutex_lock(&mi->data_lock);
+ mysql_mutex_lock(&mi->data_lock);
switch (ev->get_type_code()) {
case STOP_EVENT:
goto err;
@@ -3551,7 +3785,7 @@ static int queue_binlog_ver_3_event(Master_info *mi, const char *buf,
if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
{
delete ev;
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_RETURN(1);
}
inc_pos= 0;
@@ -3563,7 +3797,7 @@ static int queue_binlog_ver_3_event(Master_info *mi, const char *buf,
if (unlikely(rli->relay_log.append(ev)))
{
delete ev;
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_RETURN(1);
}
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
@@ -3571,7 +3805,7 @@ static int queue_binlog_ver_3_event(Master_info *mi, const char *buf,
mi->master_log_pos+= inc_pos;
err:
DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_RETURN(0);
}
@@ -3618,9 +3852,11 @@ static int queue_old_event(Master_info *mi, const char *buf,
static int queue_event(Master_info* mi,const char* buf, ulong event_len)
{
int error= 0;
+ String error_msg;
ulong inc_pos;
Relay_log_info *rli= &mi->rli;
- pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
+ mysql_mutex_t *log_lock= rli->relay_log.get_log_lock();
+ ulong s_id;
DBUG_ENTER("queue_event");
LINT_INIT(inc_pos);
@@ -3630,7 +3866,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
DBUG_RETURN(queue_old_event(mi,buf,event_len));
LINT_INIT(inc_pos);
- pthread_mutex_lock(&mi->data_lock);
+ mysql_mutex_lock(&mi->data_lock);
switch (buf[EVENT_TYPE_OFFSET]) {
case STOP_EVENT:
@@ -3652,7 +3888,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
Rotate_log_event rev(buf,event_len,mi->rli.relay_log.description_event_for_queue);
if (unlikely(process_io_rotate(mi,&rev)))
{
- error= 1;
+ error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
goto err;
}
/*
@@ -3679,7 +3915,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
Log_event::read_log_event(buf, event_len, &errmsg,
mi->rli.relay_log.description_event_for_queue)))
{
- error= 2;
+ error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
goto err;
}
delete mi->rli.relay_log.description_event_for_queue;
@@ -3698,6 +3934,56 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
}
break;
+
+ case HEARTBEAT_LOG_EVENT:
+ {
+ /*
+ HB (heartbeat) cannot come before RL (Relay)
+ */
+ char llbuf[22];
+ Heartbeat_log_event hb(buf, event_len, mi->rli.relay_log.description_event_for_queue);
+ if (!hb.is_valid())
+ {
+ error= ER_SLAVE_HEARTBEAT_FAILURE;
+ error_msg.append(STRING_WITH_LEN("inconsistent heartbeat event content;"));
+ error_msg.append(STRING_WITH_LEN("the event's data: log_file_name "));
+ error_msg.append(hb.get_log_ident(), (uint) strlen(hb.get_log_ident()));
+ error_msg.append(STRING_WITH_LEN(" log_pos "));
+ llstr(hb.log_pos, llbuf);
+ error_msg.append(llbuf, strlen(llbuf));
+ goto err;
+ }
+ mi->received_heartbeats++;
+ /*
+ compare local and event's versions of log_file, log_pos.
+
+ Heartbeat is sent only after an event corresponding to the corrdinates
+ the heartbeat carries.
+ Slave can not have a difference in coordinates except in the only
+ special case when mi->master_log_name, master_log_pos have never
+ been updated by Rotate event i.e when slave does not have any history
+ with the master (and thereafter mi->master_log_pos is NULL).
+
+ TODO: handling `when' for SHOW SLAVE STATUS' snds behind
+ */
+ if ((memcmp(mi->master_log_name, hb.get_log_ident(), hb.get_ident_len())
+ && mi->master_log_name != NULL)
+ || mi->master_log_pos != hb.log_pos)
+ {
+ /* missed events of heartbeat from the past */
+ error= ER_SLAVE_HEARTBEAT_FAILURE;
+ error_msg.append(STRING_WITH_LEN("heartbeat is not compatible with local info;"));
+ error_msg.append(STRING_WITH_LEN("the event's data: log_file_name "));
+ error_msg.append(hb.get_log_ident(), (uint) strlen(hb.get_log_ident()));
+ error_msg.append(STRING_WITH_LEN(" log_pos "));
+ llstr(hb.log_pos, llbuf);
+ error_msg.append(llbuf, strlen(llbuf));
+ goto err;
+ }
+ goto skip_relay_logging;
+ }
+ break;
+
default:
inc_pos= event_len;
break;
@@ -3716,10 +4002,21 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
direct master (an unsupported, useless setup!).
*/
- pthread_mutex_lock(log_lock);
-
- if ((uint4korr(buf + SERVER_ID_OFFSET) == ::server_id) &&
- !mi->rli.replicate_same_server_id)
+ mysql_mutex_lock(log_lock);
+ s_id= uint4korr(buf + SERVER_ID_OFFSET);
+ if ((s_id == ::server_id && !mi->rli.replicate_same_server_id) ||
+ /*
+ the following conjunction deals with IGNORE_SERVER_IDS, if set
+ If the master is on the ignore list, execution of
+ format description log events and rotate events is necessary.
+ */
+ (mi->ignore_server_ids.elements > 0 &&
+ mi->shall_ignore_server_id(s_id) &&
+ /* everything is filtered out from non-master */
+ (s_id != mi->master_id ||
+ /* for the master meta information is necessary */
+ (buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT &&
+ buf[EVENT_TYPE_OFFSET] != ROTATE_EVENT))))
{
/*
Do not write it to the relay log.
@@ -3734,10 +4031,14 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
But events which were generated by this slave and which do not exist in
the master's binlog (i.e. Format_desc, Rotate & Stop) should not increment
mi->master_log_pos.
+ If the event is originated remotely and is being filtered out by
+ IGNORE_SERVER_IDS it increments mi->master_log_pos
+ as well as rli->group_relay_log_pos.
*/
- if (buf[EVENT_TYPE_OFFSET]!=FORMAT_DESCRIPTION_EVENT &&
- buf[EVENT_TYPE_OFFSET]!=ROTATE_EVENT &&
- buf[EVENT_TYPE_OFFSET]!=STOP_EVENT)
+ if (!(s_id == ::server_id && !mi->rli.replicate_same_server_id) ||
+ (buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT &&
+ buf[EVENT_TYPE_OFFSET] != ROTATE_EVENT &&
+ buf[EVENT_TYPE_OFFSET] != STOP_EVENT))
{
mi->master_log_pos+= inc_pos;
memcpy(rli->ign_master_log_name_end, mi->master_log_name, FN_REFLEN);
@@ -3745,8 +4046,8 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
rli->ign_master_log_pos_end= mi->master_log_pos;
}
rli->relay_log.signal_update(); // the slave SQL thread needs to re-check
- DBUG_PRINT("info", ("master_log_pos: %lu, event originating from the same server, ignored",
- (ulong) mi->master_log_pos));
+ DBUG_PRINT("info", ("master_log_pos: %lu, event originating from %u server, ignored",
+ (ulong) mi->master_log_pos, uint4korr(buf + SERVER_ID_OFFSET)));
}
else
{
@@ -3758,15 +4059,23 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
}
else
- error= 3;
+ {
+ error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
+ }
rli->ign_master_log_name_end[0]= 0; // last event is not ignored
}
- pthread_mutex_unlock(log_lock);
-
+ mysql_mutex_unlock(log_lock);
+skip_relay_logging:
+
err:
- pthread_mutex_unlock(&mi->data_lock);
+ mysql_mutex_unlock(&mi->data_lock);
DBUG_PRINT("info", ("error: %d", error));
+ if (error)
+ mi->report(ERROR_LEVEL, error, ER(error),
+ (error == ER_SLAVE_RELAY_LOG_WRITE_FAILURE)?
+ "could not queue event from master" :
+ error_msg.ptr());
DBUG_RETURN(error);
}
@@ -3780,13 +4089,13 @@ void end_relay_log_info(Relay_log_info* rli)
if (rli->info_fd >= 0)
{
end_io_cache(&rli->info_file);
- (void) my_close(rli->info_fd, MYF(MY_WME));
+ mysql_file_close(rli->info_fd, MYF(MY_WME));
rli->info_fd = -1;
}
if (rli->cur_log_fd >= 0)
{
end_io_cache(&rli->cache_buf);
- (void)my_close(rli->cur_log_fd, MYF(MY_WME));
+ mysql_file_close(rli->cur_log_fd, MYF(MY_WME));
rli->cur_log_fd = -1;
}
rli->inited = 0;
@@ -3972,6 +4281,71 @@ static int safe_reconnect(THD* thd, MYSQL* mysql, Master_info* mi,
}
+MYSQL *rpl_connect_master(MYSQL *mysql)
+{
+ THD *thd= current_thd;
+ Master_info *mi= my_pthread_getspecific_ptr(Master_info*, RPL_MASTER_INFO);
+ if (!mi)
+ {
+ sql_print_error("'rpl_connect_master' must be called in slave I/O thread context.");
+ return NULL;
+ }
+
+ bool allocated= false;
+
+ if (!mysql)
+ {
+ if(!(mysql= mysql_init(NULL)))
+ {
+ sql_print_error("rpl_connect_master: failed in mysql_init()");
+ return NULL;
+ }
+ allocated= true;
+ }
+
+ /*
+ XXX: copied from connect_to_master, this function should not
+ change the slave status, so we cannot use connect_to_master
+ directly
+
+ TODO: make this part a seperate function to eliminate duplication
+ */
+ mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
+ mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout);
+
+#ifdef HAVE_OPENSSL
+ if (mi->ssl)
+ {
+ mysql_ssl_set(mysql,
+ mi->ssl_key[0]?mi->ssl_key:0,
+ mi->ssl_cert[0]?mi->ssl_cert:0,
+ mi->ssl_ca[0]?mi->ssl_ca:0,
+ mi->ssl_capath[0]?mi->ssl_capath:0,
+ mi->ssl_cipher[0]?mi->ssl_cipher:0);
+ mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+ &mi->ssl_verify_server_cert);
+ }
+#endif
+
+ mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname);
+ /* This one is not strictly needed but we have it here for completeness */
+ mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir);
+
+ if (io_slave_killed(thd, mi)
+ || !mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0,
+ mi->port, 0, 0))
+ {
+ if (!io_slave_killed(thd, mi))
+ sql_print_error("rpl_connect_master: error connecting to master: %s (server_error: %d)",
+ mysql_error(mysql), mysql_errno(mysql));
+
+ if (allocated)
+ mysql_close(mysql); // this will free the object
+ return NULL;
+ }
+ return mysql;
+}
+
/*
Store the file and position where the execute-slave thread are in the
relay log.
@@ -3981,8 +4355,9 @@ static int safe_reconnect(THD* thd, MYSQL* mysql, Master_info* mi,
rli Relay log information
NOTES
- - As this is only called by the slave thread, we don't need to
- have a lock on this.
+ - As this is only called by the slave thread or on STOP SLAVE, with the
+ log_lock grabbed and the slave thread stopped, we don't need to have
+ a lock here.
- If there is an active transaction, then we don't update the position
in the relay log. This is to ensure that we re-execute statements
if we die in the middle of an transaction that was rolled back.
@@ -4025,8 +4400,18 @@ bool flush_relay_log_info(Relay_log_info* rli)
error=1;
if (flush_io_cache(file))
error=1;
-
- /* Flushing the relay log is done by the slave I/O thread */
+ if (sync_relayloginfo_period &&
+ !error &&
+ ++(rli->sync_counter) >= sync_relayloginfo_period)
+ {
+ if (my_sync(rli->info_fd, MYF(MY_WME)))
+ error=1;
+ rli->sync_counter= 0;
+ }
+ /*
+ Flushing the relay log is done by the slave I/O thread
+ or by the user on STOP SLAVE.
+ */
DBUG_RETURN(error);
}
@@ -4070,7 +4455,7 @@ static Log_event* next_event(Relay_log_info* rli)
{
Log_event* ev;
IO_CACHE* cur_log = rli->cur_log;
- pthread_mutex_t *log_lock = rli->relay_log.get_log_lock();
+ mysql_mutex_t *log_lock = rli->relay_log.get_log_lock();
const char* errmsg=0;
THD* thd = rli->sql_thd;
DBUG_ENTER("next_event");
@@ -4087,9 +4472,9 @@ static Log_event* next_event(Relay_log_info* rli)
so we assume calling function acquired this mutex for us and we will
hold it for the most of the loop below However, we will release it
whenever it is worth the hassle, and in the cases when we go into a
- pthread_cond_wait() with the non-data_lock mutex
+ mysql_cond_wait() with the non-data_lock mutex
*/
- safe_mutex_assert_owner(&rli->data_lock);
+ mysql_mutex_assert_owner(&rli->data_lock);
while (!sql_slave_killed(thd,rli))
{
@@ -4108,7 +4493,7 @@ static Log_event* next_event(Relay_log_info* rli)
if ((hot_log = (cur_log != &rli->cache_buf)))
{
DBUG_ASSERT(rli->cur_log_fd == -1); // foreign descriptor
- pthread_mutex_lock(log_lock);
+ mysql_mutex_lock(log_lock);
/*
Reading xxx_file_id is safe because the log will only
@@ -4118,7 +4503,7 @@ static Log_event* next_event(Relay_log_info* rli)
{
// The master has switched to a new log file; Reopen the old log file
cur_log=reopen_relay_log(rli, &errmsg);
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
if (!cur_log) // No more log files
goto err;
hot_log=0; // Using old binary log
@@ -4165,7 +4550,7 @@ static Log_event* next_event(Relay_log_info* rli)
*/
rli->future_event_relay_log_pos= my_b_tell(cur_log);
if (hot_log)
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
DBUG_RETURN(ev);
}
DBUG_ASSERT(thd==rli->sql_thd);
@@ -4175,7 +4560,7 @@ static Log_event* next_event(Relay_log_info* rli)
{
errmsg = "slave SQL thread aborted because of I/O error";
if (hot_log)
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
goto err;
}
if (!cur_log->error) /* EOF */
@@ -4222,7 +4607,7 @@ static Log_event* next_event(Relay_log_info* rli)
0, rli->ign_master_log_pos_end,
Rotate_log_event::DUP_NAME);
rli->ign_master_log_name_end[0]= 0;
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
if (unlikely(!ev))
{
errmsg= "Slave SQL thread failed to create a Rotate event "
@@ -4237,7 +4622,7 @@ static Log_event* next_event(Relay_log_info* rli)
We can, and should release data_lock while we are waiting for
update. If we do not, show slave status will block
*/
- pthread_mutex_unlock(&rli->data_lock);
+ mysql_mutex_unlock(&rli->data_lock);
/*
Possible deadlock :
@@ -4263,7 +4648,7 @@ static Log_event* next_event(Relay_log_info* rli)
be stopped, and the SQL thread sets ignore_log_space_limit to 0 when
it stops.
*/
- pthread_mutex_lock(&rli->log_space_lock);
+ mysql_mutex_lock(&rli->log_space_lock);
// prevent the I/O thread from blocking next times
rli->ignore_log_space_limit= 1;
/*
@@ -4272,12 +4657,12 @@ static Log_event* next_event(Relay_log_info* rli)
~Relay_log_info(), i.e. when rli is destroyed, and rli will
not be destroyed before we exit the present function.
*/
- pthread_mutex_unlock(&rli->log_space_lock);
- pthread_cond_broadcast(&rli->log_space_cond);
- // Note that wait_for_update unlocks lock_log !
- rli->relay_log.wait_for_update(rli->sql_thd, 1);
+ mysql_mutex_unlock(&rli->log_space_lock);
+ mysql_cond_broadcast(&rli->log_space_cond);
+ // Note that wait_for_update_relay_log unlocks lock_log !
+ rli->relay_log.wait_for_update_relay_log(rli->sql_thd);
// re-acquire data lock since we released it earlier
- pthread_mutex_lock(&rli->data_lock);
+ mysql_mutex_lock(&rli->data_lock);
rli->last_master_timestamp= save_timestamp;
continue;
}
@@ -4288,7 +4673,7 @@ static Log_event* next_event(Relay_log_info* rli)
*/
end_io_cache(cur_log);
DBUG_ASSERT(rli->cur_log_fd >= 0);
- my_close(rli->cur_log_fd, MYF(MY_WME));
+ mysql_file_close(rli->cur_log_fd, MYF(MY_WME));
rli->cur_log_fd = -1;
if (relay_log_purge)
@@ -4345,7 +4730,7 @@ static Log_event* next_event(Relay_log_info* rli)
DBUG_PRINT("info",("hot_log: %d",hot_log));
if (!hot_log) /* if hot_log, we already have this mutex */
- pthread_mutex_lock(log_lock);
+ mysql_mutex_lock(log_lock);
if (rli->relay_log.is_active(rli->linfo.log_file_name))
{
#ifdef EXTRA_DEBUG
@@ -4420,13 +4805,16 @@ static Log_event* next_event(Relay_log_info* rli)
my_b_seek(cur_log, (my_off_t) 0);
if (check_binlog_magic(cur_log,&errmsg))
{
- if (!hot_log) pthread_mutex_unlock(log_lock);
+ if (!hot_log)
+ mysql_mutex_unlock(log_lock);
goto err;
}
- if (!hot_log) pthread_mutex_unlock(log_lock);
+ if (!hot_log)
+ mysql_mutex_unlock(log_lock);
continue;
}
- if (!hot_log) pthread_mutex_unlock(log_lock);
+ if (!hot_log)
+ mysql_mutex_unlock(log_lock);
/*
if we get here, the log was not hot, so we will have to open it
ourselves. We are sure that the log is still not hot now (a log can get
@@ -4449,7 +4837,7 @@ static Log_event* next_event(Relay_log_info* rli)
TODO: come up with something better to handle this error
*/
if (hot_log)
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
sql_print_error("Slave SQL thread: I/O error reading \
event(errno: %d cur_log->error: %d)",
my_errno,cur_log->error);
@@ -4487,8 +4875,7 @@ int rotate_relay_log(Master_info* mi)
Relay_log_info* rli= &mi->rli;
int error= 0;
- /* We don't lock rli->run_lock. This would lead to deadlocks. */
- pthread_mutex_lock(&mi->run_lock);
+ DBUG_EXECUTE_IF("crash_before_rotate_relaylog", DBUG_SUICIDE(););
/*
We need to test inited because otherwise, new_file() will attempt to lock
@@ -4519,7 +4906,6 @@ int rotate_relay_log(Master_info* mi)
*/
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
end:
- pthread_mutex_unlock(&mi->run_lock);
DBUG_RETURN(error);
}
diff --git a/sql/slave.h b/sql/slave.h
index da14b3ab4b0..73db3e4b61e 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -22,6 +22,17 @@
@file
*/
+
+/**
+ Some of defines are need in parser even though replication is not
+ compiled in (embedded).
+*/
+
+/**
+ The maximum is defined as (ULONG_MAX/1000) with 4 bytes ulong
+*/
+#define SLAVE_MAX_HEARTBEAT_PERIOD 4294967
+
#ifdef HAVE_REPLICATION
#include "log.h"
@@ -33,7 +44,6 @@
#define MAX_SLAVE_ERROR 2000
-
// Forward declarations
class Relay_log_info;
class Master_info;
@@ -105,6 +115,7 @@ extern char *master_info_file, *relay_log_info_file;
extern char *opt_relay_logname, *opt_relaylog_index_name;
extern my_bool opt_skip_slave_start, opt_reckless_slave;
extern my_bool opt_log_slave_updates;
+extern char *opt_slave_skip_errors;
extern ulonglong relay_log_space_limit;
/*
@@ -134,6 +145,7 @@ extern ulonglong relay_log_space_limit;
#define SLAVE_FORCE_ALL 4
int init_slave();
+int init_recovery(Master_info* mi, const char** errmsg);
void init_slave_skip_errors(const char* arg);
bool flush_relay_log_info(Relay_log_info* rli);
int register_slave_on_master(MYSQL* mysql);
@@ -146,15 +158,19 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
cond_lock is usually same as start_lock. It is needed for the case when
start_lock is 0 which happens if start_slave_thread() is called already
inside the start_lock section, but at the same time we want a
- pthread_cond_wait() on start_cond,start_lock
+ mysql_cond_wait() on start_cond, start_lock
*/
-int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
- pthread_mutex_t *cond_lock,
- pthread_cond_t* start_cond,
- volatile uint *slave_running,
- volatile ulong *slave_run_id,
- Master_info* mi,
- bool high_priority);
+int start_slave_thread(
+#ifdef HAVE_PSI_INTERFACE
+ PSI_thread_key thread_key,
+#endif
+ pthread_handler h_func,
+ mysql_mutex_t *start_lock,
+ mysql_mutex_t *cond_lock,
+ mysql_cond_t *start_cond,
+ volatile uint *slave_running,
+ volatile ulong *slave_run_id,
+ Master_info *mi);
/* If fd is -1, dump to NET */
int mysql_table_dump(THD* thd, const char* db,
@@ -194,6 +210,8 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli);
pthread_handler_t handle_slave_io(void *arg);
pthread_handler_t handle_slave_sql(void *arg);
+bool net_request_file(NET* net, const char* fname);
+
extern bool volatile abort_loop;
extern Master_info main_mi, *active_mi; /* active_mi for multi-master */
extern LIST master_list;
diff --git a/sql/sp.cc b/sql/sp.cc
index ddddaee2e10..5d424564317 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -13,11 +13,21 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
#include "sp.h"
+#include "sql_base.h" // close_thread_tables
+#include "sql_parse.h" // parse_sql
+#include "key.h" // key_copy
+#include "sql_show.h" // append_definer, append_identifier
+#include "sql_db.h" // get_default_db_collation, mysql_opt_change_db,
+ // mysql_change_db, check_db_dir_existence,
+ // load_db_opt_by_name
+#include "sql_table.h" // write_bin_log
+#include "sql_acl.h" // SUPER_ACL
#include "sp_head.h"
#include "sp_cache.h"
-#include "sql_trigger.h"
+#include "lock.h" // lock_object_name
#include <my_user.h>
@@ -31,7 +41,9 @@ create_string(THD *thd, String *buf,
const char *body, ulong bodylen,
st_sp_chistics *chistics,
const LEX_STRING *definer_user,
- const LEX_STRING *definer_host);
+ const LEX_STRING *definer_host,
+ ulong sql_mode);
+
static int
db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
ulong sql_mode, const char *params, const char *returns,
@@ -39,37 +51,6 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
const char *definer, longlong created, longlong modified,
Stored_program_creation_ctx *creation_ctx);
-/*
- *
- * DB storage of Stored PROCEDUREs and FUNCTIONs
- *
- */
-
-enum
-{
- MYSQL_PROC_FIELD_DB = 0,
- MYSQL_PROC_FIELD_NAME,
- MYSQL_PROC_MYSQL_TYPE,
- MYSQL_PROC_FIELD_SPECIFIC_NAME,
- MYSQL_PROC_FIELD_LANGUAGE,
- MYSQL_PROC_FIELD_ACCESS,
- MYSQL_PROC_FIELD_DETERMINISTIC,
- MYSQL_PROC_FIELD_SECURITY_TYPE,
- MYSQL_PROC_FIELD_PARAM_LIST,
- MYSQL_PROC_FIELD_RETURNS,
- MYSQL_PROC_FIELD_BODY,
- MYSQL_PROC_FIELD_DEFINER,
- MYSQL_PROC_FIELD_CREATED,
- MYSQL_PROC_FIELD_MODIFIED,
- MYSQL_PROC_FIELD_SQL_MODE,
- MYSQL_PROC_FIELD_COMMENT,
- MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT,
- MYSQL_PROC_FIELD_COLLATION_CONNECTION,
- MYSQL_PROC_FIELD_DB_COLLATION,
- MYSQL_PROC_FIELD_BODY_UTF8,
- MYSQL_PROC_FIELD_COUNT
-};
-
static const
TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] =
{
@@ -158,7 +139,7 @@ TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] =
},
{
{ C_STRING_WITH_LEN("comment") },
- { C_STRING_WITH_LEN("char(64)") },
+ { C_STRING_WITH_LEN("text") },
{ C_STRING_WITH_LEN("utf8") }
},
{
@@ -421,12 +402,13 @@ static Proc_table_intact proc_table_intact;
\# Pointer to TABLE object of mysql.proc
*/
-TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
+TABLE *open_proc_table_for_read(THD *thd, Open_tables_backup *backup)
{
+ TABLE_LIST table;
+
DBUG_ENTER("open_proc_table_for_read");
- TABLE_LIST table;
- table.init_one_table("mysql", "proc", TL_READ);
+ table.init_one_table("mysql", 5, "proc", 4, "proc", TL_READ);
if (open_system_tables_for_read(thd, &table, backup))
DBUG_RETURN(NULL);
@@ -456,11 +438,12 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
static TABLE *open_proc_table_for_update(THD *thd)
{
+ TABLE_LIST table_list;
+ TABLE *table;
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("open_proc_table_for_update");
- TABLE *table;
- TABLE_LIST table_list;
- table_list.init_one_table("mysql", "proc", TL_WRITE);
+ table_list.init_one_table("mysql", 5, "proc", 4, "proc", TL_WRITE);
if (!(table= open_system_table_for_update(thd, &table_list)))
DBUG_RETURN(NULL);
@@ -469,6 +452,7 @@ static TABLE *open_proc_table_for_update(THD *thd)
DBUG_RETURN(table);
close_thread_tables(thd);
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
DBUG_RETURN(NULL);
}
@@ -556,7 +540,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
String str(buff, sizeof(buff), &my_charset_bin);
bool saved_time_zone_used= thd->time_zone_used;
ulong sql_mode, saved_mode= thd->variables.sql_mode;
- Open_tables_state open_tables_state_backup;
+ Open_tables_backup open_tables_state_backup;
Stored_program_creation_ctx *creation_ctx;
DBUG_ENTER("db_find_routine");
@@ -690,16 +674,24 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
struct Silence_deprecated_warning : public Internal_error_handler
{
public:
- virtual bool handle_error(uint sql_errno, const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd);
+ virtual bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl);
};
bool
-Silence_deprecated_warning::handle_error(uint sql_errno, const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd)
+Silence_deprecated_warning::handle_condition(
+ THD *,
+ uint sql_errno,
+ const char*,
+ MYSQL_ERROR::enum_warning_level level,
+ const char*,
+ MYSQL_ERROR ** cond_hdl)
{
+ *cond_hdl= NULL;
if (sql_errno == ER_WARN_DEPRECATED_SYNTAX &&
level == MYSQL_ERROR::WARN_LEVEL_WARN)
return TRUE;
@@ -708,6 +700,62 @@ Silence_deprecated_warning::handle_error(uint sql_errno, const char *message,
}
+/**
+ @brief The function parses input strings and returns SP stucture.
+
+ @param[in] thd Thread handler
+ @param[in] defstr CREATE... string
+ @param[in] sql_mode SQL mode
+ @param[in] creation_ctx Creation context of stored routines
+
+ @return Pointer on sp_head struct
+ @retval # Pointer on sp_head struct
+ @retval 0 error
+*/
+
+static sp_head *sp_compile(THD *thd, String *defstr, ulong sql_mode,
+ Stored_program_creation_ctx *creation_ctx)
+{
+ sp_head *sp;
+ ulong old_sql_mode= thd->variables.sql_mode;
+ ha_rows old_select_limit= thd->variables.select_limit;
+ sp_rcontext *old_spcont= thd->spcont;
+ Silence_deprecated_warning warning_handler;
+ Parser_state parser_state;
+
+ thd->variables.sql_mode= sql_mode;
+ thd->variables.select_limit= HA_POS_ERROR;
+
+ if (parser_state.init(thd, defstr->c_ptr(), defstr->length()))
+ {
+ thd->variables.sql_mode= old_sql_mode;
+ thd->variables.select_limit= old_select_limit;
+ return NULL;
+ }
+
+ lex_start(thd);
+ thd->push_internal_handler(&warning_handler);
+ thd->spcont= 0;
+
+ if (parse_sql(thd, & parser_state, creation_ctx) || thd->lex == NULL)
+ {
+ sp= thd->lex->sphead;
+ delete sp;
+ sp= 0;
+ }
+ else
+ {
+ sp= thd->lex->sphead;
+ }
+
+ thd->pop_internal_handler();
+ thd->spcont= old_spcont;
+ thd->variables.sql_mode= old_sql_mode;
+ thd->variables.select_limit= old_select_limit;
+ return sp;
+}
+
+
static int
db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
ulong sql_mode, const char *params, const char *returns,
@@ -721,11 +769,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
LEX_STRING saved_cur_db_name=
{ saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
bool cur_db_changed;
- ulong old_sql_mode= thd->variables.sql_mode;
- ha_rows old_select_limit= thd->variables.select_limit;
- sp_rcontext *old_spcont= thd->spcont;
- Silence_deprecated_warning warning_handler;
-
+
char definer_user_name_holder[USERNAME_LENGTH + 1];
LEX_STRING definer_user_name= { definer_user_name_holder,
USERNAME_LENGTH };
@@ -733,10 +777,10 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
char definer_host_name_holder[HOSTNAME_LENGTH + 1];
LEX_STRING definer_host_name= { definer_host_name_holder, HOSTNAME_LENGTH };
- int ret;
+ int ret= 0;
- thd->variables.sql_mode= sql_mode;
- thd->variables.select_limit= HA_POS_ERROR;
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&ret))
+ return TRUE;
thd->lex= &newlex;
newlex.current_select= NULL;
@@ -760,7 +804,8 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
params, strlen(params),
returns, strlen(returns),
body, strlen(body),
- &chistics, &definer_user_name, &definer_host_name))
+ &chistics, &definer_user_name, &definer_host_name,
+ sql_mode))
{
ret= SP_INTERNAL_ERROR;
goto end;
@@ -779,22 +824,8 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
goto end;
}
- thd->spcont= NULL;
-
{
- Parser_state parser_state;
- if (parser_state.init(thd, defstr.c_ptr(), defstr.length()))
- {
- ret= SP_INTERNAL_ERROR;
- goto end;
- }
-
- lex_start(thd);
-
- thd->push_internal_handler(&warning_handler);
- ret= parse_sql(thd, & parser_state, creation_ctx) || newlex.sphead == NULL;
- thd->pop_internal_handler();
-
+ *sphp= sp_compile(thd, &defstr, sql_mode, creation_ctx);
/*
Force switching back to the saved current database (if changed),
because it may be NULL. In this case, mysql_change_db() would
@@ -803,19 +834,16 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
if (cur_db_changed && mysql_change_db(thd, &saved_cur_db_name, TRUE))
{
- delete newlex.sphead;
ret= SP_INTERNAL_ERROR;
goto end;
}
- if (ret)
+ if (!*sphp)
{
- delete newlex.sphead;
ret= SP_PARSE_ERROR;
goto end;
}
- *sphp= newlex.sphead;
(*sphp)->set_definer(&definer_user_name, &definer_host_name);
(*sphp)->set_info(created, modified, &chistics, sql_mode);
(*sphp)->set_creation_ctx(creation_ctx);
@@ -832,10 +860,8 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
}
end:
+ thd->lex->sphead= NULL;
lex_end(thd->lex);
- thd->spcont= old_spcont;
- thd->variables.sql_mode= old_sql_mode;
- thd->variables.select_limit= old_select_limit;
thd->lex= old_lex;
return ret;
}
@@ -858,6 +884,11 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
{
result.append(STRING_WITH_LEN(" CHARSET "));
result.append(field->charset()->csname);
+ if (!(field->charset()->state & MY_CS_PRIMARY))
+ {
+ result.append(STRING_WITH_LEN(" COLLATE "));
+ result.append(field->charset()->name);
+ }
}
delete field;
@@ -894,6 +925,8 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
TABLE *table;
char definer[USER_HOST_BUFF_SIZE];
ulong saved_mode= thd->variables.sql_mode;
+ MDL_key::enum_mdl_namespace mdl_type= type == TYPE_ENUM_FUNCTION ?
+ MDL_key::FUNCTION : MDL_key::PROCEDURE;
CHARSET_INFO *db_cs= get_default_db_collation(thd, sp->m_db.str);
@@ -912,6 +945,10 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
type == TYPE_ENUM_FUNCTION);
+ /* Grab an exclusive MDL lock. */
+ if (lock_object_name(thd, mdl_type, sp->m_db.str, sp->m_name.str))
+ DBUG_RETURN(SP_OPEN_TABLE_FAILED);
+
/* Reset sql_mode during data dictionary operations. */
thd->variables.sql_mode= 0;
@@ -920,8 +957,8 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
saved_count_cuted_fields= thd->count_cuted_fields;
thd->count_cuted_fields= CHECK_FIELD_WARN;
@@ -1089,7 +1126,10 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
ret= SP_OK;
if (table->file->ha_write_row(table->record[0]))
ret= SP_WRITE_ROW_FAILED;
- else if (mysql_bin_log.is_open())
+ if (ret == SP_OK)
+ sp_cache_invalidate();
+
+ if (ret == SP_OK && mysql_bin_log.is_open())
{
thd->clear_error();
@@ -1105,7 +1145,8 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
retstr.c_ptr(), retstr.length(),
sp->m_body.str, sp->m_body.length,
sp->m_chistics, &(thd->lex->definer->user),
- &(thd->lex->definer->host)))
+ &(thd->lex->definer->host),
+ saved_mode))
{
ret= SP_INTERNAL_ERROR;
goto done;
@@ -1113,22 +1154,21 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
/* restore sql_mode when binloging */
thd->variables.sql_mode= saved_mode;
/* Such a statement can always go directly to binlog, no trans cache */
- if (thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+ if (thd->binlog_query(THD::STMT_QUERY_TYPE,
log_query.c_ptr(), log_query.length(),
- FALSE, FALSE, 0))
+ FALSE, FALSE, FALSE, 0))
ret= SP_INTERNAL_ERROR;
thd->variables.sql_mode= 0;
}
-
}
done:
thd->count_cuted_fields= saved_count_cuted_fields;
thd->variables.sql_mode= saved_mode;
-
- close_thread_tables(thd);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(ret);
}
@@ -1154,6 +1194,8 @@ sp_drop_routine(THD *thd, int type, sp_name *name)
TABLE *table;
int ret;
bool save_binlog_row_based;
+ MDL_key::enum_mdl_namespace mdl_type= type == TYPE_ENUM_FUNCTION ?
+ MDL_key::FUNCTION : MDL_key::PROCEDURE;
DBUG_ENTER("sp_drop_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s",
type, (int) name->m_name.length, name->m_name.str));
@@ -1161,16 +1203,21 @@ sp_drop_routine(THD *thd, int type, sp_name *name)
DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
type == TYPE_ENUM_FUNCTION);
+ /* Grab an exclusive MDL lock. */
+ if (lock_object_name(thd, mdl_type, name->m_db.str, name->m_name.str))
+ DBUG_RETURN(SP_DELETE_ROW_FAILED);
+
+ if (!(table= open_proc_table_for_update(thd)))
+ DBUG_RETURN(SP_OPEN_TABLE_FAILED);
+
/*
This statement will be replicated as a statement, even when using
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
- if (!(table= open_proc_table_for_update(thd)))
- DBUG_RETURN(SP_OPEN_TABLE_FAILED);
if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
{
if (table->file->ha_delete_row(table->record[0]))
@@ -1182,11 +1229,25 @@ sp_drop_routine(THD *thd, int type, sp_name *name)
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
ret= SP_INTERNAL_ERROR;
sp_cache_invalidate();
- }
- close_thread_tables(thd);
+ /*
+ A lame workaround for lack of cache flush:
+ make sure the routine is at least gone from the
+ local cache.
+ */
+ {
+ sp_head *sp;
+ sp_cache **spc= (type == TYPE_ENUM_FUNCTION ?
+ &thd->sp_func_cache : &thd->sp_proc_cache);
+ sp= sp_cache_lookup(spc, name);
+ if (sp)
+ sp_cache_flush_obsolete(spc, &sp);
+ }
+ }
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(ret);
}
@@ -1214,24 +1275,56 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
TABLE *table;
int ret;
bool save_binlog_row_based;
+ MDL_key::enum_mdl_namespace mdl_type= type == TYPE_ENUM_FUNCTION ?
+ MDL_key::FUNCTION : MDL_key::PROCEDURE;
DBUG_ENTER("sp_update_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s",
type, (int) name->m_name.length, name->m_name.str));
DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
type == TYPE_ENUM_FUNCTION);
+
+ /* Grab an exclusive MDL lock. */
+ if (lock_object_name(thd, mdl_type, name->m_db.str, name->m_name.str))
+ DBUG_RETURN(SP_OPEN_TABLE_FAILED);
+
+ if (!(table= open_proc_table_for_update(thd)))
+ DBUG_RETURN(SP_OPEN_TABLE_FAILED);
+
/*
This statement will be replicated as a statement, even when using
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
- if (!(table= open_proc_table_for_update(thd)))
- DBUG_RETURN(SP_OPEN_TABLE_FAILED);
if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
{
+ if (type == TYPE_ENUM_FUNCTION && ! trust_function_creators &&
+ mysql_bin_log.is_open() &&
+ (chistics->daccess == SP_CONTAINS_SQL ||
+ chistics->daccess == SP_MODIFIES_SQL_DATA))
+ {
+ char *ptr;
+ bool is_deterministic;
+ ptr= get_field(thd->mem_root,
+ table->field[MYSQL_PROC_FIELD_DETERMINISTIC]);
+ if (ptr == NULL)
+ {
+ ret= SP_INTERNAL_ERROR;
+ goto err;
+ }
+ is_deterministic= ptr[0] == 'N' ? FALSE : TRUE;
+ if (!is_deterministic)
+ {
+ my_message(ER_BINLOG_UNSAFE_ROUTINE,
+ ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
+ ret= SP_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+
store_record(table,record[1]);
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
@@ -1258,15 +1351,116 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
ret= SP_INTERNAL_ERROR;
sp_cache_invalidate();
}
-
- close_thread_tables(thd);
+err:
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(ret);
}
/**
+ This internal handler is used to trap errors from opening mysql.proc.
+*/
+
+class Lock_db_routines_error_handler : public Internal_error_handler
+{
+public:
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
+ {
+ if (sql_errno == ER_NO_SUCH_TABLE ||
+ sql_errno == ER_COL_COUNT_DOESNT_MATCH_CORRUPTED)
+ return true;
+ return false;
+ }
+};
+
+
+/**
+ Acquires exclusive metadata lock on all stored routines in the
+ given database.
+
+ @note Will also return false (=success) if mysql.proc can't be opened
+ or is outdated. This allows DROP DATABASE to continue in these
+ cases.
+ */
+
+bool lock_db_routines(THD *thd, char *db)
+{
+ TABLE *table;
+ uint key_len;
+ int nxtres= 0;
+ Open_tables_backup open_tables_state_backup;
+ MDL_request_list mdl_requests;
+ Lock_db_routines_error_handler err_handler;
+ DBUG_ENTER("lock_db_routines");
+
+ /*
+ mysql.proc will be re-opened during deletion, so we can ignore
+ errors when opening the table here. The error handler is
+ used to avoid getting the same warning twice.
+ */
+ thd->push_internal_handler(&err_handler);
+ table= open_proc_table_for_read(thd, &open_tables_state_backup);
+ thd->pop_internal_handler();
+ if (!table)
+ {
+ /*
+ DROP DATABASE should not fail even if mysql.proc does not exist
+ or is outdated. We therefore only abort mysql_rm_db() if we
+ have errors not handled by the error handler.
+ */
+ DBUG_RETURN(thd->is_error() || thd->killed);
+ }
+
+ table->field[MYSQL_PROC_FIELD_DB]->store(db, strlen(db), system_charset_info);
+ key_len= table->key_info->key_part[0].store_length;
+ table->file->ha_index_init(0, 1);
+
+ if (! table->file->index_read_map(table->record[0],
+ table->field[MYSQL_PROC_FIELD_DB]->ptr,
+ (key_part_map)1, HA_READ_KEY_EXACT))
+ {
+ do
+ {
+ char *sp_name= get_field(thd->mem_root,
+ table->field[MYSQL_PROC_FIELD_NAME]);
+ longlong sp_type= table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
+ MDL_request *mdl_request= new (thd->mem_root) MDL_request;
+ mdl_request->init(sp_type == TYPE_ENUM_FUNCTION ?
+ MDL_key::FUNCTION : MDL_key::PROCEDURE,
+ db, sp_name, MDL_EXCLUSIVE, MDL_TRANSACTION);
+ mdl_requests.push_front(mdl_request);
+ } while (! (nxtres= table->file->index_next_same(table->record[0],
+ table->field[MYSQL_PROC_FIELD_DB]->ptr,
+ key_len)));
+ }
+ table->file->ha_index_end();
+ if (nxtres != 0 && nxtres != HA_ERR_END_OF_FILE)
+ {
+ table->file->print_error(nxtres, MYF(0));
+ close_system_tables(thd, &open_tables_state_backup);
+ DBUG_RETURN(true);
+ }
+ close_system_tables(thd, &open_tables_state_backup);
+
+ /* We should already hold a global IX lock and a schema X lock. */
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
+ MDL_INTENTION_EXCLUSIVE) &&
+ thd->mdl_context.is_lock_owner(MDL_key::SCHEMA, db, "",
+ MDL_EXCLUSIVE));
+ DBUG_RETURN(thd->mdl_context.acquire_locks(&mdl_requests,
+ thd->variables.lock_wait_timeout));
+}
+
+
+/**
Drop all routines in database 'db'
@note Close the thread tables, the calling code might want to
@@ -1279,6 +1473,7 @@ sp_drop_db_routines(THD *thd, char *db)
TABLE *table;
int ret;
uint key_len;
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("sp_drop_db_routines");
DBUG_PRINT("enter", ("db: %s", db));
@@ -1319,6 +1514,11 @@ sp_drop_db_routines(THD *thd, char *db)
table->file->ha_index_end();
close_thread_tables(thd);
+ /*
+ Make sure to only release the MDL lock on mysql.proc, not other
+ metadata locks DROP DATABASE might have acquired.
+ */
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
err:
DBUG_RETURN(ret);
@@ -1344,10 +1544,7 @@ err:
bool
sp_show_create_routine(THD *thd, int type, sp_name *name)
{
- bool err_status= TRUE;
sp_head *sp;
- sp_cache **cache = type == TYPE_ENUM_PROCEDURE ?
- &thd->sp_proc_cache : &thd->sp_func_cache;
DBUG_ENTER("sp_show_create_routine");
DBUG_PRINT("enter", ("name: %.*s",
@@ -1357,28 +1554,29 @@ sp_show_create_routine(THD *thd, int type, sp_name *name)
DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
type == TYPE_ENUM_FUNCTION);
- if (type == TYPE_ENUM_PROCEDURE)
+ /*
+ @todo: Consider using prelocking for this code as well. Currently
+ SHOW CREATE PROCEDURE/FUNCTION is a dirty read of the data
+ dictionary, i.e. takes no metadata locks.
+ It is "safe" to do as long as it doesn't affect the results
+ of the binary log or the query cache, which currently it does not.
+ */
+ if (sp_cache_routine(thd, type, name, FALSE, &sp))
+ DBUG_RETURN(TRUE);
+
+ if (sp == NULL || sp->show_create_routine(thd, type))
{
/*
- SHOW CREATE PROCEDURE may require two instances of one sp_head
- object when SHOW CREATE PROCEDURE is called for the procedure that
- is being executed. Basically, there is no actual recursion, so we
- increase the recursion limit for this statement (kind of hack).
-
- SHOW CREATE FUNCTION does not require this because SHOW CREATE
- statements are prohibitted within stored functions.
- */
-
- thd->variables.max_sp_recursion_depth++;
+ If we have insufficient privileges, pretend the routine
+ does not exist.
+ */
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE",
+ name->m_name.str);
+ DBUG_RETURN(TRUE);
}
- if ((sp= sp_find_routine(thd, type, name, cache, FALSE)))
- err_status= sp->show_create_routine(thd, type);
-
- if (type == TYPE_ENUM_PROCEDURE)
- thd->variables.max_sp_recursion_depth--;
-
- DBUG_RETURN(err_status);
+ DBUG_RETURN(FALSE);
}
@@ -1413,6 +1611,9 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
(int) name->m_name.length, name->m_name.str,
type, cache_only));
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&depth))
+ return NULL;
+
if ((sp= sp_cache_lookup(cp, name)))
{
ulong level;
@@ -1527,7 +1728,7 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any)
&thd->sp_proc_cache, FALSE) != NULL ||
sp_find_routine(thd, TYPE_ENUM_FUNCTION, name,
&thd->sp_func_cache, FALSE) != NULL;
- mysql_reset_errors(thd, TRUE);
+ thd->warning_info->clear_warning_info(thd->query_id);
if (sp_object_found)
{
if (any)
@@ -1544,104 +1745,12 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any)
}
-/**
- Check if a routine exists in the mysql.proc table, without actually
- parsing the definition. (Used for dropping).
-
- @param thd thread context
- @param name name of procedure
-
- @retval
- 0 Success
- @retval
- non-0 Error; SP_OPEN_TABLE_FAILED or SP_KEY_NOT_FOUND
-*/
-
-int
-sp_routine_exists_in_table(THD *thd, int type, sp_name *name)
-{
- TABLE *table;
- int ret;
- Open_tables_state open_tables_state_backup;
-
- if (!(table= open_proc_table_for_read(thd, &open_tables_state_backup)))
- ret= SP_OPEN_TABLE_FAILED;
- else
- {
- if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
- ret= SP_KEY_NOT_FOUND;
- close_system_tables(thd, &open_tables_state_backup);
- }
- return ret;
-}
-
-
-/**
- Structure that represents element in the set of stored routines
- used by statement or routine.
-*/
-struct Sroutine_hash_entry;
-
-struct Sroutine_hash_entry
-{
- /**
- Set key consisting of one-byte routine type and quoted routine name.
- */
- LEX_STRING key;
- /**
- Next element in list linking all routines in set. See also comments
- for LEX::sroutine/sroutine_list and sp_head::m_sroutines.
- */
- Sroutine_hash_entry *next;
- /**
- Uppermost view which directly or indirectly uses this routine.
- 0 if routine is not used in view. Note that it also can be 0 if
- statement uses routine both via view and directly.
- */
- TABLE_LIST *belong_to_view;
-};
-
-
extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
my_bool first)
{
Sroutine_hash_entry *rn= (Sroutine_hash_entry *)ptr;
- *plen= rn->key.length;
- return (uchar *)rn->key.str;
-}
-
-
-/**
- Check if
- - current statement (the one in thd->lex) needs table prelocking
- - first routine in thd->lex->sroutines_list needs to execute its body in
- prelocked mode.
-
- @param thd Current thread, thd->lex is the statement to be
- checked.
- @param[out] need_prelocking TRUE - prelocked mode should be activated
- before executing the statement;
- FALSE - Don't activate prelocking
- @param[out] first_no_prelocking TRUE - Tables used by first routine in
- thd->lex->sroutines_list should be
- prelocked. FALSE - Otherwise.
-
- @note
- This function assumes that for any "CALL proc(...)" statement routines_list
- will have 'proc' as first element (it may have several, consider e.g.
- "proc(sp_func(...)))". This property is currently guaranted by the parser.
-*/
-
-void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
- bool *first_no_prelocking)
-{
- Sroutine_hash_entry *routine= thd->lex->sroutines_list.first;
-
- DBUG_ASSERT(routine);
- bool first_is_procedure= (routine->key.str[0] == TYPE_ENUM_PROCEDURE);
-
- *first_no_prelocking= first_is_procedure;
- *need_prelocking= !first_is_procedure || test(routine->next);
+ *plen= rn->mdl_request.key.length();
+ return (uchar *)rn->mdl_request.key.ptr();
}
@@ -1651,11 +1760,11 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
In case when statement uses stored routines but does not need
prelocking (i.e. it does not use any tables) we will access the
- elements of LEX::sroutines set on prepared statement re-execution.
- Because of this we have to allocate memory for both hash element
- and copy of its key in persistent arena.
+ elements of Query_tables_list::sroutines set on prepared statement
+ re-execution. Because of this we have to allocate memory for both
+ hash element and copy of its key in persistent arena.
- @param lex LEX representing statement
+ @param prelocking_ctx Prelocking context of the statement
@param arena Arena in which memory for new element will be
allocated
@param key Key for the hash representing set
@@ -1663,7 +1772,7 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
(0 if routine is not used by view)
@note
- Will also add element to end of 'LEX::sroutines_list' list.
+ Will also add element to end of 'Query_tables_list::sroutines_list' list.
@todo
When we will got rid of these accesses on re-executions we will be
@@ -1678,28 +1787,25 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
the set).
*/
-static bool add_used_routine(LEX *lex, Query_arena *arena,
- const LEX_STRING *key,
- TABLE_LIST *belong_to_view)
+bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
+ const MDL_key *key, TABLE_LIST *belong_to_view)
{
- hash_init_opt(&lex->sroutines, system_charset_info,
- Query_tables_list::START_SROUTINES_HASH_SIZE,
- 0, 0, sp_sroutine_key, 0, 0);
+ my_hash_init_opt(&prelocking_ctx->sroutines, system_charset_info,
+ Query_tables_list::START_SROUTINES_HASH_SIZE,
+ 0, 0, sp_sroutine_key, 0, 0);
- if (!hash_search(&lex->sroutines, (uchar *)key->str, key->length))
+ if (!my_hash_search(&prelocking_ctx->sroutines, key->ptr(), key->length()))
{
Sroutine_hash_entry *rn=
- (Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) +
- key->length + 1);
+ (Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry));
if (!rn) // OOM. Error will be reported using fatal_error().
return FALSE;
- rn->key.length= key->length;
- rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry);
- memcpy(rn->key.str, key->str, key->length + 1);
- if (my_hash_insert(&lex->sroutines, (uchar *)rn))
+ rn->mdl_request.init(key, MDL_SHARED, MDL_TRANSACTION);
+ if (my_hash_insert(&prelocking_ctx->sroutines, (uchar *)rn))
return FALSE;
- lex->sroutines_list.link_in_list(rn, &rn->next);
+ prelocking_ctx->sroutines_list.link_in_list(rn, &rn->next);
rn->belong_to_view= belong_to_view;
+ rn->m_sp_cache_version= 0;
return TRUE;
}
return FALSE;
@@ -1713,24 +1819,27 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
To be friendly towards prepared statements one should pass
persistent arena as second argument.
- @param lex LEX representing statement
- @param arena arena in which memory for new element of the set
- will be allocated
- @param rt routine name
- @param rt_type routine type (one of TYPE_ENUM_PROCEDURE/...)
+ @param prelocking_ctx Prelocking context of the statement
+ @param arena Arena in which memory for new element of the set
+ will be allocated
+ @param rt Routine name
+ @param rt_type Routine type (one of TYPE_ENUM_PROCEDURE/...)
@note
- Will also add element to end of 'LEX::sroutines_list' list (and will
- take into account that this is explicitly used routine).
+ Will also add element to end of 'Query_tables_list::sroutines_list' list
+ (and will take into account that this is an explicitly used routine).
*/
-void sp_add_used_routine(LEX *lex, Query_arena *arena,
+void sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
sp_name *rt, char rt_type)
{
- rt->set_routine_type(rt_type);
- (void)add_used_routine(lex, arena, &rt->m_sroutines_key, 0);
- lex->sroutines_list_own_last= lex->sroutines_list.next;
- lex->sroutines_list_own_elements= lex->sroutines_list.elements;
+ MDL_key key((rt_type == TYPE_ENUM_FUNCTION) ? MDL_key::FUNCTION :
+ MDL_key::PROCEDURE,
+ rt->m_db.str, rt->m_name.str);
+ (void)sp_add_used_routine(prelocking_ctx, arena, &key, 0);
+ prelocking_ctx->sroutines_list_own_last= prelocking_ctx->sroutines_list.next;
+ prelocking_ctx->sroutines_list_own_elements=
+ prelocking_ctx->sroutines_list.elements;
}
@@ -1738,13 +1847,13 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena,
Remove routines which are only indirectly used by statement from
the set of routines used by this statement.
- @param lex LEX representing statement
+ @param prelocking_ctx Prelocking context of the statement
*/
-void sp_remove_not_own_routines(LEX *lex)
+void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx)
{
Sroutine_hash_entry *not_own_rt, *next_rt;
- for (not_own_rt= *lex->sroutines_list_own_last;
+ for (not_own_rt= *prelocking_ctx->sroutines_list_own_last;
not_own_rt; not_own_rt= next_rt)
{
/*
@@ -1752,12 +1861,13 @@ void sp_remove_not_own_routines(LEX *lex)
but we want to be more future-proof.
*/
next_rt= not_own_rt->next;
- hash_delete(&lex->sroutines, (uchar *)not_own_rt);
+ my_hash_delete(&prelocking_ctx->sroutines, (uchar *)not_own_rt);
}
- *lex->sroutines_list_own_last= NULL;
- lex->sroutines_list.next= lex->sroutines_list_own_last;
- lex->sroutines_list.elements= lex->sroutines_list_own_elements;
+ *prelocking_ctx->sroutines_list_own_last= NULL;
+ prelocking_ctx->sroutines_list.next= prelocking_ctx->sroutines_list_own_last;
+ prelocking_ctx->sroutines_list.elements=
+ prelocking_ctx->sroutines_list_own_elements;
}
@@ -1785,8 +1895,9 @@ bool sp_update_sp_used_routines(HASH *dst, HASH *src)
{
for (uint i=0 ; i < src->records ; i++)
{
- Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
- if (!hash_search(dst, (uchar *)rt->key.str, rt->key.length))
+ Sroutine_hash_entry *rt= (Sroutine_hash_entry *)my_hash_element(src, i);
+ if (!my_hash_search(dst, (uchar *)rt->mdl_request.key.ptr(),
+ rt->mdl_request.key.length()))
{
if (my_hash_insert(dst, (uchar *)rt))
return TRUE;
@@ -1801,23 +1912,24 @@ bool sp_update_sp_used_routines(HASH *dst, HASH *src)
routines used by statement.
@param thd Thread context
- @param lex LEX representing statement
+ @param prelocking_ctx Prelocking context of the statement
@param src Hash representing set from which routines will
be added
@param belong_to_view Uppermost view which uses these routines, 0 if none
- @note
- It will also add elements to end of 'LEX::sroutines_list' list.
+ @note It will also add elements to end of
+ 'Query_tables_list::sroutines_list' list.
*/
-static void
-sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src,
- TABLE_LIST *belong_to_view)
+void
+sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
+ HASH *src, TABLE_LIST *belong_to_view)
{
for (uint i=0 ; i < src->records ; i++)
{
- Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
- (void)add_used_routine(lex, thd->stmt_arena, &rt->key, belong_to_view);
+ Sroutine_hash_entry *rt= (Sroutine_hash_entry *)my_hash_element(src, i);
+ (void)sp_add_used_routine(prelocking_ctx, thd->stmt_arena,
+ &rt->mdl_request.key, belong_to_view);
}
}
@@ -1827,240 +1939,139 @@ sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src,
routines used by statement.
@param thd Thread context
- @param lex LEX representing statement
+ @param prelocking_ctx Prelocking context of the statement
@param src List representing set from which routines will
be added
@param belong_to_view Uppermost view which uses these routines, 0 if none
- @note
- It will also add elements to end of 'LEX::sroutines_list' list.
+ @note It will also add elements to end of
+ 'Query_tables_list::sroutines_list' list.
*/
-static void sp_update_stmt_used_routines(THD *thd, LEX *lex,
- SQL_I_List<Sroutine_hash_entry> *src,
- TABLE_LIST *belong_to_view)
+void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
+ SQL_I_List<Sroutine_hash_entry> *src,
+ TABLE_LIST *belong_to_view)
{
for (Sroutine_hash_entry *rt= src->first; rt; rt= rt->next)
- (void)add_used_routine(lex, thd->stmt_arena, &rt->key, belong_to_view);
+ (void)sp_add_used_routine(prelocking_ctx, thd->stmt_arena,
+ &rt->mdl_request.key, belong_to_view);
}
/**
- Cache sub-set of routines used by statement, add tables used by these
- routines to statement table list. Do the same for all routines used
- by these routines.
-
- @param thd thread context
- @param lex LEX representing statement
- @param start first routine from the list of routines to be cached
- (this list defines mentioned sub-set).
- @param first_no_prelock If true, don't add tables or cache routines used by
- the body of the first routine (i.e. *start)
- will be executed in non-prelocked mode.
- @param tabs_changed Set to TRUE some tables were added, FALSE otherwise
-
- @note
- If some function is missing this won't be reported here.
- Instead this fact will be discovered during query execution.
-
- @retval
- 0 success
- @retval
- non-0 failure
+ A helper wrapper around sp_cache_routine() to use from
+ prelocking until 'sp_name' is eradicated as a class.
*/
-static int
-sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
- Sroutine_hash_entry *start,
- bool first_no_prelock)
+int sp_cache_routine(THD *thd, Sroutine_hash_entry *rt,
+ bool lookup_only, sp_head **sp)
{
- int ret= 0;
- bool first= TRUE;
- DBUG_ENTER("sp_cache_routines_and_add_tables_aux");
-
- for (Sroutine_hash_entry *rt= start; rt; rt= rt->next)
- {
- sp_name name(thd, rt->key.str, rt->key.length);
- int type= rt->key.str[0];
- sp_head *sp;
-
- if (!(sp= sp_cache_lookup((type == TYPE_ENUM_FUNCTION ?
- &thd->sp_func_cache : &thd->sp_proc_cache),
- &name)))
- {
- switch ((ret= db_find_routine(thd, type, &name, &sp)))
- {
- case SP_OK:
- {
- if (type == TYPE_ENUM_FUNCTION)
- sp_cache_insert(&thd->sp_func_cache, sp);
- else
- sp_cache_insert(&thd->sp_proc_cache, sp);
- }
- break;
- case SP_KEY_NOT_FOUND:
- ret= SP_OK;
- break;
- default:
- /* Query might have been killed, don't set error. */
- if (thd->killed)
- break;
-
- /*
- Any error when loading an existing routine is either some problem
- with the mysql.proc table, or a parse error because the contents
- has been tampered with (in which case we clear that error).
- */
- if (ret == SP_PARSE_ERROR)
- thd->clear_error();
- /*
- If we cleared the parse error, or when db_find_routine() flagged
- an error with it's return value without calling my_error(), we
- set the generic "mysql.proc table corrupt" error here.
- */
- if (! thd->is_error())
- {
- /*
- SP allows full NAME_LEN chars thus he have to allocate enough
- size in bytes. Otherwise there is stack overrun could happen
- if multibyte sequence is `name`. `db` is still safe because the
- rest of the server checks agains NAME_LEN bytes and not chars.
- Hence, the overrun happens only if the name is in length > 32 and
- uses multibyte (cyrillic, greek, etc.)
- */
- char n[NAME_LEN*2+2];
-
- /* m_qname.str is not always \0 terminated */
- memcpy(n, name.m_qname.str, name.m_qname.length);
- n[name.m_qname.length]= '\0';
- my_error(ER_SP_PROC_TABLE_CORRUPT, MYF(0), n, ret);
- }
- break;
- }
- }
- if (sp)
- {
- if (!(first && first_no_prelock))
- {
- sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines,
- rt->belong_to_view);
- (void)sp->add_used_tables_to_table_list(thd, &lex->query_tables_last,
- rt->belong_to_view);
- }
- sp->propagate_attributes(lex);
- }
- first= FALSE;
- }
- DBUG_RETURN(ret);
-}
-
-
-/**
- Cache all routines from the set of used by statement, add tables used
- by those routines to statement table list. Do the same for all routines
- used by those routines.
-
- @param thd thread context
- @param lex LEX representing statement
- @param first_no_prelock If true, don't add tables or cache routines used by
- the body of the first routine (i.e. *start)
+ char qname_buff[NAME_LEN*2+1+1];
+ sp_name name(&rt->mdl_request.key, qname_buff);
+ MDL_key::enum_mdl_namespace mdl_type= rt->mdl_request.key.mdl_namespace();
+ int type= ((mdl_type == MDL_key::FUNCTION) ?
+ TYPE_ENUM_FUNCTION : TYPE_ENUM_PROCEDURE);
- @retval
- 0 success
- @retval
- non-0 failure
-*/
+ /*
+ Check that we have an MDL lock on this routine, unless it's a top-level
+ CALL. The assert below should be unambiguous: the first element
+ in sroutines_list has an MDL lock unless it's a top-level call, or a
+ trigger, but triggers can't occur here (see the preceding assert).
+ */
+ DBUG_ASSERT(rt->mdl_request.ticket || rt == thd->lex->sroutines_list.first);
-int
-sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock)
-{
- return sp_cache_routines_and_add_tables_aux(thd, lex,
- lex->sroutines_list.first, first_no_prelock);
+ return sp_cache_routine(thd, type, &name, lookup_only, sp);
}
/**
- Add all routines used by view to the set of routines used by
- statement.
-
- Add tables used by those routines to statement table list. Do the same
- for all routines used by these routines.
-
- @param thd Thread context
- @param lex LEX representing statement
- @param view Table list element representing view
-
- @retval
- 0 success
- @retval
- non-0 failure
+ Ensure that routine is present in cache by loading it from the mysql.proc
+ table if needed. If the routine is present but old, reload it.
+ Emit an appropriate error if there was a problem during
+ loading.
+
+ @param[in] thd Thread context.
+ @param[in] type Type of object (TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE).
+ @param[in] name Name of routine.
+ @param[in] lookup_only Only check that the routine is in the cache.
+ If it's not, don't try to load. If it is present,
+ but old, don't try to reload.
+ @param[out] sp Pointer to sp_head object for routine, NULL if routine was
+ not found.
+
+ @retval 0 Either routine is found and was succesfully loaded into cache
+ or it does not exist.
+ @retval non-0 Error while loading routine from mysql,proc table.
*/
-int
-sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, TABLE_LIST *view)
+int sp_cache_routine(THD *thd, int type, sp_name *name,
+ bool lookup_only, sp_head **sp)
{
- Sroutine_hash_entry **last_cached_routine_ptr= lex->sroutines_list.next;
- sp_update_stmt_used_routines(thd, lex, &view->view->sroutines_list,
- view->top_table());
- return sp_cache_routines_and_add_tables_aux(thd, lex,
- *last_cached_routine_ptr, FALSE);
-}
+ int ret= 0;
+ sp_cache **spc= (type == TYPE_ENUM_FUNCTION ?
+ &thd->sp_func_cache : &thd->sp_proc_cache);
+ DBUG_ENTER("sp_cache_routine");
-/**
- Add triggers for table to the set of routines used by statement.
- Add tables used by them to statement table list. Do the same for
- all implicitly used routines.
+ DBUG_ASSERT(type == TYPE_ENUM_FUNCTION || type == TYPE_ENUM_PROCEDURE);
- @param thd thread context
- @param lex LEX respresenting statement
- @param table Table list element for table with trigger
- @retval
- 0 success
- @retval
- non-0 failure
-*/
+ *sp= sp_cache_lookup(spc, name);
-int
-sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
- TABLE_LIST *table)
-{
- int ret= 0;
+ if (lookup_only)
+ DBUG_RETURN(SP_OK);
- Sroutine_hash_entry **last_cached_routine_ptr= lex->sroutines_list.next;
+ if (*sp)
+ {
+ sp_cache_flush_obsolete(spc, sp);
+ if (*sp)
+ DBUG_RETURN(SP_OK);
+ }
- if (static_cast<int>(table->lock_type) >=
- static_cast<int>(TL_WRITE_ALLOW_WRITE))
+ switch ((ret= db_find_routine(thd, type, name, sp)))
{
- for (int i= 0; i < (int)TRG_EVENT_MAX; i++)
- {
- if (table->trg_event_map &
- static_cast<uint8>(1 << static_cast<int>(i)))
+ case SP_OK:
+ sp_cache_insert(spc, *sp);
+ break;
+ case SP_KEY_NOT_FOUND:
+ ret= SP_OK;
+ break;
+ default:
+ /* Query might have been killed, don't set error. */
+ if (thd->killed)
+ break;
+ /*
+ Any error when loading an existing routine is either some problem
+ with the mysql.proc table, or a parse error because the contents
+ has been tampered with (in which case we clear that error).
+ */
+ if (ret == SP_PARSE_ERROR)
+ thd->clear_error();
+ /*
+ If we cleared the parse error, or when db_find_routine() flagged
+ an error with it's return value without calling my_error(), we
+ set the generic "mysql.proc table corrupt" error here.
+ */
+ if (! thd->is_error())
{
- for (int j= 0; j < (int)TRG_ACTION_MAX; j++)
- {
- /* We can have only one trigger per action type currently */
- sp_head *trigger= table->table->triggers->bodies[i][j];
- if (trigger &&
- add_used_routine(lex, thd->stmt_arena, &trigger->m_sroutines_key,
- table->belong_to_view))
- {
- trigger->add_used_tables_to_table_list(thd, &lex->query_tables_last,
- table->belong_to_view);
- trigger->propagate_attributes(lex);
- sp_update_stmt_used_routines(thd, lex,
- &trigger->m_sroutines,
- table->belong_to_view);
- }
- }
+ /*
+ SP allows full NAME_LEN chars thus he have to allocate enough
+ size in bytes. Otherwise there is stack overrun could happen
+ if multibyte sequence is `name`. `db` is still safe because the
+ rest of the server checks agains NAME_LEN bytes and not chars.
+ Hence, the overrun happens only if the name is in length > 32 and
+ uses multibyte (cyrillic, greek, etc.)
+ */
+ char n[NAME_LEN*2+2];
+
+ /* m_qname.str is not always \0 terminated */
+ memcpy(n, name->m_qname.str, name->m_qname.length);
+ n[name->m_qname.length]= '\0';
+ my_error(ER_SP_PROC_TABLE_CORRUPT, MYF(0), n, ret);
}
- }
+ break;
}
- ret= sp_cache_routines_and_add_tables_aux(thd, lex,
- *last_cached_routine_ptr,
- FALSE);
- return ret;
+ DBUG_RETURN(ret);
}
@@ -2071,6 +2082,7 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
Returns TRUE on success, FALSE on (alloc) failure.
*/
static bool
+
create_string(THD *thd, String *buf,
int type,
const char *db, ulong dblen,
@@ -2080,14 +2092,17 @@ create_string(THD *thd, String *buf,
const char *body, ulong bodylen,
st_sp_chistics *chistics,
const LEX_STRING *definer_user,
- const LEX_STRING *definer_host)
+ const LEX_STRING *definer_host,
+ ulong sql_mode)
{
+ ulong old_sql_mode= thd->variables.sql_mode;
/* Make some room to begin with */
if (buf->alloc(100 + dblen + 1 + namelen + paramslen + returnslen + bodylen +
chistics->comment.length + 10 /* length of " DEFINER= "*/ +
USER_HOST_BUFF_SIZE))
return FALSE;
+ thd->variables.sql_mode= sql_mode;
buf->append(STRING_WITH_LEN("CREATE "));
append_definer(thd, buf, definer_user, definer_host);
if (type == TYPE_ENUM_FUNCTION)
@@ -2135,5 +2150,80 @@ create_string(THD *thd, String *buf,
buf->append('\n');
}
buf->append(body, bodylen);
+ thd->variables.sql_mode= old_sql_mode;
return TRUE;
}
+
+
+/**
+ @brief The function loads sp_head struct for information schema purposes
+ (used for I_S ROUTINES & PARAMETERS tables).
+
+ @param[in] thd thread handler
+ @param[in] proc_table mysql.proc table structurte
+ @param[in] db database name
+ @param[in] name sp name
+ @param[in] sql_mode SQL mode
+ @param[in] type Routine type
+ @param[in] returns 'returns' string
+ @param[in] params parameters definition string
+ @param[out] free_sp_head returns 1 if we need to free sp_head struct
+ otherwise returns 0
+
+ @return Pointer on sp_head struct
+ @retval # Pointer on sp_head struct
+ @retval 0 error
+*/
+
+sp_head *
+sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db,
+ String *name, ulong sql_mode, int type,
+ const char *returns, const char *params,
+ bool *free_sp_head)
+{
+ const char *sp_body;
+ String defstr;
+ struct st_sp_chistics sp_chistics;
+ const LEX_STRING definer_user= {(char*)STRING_WITH_LEN("")};
+ const LEX_STRING definer_host= {(char*)STRING_WITH_LEN("")};
+ LEX_STRING sp_db_str;
+ LEX_STRING sp_name_str;
+ sp_head *sp;
+ sp_cache **spc= ((type == TYPE_ENUM_PROCEDURE) ?
+ &thd->sp_proc_cache : &thd->sp_func_cache);
+ sp_db_str.str= db->c_ptr();
+ sp_db_str.length= db->length();
+ sp_name_str.str= name->c_ptr();
+ sp_name_str.length= name->length();
+ sp_name sp_name_obj(sp_db_str, sp_name_str, true);
+ sp_name_obj.init_qname(thd);
+ *free_sp_head= 0;
+ if ((sp= sp_cache_lookup(spc, &sp_name_obj)))
+ {
+ return sp;
+ }
+
+ LEX *old_lex= thd->lex, newlex;
+ Stored_program_creation_ctx *creation_ctx=
+ Stored_routine_creation_ctx::load_from_db(thd, &sp_name_obj, proc_table);
+ sp_body= (type == TYPE_ENUM_FUNCTION ? "RETURN NULL" : "BEGIN END");
+ bzero((char*) &sp_chistics, sizeof(sp_chistics));
+ defstr.set_charset(creation_ctx->get_client_cs());
+ if (!create_string(thd, &defstr, type,
+ sp_db_str.str, sp_db_str.length,
+ sp_name_obj.m_name.str, sp_name_obj.m_name.length,
+ params, strlen(params),
+ returns, strlen(returns),
+ sp_body, strlen(sp_body),
+ &sp_chistics, &definer_user, &definer_host, sql_mode))
+ return 0;
+
+ thd->lex= &newlex;
+ newlex.current_select= NULL;
+ sp= sp_compile(thd, &defstr, sql_mode, creation_ctx);
+ *free_sp_head= 1;
+ thd->lex->sphead= NULL;
+ lex_end(thd->lex);
+ thd->lex= old_lex;
+ return sp;
+}
diff --git a/sql/sp.h b/sql/sp.h
index 876287d9704..68c45768857 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -17,6 +17,26 @@
#ifndef _SP_H_
#define _SP_H_
+#include "sql_string.h" // LEX_STRING
+
+class Field;
+class Open_tables_backup;
+class Open_tables_state;
+class Query_arena;
+class Query_tables_list;
+class Sroutine_hash_entry;
+class THD;
+class sp_cache;
+class sp_head;
+class sp_name;
+struct st_sp_chistics;
+struct LEX;
+struct TABLE;
+struct TABLE_LIST;
+typedef struct st_hash HASH;
+template <typename T> class SQL_I_List;
+
+
/* Tells what SP_DEFAULT_ACCESS should be mapped to */
#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
@@ -34,19 +54,63 @@
#define SP_BODY_TOO_LONG -10
#define SP_FLD_STORE_FAILED -11
+/* DB storage of Stored PROCEDUREs and FUNCTIONs */
+enum
+{
+ MYSQL_PROC_FIELD_DB = 0,
+ MYSQL_PROC_FIELD_NAME,
+ MYSQL_PROC_MYSQL_TYPE,
+ MYSQL_PROC_FIELD_SPECIFIC_NAME,
+ MYSQL_PROC_FIELD_LANGUAGE,
+ MYSQL_PROC_FIELD_ACCESS,
+ MYSQL_PROC_FIELD_DETERMINISTIC,
+ MYSQL_PROC_FIELD_SECURITY_TYPE,
+ MYSQL_PROC_FIELD_PARAM_LIST,
+ MYSQL_PROC_FIELD_RETURNS,
+ MYSQL_PROC_FIELD_BODY,
+ MYSQL_PROC_FIELD_DEFINER,
+ MYSQL_PROC_FIELD_CREATED,
+ MYSQL_PROC_FIELD_MODIFIED,
+ MYSQL_PROC_FIELD_SQL_MODE,
+ MYSQL_PROC_FIELD_COMMENT,
+ MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT,
+ MYSQL_PROC_FIELD_COLLATION_CONNECTION,
+ MYSQL_PROC_FIELD_DB_COLLATION,
+ MYSQL_PROC_FIELD_BODY_UTF8,
+ MYSQL_PROC_FIELD_COUNT
+};
+
/* Drop all routines in database 'db' */
int
sp_drop_db_routines(THD *thd, char *db);
+/**
+ Acquires exclusive metadata lock on all stored routines in the
+ given database.
+
+ @param thd Thread handler
+ @param db Database name
+
+ @retval false Success
+ @retval true Failure
+ */
+bool lock_db_routines(THD *thd, char *db);
+
sp_head *
sp_find_routine(THD *thd, int type, sp_name *name,
sp_cache **cp, bool cache_only);
-bool
-sp_exist_routines(THD *thd, TABLE_LIST *procs, bool any);
+int
+sp_cache_routine(THD *thd, Sroutine_hash_entry *rt,
+ bool lookup_only, sp_head **sp);
+
int
-sp_routine_exists_in_table(THD *thd, int type, sp_name *name);
+sp_cache_routine(THD *thd, int type, sp_name *name,
+ bool lookup_only, sp_head **sp);
+
+bool
+sp_exist_routines(THD *thd, TABLE_LIST *procs, bool any);
bool
sp_show_create_routine(THD *thd, int type, sp_name *name);
@@ -60,22 +124,58 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics);
int
sp_drop_routine(THD *thd, int type, sp_name *name);
+
+/**
+ Structure that represents element in the set of stored routines
+ used by statement or routine.
+*/
+
+class Sroutine_hash_entry
+{
+public:
+ /**
+ Metadata lock request for routine.
+ MDL_key in this request is also used as a key for set.
+ */
+ MDL_request mdl_request;
+ /**
+ Next element in list linking all routines in set. See also comments
+ for LEX::sroutine/sroutine_list and sp_head::m_sroutines.
+ */
+ Sroutine_hash_entry *next;
+ /**
+ Uppermost view which directly or indirectly uses this routine.
+ 0 if routine is not used in view. Note that it also can be 0 if
+ statement uses routine both via view and directly.
+ */
+ TABLE_LIST *belong_to_view;
+ /**
+ This is for prepared statement validation purposes.
+ A statement looks up and pre-loads all its stored functions
+ at prepare. Later on, if a function is gone from the cache,
+ execute may fail.
+ Remember the version of sp_head at prepare to be able to
+ invalidate the prepared statement at execute if it
+ changes.
+ */
+ ulong m_sp_cache_version;
+};
+
+
/*
- Procedures for pre-caching of stored routines and building table list
- for prelocking.
+ Procedures for handling sets of stored routines used by statement or routine.
*/
-void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
- bool *first_no_prelocking);
-void sp_add_used_routine(LEX *lex, Query_arena *arena,
+void sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
sp_name *rt, char rt_type);
-void sp_remove_not_own_routines(LEX *lex);
+bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
+ const MDL_key *key, TABLE_LIST *belong_to_view);
+void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx);
bool sp_update_sp_used_routines(HASH *dst, HASH *src);
-int sp_cache_routines_and_add_tables(THD *thd, LEX *lex,
- bool first_no_prelock);
-int sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex,
- TABLE_LIST *view);
-int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
- TABLE_LIST *table);
+void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
+ HASH *src, TABLE_LIST *belong_to_view);
+void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
+ SQL_I_List<Sroutine_hash_entry> *src,
+ TABLE_LIST *belong_to_view);
extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
my_bool first);
@@ -84,6 +184,22 @@ extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
Routines which allow open/lock and close mysql.proc table even when
we already have some tables open and locked.
*/
-TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup);
+TABLE *open_proc_table_for_read(THD *thd, Open_tables_backup *backup);
+
+sp_head *
+sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db,
+ String *name, ulong sql_mode, int type,
+ const char *returns, const char *params,
+ bool *free_sp_head);
+
+bool load_charset(MEM_ROOT *mem_root,
+ Field *field,
+ CHARSET_INFO *dflt_cs,
+ CHARSET_INFO **cs);
+
+bool load_collation(MEM_ROOT *mem_root,
+ Field *field,
+ CHARSET_INFO *dflt_cl,
+ CHARSET_INFO **cl);
#endif /* _SP_H_ */
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index 12d21aee22c..f062276a9de 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 MySQL AB
+/* Copyright (C) 2002 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -13,14 +13,15 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
#include "sp_cache.h"
#include "sp_head.h"
-static pthread_mutex_t Cversion_lock;
+static mysql_mutex_t Cversion_lock;
static ulong volatile Cversion= 0;
@@ -31,8 +32,6 @@ static ulong volatile Cversion= 0;
class sp_cache
{
public:
- ulong version;
-
sp_cache();
~sp_cache();
@@ -50,28 +49,14 @@ public:
inline sp_head *lookup(char *name, uint namelen)
{
- return (sp_head *)hash_search(&m_hashtable, (const uchar *)name, namelen);
- }
-
-#ifdef NOT_USED
- inline bool remove(char *name, uint namelen)
- {
- sp_head *sp= lookup(name, namelen);
- if (sp)
- {
- hash_delete(&m_hashtable, (uchar *)sp);
- return TRUE;
- }
- return FALSE;
+ return (sp_head *) my_hash_search(&m_hashtable, (const uchar *)name,
+ namelen);
}
-#endif
- inline void remove_all()
+ inline void remove(sp_head *sp)
{
- cleanup();
- init();
+ my_hash_delete(&m_hashtable, (uchar *)sp);
}
-
private:
void init();
void cleanup();
@@ -80,12 +65,36 @@ private:
HASH m_hashtable;
}; // class sp_cache
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_Cversion_lock;
+
+static PSI_mutex_info all_sp_cache_mutexes[]=
+{
+ { &key_Cversion_lock, "Cversion_lock", PSI_FLAG_GLOBAL}
+};
+
+static void init_sp_cache_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_sp_cache_mutexes);
+ PSI_server->register_mutex(category, all_sp_cache_mutexes, count);
+}
+#endif
/* Initialize the SP caching once at startup */
void sp_cache_init()
{
- pthread_mutex_init(&Cversion_lock, MY_MUTEX_INIT_FAST);
+#ifdef HAVE_PSI_INTERFACE
+ init_sp_cache_psi_keys();
+#endif
+
+ mysql_mutex_init(key_Cversion_lock, &Cversion_lock, MY_MUTEX_INIT_FAST);
}
@@ -134,8 +143,9 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp)
{
if (!(c= new sp_cache()))
return; // End of memory error
- c->version= Cversion; // No need to lock when reading long variable
}
+ /* Reading a ulong variable with no lock. */
+ sp->set_sp_cache_version(Cversion);
DBUG_PRINT("info",("sp_cache: inserting: %.*s", (int) sp->m_qname.length,
sp->m_qname.str));
c->insert(sp);
@@ -187,46 +197,34 @@ void sp_cache_invalidate()
}
-/*
- Remove out-of-date SPs from the cache.
-
- SYNOPSIS
- sp_cache_flush_obsolete()
- cp Cache to flush
+/**
+ Remove an out-of-date SP from the cache.
- NOTE
- This invalidates pointers to sp_head objects this thread uses.
- In practice that means 'dont call this function when inside SP'.
+ @param[in] cp Cache to flush
+ @param[in] sp SP to remove.
+
+ @note This invalidates pointers to sp_head objects this thread
+ uses. In practice that means 'dont call this function when
+ inside SP'.
*/
-void sp_cache_flush_obsolete(sp_cache **cp)
+void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp)
{
- sp_cache *c= *cp;
- if (c)
+ if ((*sp)->sp_cache_version() < Cversion && !(*sp)->is_invoked())
{
- ulong v;
- v= Cversion; // No need to lock when reading long variable
- if (c->version < v)
- {
- DBUG_PRINT("info",("sp_cache: deleting all functions"));
- /* We need to delete all elements. */
- c->remove_all();
- c->version= v;
- }
+ (*cp)->remove(*sp);
+ *sp= NULL;
}
}
/**
- Return the current version of the cache.
+ Return the current global version of the cache.
*/
-ulong sp_cache_version(sp_cache **cp)
+ulong sp_cache_version()
{
- sp_cache *c= *cp;
- if (c)
- return c->version;
- return 0;
+ return Cversion;
}
@@ -262,21 +260,20 @@ sp_cache::sp_cache()
sp_cache::~sp_cache()
{
- hash_free(&m_hashtable);
+ my_hash_free(&m_hashtable);
}
void
sp_cache::init()
{
- hash_init(&m_hashtable, system_charset_info, 0, 0, 0,
- hash_get_key_for_sp_head, hash_free_sp_head, 0);
- version= 0;
+ my_hash_init(&m_hashtable, system_charset_info, 0, 0, 0,
+ hash_get_key_for_sp_head, hash_free_sp_head, 0);
}
void
sp_cache::cleanup()
{
- hash_free(&m_hashtable);
+ my_hash_free(&m_hashtable);
}
diff --git a/sql/sp_cache.h b/sql/sp_cache.h
index f4d44a1f29f..c75e29474bc 100644
--- a/sql/sp_cache.h
+++ b/sql/sp_cache.h
@@ -21,6 +21,8 @@
#pragma interface /* gcc class implementation */
#endif
+#include "my_global.h" /* ulong */
+
/*
Stored procedures/functions cache. This is used as follows:
* Each thread has its own cache.
@@ -30,6 +32,7 @@
class sp_head;
class sp_cache;
+class sp_name;
/*
Cache usage scenarios:
@@ -57,7 +60,7 @@ void sp_cache_clear(sp_cache **cp);
void sp_cache_insert(sp_cache **cp, sp_head *sp);
sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name);
void sp_cache_invalidate();
-void sp_cache_flush_obsolete(sp_cache **cp);
-ulong sp_cache_version(sp_cache **cp);
+void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp);
+ulong sp_cache_version();
#endif /* _SP_CACHE_H_ */
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 2473abea3c7..2f165310c28 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1,4 +1,4 @@
-/* Copyright 2002-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2002-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc.
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
@@ -13,7 +13,20 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_prepare.h"
+#include "sql_cache.h" // query_cache_*
+#include "probes_mysql.h"
+#include "sql_show.h" // append_identifier
+#include "sql_db.h" // mysql_opt_change_db, mysql_change_db
+#include "sql_table.h" // sp_prepare_create_field,
+ // prepare_create_field
+#include "sql_acl.h" // *_ACL
+#include "sql_array.h" // Dynamic_array
+#include "log_event.h" // append_query_string, Query_log_event
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
@@ -22,6 +35,10 @@
#include "sp_pcontext.h"
#include "sp_rcontext.h"
#include "sp_cache.h"
+#include "set_var.h"
+#include "sql_parse.h" // cleanup_items
+#include "sql_base.h" // close_thread_tables
+#include "transaction.h" // trans_commit_stmt
/*
Sufficient max length of printed destinations and frame offsets (all uints).
@@ -44,10 +61,6 @@ extern "C" uchar *sp_table_key(const uchar *ptr, size_t *plen, my_bool first);
static void reset_start_time_for_sp(THD *thd)
{
- /*
- Do nothing if the context is a trigger or function because time should be
- constant during the execution of those.
- */
if (!thd->in_sub_stmt)
{
/*
@@ -139,10 +152,10 @@ sp_get_item_value(THD *thd, Item *item, String *str)
case STRING_RESULT:
{
String *result= item->val_str(str);
-
+
if (!result)
return NULL;
-
+
{
char buf_holder[STRING_BUFFER_USUAL_SIZE];
String buf(buf_holder, sizeof(buf_holder), result->charset());
@@ -194,7 +207,6 @@ sp_get_flags_for_command(LEX *lex)
}
/* fallthrough */
case SQLCOM_ANALYZE:
- case SQLCOM_BACKUP_TABLE:
case SQLCOM_OPTIMIZE:
case SQLCOM_PRELOAD_KEYS:
case SQLCOM_ASSIGN_TO_KEYCACHE:
@@ -204,9 +216,9 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_SHOW_AUTHORS:
case SQLCOM_SHOW_BINLOGS:
case SQLCOM_SHOW_BINLOG_EVENTS:
+ case SQLCOM_SHOW_RELAYLOG_EVENTS:
case SQLCOM_SHOW_CHARSETS:
case SQLCOM_SHOW_COLLATIONS:
- case SQLCOM_SHOW_COLUMN_TYPES:
case SQLCOM_SHOW_CONTRIBUTORS:
case SQLCOM_SHOW_CREATE:
case SQLCOM_SHOW_CREATE_DB:
@@ -241,7 +253,6 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_SHOW_VARIABLES:
case SQLCOM_SHOW_WARNS:
case SQLCOM_REPAIR:
- case SQLCOM_RESTORE_TABLE:
flags= sp_head::MULTI_RESULTS;
break;
/*
@@ -296,7 +307,6 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_COMMIT:
case SQLCOM_ROLLBACK:
case SQLCOM_LOAD:
- case SQLCOM_LOAD_MASTER_DATA:
case SQLCOM_LOCK_TABLES:
case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_CREATE_SPFUNCTION:
@@ -383,7 +393,7 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
Save original values and restore them after save.
*/
-
+
thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
thd->abort_on_warning=
thd->variables.sql_mode &
@@ -413,31 +423,34 @@ error:
}
-/*
- *
- * sp_name
- *
- */
+/**
+ Create temporary sp_name object from MDL key.
+
+ @note The lifetime of this object is bound to the lifetime of the MDL_key.
+ This should be fine as sp_name objects created by this constructor
+ are mainly used for SP-cache lookups.
+
+ @param key MDL key containing database and routine name.
+ @param qname_buff Buffer to be used for storing quoted routine name
+ (should be at least 2*NAME_LEN+1+1 bytes).
+*/
-sp_name::sp_name(THD *thd, char *key, uint key_len)
+sp_name::sp_name(const MDL_key *key, char *qname_buff)
{
- m_sroutines_key.str= key;
- m_sroutines_key.length= key_len;
- m_qname.str= ++key;
- m_qname.length= key_len - 1;
- if ((m_name.str= strchr(m_qname.str, '.')))
+ m_db.str= (char*)key->db_name();
+ m_db.length= key->db_name_length();
+ m_name.str= (char*)key->name();
+ m_name.length= key->name_length();
+ m_qname.str= qname_buff;
+ if (m_db.length)
{
- m_db.length= m_name.str - key;
- m_db.str= strmake_root(thd->mem_root, key, m_db.length);
- m_name.str++;
- m_name.length= m_qname.length - m_db.length - 1;
+ strxmov(qname_buff, m_db.str, ".", m_name.str, NullS);
+ m_qname.length= m_db.length + 1 + m_name.length;
}
else
{
- m_name.str= m_qname.str;
- m_name.length= m_qname.length;
- m_db.str= 0;
- m_db.length= 0;
+ strmov(qname_buff, m_name.str);
+ m_qname.length= m_name.length;
}
m_explicit_name= false;
}
@@ -450,12 +463,10 @@ void
sp_name::init_qname(THD *thd)
{
const uint dot= !!m_db.length;
- /* m_sroutines format: m_type + [database + dot] + name + nul */
- m_sroutines_key.length= 1 + m_db.length + dot + m_name.length;
- if (!(m_sroutines_key.str= (char*) thd->alloc(m_sroutines_key.length + 1)))
+ /* m_qname format: [database + dot] + name + '\0' */
+ m_qname.length= m_db.length + dot + m_name.length;
+ if (!(m_qname.str= (char*) thd->alloc(m_qname.length + 1)))
return;
- m_qname.length= m_sroutines_key.length - 1;
- m_qname.str= m_sroutines_key.str + 1;
sprintf(m_qname.str, "%.*s%.*s%.*s",
(int) m_db.length, (m_db.length ? m_db.str : ""),
dot, ".",
@@ -481,7 +492,7 @@ check_routine_name(LEX_STRING *ident)
{
if (!ident || !ident->str || !ident->str[0] ||
ident->str[ident->length-1] == ' ')
- {
+ {
my_error(ER_SP_WRONG_NAME, MYF(0), ident->str);
return TRUE;
}
@@ -518,7 +529,7 @@ sp_head::operator new(size_t size) throw()
DBUG_RETURN(sp);
}
-void
+void
sp_head::operator delete(void *ptr, size_t size) throw()
{
DBUG_ENTER("sp_head::operator delete");
@@ -541,7 +552,11 @@ sp_head::operator delete(void *ptr, size_t size) throw()
sp_head::sp_head()
:Query_arena(&main_mem_root, INITIALIZED_FOR_SP),
- m_flags(0), m_recursion_level(0), m_next_cached_sp(0),
+ m_flags(0),
+ m_sp_cache_version(0),
+ unsafe_flags(0),
+ m_recursion_level(0),
+ m_next_cached_sp(0),
m_cont_level(0)
{
const LEX_STRING str_reset= { NULL, 0 };
@@ -563,8 +578,9 @@ sp_head::sp_head()
m_backpatch.empty();
m_cont_backpatch.empty();
m_lex.empty();
- hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
- hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
+ my_hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
+ my_hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key,
+ 0, 0);
m_body_utf8.str= NULL;
m_body_utf8.length= 0;
@@ -615,9 +631,6 @@ sp_head::init(LEX *lex)
m_defstr.str= NULL;
m_defstr.length= 0;
- m_sroutines_key.str= NULL;
- m_sroutines_key.length= 0;
-
m_return_field_def.charset= NULL;
DBUG_VOID_RETURN;
@@ -647,14 +660,10 @@ sp_head::init_sp_name(THD *thd, sp_name *spname)
if (spname->m_qname.length == 0)
spname->init_qname(thd);
- m_sroutines_key.length= spname->m_sroutines_key.length;
- m_sroutines_key.str= (char*) memdup_root(thd->mem_root,
- spname->m_sroutines_key.str,
- spname->m_sroutines_key.length + 1);
- m_sroutines_key.str[0]= static_cast<char>(m_type);
-
- m_qname.length= m_sroutines_key.length - 1;
- m_qname.str= m_sroutines_key.str + 1;
+ m_qname.length= spname->m_qname.length;
+ m_qname.str= (char*) memdup_root(thd->mem_root,
+ spname->m_qname.str,
+ spname->m_qname.length + 1);
DBUG_VOID_RETURN;
}
@@ -736,7 +745,7 @@ create_typelib(MEM_ROOT *mem_root, Create_field *field_def, List<String> *src)
String *tmp= it++;
if (String::needs_conversion(tmp->length(), tmp->charset(),
- cs, &dummy))
+ cs, &dummy))
{
uint cnv_errs;
conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
@@ -763,16 +772,6 @@ create_typelib(MEM_ROOT *mem_root, Create_field *field_def, List<String> *src)
}
-int
-sp_head::create(THD *thd)
-{
- DBUG_ENTER("sp_head::create");
- DBUG_PRINT("info", ("type: %d name: %s params: %s body: %s",
- m_type, m_name.str, m_params.str, m_body.str));
-
- DBUG_RETURN(sp_create_routine(thd, m_type, this));
-}
-
sp_head::~sp_head()
{
LEX *lex;
@@ -797,13 +796,14 @@ sp_head::~sp_head()
while ((lex= (LEX *)m_lex.pop()))
{
THD *thd= lex->thd;
+ thd->lex->sphead= NULL;
lex_end(thd->lex);
delete thd->lex;
thd->lex= lex;
}
- hash_free(&m_sptabs);
- hash_free(&m_sroutines);
+ my_hash_free(&m_sptabs);
+ my_hash_free(&m_sroutines);
delete m_next_cached_sp;
@@ -843,7 +843,7 @@ sp_head::create_result_field(uint field_max_length, const char *field_name,
if (field)
field->init(table);
-
+
DBUG_RETURN(field);
}
@@ -872,7 +872,7 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b)
Statements that have is_update_query(stmt) == FALSE (e.g. SELECTs) are not
written into binary log. Instead we catch function calls the statement
makes and write it into binary log separately (see #3).
-
+
2. PROCEDURE calls
CALL statements are not written into binary log. Instead
@@ -885,8 +885,8 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b)
This substitution is done in subst_spvars().
3. FUNCTION calls
-
- In sp_head::execute_function(), we check
+
+ In sp_head::execute_function(), we check
* If this function invocation is done from a statement that is written
into the binary log.
* If there were any attempts to write events to the binary log during
@@ -894,28 +894,28 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b)
If the answers are No and Yes, we write the function call into the binary
log as "SELECT spfunc(<param1value>, <param2value>, ...)"
-
-
+
+
4. Miscellaneous issues.
-
- 4.1 User variables.
+
+ 4.1 User variables.
When we call mysql_bin_log.write() for an SP statement, thd->user_var_events
- must hold set<{var_name, value}> pairs for all user variables used during
+ must hold set<{var_name, value}> pairs for all user variables used during
the statement execution.
This set is produced by tracking user variable reads during statement
- execution.
+ execution.
For SPs, this has the following implications:
- 1) thd->user_var_events may contain events from several SP statements and
- needs to be valid after exection of these statements was finished. In
+ 1) thd->user_var_events may contain events from several SP statements and
+ needs to be valid after exection of these statements was finished. In
order to achieve that, we
* Allocate user_var_events array elements on appropriate mem_root (grep
for user_var_events_alloc).
* Use is_query_in_union() to determine if user_var_event is created.
-
+
2) We need to empty thd->user_var_events after we have wrote a function
- call. This is currently done by making
+ call. This is currently done by making
reset_dynamic(&thd->user_var_events);
calls in several different places. (TODO cosider moving this into
mysql_bin_log.write() function)
@@ -934,7 +934,7 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b)
Replace thd->query{_length} with a string that one can write to
the binlog.
- The binlog-suitable string is produced by replacing references to SP local
+ The binlog-suitable string is produced by replacing references to SP local
variables with NAME_CONST('sp_var_name', value) calls.
@param thd Current thread.
@@ -971,11 +971,11 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
}
if (!sp_vars_uses.elements())
DBUG_RETURN(FALSE);
-
+
/* Sort SP var refs by their occurences in the query */
sp_vars_uses.sort(cmp_splocal_locations);
- /*
+ /*
Construct a statement string where SP local var refs are replaced
with "NAME_CONST(name, value)"
*/
@@ -983,7 +983,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
cur= query_str->str;
prev_pos= res= 0;
thd->query_name_consts= 0;
-
+
for (Item_splocal **splocal= sp_vars_uses.front();
splocal < sp_vars_uses.back(); splocal++)
{
@@ -993,16 +993,25 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
String str_value_holder(str_buffer, sizeof(str_buffer),
&my_charset_latin1);
String *str_value;
-
+
/* append the text between sp ref occurences */
res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
prev_pos= (*splocal)->pos_in_query + (*splocal)->len_in_query;
-
+
+ res|= (*splocal)->fix_fields(thd, (Item **) splocal);
+ if (res)
+ break;
+
+ if ((*splocal)->limit_clause_param)
+ {
+ res|= qbuf.append_ulonglong((*splocal)->val_uint());
+ continue;
+ }
+
/* append the spvar substitute */
res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('"));
res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length);
res|= qbuf.append(STRING_WITH_LEN("',"));
- res|= (*splocal)->fix_fields(thd, (Item **) splocal);
if (res)
break;
@@ -1017,7 +1026,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
res|= qbuf.append(')');
if (res)
break;
-
+
thd->query_name_consts++;
}
res|= qbuf.append(cur + prev_pos, query_str->length - prev_pos);
@@ -1043,16 +1052,14 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
}
-/*
+/**
Return appropriate error about recursion limit reaching
- SYNOPSIS
- sp_head::recursion_level_error()
- thd Thread handle
+ @param thd Thread handle
- NOTE
- For functions and triggers we return error about prohibited recursion.
- For stored procedures we return about reaching recursion limit.
+ @remark For functions and triggers we return error about
+ prohibited recursion. For stored procedures we
+ return about reaching recursion limit.
*/
void sp_head::recursion_level_error(THD *thd)
@@ -1069,12 +1076,117 @@ void sp_head::recursion_level_error(THD *thd)
/**
+ Find an SQL handler for any condition (warning or error) after execution
+ of a stored routine instruction. Basically, this function looks for an
+ appropriate SQL handler in RT-contexts. If an SQL handler is found, it is
+ remembered in the RT-context for future activation (the context can be
+ inactive at the moment).
+
+ If there is no pending condition, the function just returns.
+
+ If there was an error during the execution, an SQL handler for it will be
+ searched within the current and outer scopes.
+
+ There might be several errors in the Warning Info (that's possible by using
+ SIGNAL/RESIGNAL in nested scopes) -- the function is looking for an SQL
+ handler for the latest (current) error only.
+
+ If there was a warning during the execution, an SQL handler for it will be
+ searched within the current scope only.
+
+ If several warnings were thrown during the execution and there are different
+ SQL handlers for them, it is not determined which SQL handler will be chosen.
+ Only one SQL handler will be executed.
+
+ If warnings and errors were thrown during the execution, the error takes
+ precedence. I.e. error handler will be executed. If there is no handler
+ for that error, condition will remain unhandled.
+
+ Once a warning or an error has been handled it is not removed from
+ Warning Info.
+
+ According to The Standard (quoting PeterG):
+
+ An SQL procedure statement works like this ...
+ SQL/Foundation 13.5 <SQL procedure statement>
+ (General Rules) (greatly summarized) says:
+ (1) Empty diagnostics area, thus clearing the condition.
+ (2) Execute statement.
+ During execution, if Exception Condition occurs,
+ set Condition Area = Exception Condition and stop
+ statement.
+ During execution, if No Data occurs,
+ set Condition Area = No Data Condition and continue
+ statement.
+ During execution, if Warning occurs,
+ and Condition Area is not already full due to
+ an earlier No Data condition, set Condition Area
+ = Warning and continue statement.
+ (3) Finish statement.
+ At end of execution, if Condition Area is not
+ already full due to an earlier No Data or Warning,
+ set Condition Area = Successful Completion.
+ In effect, this system means there is a precedence:
+ Exception trumps No Data, No Data trumps Warning,
+ Warning trumps Successful Completion.
+
+ NB: "Procedure statements" include any DDL or DML or
+ control statements. So CREATE and DELETE and WHILE
+ and CALL and RETURN are procedure statements. But
+ DECLARE and END are not procedure statements.
+
+ @param thd thread handle
+ @param ctx runtime context of the stored routine
+*/
+
+static void
+find_handler_after_execution(THD *thd, sp_rcontext *ctx)
+{
+ if (thd->is_error())
+ {
+ ctx->find_handler(thd,
+ thd->stmt_da->sql_errno(),
+ thd->stmt_da->get_sqlstate(),
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ thd->stmt_da->message());
+ }
+ else if (thd->warning_info->statement_warn_count())
+ {
+ List_iterator<MYSQL_ERROR> it(thd->warning_info->warn_list());
+ MYSQL_ERROR *err;
+ while ((err= it++))
+ {
+ if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_WARN &&
+ err->get_level() != MYSQL_ERROR::WARN_LEVEL_NOTE)
+ continue;
+
+ if (ctx->find_handler(thd,
+ err->get_sql_errno(),
+ err->get_sqlstate(),
+ err->get_level(),
+ err->get_message_text()))
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+/**
Execute the routine. The main instruction jump loop is there.
Assume the parameters already set.
+
+ @param thd Thread context.
+ @param merge_da_on_success Flag specifying if Warning Info should be
+ propagated to the caller on Completion
+ Condition or not.
+
@todo
- - Will write this SP statement into binlog separately
+ - Will write this SP statement into binlog separately
(TODO: consider changing the condition to "not inside event union")
+ @return Error status.
@retval
FALSE on success
@retval
@@ -1082,14 +1194,14 @@ void sp_head::recursion_level_error(THD *thd)
*/
bool
-sp_head::execute(THD *thd)
+sp_head::execute(THD *thd, bool merge_da_on_success)
{
DBUG_ENTER("sp_head::execute");
char saved_cur_db_name_buf[NAME_LEN+1];
LEX_STRING saved_cur_db_name=
{ saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
bool cur_db_changed= FALSE;
- sp_rcontext *ctx;
+ sp_rcontext *ctx= thd->spcont;
bool err_status= FALSE;
uint ip= 0;
ulong save_sql_mode;
@@ -1105,11 +1217,31 @@ sp_head::execute(THD *thd)
Item_change_list old_change_list;
String old_packet;
Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer;
-
Object_creation_ctx *saved_creation_ctx;
+ Warning_info *saved_warning_info, warning_info(thd->warning_info->warn_id());
- /* Use some extra margin for possible SP recursion and functions */
- if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (uchar*)&old_packet))
+ /*
+ Just reporting a stack overrun error
+ (@sa check_stack_overrun()) requires stack memory for error
+ message buffer. Thus, we have to put the below check
+ relatively close to the beginning of the execution stack,
+ where available stack margin is still big. As long as the check
+ has to be fairly high up the call stack, the amount of memory
+ we "book" for has to stay fairly high as well, and hence
+ not very accurate. The number below has been calculated
+ by trial and error, and reflects the amount of memory necessary
+ to execute a single stored procedure instruction, be it either
+ an SQL statement, or, heaviest of all, a CALL, which involves
+ parsing and loading of another stored procedure into the cache
+ (@sa db_load_routine() and Bug#10100).
+ At the time of measuring, a recursive SP invocation required
+ 3232 bytes of stack on 32 bit Linux, 6016 bytes on 64 bit Mac
+ and 11152 on 64 bit Solaris sparc.
+ The same with db_load_routine() required circa 7k bytes and
+ 14k bytes accordingly. Hence, here we book the stack with some
+ reasonable margin.
+ */
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&old_packet))
DBUG_RETURN(TRUE);
/* init per-instruction memroot */
@@ -1150,11 +1282,14 @@ sp_head::execute(THD *thd)
goto done;
}
- if ((ctx= thd->spcont))
- ctx->clear_handler();
thd->is_slave_error= 0;
old_arena= thd->stmt_arena;
+ /* Push a new warning information area. */
+ warning_info.append_warning_info(thd, thd->warning_info);
+ saved_warning_info= thd->warning_info;
+ thd->warning_info= &warning_info;
+
/*
Switch query context. This has to be done early as this is sometimes
allocated trough sql_alloc
@@ -1201,8 +1336,7 @@ sp_head::execute(THD *thd)
We should also save Item tree change list to avoid rollback something
too early in the calling query.
*/
- old_change_list= thd->change_list;
- thd->change_list.empty();
+ thd->change_list.move_elements_to(&old_change_list);
/*
Cursors will use thd->packet, so they may corrupt data which was prepared
for sending by upper level. OTOH cursors in the same routine can share this
@@ -1225,17 +1359,16 @@ sp_head::execute(THD *thd)
*/
thd->spcont->callers_arena= &backup_arena;
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
/* Discard the initial part of executing routines. */
thd->profiling.discard_current_query();
#endif
do
{
sp_instr *i;
- uint hip; // Handler ip
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
- /*
+#if defined(ENABLED_PROFILING)
+ /*
Treat each "instr" of a routine as discrete unit that could be profiled.
Profiling only records information for segments of code that set the
source of the query, and almost all kinds of instructions in s-p do not.
@@ -1244,15 +1377,19 @@ sp_head::execute(THD *thd)
thd->profiling.start_new_query("continuing inside routine");
#endif
- i = get_instr(ip); // Returns NULL when we're done.
+ /* get_instr returns NULL when we're done. */
+ i = get_instr(ip);
if (i == NULL)
{
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
thd->profiling.discard_current_query();
#endif
break;
}
+ /* Reset number of warnings for this query. */
+ thd->warning_info->reset_for_next_command();
+
DBUG_PRINT("execute", ("Instruction %u", ip));
/*
@@ -1269,24 +1406,24 @@ sp_head::execute(THD *thd)
items made during other permanent subquery transformations).
*/
thd->stmt_arena= i;
-
- /*
- Will write this SP statement into binlog separately
- (TODO: consider changing the condition to "not inside event union")
+
+ /*
+ Will write this SP statement into binlog separately.
+ TODO: consider changing the condition to "not inside event union".
*/
- if (thd->prelocked_mode == NON_PRELOCKED)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
thd->user_var_events_alloc= thd->mem_root;
err_status= i->execute(thd, &ip);
if (i->free_list)
cleanup_items(i->free_list);
-
- /*
+
+ /*
If we've set thd->user_var_events_alloc to mem_root of this SP
statement, clean all the events allocated in it.
*/
- if (thd->prelocked_mode == NON_PRELOCKED)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
{
reset_dynamic(&thd->user_var_events);
thd->user_var_events_alloc= NULL;//DEBUG
@@ -1294,42 +1431,34 @@ sp_head::execute(THD *thd)
/* we should cleanup free_list and memroot, used by instruction */
thd->cleanup_after_query();
- free_root(&execute_mem_root, MYF(0));
+ free_root(&execute_mem_root, MYF(0));
/*
- Check if an exception has occurred and a handler has been found
- Note: We have to check even if err_status == FALSE, since warnings (and
- some errors) don't return a non-zero value. We also have to check even
- if thd->killed != 0, since some errors return with this even when a
- handler has been found (e.g. "bad data").
+ Find and process SQL handlers unless it is a fatal error (fatal
+ errors are not catchable by SQL handlers) or the connection has been
+ killed during execution.
*/
- if (ctx)
+ if (!thd->is_fatal_error && !thd->killed_errno())
{
- uint hf;
-
- switch (ctx->found_handler(&hip, &hf)) {
- case SP_HANDLER_NONE:
- break;
- case SP_HANDLER_CONTINUE:
- thd->restore_active_arena(&execute_arena, &backup_arena);
- thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
- ctx->push_hstack(i->get_cont_dest());
- // Fall through
- default:
- ip= hip;
- err_status= FALSE;
- ctx->clear_handler();
- ctx->enter_handler(hip);
- thd->clear_error();
- thd->is_fatal_error= 0;
- thd->killed= THD::NOT_KILLED;
- thd->mysys_var->abort= 0;
- continue;
- }
+ /*
+ Find SQL handler in the appropriate RT-contexts:
+ - warnings can be handled by SQL handlers within
+ the current scope only;
+ - errors can be handled by any SQL handler from outer scope.
+ */
+ find_handler_after_execution(thd, ctx);
+
+ /* If found, activate handler for the current scope. */
+ if (ctx->activate_handler(thd, &ip, i, &execute_arena, &backup_arena))
+ err_status= FALSE;
}
- } while (!err_status && !thd->killed);
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+ /* Reset sp_rcontext::end_partial_result_set flag. */
+ ctx->end_partial_result_set= FALSE;
+
+ } while (!err_status && !thd->killed && !thd->is_fatal_error);
+
+#if defined(ENABLED_PROFILING)
thd->profiling.finish_current_query();
thd->profiling.start_new_query("tail end of routine");
#endif
@@ -1347,11 +1476,9 @@ sp_head::execute(THD *thd)
/* Restore all saved */
old_packet.swap(thd->packet);
DBUG_ASSERT(thd->change_list.is_empty());
- thd->change_list= old_change_list;
- /* To avoid wiping out thd->change_list on old_change_list destruction */
- old_change_list.empty();
+ old_change_list.move_elements_to(&thd->change_list);
thd->lex= old_lex;
- thd->query_id= old_query_id;
+ thd->set_query_id(old_query_id);
DBUG_ASSERT(!thd->derived_tables);
thd->derived_tables= old_derived_tables;
thd->variables.sql_mode= save_sql_mode;
@@ -1361,9 +1488,20 @@ sp_head::execute(THD *thd)
thd->stmt_arena= old_arena;
state= EXECUTED;
+ /*
+ Restore the caller's original warning information area:
+ - warnings generated during trigger execution should not be
+ propagated to the caller on success;
+ - if there was an exception during execution, warning info should be
+ propagated to the caller in any case.
+ */
+ if (err_status || merge_da_on_success)
+ saved_warning_info->merge_with_routine_info(thd, thd->warning_info);
+ thd->warning_info= saved_warning_info;
+
done:
DBUG_PRINT("info", ("err_status: %d killed: %d is_slave_error: %d report_error: %d",
- err_status, thd->killed, thd->is_slave_error,
+ err_status, thd->killed, thd->is_slave_error,
thd->is_error()));
if (thd->killed)
@@ -1580,7 +1718,7 @@ sp_head::execute_trigger(THD *thd,
thd->spcont= nctx;
- err_status= execute(thd);
+ err_status= execute(thd, FALSE);
err_with_cleanup:
thd->restore_active_arena(&call_arena, &backup_arena);
@@ -1639,7 +1777,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
Field *return_value_fld)
{
ulonglong binlog_save_options;
- bool need_binlog_call;
+ bool need_binlog_call= FALSE;
uint arg_no;
sp_rcontext *octx = thd->spcont;
sp_rcontext *nctx = NULL;
@@ -1719,7 +1857,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
each substatement be binlogged its way.
*/
need_binlog_call= mysql_bin_log.is_open() &&
- (thd->options & OPTION_BIN_LOG) && !thd->current_stmt_binlog_row_based;
+ (thd->variables.option_bits & OPTION_BIN_LOG) &&
+ !thd->is_current_stmt_binlog_format_row();
/*
Remember the original arguments for unrolled replication of functions
@@ -1778,12 +1917,12 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
as one select and not resetting THD::user_var_events before
each invocation.
*/
- VOID(pthread_mutex_lock(&LOCK_thread_count));
+ mysql_mutex_lock(&LOCK_thread_count);
q= global_query_id;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_mutex_unlock(&LOCK_thread_count);
mysql_bin_log.start_union_events(thd, q + 1);
- binlog_save_options= thd->options;
- thd->options&= ~OPTION_BIN_LOG;
+ binlog_save_options= thd->variables.option_bits;
+ thd->variables.option_bits&= ~OPTION_BIN_LOG;
}
/*
@@ -1796,19 +1935,19 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
*/
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
- err_status= execute(thd);
+ err_status= execute(thd, TRUE);
thd->restore_active_arena(&call_arena, &backup_arena);
if (need_binlog_call)
{
mysql_bin_log.stop_union_events(thd);
- thd->options= binlog_save_options;
+ thd->variables.option_bits= binlog_save_options;
if (thd->binlog_evt_union.unioned_events)
{
int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(),
- thd->binlog_evt_union.unioned_events_trans, FALSE, errcode);
+ thd->binlog_evt_union.unioned_events_trans, FALSE, FALSE, errcode);
if (mysql_bin_log.write(&qinfo) &&
thd->binlog_evt_union.unioned_events_trans)
{
@@ -1845,15 +1984,23 @@ err_with_cleanup:
free_root(&call_mem_root, MYF(0));
thd->spcont= octx;
+ /*
+ If not insided a procedure and a function printing warning
+ messsages.
+ */
+ if (need_binlog_call &&
+ thd->spcont == NULL && !thd->binlog_evt_union.do_union)
+ thd->issue_unsafe_warnings();
+
DBUG_RETURN(err_status);
}
/**
- Execute a procedure.
+ Execute a procedure.
The function does the following steps:
- - Set all parameters
+ - Set all parameters
- changes security context for SUID routines
- call sp_head::execute
- copy back values of INOUT and OUT parameters
@@ -1873,6 +2020,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
{
bool err_status= FALSE;
uint params = m_pcont->context_var_count();
+ /* Query start time may be reset in a multi-stmt SP; keep this for later. */
+ ulonglong utime_before_sp_exec= thd->utime_after_lock;
sp_rcontext *save_spcont, *octx;
sp_rcontext *nctx = NULL;
bool save_enable_slow_log= false;
@@ -1889,14 +2038,14 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
save_spcont= octx= thd->spcont;
if (! octx)
- { // Create a temporary old context
- if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) ||
- octx->init(thd))
+ {
+ /* Create a temporary old context. */
+ if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) || octx->init(thd))
{
delete octx; /* Delete octx if it was init() that failed. */
DBUG_RETURN(TRUE);
}
-
+
#ifndef DBUG_OFF
octx->sp= 0;
#endif
@@ -1971,18 +2120,31 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
}
}
- /*
- Okay, got values for all arguments. Close tables that might be used by
- arguments evaluation. If arguments evaluation required prelocking mode,
+ /*
+ Okay, got values for all arguments. Close tables that might be used by
+ arguments evaluation. If arguments evaluation required prelocking mode,
we'll leave it here.
*/
+ thd->lex->unit.cleanup();
+
if (!thd->in_sub_stmt)
{
- thd->lex->unit.cleanup();
- close_thread_tables(thd);
- thd->rollback_item_tree_changes();
+ thd->stmt_da->can_overwrite_status= TRUE;
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ thd->stmt_da->can_overwrite_status= FALSE;
}
+ thd_proc_info(thd, "closing tables");
+ close_thread_tables(thd);
+ thd_proc_info(thd, 0);
+
+ if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
+ thd->mdl_context.release_transactional_locks();
+ else if (! thd->in_sub_stmt)
+ thd->mdl_context.release_statement_locks();
+
+ thd->rollback_item_tree_changes();
+
DBUG_PRINT("info",(" %.*s: eval args done", (int) m_name.length,
m_name.str));
}
@@ -1992,12 +2154,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
save_enable_slow_log= true;
thd->enable_slow_log= FALSE;
}
- if (!(m_flags & LOG_GENERAL_LOG) && !(thd->options & OPTION_LOG_OFF))
+ if (!(m_flags & LOG_GENERAL_LOG) && !(thd->variables.option_bits & OPTION_LOG_OFF))
{
DBUG_PRINT("info", ("Disabling general log for the execution"));
save_log_general= true;
/* disable this bit */
- thd->options |= OPTION_LOG_OFF;
+ thd->variables.option_bits |= OPTION_LOG_OFF;
}
thd->spcont= nctx;
@@ -2008,10 +2170,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
#endif
if (!err_status)
- err_status= execute(thd);
+ err_status= execute(thd, TRUE);
if (save_log_general)
- thd->options &= ~OPTION_LOG_OFF;
+ thd->variables.option_bits &= ~OPTION_LOG_OFF;
if (save_enable_slow_log)
thd->enable_slow_log= true;
/*
@@ -2052,6 +2214,16 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
err_status= TRUE;
break;
}
+
+ Send_field *out_param_info= new (thd->mem_root) Send_field();
+ nctx->get_item(i)->make_field(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;
+ out_param_info->col_name= spvar->name.str;
+ out_param_info->org_col_name= spvar->name.str;
+
+ srp->set_out_param_info(out_param_info);
}
}
@@ -2065,6 +2237,19 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
delete nctx;
thd->spcont= save_spcont;
+ thd->utime_after_lock= utime_before_sp_exec;
+
+ /*
+ If not insided a procedure and a function printing warning
+ messsages.
+ */
+ bool need_binlog_call= mysql_bin_log.is_open() &&
+ (thd->variables.option_bits & OPTION_BIN_LOG) &&
+ !thd->is_current_stmt_binlog_format_row();
+ if (need_binlog_call && thd->spcont == NULL &&
+ !thd->binlog_evt_union.do_union)
+ thd->issue_unsafe_warnings();
+
DBUG_RETURN(err_status);
}
@@ -2112,6 +2297,9 @@ sp_head::reset_lex(THD *thd)
sublex->interval_list.empty();
sublex->type= 0;
+ /* Reset part of parser state which needs this. */
+ thd->m_parser_state->m_yacc.reset_before_substatement();
+
DBUG_RETURN(FALSE);
}
@@ -2137,17 +2325,14 @@ sp_head::restore_lex(THD *thd)
oldlex= (LEX *)m_lex.pop();
if (! oldlex)
- DBUG_RETURN(FALSE); // Nothing to restore
+ DBUG_RETURN(FALSE); // Nothing to restore
oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
- /*
- If this substatement needs row-based, the entire routine does too (we
- cannot switch from statement-based to row-based only for this
- substatement).
- */
- if (sublex->is_stmt_unsafe())
- m_flags|= BINLOG_ROW_BASED_IF_MIXED;
+ /* If this substatement is unsafe, the entire routine is too. */
+ DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags: 0x%x",
+ thd->lex->get_stmt_unsafe_flags()));
+ unsafe_flags|= sublex->get_stmt_unsafe_flags();
/*
Add routines which are used by statement to respective set for
@@ -2162,6 +2347,7 @@ sp_head::restore_lex(THD *thd)
merge_table_list(thd, sublex->query_tables, sublex);
if (! sublex->sp_lex_in_use)
{
+ sublex->sphead= NULL;
lex_end(sublex);
delete sublex;
}
@@ -2293,7 +2479,7 @@ sp_head::do_cont_backpatch()
void
sp_head::set_info(longlong created, longlong modified,
- st_sp_chistics *chistics, ulong sql_mode)
+ st_sp_chistics *chistics, ulong sql_mode)
{
m_created= created;
m_modified= modified;
@@ -2303,8 +2489,8 @@ sp_head::set_info(longlong created, longlong modified,
m_chistics->comment.str= 0;
else
m_chistics->comment.str= strmake_root(mem_root,
- m_chistics->comment.str,
- m_chistics->comment.length);
+ m_chistics->comment.str,
+ m_chistics->comment.length);
m_sql_mode= sql_mode;
}
@@ -2345,7 +2531,7 @@ sp_head::reset_thd_mem_root(THD *thd)
DBUG_PRINT("info", ("mem_root 0x%lx moved to thd mem root 0x%lx",
(ulong) &mem_root, (ulong) &thd->mem_root));
free_list= thd->free_list; // Keep the old list
- thd->free_list= NULL; // Start a new one
+ thd->free_list= NULL; // Start a new one
m_thd= thd;
DBUG_VOID_RETURN;
}
@@ -2354,13 +2540,13 @@ void
sp_head::restore_thd_mem_root(THD *thd)
{
DBUG_ENTER("sp_head::restore_thd_mem_root");
- Item *flist= free_list; // The old list
+ Item *flist= free_list; // The old list
set_query_arena(thd); // Get new free_list and mem_root
state= INITIALIZED_FOR_SP;
DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
(ulong) &mem_root, (ulong) &thd->mem_root));
- thd->free_list= flist; // Restore the old one
+ thd->free_list= flist; // Restore the old one
thd->mem_root= m_thd_root;
m_thd= NULL;
DBUG_VOID_RETURN;
@@ -2370,10 +2556,10 @@ sp_head::restore_thd_mem_root(THD *thd)
/**
Check if a user has access right to a routine.
- @param thd Thread handler
- @param sp SP
- @param full_access Set to 1 if the user has SELECT right to the
- 'mysql.proc' able or is the owner of the routine
+ @param thd Thread handler
+ @param sp SP
+ @param full_access Set to 1 if the user has SELECT right to the
+ 'mysql.proc' able or is the owner of the routine
@retval
false ok
@retval
@@ -2386,7 +2572,8 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
bzero((char*) &tables,sizeof(tables));
tables.db= (char*) "mysql";
tables.table_name= tables.alias= (char*) "proc";
- *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1, TRUE) ||
+ *full_access= (!check_table_access(thd, SELECT_ACL, &tables, FALSE,
+ 1, TRUE) ||
(!strcmp(sp->m_definer_user.str,
thd->security_ctx->priv_user) &&
!strcmp(sp->m_definer_host.str,
@@ -2437,8 +2624,7 @@ sp_head::show_create_routine(THD *thd, int type)
if (check_show_routine_access(thd, this, &full_access))
DBUG_RETURN(TRUE);
- sys_var_thd_sql_mode::symbolic_mode_representation(
- thd, m_sql_mode, &sql_mode);
+ sql_mode_string_representation(thd, m_sql_mode, &sql_mode);
/* Send header. */
@@ -2469,7 +2655,7 @@ sp_head::show_create_routine(THD *thd, int type)
fields.push_back(new Item_empty_string("Database Collation",
MY_CS_NAME_SIZE));
- if (protocol->send_fields(&fields,
+ if (protocol->send_result_set_metadata(&fields,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
{
DBUG_RETURN(TRUE);
@@ -2502,8 +2688,6 @@ sp_head::show_create_routine(THD *thd, int type)
}
-
-
/**
Add instruction to SP.
@@ -2561,12 +2745,13 @@ void sp_head::optimize()
else
{
if (src != dst)
- { // Move the instruction and update prev. jumps
- sp_instr *ibp;
- List_iterator_fast<sp_instr> li(bp);
+ {
+ /* Move the instruction and update prev. jumps */
+ sp_instr *ibp;
+ List_iterator_fast<sp_instr> li(bp);
- set_dynamic(&m_instr, (uchar*)&i, dst);
- while ((ibp= li++))
+ set_dynamic(&m_instr, (uchar*)&i, dst);
+ while ((ibp= li++))
{
sp_instr_opt_meta *im= static_cast<sp_instr_opt_meta *>(ibp);
im->set_destination(src, dst);
@@ -2654,14 +2839,14 @@ sp_head::show_routine_code(THD *thd)
field_list.push_back(new Item_uint("Pos", 9));
// 1024 is for not to confuse old clients
field_list.push_back(new Item_empty_string("Instruction",
- max(buffer.length(), 1024)));
- if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+ max(buffer.length(), 1024)));
+ if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF))
DBUG_RETURN(1);
for (ip= 0; (i = get_instr(ip)) ; ip++)
{
- /*
+ /*
Consistency check. If these are different something went wrong
during optimization.
*/
@@ -2724,12 +2909,15 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
int res= 0;
DBUG_ENTER("reset_lex_and_exec_core");
- /*
+ /*
The flag is saved at the entry to the following substatement.
It's reset further in the common code part.
It's merged with the saved parent's value at the exit of this func.
*/
bool parent_modified_non_trans_table= thd->transaction.stmt.modified_non_trans_table;
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&parent_modified_non_trans_table))
+ DBUG_RETURN(TRUE);
+
thd->transaction.stmt.modified_non_trans_table= FALSE;
DBUG_ASSERT(!thd->derived_tables);
DBUG_ASSERT(thd->change_list.is_empty());
@@ -2740,11 +2928,9 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
*/
thd->lex= m_lex;
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id= next_query_id();
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ thd->set_query_id(next_query_id());
- if (thd->prelocked_mode == NON_PRELOCKED)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
{
/*
This statement will enter/leave prelocked mode on its own.
@@ -2774,12 +2960,29 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
DBUG_PRINT("info",("exec_core returned: %d", res));
}
- m_lex->unit.cleanup();
-
- thd_proc_info(thd, "closing tables");
- /* Here we also commit or rollback the current statement. */
- close_thread_tables(thd);
- thd_proc_info(thd, 0);
+ /*
+ Call after unit->cleanup() to close open table
+ key read.
+ */
+ if (open_tables)
+ {
+ m_lex->unit.cleanup();
+ /* Here we also commit or rollback the current statement. */
+ if (! thd->in_sub_stmt)
+ {
+ thd->stmt_da->can_overwrite_status= TRUE;
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ thd->stmt_da->can_overwrite_status= FALSE;
+ }
+ thd_proc_info(thd, "closing tables");
+ close_thread_tables(thd);
+ thd_proc_info(thd, 0);
+
+ if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
+ thd->mdl_context.release_transactional_locks();
+ else if (! thd->in_sub_stmt)
+ thd->mdl_context.release_statement_locks();
+ }
if (m_lex->query_tables_own_last)
{
@@ -2803,9 +3006,9 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
open_tables stage.
*/
if (!res || !thd->is_error() ||
- (thd->main_da.sql_errno() != ER_CANT_REOPEN_TABLE &&
- thd->main_da.sql_errno() != ER_NO_SUCH_TABLE &&
- thd->main_da.sql_errno() != ER_UPDATE_TABLE_USED))
+ (thd->stmt_da->sql_errno() != ER_CANT_REOPEN_TABLE &&
+ thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE &&
+ thd->stmt_da->sql_errno() != ER_UPDATE_TABLE_USED))
thd->stmt_arena->state= Query_arena::EXECUTED;
/*
@@ -2838,8 +3041,8 @@ int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
Check whenever we have access to tables for this statement
and open and lock them before executing instructions core function.
*/
- if (check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE)
- || open_and_lock_tables(thd, tables))
+ if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)
+ || open_and_lock_tables(thd, tables, TRUE, 0))
result= -1;
else
result= 0;
@@ -2866,15 +3069,15 @@ int sp_instr::exec_core(THD *thd, uint *nextp)
int
sp_instr_stmt::execute(THD *thd, uint *nextp)
{
- char *query;
- uint32 query_length;
int res;
DBUG_ENTER("sp_instr_stmt::execute");
DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command()));
- query= thd->query();
- query_length= thd->query_length();
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res))
+ DBUG_RETURN(TRUE);
+
+ const CSET_STRING query_backup= thd->query_string;
+#if defined(ENABLED_PROFILING)
/* This s-p instr is profilable and will be captured. */
thd->profiling.set_query_source(m_query.str, m_query.length);
#endif
@@ -2885,17 +3088,21 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
(the order of query cache and subst_spvars calls is irrelevant because
queries with SP vars can't be cached)
*/
- if (unlikely((thd->options & OPTION_LOG_OFF)==0))
+ if (unlikely((thd->variables.option_bits & OPTION_LOG_OFF)==0))
general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
- if (query_cache_send_result_to_client(thd,
- thd->query(),
- thd->query_length()) <= 0)
+ if (query_cache_send_result_to_client(thd, thd->query(),
+ thd->query_length()) <= 0)
{
res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this);
- if (thd->main_da.is_eof())
- net_end_statement(thd);
+ if (thd->stmt_da->is_eof())
+ {
+ /* Finalize server status flags after executing a statement. */
+ thd->update_server_status();
+
+ thd->protocol->end_statement();
+ }
query_cache_end_of_result(thd);
@@ -2904,11 +3111,11 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
}
else
*nextp= m_ip+1;
- thd->set_query(query, query_length);
+ thd->set_query(query_backup);
thd->query_name_consts= 0;
if (!thd->is_error())
- thd->main_da.reset_diagnostics_area();
+ thd->stmt_da->reset_diagnostics_area();
}
DBUG_RETURN(res || thd->is_error());
}
@@ -2949,7 +3156,14 @@ sp_instr_stmt::print(String *str)
int
sp_instr_stmt::exec_core(THD *thd, uint *nextp)
{
+ MYSQL_QUERY_EXEC_START(thd->query(),
+ thd->thread_id,
+ (char *) (thd->db ? thd->db : ""),
+ thd->security_ctx->priv_user,
+ (char *)thd->security_ctx->host_or_ip,
+ 3);
int res= mysql_execute_command(thd);
+ MYSQL_QUERY_EXEC_DONE(res);
*nextp= m_ip+1;
return res;
}
@@ -2974,23 +3188,14 @@ sp_instr_set::exec_core(THD *thd, uint *nextp)
{
int res= thd->spcont->set_variable(thd, m_offset, &m_value);
- if (res && thd->spcont->found_handler_here())
+ if (res)
{
- /*
- Failed to evaluate the value, and a handler has been found. Reset the
- variable to NULL.
- */
+ /* Failed to evaluate the value. Reset the variable to NULL. */
if (thd->spcont->set_variable(thd, m_offset, 0))
{
/* If this also failed, let's abort. */
-
- sp_rcontext *spcont= thd->spcont;
-
- thd->spcont= NULL; /* Avoid handlers */
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- spcont->clear_handler();
- thd->spcont= spcont;
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
}
}
@@ -3090,7 +3295,7 @@ uint
sp_instr_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
{
m_dest= opt_shortcut_jump(sp, this);
- if (m_dest != m_ip+1) /* Jumping to following instruction? */
+ if (m_dest != m_ip+1) /* Jumping to following instruction? */
marked= 1;
m_optdest= sp->get_instr(m_dest);
return m_dest;
@@ -3120,9 +3325,9 @@ void
sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp)
{
if (m_dest > m_ip)
- bp->push_back(this); // Forward
+ bp->push_back(this); // Forward
else if (m_optdest)
- m_dest= m_optdest->m_ip; // Backward
+ m_dest= m_optdest->m_ip; // Backward
m_ip= dst;
}
@@ -3278,7 +3483,7 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
sp_cond_type_t *p;
while ((p= li++))
- thd->spcont->push_handler(p, m_ip+1, m_type, m_frame);
+ thd->spcont->push_handler(p, m_ip+1, m_type);
*nextp= m_dest;
DBUG_RETURN(0);
@@ -3395,7 +3600,7 @@ uint
sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
{
marked= 1;
-
+
if (m_dest)
{
/*
@@ -3403,7 +3608,7 @@ sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
*/
return m_dest;
}
-
+
/*
This is a CONTINUE handler; next instruction step will come from
the handler stack and not from opt_mark.
@@ -3523,18 +3728,6 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
if (thd->stmt_arena->free_list)
cleanup_items(thd->stmt_arena->free_list);
thd->stmt_arena= old_arena;
- /*
- Work around the fact that errors in selects are not returned properly
- (but instead converted into a warning), so if a condition handler
- caught, we have lost the result code.
- */
- if (!res)
- {
- uint dummy1, dummy2;
-
- if (thd->spcont->found_handler(&dummy1, &dummy2))
- res= -1;
- }
/* TODO: Assert here that we either have an error or a cursor */
}
DBUG_RETURN(res);
@@ -3710,28 +3903,20 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
{
int res= thd->spcont->set_case_expr(thd, m_case_expr_id, &m_case_expr);
- if (res &&
- !thd->spcont->get_case_expr(m_case_expr_id) &&
- thd->spcont->found_handler_here())
+ if (res && !thd->spcont->get_case_expr(m_case_expr_id))
{
/*
Failed to evaluate the value, the case expression is still not
- initialized, and a handler has been found. Set to NULL so we can continue.
+ initialized. Set to NULL so we can continue.
*/
Item *null_item= new Item_null();
-
+
if (!null_item ||
thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item))
{
/* If this also failed, we have to abort. */
-
- sp_rcontext *spcont= thd->spcont;
-
- thd->spcont= NULL; /* Avoid handlers */
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- spcont->clear_handler();
- thd->spcont= spcont;
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
}
}
else
@@ -3845,7 +4030,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
for (uint i= 0 ; i < m_sptabs.records ; i++)
{
- tab= (SP_TABLE *)hash_element(&m_sptabs, i);
+ tab= (SP_TABLE*) my_hash_element(&m_sptabs, i);
tab->query_lock_count= 0;
}
@@ -3879,8 +4064,8 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
(and therefore should not be prelocked). Otherwise we will erroneously
treat table with same name but with different alias as non-temporary.
*/
- if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (uchar *)tname, tlen)) ||
- ((tab= (SP_TABLE *)hash_search(&m_sptabs, (uchar *)tname,
+ if ((tab= (SP_TABLE*) my_hash_search(&m_sptabs, (uchar *)tname, tlen)) ||
+ ((tab= (SP_TABLE*) my_hash_search(&m_sptabs, (uchar *)tname,
tlen - alen - 1)) &&
tab->temp))
{
@@ -3893,13 +4078,13 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
}
else
{
- if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE))))
- return FALSE;
- if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
- lex_for_tmp_check->query_tables == table &&
- lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE))))
+ return FALSE;
+ if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
+ lex_for_tmp_check->query_tables == table &&
+ lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
{
- tab->temp= TRUE;
+ tab->temp= TRUE;
tab->qname.length= tlen - alen - 1;
}
else
@@ -3912,7 +4097,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
tab->lock_type= table->lock_type;
tab->lock_count= tab->query_lock_count= 1;
tab->trg_event_map= table->trg_event_map;
- if (my_hash_insert(&m_sptabs, (uchar *)tab))
+ if (my_hash_insert(&m_sptabs, (uchar *)tab))
return FALSE;
}
}
@@ -3966,7 +4151,7 @@ sp_head::add_used_tables_to_table_list(THD *thd,
{
char *tab_buff, *key_buff;
TABLE_LIST *table;
- SP_TABLE *stab= (SP_TABLE *)hash_element(&m_sptabs, i);
+ SP_TABLE *stab= (SP_TABLE*) my_hash_element(&m_sptabs, i);
if (stab->temp)
continue;
@@ -3990,6 +4175,15 @@ sp_head::add_used_tables_to_table_list(THD *thd,
table->prelocking_placeholder= 1;
table->belong_to_view= belong_to_view;
table->trg_event_map= stab->trg_event_map;
+ /*
+ Since we don't allow DDL on base tables in prelocked mode it
+ is safe to infer the type of metadata lock from the type of
+ table lock.
+ */
+ table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
+ table->lock_type >= TL_WRITE_ALLOW_WRITE ?
+ MDL_SHARED_WRITE : MDL_SHARED_READ,
+ MDL_TRANSACTION);
/* Everyting else should be zeroed */
@@ -4010,22 +4204,20 @@ sp_head::add_used_tables_to_table_list(THD *thd,
/**
- Simple function for adding an explicetly named (systems) table to
+ Simple function for adding an explicitly named (systems) table to
the global table list, e.g. "mysql", "proc".
*/
TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
const char *db, const char *name,
- thr_lock_type locktype)
+ thr_lock_type locktype,
+ enum_mdl_type mdl_type)
{
TABLE_LIST *table;
if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST))))
- {
- thd->fatal_error();
return NULL;
- }
table->db_length= strlen(db);
table->db= thd->strmake(db, table->db_length);
table->table_name_length= strlen(name);
@@ -4034,7 +4226,9 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
table->lock_type= locktype;
table->select_lex= lex->current_select;
table->cacheable_table= 1;
-
+ table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
+ mdl_type, MDL_TRANSACTION);
+
lex->add_to_query_tables(table);
return table;
}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index d422adc8927..5efd48fc7c6 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -21,6 +21,15 @@
#pragma interface /* gcc class implementation */
#endif
+/*
+ It is necessary to include set_var.h instead of item.h because there
+ are dependencies on include order for set_var.h and item.h. This
+ will be resolved later.
+*/
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_class.h" // THD, set_var.h: THD
+#include "set_var.h" // Item
+
#include <stddef.h>
/**
@@ -33,6 +42,7 @@
#define TYPE_ENUM_FUNCTION 1
#define TYPE_ENUM_PROCEDURE 2
#define TYPE_ENUM_TRIGGER 3
+#define TYPE_ENUM_PROXY 4
Item_result
sp_map_result_type(enum enum_field_types type);
@@ -109,36 +119,21 @@ public:
LEX_STRING m_db;
LEX_STRING m_name;
LEX_STRING m_qname;
- /**
- Key representing routine in the set of stored routines used by statement.
- Consists of 1-byte routine type and m_qname (which usually refences to
- same buffer). Note that one must complete initialization of the key by
- calling set_routine_type().
- */
- LEX_STRING m_sroutines_key;
bool m_explicit_name; /**< Prepend the db name? */
sp_name(LEX_STRING db, LEX_STRING name, bool use_explicit_name)
: m_db(db), m_name(name), m_explicit_name(use_explicit_name)
{
- m_qname.str= m_sroutines_key.str= 0;
- m_qname.length= m_sroutines_key.length= 0;
+ m_qname.str= 0;
+ m_qname.length= 0;
}
- /**
- Creates temporary sp_name object from key, used mainly
- for SP-cache lookups.
- */
- sp_name(THD *thd, char *key, uint key_len);
+ /** Create temporary sp_name object from MDL key. */
+ sp_name(const MDL_key *key, char *qname_buff);
// Init. the qualified name from the db and name.
void init_qname(THD *thd); // thd for memroot allocation
- void set_routine_type(char type)
- {
- m_sroutines_key.str[0]= type;
- }
-
~sp_name()
{}
};
@@ -165,9 +160,8 @@ public:
HAS_COMMIT_OR_ROLLBACK= 128,
LOG_SLOW_STATEMENTS= 256, // Used by events
LOG_GENERAL_LOG= 512, // Used by events
- BINLOG_ROW_BASED_IF_MIXED= 1024,
- HAS_SQLCOM_RESET= 2048,
- HAS_SQLCOM_FLUSH= 4096
+ HAS_SQLCOM_RESET= 1024,
+ HAS_SQLCOM_FLUSH= 2048
};
/** TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */
@@ -181,12 +175,6 @@ public:
ulong m_sql_mode; ///< For SHOW CREATE and execution
LEX_STRING m_qname; ///< db.name
bool m_explicit_name; ///< Prepend the db name? */
- /**
- Key representing routine in the set of stored routines used by statement.
- [routine_type]db.name
- @sa sp_name::m_sroutines_key
- */
- LEX_STRING m_sroutines_key;
LEX_STRING m_db;
LEX_STRING m_name;
LEX_STRING m_params;
@@ -196,8 +184,40 @@ public:
LEX_STRING m_definer_user;
LEX_STRING m_definer_host;
+ /**
+ Is this routine being executed?
+ */
+ bool is_invoked() const { return m_flags & IS_INVOKED; }
+
+ /**
+ Get the value of the SP cache version, as remembered
+ when the routine was inserted into the cache.
+ */
+ ulong sp_cache_version() const { return m_sp_cache_version; }
+
+ /** Set the value of the SP cache version. */
+ void set_sp_cache_version(ulong version_arg)
+ {
+ m_sp_cache_version= version_arg;
+ }
private:
+ /**
+ Version of the stored routine cache at the moment when the
+ routine was added to it. Is used only for functions and
+ procedures, not used for triggers or events. When sp_head is
+ created, its version is 0. When it's added to the cache, the
+ version is assigned the global value 'Cversion'.
+ If later on Cversion is incremented, we know that the routine
+ is obsolete and should not be used --
+ sp_cache_flush_obsolete() will purge it.
+ */
+ ulong m_sp_cache_version;
Stored_program_creation_ctx *m_creation_ctx;
+ /**
+ Boolean combination of (1<<flag), where flag is a member of
+ LEX::enum_binlog_stmt_unsafe.
+ */
+ uint32 unsafe_flags;
public:
inline Stored_program_creation_ctx *get_creation_ctx()
@@ -284,9 +304,6 @@ public:
void
set_stmt_end(THD *thd);
- int
- create(THD *thd);
-
virtual ~sp_head();
bool
@@ -450,21 +467,27 @@ public:
/*
This method is intended for attributes of a routine which need
- to propagate upwards to the LEX of the caller (when a property of a
- sp_head needs to "taint" the caller).
+ to propagate upwards to the Query_tables_list of the caller (when
+ a property of a sp_head needs to "taint" the calling statement).
*/
- void propagate_attributes(LEX *lex)
+ void propagate_attributes(Query_tables_list *prelocking_ctx)
{
+ DBUG_ENTER("sp_head::propagate_attributes");
/*
If this routine needs row-based binary logging, the entire top statement
too (we cannot switch from statement-based to row-based only for this
routine, as in statement-based the top-statement may be binlogged and
the substatements not).
*/
- if (m_flags & BINLOG_ROW_BASED_IF_MIXED)
- lex->set_stmt_unsafe();
+ DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
+ prelocking_ctx->get_stmt_unsafe_flags()));
+ DBUG_PRINT("info", ("sp_head(0x%p=%s)->unsafe_flags: 0x%x",
+ this, name(), unsafe_flags));
+ prelocking_ctx->set_stmt_unsafe_flags(unsafe_flags);
+ DBUG_VOID_RETURN;
}
+ sp_pcontext *get_parse_context() { return m_pcont; }
private:
@@ -504,7 +527,7 @@ private:
HASH m_sptabs;
bool
- execute(THD *thd);
+ execute(THD *thd, bool merge_da_on_success);
/**
Perform a forward flow analysis in the generated code.
@@ -660,6 +683,8 @@ public:
{
if (m_lex_resp)
{
+ /* Prevent endless recursion. */
+ m_lex->sphead= NULL;
lex_end(m_lex);
delete m_lex;
}
@@ -1320,7 +1345,9 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
const char *db, const char *name,
- thr_lock_type locktype);
+ thr_lock_type locktype,
+ enum_mdl_type mdl_type);
+
Item *
sp_prepare_func_item(THD* thd, Item **it_addr);
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index 302faf3f681..bbf38f52efb 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -13,15 +13,12 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
-#if defined(WIN32) || defined(__WIN__)
-#undef SAFEMALLOC /* Problems with threads */
-#endif
-
#include "sp_pcontext.h"
#include "sp_head.h"
@@ -51,7 +48,8 @@ sp_cond_check(LEX_STRING *sqlstate)
(c < 'A' || 'Z' < c))
return FALSE;
}
- if (strcmp(sqlstate->str, "00000") == 0)
+ /* SQLSTATE class '00' : completion condition */
+ if (strncmp(sqlstate->str, "00", 2) == 0)
return FALSE;
return TRUE;
}
@@ -62,21 +60,21 @@ sp_pcontext::sp_pcontext()
m_context_handlers(0), m_parent(NULL), m_pboundary(0),
m_label_scope(LABEL_DEFAULT_SCOPE)
{
- VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
+ (void) my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC));
- VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
+ PCONTEXT_ARRAY_INCREMENT_ALLOC);
+ (void) my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC));
- VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INCREMENT_ALLOC);
+ (void) my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC));
- VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
+ PCONTEXT_ARRAY_INCREMENT_ALLOC);
+ (void) my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC));
- VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INCREMENT_ALLOC);
+ (void) my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ PCONTEXT_ARRAY_INCREMENT_ALLOC);
m_label.empty();
m_children.empty();
@@ -90,21 +88,21 @@ sp_pcontext::sp_pcontext(sp_pcontext *prev, label_scope_type label_scope)
m_context_handlers(0), m_parent(prev), m_pboundary(0),
m_label_scope(label_scope)
{
- VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
+ (void) my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC));
- VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
+ PCONTEXT_ARRAY_INCREMENT_ALLOC);
+ (void) my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC));
- VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INCREMENT_ALLOC);
+ (void) my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC));
- VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
+ PCONTEXT_ARRAY_INCREMENT_ALLOC);
+ (void) my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC));
- VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INCREMENT_ALLOC);
+ (void) my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ PCONTEXT_ARRAY_INCREMENT_ALLOC);
m_label.empty();
m_children.empty();
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 75e55880e60..c27c7d22da2 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -21,6 +21,12 @@
#pragma interface /* gcc class implementation */
#endif
+#include "sql_string.h" // LEX_STRING
+#include "mysql_com.h" // enum_field_types
+#include "field.h" // Create_field
+
+class sp_pcontext;
+
typedef enum
{
sp_param_in,
@@ -326,13 +332,6 @@ public:
int
push_cond(LEX_STRING *name, sp_cond_type_t *val);
- inline void
- pop_cond(uint num)
- {
- while (num--)
- pop_dynamic(&m_conds);
- }
-
sp_cond_type_t *
find_cond(LEX_STRING *name, my_bool scoped=0);
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index be8f705a53e..e76a5e9ebde 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -13,26 +13,24 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
-#if defined(WIN32) || defined(__WIN__)
-#undef SAFEMALLOC /* Problems with threads */
-#endif
-
#include "mysql.h"
#include "sp_head.h"
#include "sql_cursor.h"
#include "sp_rcontext.h"
#include "sp_pcontext.h"
-
+#include "sql_select.h" // create_virtual_tmp_table
sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx,
Field *return_value_fld,
sp_rcontext *prev_runtime_ctx)
- :m_root_parsing_ctx(root_parsing_ctx),
+ :end_partial_result_set(FALSE),
+ m_root_parsing_ctx(root_parsing_ctx),
m_var_table(0),
m_var_items(0),
m_return_value_fld(return_value_fld),
@@ -68,21 +66,28 @@ sp_rcontext::~sp_rcontext()
bool sp_rcontext::init(THD *thd)
{
+ uint handler_count= m_root_parsing_ctx->max_handler_index();
+ uint i;
+
in_sub_stmt= thd->in_sub_stmt;
if (init_var_table(thd) || init_var_items())
return TRUE;
+ if (!(m_raised_conditions= new (thd->mem_root) MYSQL_ERROR[handler_count]))
+ return TRUE;
+
+ for (i= 0; i<handler_count; i++)
+ m_raised_conditions[i].init(thd->mem_root);
+
return
!(m_handler=
- (sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handler_index() *
- sizeof(sp_handler_t))) ||
+ (sp_handler_t*)thd->alloc(handler_count * sizeof(sp_handler_t))) ||
!(m_hstack=
- (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() *
- sizeof(uint))) ||
+ (uint*)thd->alloc(handler_count * sizeof(uint))) ||
!(m_in_handler=
- (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() *
- sizeof(uint))) ||
+ (sp_active_handler_t*)thd->alloc(handler_count *
+ sizeof(sp_active_handler_t))) ||
!(m_cstack=
(sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursor_index() *
sizeof(sp_cursor*))) ||
@@ -166,42 +171,50 @@ sp_rcontext::set_return_value(THD *thd, Item **return_value_item)
#define IS_NOT_FOUND_CONDITION(S) ((S)[0] == '0' && (S)[1] == '2')
#define IS_EXCEPTION_CONDITION(S) ((S)[0] != '0' || (S)[1] > '2')
-/*
- Find a handler for the given errno.
- This is called from all error message functions (e.g. push_warning,
- net_send_error, et al) when a sp_rcontext is in effect. If a handler
- is found, no error is sent, and the the SP execution loop will instead
- invoke the found handler.
- This might be called several times before we get back to the execution
- loop, so m_hfound can be >= 0 if a handler has already been found.
- (In which case we don't search again - the first found handler will
- be used.)
- Handlers are pushed on the stack m_handler, with the latest/innermost
+/**
+ Find an SQL handler for the given error.
+
+ SQL handlers are pushed on the stack m_handler, with the latest/innermost
one on the top; we then search for matching handlers from the top and
down.
+
We search through all the handlers, looking for the most specific one
(sql_errno more specific than sqlstate more specific than the rest).
Note that mysql error code handlers is a MySQL extension, not part of
the standard.
- SYNOPSIS
- sql_errno The error code
- level Warning level
+ SQL handlers for warnings are searched in the current scope only.
- RETURN
- 1 if a handler was found, m_hfound is set to its index (>= 0)
- 0 if not found, m_hfound is -1
+ SQL handlers for errors are searched in the current and in outer scopes.
+ That's why finding and activation of handler must be separated: an errror
+ handler might be located in the outer scope, which is not active at the
+ moment. Before such handler can be activated, execution flow should
+ unwind to that scope.
+
+ Found SQL handler is remembered in m_hfound for future activation.
+ If no handler is found, m_hfound is -1.
+
+ @param thd Thread handle
+ @param sql_errno The error code
+ @param sqlstate The error SQL state
+ @param level The error level
+ @param msg The error message
+
+ @retval TRUE if an SQL handler was found
+ @retval FALSE otherwise
*/
bool
-sp_rcontext::find_handler(THD *thd, uint sql_errno,
- MYSQL_ERROR::enum_warning_level level)
+sp_rcontext::find_handler(THD *thd,
+ uint sql_errno,
+ const char *sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char *msg)
{
- if (m_hfound >= 0)
- return 1; // Already got one
+ int i= m_hcount;
- const char *sqlstate= mysql_errno_to_sqlstate(sql_errno);
- int i= m_hcount, found= -1;
+ /* Reset previously found handler. */
+ m_hfound= -1;
/*
If this is a fatal sub-statement error, and this runtime
@@ -220,7 +233,7 @@ sp_rcontext::find_handler(THD *thd, uint sql_errno,
/* Check active handlers, to avoid invoking one recursively */
while (j--)
- if (m_in_handler[j] == m_handler[i].handler)
+ if (m_in_handler[j].ip == m_handler[i].handler)
break;
if (j >= 0)
continue; // Already executing this handler
@@ -229,86 +242,56 @@ sp_rcontext::find_handler(THD *thd, uint sql_errno,
{
case sp_cond_type_t::number:
if (sql_errno == cond->mysqlerr &&
- (found < 0 || m_handler[found].cond->type > sp_cond_type_t::number))
- found= i; // Always the most specific
+ (m_hfound < 0 || m_handler[m_hfound].cond->type > sp_cond_type_t::number))
+ m_hfound= i; // Always the most specific
break;
case sp_cond_type_t::state:
if (strcmp(sqlstate, cond->sqlstate) == 0 &&
- (found < 0 || m_handler[found].cond->type > sp_cond_type_t::state))
- found= i;
+ (m_hfound < 0 || m_handler[m_hfound].cond->type > sp_cond_type_t::state))
+ m_hfound= i;
break;
case sp_cond_type_t::warning:
if ((IS_WARNING_CONDITION(sqlstate) ||
level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
- found < 0)
- found= i;
+ m_hfound < 0)
+ m_hfound= i;
break;
case sp_cond_type_t::notfound:
- if (IS_NOT_FOUND_CONDITION(sqlstate) && found < 0)
- found= i;
+ if (IS_NOT_FOUND_CONDITION(sqlstate) && m_hfound < 0)
+ m_hfound= i;
break;
case sp_cond_type_t::exception:
if (IS_EXCEPTION_CONDITION(sqlstate) &&
level == MYSQL_ERROR::WARN_LEVEL_ERROR &&
- found < 0)
- found= i;
+ m_hfound < 0)
+ m_hfound= i;
break;
}
}
- if (found < 0)
- {
- /*
- Only "exception conditions" are propagated to handlers in calling
- contexts. If no handler is found locally for a "completion condition"
- (warning or "not found") we will simply resume execution.
- */
- if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
- level == MYSQL_ERROR::WARN_LEVEL_ERROR)
- return m_prev_runtime_ctx->find_handler(thd, sql_errno, level);
- return FALSE;
- }
- m_hfound= found;
- return TRUE;
-}
-/*
- Handle the error for a given errno.
- The severity of the error is adjusted depending of the current sql_mode.
- If an handler is present for the error (see find_handler()),
- this function will return true.
- If a handler is found and if the severity of the error indicate
- that the current instruction executed should abort,
- the flag thd->net.report_error is also set.
- This will cause the execution of the current instruction in a
- sp_instr* to fail, and give control to the handler code itself
- in the sp_head::execute() loop.
+ if (m_hfound >= 0)
+ {
+ DBUG_ASSERT((uint) m_hfound < m_root_parsing_ctx->max_handler_index());
- SYNOPSIS
- sql_errno The error code
- level Warning level
- thd The current thread
-
- RETURN
- TRUE if a handler was found.
- FALSE if no handler was found.
-*/
-bool
-sp_rcontext::handle_error(uint sql_errno,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd)
-{
- MYSQL_ERROR::enum_warning_level elevated_level= level;
+ m_raised_conditions[m_hfound].clear();
+ m_raised_conditions[m_hfound].set(sql_errno, sqlstate, level, msg);
+ return TRUE;
+ }
- /* Depending on the sql_mode of execution,
- warnings may be considered errors */
- if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
- thd->really_abort_on_warning())
+ /*
+ Only "exception conditions" are propagated to handlers in calling
+ contexts. If no handler is found locally for a "completion condition"
+ (warning or "not found") we will simply resume execution.
+ */
+ if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
+ level == MYSQL_ERROR::WARN_LEVEL_ERROR)
{
- elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+ return m_prev_runtime_ctx->find_handler(thd, sql_errno, sqlstate,
+ level, msg);
}
- return find_handler(thd, sql_errno, elevated_level);
+ return FALSE;
}
void
@@ -335,7 +318,7 @@ sp_rcontext::pop_cursors(uint count)
}
void
-sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type, uint f)
+sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type)
{
DBUG_ENTER("sp_rcontext::push_handler");
DBUG_ASSERT(m_hcount < m_root_parsing_ctx->max_handler_index());
@@ -343,7 +326,6 @@ sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type, uint f)
m_handler[m_hcount].cond= cond;
m_handler[m_hcount].handler= h;
m_handler[m_hcount].type= type;
- m_handler[m_hcount].foffset= f;
m_hcount+= 1;
DBUG_PRINT("info", ("m_hcount: %d", m_hcount));
@@ -355,7 +337,9 @@ sp_rcontext::pop_handlers(uint count)
{
DBUG_ENTER("sp_rcontext::pop_handlers");
DBUG_ASSERT(m_hcount >= count);
+
m_hcount-= count;
+
DBUG_PRINT("info", ("m_hcount: %d", m_hcount));
DBUG_VOID_RETURN;
}
@@ -365,7 +349,9 @@ sp_rcontext::push_hstack(uint h)
{
DBUG_ENTER("sp_rcontext::push_hstack");
DBUG_ASSERT(m_hsp < m_root_parsing_ctx->max_handler_index());
+
m_hstack[m_hsp++]= h;
+
DBUG_PRINT("info", ("m_hsp: %d", m_hsp));
DBUG_VOID_RETURN;
}
@@ -376,19 +362,74 @@ sp_rcontext::pop_hstack()
uint handler;
DBUG_ENTER("sp_rcontext::pop_hstack");
DBUG_ASSERT(m_hsp);
+
handler= m_hstack[--m_hsp];
+
DBUG_PRINT("info", ("m_hsp: %d", m_hsp));
DBUG_RETURN(handler);
}
-void
-sp_rcontext::enter_handler(int hid)
+/**
+ Prepare found handler to be executed.
+
+ @retval TRUE if an SQL handler is activated (was found) and IP of the
+ first handler instruction.
+ @retval FALSE if there is no active handler
+*/
+
+bool
+sp_rcontext::activate_handler(THD *thd,
+ uint *ip,
+ sp_instr *instr,
+ Query_arena *execute_arena,
+ Query_arena *backup_arena)
{
- DBUG_ENTER("sp_rcontext::enter_handler");
- DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index());
- m_in_handler[m_ihsp++]= hid;
- DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
- DBUG_VOID_RETURN;
+ if (m_hfound < 0)
+ return FALSE;
+
+ switch (m_handler[m_hfound].type) {
+ case SP_HANDLER_NONE:
+ break;
+
+ case SP_HANDLER_CONTINUE:
+ thd->restore_active_arena(execute_arena, backup_arena);
+ thd->set_n_backup_active_arena(execute_arena, backup_arena);
+ push_hstack(instr->get_cont_dest());
+
+ /* Fall through */
+
+ default:
+ /* End aborted result set. */
+
+ if (end_partial_result_set)
+ thd->protocol->end_partial_result_set(thd);
+
+ /* Enter handler. */
+
+ DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index());
+ DBUG_ASSERT(m_hfound >= 0);
+
+ m_in_handler[m_ihsp].ip= m_handler[m_hfound].handler;
+ m_in_handler[m_ihsp].index= m_hfound;
+ m_ihsp++;
+
+ DBUG_PRINT("info", ("Entering handler..."));
+ DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
+
+ /* Reset error state. */
+
+ thd->clear_error();
+ thd->killed= THD::NOT_KILLED; // Some errors set thd->killed
+ // (e.g. "bad data").
+
+ /* Return IP of the activated SQL handler. */
+ *ip= m_handler[m_hfound].handler;
+
+ /* Reset found handler. */
+ m_hfound= -1;
+ }
+
+ return TRUE;
}
void
@@ -396,11 +437,31 @@ sp_rcontext::exit_handler()
{
DBUG_ENTER("sp_rcontext::exit_handler");
DBUG_ASSERT(m_ihsp);
+
+ uint hindex= m_in_handler[m_ihsp-1].index;
+ m_raised_conditions[hindex].clear();
m_ihsp-= 1;
+
DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
DBUG_VOID_RETURN;
}
+MYSQL_ERROR*
+sp_rcontext::raised_condition() const
+{
+ if (m_ihsp > 0)
+ {
+ uint hindex= m_in_handler[m_ihsp - 1].index;
+ MYSQL_ERROR *raised= & m_raised_conditions[hindex];
+ return raised;
+ }
+
+ if (m_prev_runtime_ctx)
+ return m_prev_runtime_ctx->raised_condition();
+
+ return NULL;
+}
+
int
sp_rcontext::set_variable(THD *thd, uint var_idx, Item **value)
@@ -476,8 +537,7 @@ sp_cursor::open(THD *thd)
MYF(0));
return -1;
}
- if (mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR, &result,
- &server_side_cursor))
+ if (mysql_open_cursor(thd, &result, &server_side_cursor))
return -1;
return 0;
}
@@ -519,6 +579,11 @@ sp_cursor::fetch(THD *thd, List<struct sp_variable> *vars)
return -1;
}
+ DBUG_EXECUTE_IF("bug23032_emit_warning",
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_UNKNOWN_ERROR,
+ ER(ER_UNKNOWN_ERROR)););
+
result.set_spvar_list(vars);
/* Attempt to fetch one row */
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 368a017da21..ec8d82063e4 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -21,11 +21,19 @@
#pragma interface /* gcc class implementation */
#endif
+#include "sql_class.h" // select_result_interceptor
+
struct sp_cond_type;
class sp_cursor;
struct sp_variable;
class sp_lex_keeper;
class sp_instr_cpush;
+class Query_arena;
+class sp_head;
+class sp_pcontext;
+class Item_cache;
+typedef class st_select_lex_unit SELECT_LEX_UNIT;
+class Server_side_cursor;
#define SP_HANDLER_NONE 0
#define SP_HANDLER_EXIT 1
@@ -34,12 +42,21 @@ class sp_instr_cpush;
typedef struct
{
+ /** Condition caught by this HANDLER. */
struct sp_cond_type *cond;
- uint handler; // Location of handler
+ /** Location (instruction pointer) of the handler code. */
+ uint handler;
+ /** Handler type (EXIT, CONTINUE). */
int type;
- uint foffset; // Frame offset for the handlers declare level
} sp_handler_t;
+typedef struct
+{
+ /** Instruction pointer of the active handler. */
+ uint ip;
+ /** Handler index of the active handler. */
+ uint index;
+} sp_active_handler_t;
/*
This class is a runtime context of a Stored Routine. It is used in an
@@ -75,6 +92,13 @@ class sp_rcontext : public Sql_alloc
*/
Query_arena *callers_arena;
+ /*
+ End a open result set before start executing a continue/exit
+ handler if one is found as otherwise the client will hang
+ due to a violation of the client/server protocol.
+ */
+ bool end_partial_result_set;
+
#ifndef DBUG_OFF
/*
The routine for which this runtime context is created. Used for checking
@@ -107,52 +131,40 @@ class sp_rcontext : public Sql_alloc
return m_return_value_set;
}
- void push_handler(struct sp_cond_type *cond, uint h, int type, uint f);
+ /*
+ SQL handlers support.
+ */
- void pop_handlers(uint count);
+ void push_handler(struct sp_cond_type *cond, uint h, int type);
- // Returns 1 if a handler was found, 0 otherwise.
- bool
- find_handler(THD *thd, uint sql_errno,MYSQL_ERROR::enum_warning_level level);
+ void pop_handlers(uint count);
- // If there is an error handler for this error, handle it and return TRUE.
bool
- handle_error(uint sql_errno,
+ find_handler(THD *thd,
+ uint sql_errno,
+ const char *sqlstate,
MYSQL_ERROR::enum_warning_level level,
- THD *thd);
+ const char *msg);
- // Returns handler type and sets *ip to location if one was found
- inline int
- found_handler(uint *ip, uint *fp)
- {
- if (m_hfound < 0)
- return SP_HANDLER_NONE;
- *ip= m_handler[m_hfound].handler;
- *fp= m_handler[m_hfound].foffset;
- return m_handler[m_hfound].type;
- }
-
- // Returns true if we found a handler in this context
- inline bool
- found_handler_here()
- {
- return (m_hfound >= 0);
- }
+ MYSQL_ERROR *
+ raised_condition() const;
- // Clears the handler find state
- inline void
- clear_handler()
- {
- m_hfound= -1;
- }
+ void
+ push_hstack(uint h);
- void push_hstack(uint h);
+ uint
+ pop_hstack();
- uint pop_hstack();
+ bool
+ activate_handler(THD *thd,
+ uint *ip,
+ sp_instr *instr,
+ Query_arena *execute_arena,
+ Query_arena *backup_arena);
- void enter_handler(int hid);
- void exit_handler();
+ void
+ exit_handler();
void
push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
@@ -160,7 +172,7 @@ class sp_rcontext : public Sql_alloc
void
pop_cursors(uint count);
- void
+ inline void
pop_all_cursors()
{
pop_cursors(m_ccount);
@@ -208,16 +220,25 @@ private:
during execution.
*/
bool m_return_value_set;
+
/**
TRUE if the context is created for a sub-statement.
*/
bool in_sub_stmt;
sp_handler_t *m_handler; // Visible handlers
+
+ /**
+ SQL conditions caught by each handler.
+ This is an array indexed by handler index.
+ */
+ MYSQL_ERROR *m_raised_conditions;
+
uint m_hcount; // Stack pointer for m_handler
uint *m_hstack; // Return stack for continue handlers
uint m_hsp; // Stack pointer for m_hstack
- uint *m_in_handler; // Active handler, for recursion check
+ /** Active handler stack. */
+ sp_active_handler_t *m_in_handler;
uint m_ihsp; // Stack pointer for m_in_handler
int m_hfound; // Set by find_handler; -1 if not found
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 8b869a5b1ca..b02feb722f7 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -13,32 +13,15 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "my_global.h" // REQUIRED for HAVE_* below
+#include "spatial.h"
+#include "gstream.h" // Gis_read_stream
+#include "sql_string.h" // String
#ifdef HAVE_SPATIAL
-/*
- exponential notation :
- 1 sign
- 1 number before the decimal point
- 1 decimal point
- 14 number of significant digits (see String::qs_append(double))
- 1 'e' sign
- 1 exponent sign
- 3 exponent digits
- ==
- 22
-
- "f" notation :
- 1 optional 0
- 1 sign
- 14 number significant digits (see String::qs_append(double) )
- 1 decimal point
- ==
- 17
-*/
-
-#define MAX_DIGITS_IN_DOUBLE 22
+#define MAX_DIGITS_IN_DOUBLE MY_GCVT_MAX_FIELD_WIDTH
/***************************** Gis_class_info *******************************/
@@ -1641,9 +1624,8 @@ int Gis_multi_polygon::area(double *ar, const char **end_of_data) const
int Gis_multi_polygon::centroid(String *result) const
{
uint32 n_polygons;
- bool first_loop= 1;
Gis_polygon p;
- double UNINIT_VAR(res_area), UNINIT_VAR(res_cx), UNINIT_VAR(res_cy);
+ double res_area= 0.0, res_cx= 0.0, res_cy= 0.0;
double cur_area, cur_cx, cur_cy;
const char *data= m_data;
@@ -1660,20 +1642,13 @@ int Gis_multi_polygon::centroid(String *result) const
p.centroid_xy(&cur_cx, &cur_cy))
return 1;
- if (!first_loop)
- {
- double sum_area= res_area + cur_area;
- res_cx= (res_area * res_cx + cur_area * cur_cx) / sum_area;
- res_cy= (res_area * res_cy + cur_area * cur_cy) / sum_area;
- }
- else
- {
- first_loop= 0;
- res_area= cur_area;
- res_cx= cur_cx;
- res_cy= cur_cy;
- }
+ res_area+= cur_area;
+ res_cx+= cur_area * cur_cx;
+ res_cy+= cur_area * cur_cy;
}
+
+ res_cx/= res_area;
+ res_cy/= res_area;
return create_point(result, res_cx, res_cy);
}
diff --git a/sql/spatial.h b/sql/spatial.h
index f778acd6c34..b0c609ceeef 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -16,8 +16,13 @@
#ifndef _spatial_h
#define _spatial_h
+#include "sql_string.h" /* String, LEX_STRING */
+#include <my_compiler.h>
+
#ifdef HAVE_SPATIAL
+class Gis_read_stream;
+
const uint SRID_SIZE= 4;
const uint SIZEOF_STORED_DOUBLE= 8;
const uint POINT_DATA_SIZE= SIZEOF_STORED_DOUBLE*2;
@@ -267,6 +272,7 @@ public:
public:
static Geometry *create_by_typeid(Geometry_buffer *buffer, int type_id);
+
static Geometry *construct(Geometry_buffer *buffer,
const char *data, uint32 data_len);
static Geometry *create_from_wkt(Geometry_buffer *buffer,
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 1733a0f74b4..5ac31d1f578 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -24,12 +24,33 @@
in the relevant fields. Empty strings comes last.
*/
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "sql_acl.h" // MYSQL_DB_FIELD_COUNT, ACL_ACCESS
+#include "sql_base.h" // close_mysql_tables
+#include "key.h" // key_copy, key_cmp_if_same, key_restore
+#include "sql_show.h" // append_identifier
+#include "sql_table.h" // build_table_filename
#include "hash_filo.h"
+#include "sql_parse.h" // check_access
+#include "sql_view.h" // VIEW_ANY_ACL
+#include "records.h" // READ_RECORD, read_record_info,
+ // init_read_record, end_read_record
+#include "rpl_filter.h" // rpl_filter
#include <m_ctype.h>
#include <stdarg.h>
#include "sp_head.h"
#include "sp.h"
+#include "transaction.h"
+#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
+#include "records.h" // init_read_record, end_read_record
+#include <sql_common.h>
+#include <mysql/plugin_auth.h>
+#include "sql_connect.h"
+#include "hostname.h"
+#include "sql_db.h"
+
+bool mysql_user_table_is_in_short_password_format= false;
static const
TABLE_FIELD_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = {
@@ -148,7 +169,334 @@ TABLE_FIELD_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = {
const TABLE_FIELD_DEF
mysql_db_table_def= {MYSQL_DB_FIELD_COUNT, mysql_db_table_fields};
+static LEX_STRING native_password_plugin_name= {
+ C_STRING_WITH_LEN("mysql_native_password")
+};
+
+static LEX_STRING old_password_plugin_name= {
+ C_STRING_WITH_LEN("mysql_old_password")
+};
+
+/// @todo make it configurable
+LEX_STRING *default_auth_plugin_name= &native_password_plugin_name;
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+static plugin_ref old_password_plugin;
+#endif
+static plugin_ref native_password_plugin;
+
+/* Classes */
+
+struct acl_host_and_ip
+{
+ char *hostname;
+ long ip, ip_mask; // Used with masked ip:s
+};
+
+class ACL_ACCESS {
+public:
+ ulong sort;
+ ulong access;
+};
+
+/* ACL_HOST is used if no host is specified */
+
+class ACL_HOST :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ char *db;
+};
+
+class ACL_USER :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ uint hostname_length;
+ USER_RESOURCES user_resource;
+ char *user;
+ uint8 salt[SCRAMBLE_LENGTH + 1]; // scrambled password in binary form
+ uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 4.0, 20 - 4.1.1
+ enum SSL_type ssl_type;
+ const char *ssl_cipher, *x509_issuer, *x509_subject;
+ LEX_STRING plugin;
+ LEX_STRING auth_string;
+
+ ACL_USER *copy(MEM_ROOT *root)
+ {
+ ACL_USER *dst= (ACL_USER *) alloc_root(root, sizeof(ACL_USER));
+ if (!dst)
+ return 0;
+ *dst= *this;
+ dst->user= safe_strdup_root(root, user);
+ dst->ssl_cipher= safe_strdup_root(root, ssl_cipher);
+ dst->x509_issuer= safe_strdup_root(root, x509_issuer);
+ dst->x509_subject= safe_strdup_root(root, x509_subject);
+ if (plugin.str == native_password_plugin_name.str ||
+ plugin.str == old_password_plugin_name.str)
+ dst->plugin= plugin;
+ else
+ dst->plugin.str= strmake_root(root, plugin.str, plugin.length);
+ dst->auth_string.str= safe_strdup_root(root, auth_string.str);
+ dst->host.hostname= safe_strdup_root(root, host.hostname);
+ return dst;
+ }
+};
+
+class ACL_DB :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ char *user,*db;
+};
+
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+static void update_hostname(acl_host_and_ip *host, const char *hostname);
+static ulong get_sort(uint count,...);
+static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
+ const char *ip);
+static bool show_proxy_grants (THD *thd, LEX_USER *user,
+ char *buff, size_t buffsize);
+
+class ACL_PROXY_USER :public ACL_ACCESS
+{
+ acl_host_and_ip host;
+ const char *user;
+ acl_host_and_ip proxied_host;
+ const char *proxied_user;
+ bool with_grant;
+
+ typedef enum {
+ MYSQL_PROXIES_PRIV_HOST,
+ MYSQL_PROXIES_PRIV_USER,
+ MYSQL_PROXIES_PRIV_PROXIED_HOST,
+ MYSQL_PROXIES_PRIV_PROXIED_USER,
+ MYSQL_PROXIES_PRIV_WITH_GRANT,
+ MYSQL_PROXIES_PRIV_GRANTOR,
+ MYSQL_PROXIES_PRIV_TIMESTAMP } old_acl_proxy_users;
+public:
+ ACL_PROXY_USER () {};
+
+ void init(const char *host_arg, const char *user_arg,
+ const char *proxied_host_arg, const char *proxied_user_arg,
+ bool with_grant_arg)
+ {
+ user= (user_arg && *user_arg) ? user_arg : NULL;
+ update_hostname (&host,
+ (host_arg && *host_arg) ? host_arg : NULL);
+ proxied_user= (proxied_user_arg && *proxied_user_arg) ?
+ proxied_user_arg : NULL;
+ update_hostname (&proxied_host,
+ (proxied_host_arg && *proxied_host_arg) ?
+ proxied_host_arg : NULL);
+ with_grant= with_grant_arg;
+ sort= get_sort(4, host.hostname, user,
+ proxied_host.hostname, proxied_user);
+ }
+
+ void init(MEM_ROOT *mem, const char *host_arg, const char *user_arg,
+ const char *proxied_host_arg, const char *proxied_user_arg,
+ bool with_grant_arg)
+ {
+ init ((host_arg && *host_arg) ? strdup_root (mem, host_arg) : NULL,
+ (user_arg && *user_arg) ? strdup_root (mem, user_arg) : NULL,
+ (proxied_host_arg && *proxied_host_arg) ?
+ strdup_root (mem, proxied_host_arg) : NULL,
+ (proxied_user_arg && *proxied_user_arg) ?
+ strdup_root (mem, proxied_user_arg) : NULL,
+ with_grant_arg);
+ }
+
+ void init(TABLE *table, MEM_ROOT *mem)
+ {
+ init (get_field(mem, table->field[MYSQL_PROXIES_PRIV_HOST]),
+ get_field(mem, table->field[MYSQL_PROXIES_PRIV_USER]),
+ get_field(mem, table->field[MYSQL_PROXIES_PRIV_PROXIED_HOST]),
+ get_field(mem, table->field[MYSQL_PROXIES_PRIV_PROXIED_USER]),
+ table->field[MYSQL_PROXIES_PRIV_WITH_GRANT]->val_int() != 0);
+ }
+
+ bool get_with_grant() { return with_grant; }
+ const char *get_user() { return user; }
+ const char *get_host() { return host.hostname; }
+ const char *get_proxied_user() { return proxied_user; }
+ const char *get_proxied_host() { return proxied_host.hostname; }
+ void set_user(MEM_ROOT *mem, const char *user_arg)
+ {
+ user= user_arg && *user_arg ? strdup_root(mem, user_arg) : NULL;
+ }
+ void set_host(MEM_ROOT *mem, const char *host_arg)
+ {
+ update_hostname(&host,
+ (host_arg && *host_arg) ?
+ strdup_root(mem, host_arg) : NULL);
+ }
+
+ bool check_validity(bool check_no_resolve)
+ {
+ if (check_no_resolve &&
+ (hostname_requires_resolving(host.hostname) ||
+ hostname_requires_resolving(proxied_host.hostname)))
+ {
+ sql_print_warning("'proxies_priv' entry '%s@%s %s@%s' "
+ "ignored in --skip-name-resolve mode.",
+ proxied_user ? proxied_user : "",
+ proxied_host.hostname ? proxied_host.hostname : "",
+ user ? user : "",
+ host.hostname ? host.hostname : "");
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ bool matches(const char *host_arg, const char *user_arg, const char *ip_arg,
+ const char *proxied_user_arg)
+ {
+ DBUG_ENTER("ACL_PROXY_USER::matches");
+ DBUG_PRINT("info", ("compare_hostname(%s,%s,%s) &&"
+ "compare_hostname(%s,%s,%s) &&"
+ "wild_compare (%s,%s) &&"
+ "wild_compare (%s,%s)",
+ host.hostname ? host.hostname : "<NULL>",
+ host_arg ? host_arg : "<NULL>",
+ ip_arg ? ip_arg : "<NULL>",
+ proxied_host.hostname ? proxied_host.hostname : "<NULL>",
+ host_arg ? host_arg : "<NULL>",
+ ip_arg ? ip_arg : "<NULL>",
+ user_arg ? user_arg : "<NULL>",
+ user ? user : "<NULL>",
+ proxied_user_arg ? proxied_user_arg : "<NULL>",
+ proxied_user ? proxied_user : "<NULL>"));
+ DBUG_RETURN(compare_hostname(&host, host_arg, ip_arg) &&
+ compare_hostname(&proxied_host, host_arg, ip_arg) &&
+ (!user ||
+ (user_arg && !wild_compare(user_arg, user, TRUE))) &&
+ (!proxied_user ||
+ (proxied_user && !wild_compare(proxied_user_arg,
+ proxied_user, TRUE))));
+ }
+
+
+ inline static bool auth_element_equals(const char *a, const char *b)
+ {
+ return (a == b || (a != NULL && b != NULL && !strcmp(a,b)));
+ }
+
+
+ bool pk_equals(ACL_PROXY_USER *grant)
+ {
+ DBUG_ENTER("pk_equals");
+ DBUG_PRINT("info", ("strcmp(%s,%s) &&"
+ "strcmp(%s,%s) &&"
+ "wild_compare (%s,%s) &&"
+ "wild_compare (%s,%s)",
+ user ? user : "<NULL>",
+ grant->user ? grant->user : "<NULL>",
+ proxied_user ? proxied_user : "<NULL>",
+ grant->proxied_user ? grant->proxied_user : "<NULL>",
+ host.hostname ? host.hostname : "<NULL>",
+ grant->host.hostname ? grant->host.hostname : "<NULL>",
+ proxied_host.hostname ? proxied_host.hostname : "<NULL>",
+ grant->proxied_host.hostname ?
+ grant->proxied_host.hostname : "<NULL>"));
+
+ DBUG_RETURN(auth_element_equals(user, grant->user) &&
+ auth_element_equals(proxied_user, grant->proxied_user) &&
+ auth_element_equals(host.hostname, grant->host.hostname) &&
+ auth_element_equals(proxied_host.hostname,
+ grant->proxied_host.hostname));
+ }
+
+
+ bool granted_on(const char *host_arg, const char *user_arg)
+ {
+ return (((!user && (!user_arg || !user_arg[0])) ||
+ (user && user_arg && !strcmp(user, user_arg))) &&
+ ((!host.hostname && (!host_arg || !host_arg[0])) ||
+ (host.hostname && host_arg && !strcmp(host.hostname, host_arg))));
+ }
+
+
+ void print_grant(String *str)
+ {
+ str->append(STRING_WITH_LEN("GRANT PROXY ON '"));
+ if (proxied_user)
+ str->append(proxied_user, strlen(proxied_user));
+ str->append(STRING_WITH_LEN("'@'"));
+ if (proxied_host.hostname)
+ str->append(proxied_host.hostname, strlen(proxied_host.hostname));
+ str->append(STRING_WITH_LEN("' TO '"));
+ if (user)
+ str->append(user, strlen(user));
+ str->append(STRING_WITH_LEN("'@'"));
+ if (host.hostname)
+ str->append(host.hostname, strlen(host.hostname));
+ str->append(STRING_WITH_LEN("'"));
+ if (with_grant)
+ str->append(STRING_WITH_LEN(" WITH GRANT OPTION"));
+ }
+
+ void set_data(ACL_PROXY_USER *grant)
+ {
+ with_grant= grant->with_grant;
+ }
+
+ static int store_pk(TABLE *table,
+ const LEX_STRING *host,
+ const LEX_STRING *user,
+ const LEX_STRING *proxied_host,
+ const LEX_STRING *proxied_user)
+ {
+ DBUG_ENTER("ACL_PROXY_USER::store_pk");
+ DBUG_PRINT("info", ("host=%s, user=%s, proxied_host=%s, proxied_user=%s",
+ host->str ? host->str : "<NULL>",
+ user->str ? user->str : "<NULL>",
+ proxied_host->str ? proxied_host->str : "<NULL>",
+ proxied_user->str ? proxied_user->str : "<NULL>"));
+ if (table->field[MYSQL_PROXIES_PRIV_HOST]->store(host->str,
+ host->length,
+ system_charset_info))
+ DBUG_RETURN(TRUE);
+ if (table->field[MYSQL_PROXIES_PRIV_USER]->store(user->str,
+ user->length,
+ system_charset_info))
+ DBUG_RETURN(TRUE);
+ if (table->field[MYSQL_PROXIES_PRIV_PROXIED_HOST]->store(proxied_host->str,
+ proxied_host->length,
+ system_charset_info))
+ DBUG_RETURN(TRUE);
+ if (table->field[MYSQL_PROXIES_PRIV_PROXIED_USER]->store(proxied_user->str,
+ proxied_user->length,
+ system_charset_info))
+ DBUG_RETURN(TRUE);
+
+ DBUG_RETURN(FALSE);
+ }
+
+ static int store_data_record(TABLE *table,
+ const LEX_STRING *host,
+ const LEX_STRING *user,
+ const LEX_STRING *proxied_host,
+ const LEX_STRING *proxied_user,
+ bool with_grant,
+ const char *grantor)
+ {
+ DBUG_ENTER("ACL_PROXY_USER::store_pk");
+ if (store_pk(table, host, user, proxied_host, proxied_user))
+ DBUG_RETURN(TRUE);
+ DBUG_PRINT("info", ("with_grant=%s", with_grant ? "TRUE" : "FALSE"));
+ if (table->field[MYSQL_PROXIES_PRIV_WITH_GRANT]->store(with_grant ? 1 : 0,
+ TRUE))
+ DBUG_RETURN(TRUE);
+ if (table->field[MYSQL_PROXIES_PRIV_GRANTOR]->store(grantor,
+ strlen(grantor),
+ system_charset_info))
+ DBUG_RETURN(TRUE);
+
+ DBUG_RETURN(FALSE);
+ }
+};
#define FIRST_NON_YN_FIELD 26
@@ -168,10 +516,29 @@ static uchar* acl_entry_get_key(acl_entry *entry, size_t *length,
return (uchar*) entry->key;
}
-#define IP_ADDR_STRLEN (3+1+3+1+3+1+3)
-#define ACL_KEY_LENGTH (IP_ADDR_STRLEN+1+NAME_LEN+1+USERNAME_LENGTH+1)
+#define IP_ADDR_STRLEN (3 + 1 + 3 + 1 + 3 + 1 + 3)
+#define ACL_KEY_LENGTH (IP_ADDR_STRLEN + 1 + NAME_LEN + \
+ 1 + USERNAME_LENGTH + 1)
-static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
+#if defined(HAVE_OPENSSL)
+/*
+ Without SSL the handshake consists of one packet. This packet
+ has both client capabilities and scrambled password.
+ With SSL the handshake might consist of two packets. If the first
+ packet (client capabilities) has CLIENT_SSL flag set, we have to
+ switch to SSL and read the second packet. The scrambled password
+ is in the second packet and client_capabilities field will be ignored.
+ Maybe it is better to accept flags other than CLIENT_SSL from the
+ second packet?
+*/
+#define SSL_HANDSHAKE_SIZE 2
+#define NORMAL_HANDSHAKE_SIZE 6
+#define MIN_HANDSHAKE_SIZE 2
+#else
+#define MIN_HANDSHAKE_SIZE 6
+#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
+
+static DYNAMIC_ARRAY acl_hosts, acl_users, acl_dbs, acl_proxy_users;
static MEM_ROOT mem, memex;
static bool initialized=0;
static bool allow_all_hosts=1;
@@ -189,9 +556,6 @@ static ACL_USER *find_acl_user(const char *host, const char *user,
static bool update_user_table(THD *thd, TABLE *table,
const char *host, const char *user,
const char *new_password, uint new_password_len);
-static void update_hostname(acl_host_and_ip *host, const char *hostname);
-static bool compare_hostname(const acl_host_and_ip *host,const char *hostname,
- const char *ip);
static my_bool acl_load(THD *thd, TABLE_LIST *tables);
static my_bool grant_load(THD *thd, TABLE_LIST *tables);
static inline void get_grantor(THD *thd, char* grantor);
@@ -220,25 +584,6 @@ set_user_salt(ACL_USER *acl_user, const char *password, uint password_len)
}
/*
- This after_update function is used when user.password is less than
- SCRAMBLE_LENGTH bytes.
-*/
-
-static void restrict_update_of_old_passwords_var(THD *thd,
- enum_var_type var_type)
-{
- if (var_type == OPT_GLOBAL)
- {
- pthread_mutex_lock(&LOCK_global_system_variables);
- global_system_variables.old_passwords= 1;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- thd->variables.old_passwords= 1;
-}
-
-
-/*
Initialize structures responsible for user/db-level privilege checking and
load privilege information for them from tables in the 'mysql' database.
@@ -263,9 +608,22 @@ my_bool acl_init(bool dont_read_acl_tables)
DBUG_ENTER("acl_init");
acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0,
- (hash_get_key) acl_entry_get_key,
- (hash_free_key) free,
+ (my_hash_get_key) acl_entry_get_key,
+ (my_hash_free_key) free,
&my_charset_utf8_bin);
+
+ /*
+ cache built-in native authentication plugins,
+ to avoid hash searches and a global mutex lock on every connect
+ */
+ native_password_plugin= my_plugin_lock_by_name(0,
+ &native_password_plugin_name, MYSQL_AUTHENTICATION_PLUGIN);
+ old_password_plugin= my_plugin_lock_by_name(0,
+ &old_password_plugin_name, MYSQL_AUTHENTICATION_PLUGIN);
+
+ if (!native_password_plugin || !old_password_plugin)
+ DBUG_RETURN(1);
+
if (dont_read_acl_tables)
{
DBUG_RETURN(0); /* purecov: tested */
@@ -278,7 +636,6 @@ my_bool acl_init(bool dont_read_acl_tables)
DBUG_RETURN(1); /* purecov: inspected */
thd->thread_stack= (char*) &thd;
thd->store_globals();
- lex_start(thd);
/*
It is safe to call acl_reload() since acl_* arrays and hashes which
will be freed there are global static objects and thus are initialized
@@ -291,6 +648,37 @@ my_bool acl_init(bool dont_read_acl_tables)
DBUG_RETURN(return_val);
}
+/**
+ Choose from either native or old password plugins when assigning a password
+*/
+
+static bool
+set_user_plugin (ACL_USER *user, int password_len)
+{
+ switch (password_len)
+ {
+ case 0: /* no password */
+ case SCRAMBLED_PASSWORD_CHAR_LENGTH:
+ user->plugin= native_password_plugin_name;
+ return FALSE;
+ case SCRAMBLED_PASSWORD_CHAR_LENGTH_323:
+ user->plugin= old_password_plugin_name;
+ return FALSE;
+ case 45: /* 4.1: to be removed */
+ sql_print_warning("Found 4.1.0 style password for user '%s@%s'. "
+ "Ignoring user. "
+ "You should change password for this user.",
+ user->user ? user->user : "",
+ user->host.hostname ? user->host.hostname : "");
+ return TRUE;
+ default:
+ sql_print_warning("Found invalid password for user: '%s@%s'; "
+ "Ignoring user", user->user ? user->user : "",
+ user->host.hostname ? user->host.hostname : "");
+ return TRUE;
+ }
+}
+
/*
Initialize structures responsible for user/db-level privilege checking
@@ -328,7 +716,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0,
FALSE);
table->use_all_columns();
- VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50));
+ (void) my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50);
while (!(read_record_info.read_record(&read_record_info)))
{
ACL_HOST host;
@@ -368,7 +756,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL;
}
#endif
- VOID(push_dynamic(&acl_hosts,(uchar*) &host));
+ (void) push_dynamic(&acl_hosts,(uchar*) &host);
}
my_qsort((uchar*) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
sizeof(ACL_HOST),(qsort_cmp) acl_compare);
@@ -377,7 +765,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0,FALSE);
table->use_all_columns();
- VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100));
+ (void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100);
password_length= table->field[2]->field_length /
table->field[2]->charset()->mbmaxlen;
if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
@@ -390,23 +778,23 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
DBUG_PRINT("info",("user table fields: %d, password length: %d",
table->s->fields, password_length));
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
{
if (opt_secure_auth)
{
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
sql_print_error("Fatal error: mysql.user table is in old format, "
"but server started with --secure-auth option.");
goto end;
}
- sys_old_passwords.after_update= restrict_update_of_old_passwords_var;
+ mysql_user_table_is_in_short_password_format= true;
if (global_system_variables.old_passwords)
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
else
{
global_system_variables.old_passwords= 1;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
sql_print_warning("mysql.user table is not updated to new password format; "
"Disabling new password usage until "
"mysql_fix_privilege_tables is run");
@@ -415,14 +803,15 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
}
else
{
- sys_old_passwords.after_update= 0;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_user_table_is_in_short_password_format= false;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
}
allow_all_hosts=0;
while (!(read_record_info.read_record(&read_record_info)))
{
ACL_USER user;
+ bzero(&user, sizeof(user));
update_hostname(&user.host, get_field(&mem, table->field[0]));
user.user= get_field(&mem, table->field[1]);
if (check_no_resolve && hostname_requires_resolving(user.host.hostname))
@@ -434,27 +823,15 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
continue;
}
- const char *password= get_field(thd->mem_root, table->field[2]);
+ char *password= get_field(&mem, table->field[2]);
uint password_len= password ? strlen(password) : 0;
+ user.auth_string.str= password ? password : const_cast<char*>("");
+ user.auth_string.length= password_len;
set_user_salt(&user, password, password_len);
- if (user.salt_len == 0 && password_len != 0)
- {
- switch (password_len) {
- case 45: /* 4.1: to be removed */
- sql_print_warning("Found 4.1 style password for user '%s@%s'. "
- "Ignoring user. "
- "You should change password for this user.",
- user.user ? user.user : "",
- user.host.hostname ? user.host.hostname : "");
- break;
- default:
- sql_print_warning("Found invalid password for user: '%s@%s'; "
- "Ignoring user", user.user ? user.user : "",
- user.host.hostname ? user.host.hostname : "");
- break;
- }
- }
- else // password is correct
+
+ if (set_user_plugin(&user, password_len))
+ continue;
+
{
uint next_field;
user.access= get_access(table,3,&next_field) & GLOBAL_ACLS;
@@ -531,13 +908,43 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
ptr= get_field(thd->mem_root, table->field[next_field++]);
user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
}
- else
- user.user_resource.user_conn= 0;
+
+ if (table->s->fields >= 41)
+ {
+ /* We may have plugin & auth_String fields */
+ char *tmpstr= get_field(&mem, table->field[next_field++]);
+ if (tmpstr)
+ {
+ if (user.auth_string.length)
+ {
+ sql_print_warning("'user' entry '%s@%s' has both a password "
+ "and an authentication plugin specified. The "
+ "password will be ignored.",
+ user.user ? user.user : "",
+ user.host.hostname ? user.host.hostname : "");
+ }
+ if (my_strcasecmp(system_charset_info, tmpstr,
+ native_password_plugin_name.str) == 0)
+ user.plugin= native_password_plugin_name;
+ else
+ if (my_strcasecmp(system_charset_info, tmpstr,
+ old_password_plugin_name.str) == 0)
+ user.plugin= old_password_plugin_name;
+ else
+ {
+ user.plugin.str= tmpstr;
+ user.plugin.length= strlen(tmpstr);
+ }
+ user.auth_string.str= get_field(&mem, table->field[next_field++]);
+ if (!user.auth_string.str)
+ user.auth_string.str= const_cast<char*>("");
+ user.auth_string.length= strlen(user.auth_string.str);
+ }
+ }
}
else
{
user.ssl_type=SSL_TYPE_NONE;
- bzero((char *)&(user.user_resource),sizeof(user.user_resource));
#ifndef TO_BE_REMOVED
if (table->s->fields <= 13)
{ // Without grant
@@ -552,7 +959,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
user.access|= SUPER_ACL | EXECUTE_ACL;
#endif
}
- VOID(push_dynamic(&acl_users,(uchar*) &user));
+ (void) push_dynamic(&acl_users,(uchar*) &user);
if (!user.host.hostname ||
(user.host.hostname[0] == wild_many && !user.host.hostname[1]))
allow_all_hosts=1; // Anyone can connect
@@ -565,7 +972,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0,FALSE);
table->use_all_columns();
- VOID(my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100));
+ (void) my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100);
while (!(read_record_info.read_record(&read_record_info)))
{
ACL_DB db;
@@ -615,12 +1022,44 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
}
#endif
- VOID(push_dynamic(&acl_dbs,(uchar*) &db));
+ (void) push_dynamic(&acl_dbs,(uchar*) &db);
}
my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
sizeof(ACL_DB),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_dbs);
+
+ (void) my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER),
+ 50, 100);
+ if (tables[3].table)
+ {
+ init_read_record(&read_record_info, thd, table= tables[3].table, NULL, 1,
+ 0, FALSE);
+ table->use_all_columns();
+ while (!(read_record_info.read_record(&read_record_info)))
+ {
+ ACL_PROXY_USER proxy;
+ proxy.init(table, &mem);
+ if (proxy.check_validity(check_no_resolve))
+ continue;
+ if (push_dynamic(&acl_proxy_users, (uchar*) &proxy))
+ {
+ end_read_record(&read_record_info);
+ goto end;
+ }
+ }
+ my_qsort((uchar*) dynamic_element(&acl_proxy_users, 0, ACL_PROXY_USER*),
+ acl_proxy_users.elements,
+ sizeof(ACL_PROXY_USER), (qsort_cmp) acl_compare);
+ end_read_record(&read_record_info);
+ }
+ else
+ {
+ sql_print_error("Missing system table mysql.proxies_priv; "
+ "please run mysql_upgrade to create it");
+ }
+ freeze_size(&acl_proxy_users);
+
init_check_host();
initialized=1;
@@ -639,7 +1078,10 @@ void acl_free(bool end)
delete_dynamic(&acl_users);
delete_dynamic(&acl_dbs);
delete_dynamic(&acl_wild_hosts);
- hash_free(&acl_check_hosts);
+ delete_dynamic(&acl_proxy_users);
+ my_hash_free(&acl_check_hosts);
+ plugin_unlock(0, native_password_plugin);
+ plugin_unlock(0, old_password_plugin);
if (!end)
acl_cache->clear(1); /* purecov: inspected */
else
@@ -671,65 +1113,65 @@ void acl_free(bool end)
my_bool acl_reload(THD *thd)
{
- TABLE_LIST tables[3];
- DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
+ TABLE_LIST tables[4];
+ DYNAMIC_ARRAY old_acl_hosts, old_acl_users, old_acl_dbs, old_acl_proxy_users;
MEM_ROOT old_mem;
bool old_initialized;
my_bool return_val= TRUE;
DBUG_ENTER("acl_reload");
- if (thd->locked_tables)
- { // Can't have locked tables here
- thd->lock=thd->locked_tables;
- thd->locked_tables=0;
- close_thread_tables(thd);
- }
-
/*
To avoid deadlocks we should obtain table locks before
obtaining acl_cache->lock mutex.
*/
- bzero((char*) tables, sizeof(tables));
- tables[0].alias= tables[0].table_name= (char*) "host";
- tables[1].alias= tables[1].table_name= (char*) "user";
- tables[2].alias= tables[2].table_name= (char*) "db";
- tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
- tables[0].next_local= tables[0].next_global= tables+1;
- tables[1].next_local= tables[1].next_global= tables+2;
- tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
- tables[0].skip_temporary= tables[1].skip_temporary=
- tables[2].skip_temporary= TRUE;
-
- if (simple_open_n_lock_tables(thd, tables))
+ tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("host"), "host", TL_READ);
+ tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("user"), "user", TL_READ);
+ tables[2].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("db"), "db", TL_READ);
+ tables[3].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("proxies_priv"),
+ "proxies_priv", TL_READ);
+ tables[0].next_local= tables[0].next_global= tables + 1;
+ tables[1].next_local= tables[1].next_global= tables + 2;
+ tables[2].next_local= tables[2].next_global= tables + 3;
+ tables[0].open_type= tables[1].open_type= tables[2].open_type=
+ tables[3].open_type= OT_BASE_ONLY;
+ tables[3].open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
+
+ if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{
/*
Execution might have been interrupted; only print the error message
if an error condition has been raised.
*/
- if (thd->main_da.is_error())
+ if (thd->stmt_da->is_error())
sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
- thd->main_da.message());
+ thd->stmt_da->message());
goto end;
}
if ((old_initialized=initialized))
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_mutex_lock(&acl_cache->lock);
- old_acl_hosts=acl_hosts;
- old_acl_users=acl_users;
- old_acl_dbs=acl_dbs;
- old_mem=mem;
+ old_acl_hosts= acl_hosts;
+ old_acl_users= acl_users;
+ old_acl_proxy_users= acl_proxy_users;
+ old_acl_dbs= acl_dbs;
+ old_mem= mem;
delete_dynamic(&acl_wild_hosts);
- hash_free(&acl_check_hosts);
+ my_hash_free(&acl_check_hosts);
if ((return_val= acl_load(thd, tables)))
{ // Error. Revert to old list
DBUG_PRINT("error",("Reverting to old privileges"));
acl_free(); /* purecov: inspected */
- acl_hosts=old_acl_hosts;
- acl_users=old_acl_users;
- acl_dbs=old_acl_dbs;
- mem=old_mem;
+ acl_hosts= old_acl_hosts;
+ acl_users= old_acl_users;
+ acl_proxy_users= old_acl_proxy_users;
+ acl_dbs= old_acl_dbs;
+ mem= old_mem;
init_check_host();
}
else
@@ -737,12 +1179,13 @@ my_bool acl_reload(THD *thd)
free_root(&old_mem,MYF(0));
delete_dynamic(&old_acl_hosts);
delete_dynamic(&old_acl_users);
+ delete_dynamic(&old_acl_proxy_users);
delete_dynamic(&old_acl_dbs);
}
if (old_initialized)
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
end:
- close_thread_tables(thd);
+ close_mysql_tables(thd);
DBUG_RETURN(return_val);
}
@@ -842,246 +1285,10 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
/*
- Seek ACL entry for a user, check password, SSL cypher, and if
- everything is OK, update THD user data and USER_RESOURCES struct.
-
- IMPLEMENTATION
- This function does not check if the user has any sensible privileges:
- only user's existence and validity is checked.
- Note, that entire operation is protected by acl_cache_lock.
+ Gets user credentials without authentication and resource limit checks.
SYNOPSIS
acl_getroot()
- thd thread handle. If all checks are OK,
- thd->security_ctx->priv_user/master_access are updated.
- thd->security_ctx->host/ip/user are used for checks.
- mqh user resources; on success mqh is reset, else
- unchanged
- passwd scrambled & crypted password, received from client
- (to check): thd->scramble or thd->scramble_323 is
- used to decrypt passwd, so they must contain
- original random string,
- passwd_len length of passwd, must be one of 0, 8,
- SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
- 'thd' and 'mqh' are updated on success; other params are IN.
-
- RETURN VALUE
- 0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are
- updated
- 1 user not found or authentication failure
- 2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format.
- -1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format.
-*/
-
-int acl_getroot(THD *thd, USER_RESOURCES *mqh,
- const char *passwd, uint passwd_len)
-{
- ulong user_access= NO_ACCESS;
- int res= 1;
- ACL_USER *acl_user= 0;
- Security_context *sctx= thd->security_ctx;
- DBUG_ENTER("acl_getroot");
-
- if (!initialized)
- {
- /*
- here if mysqld's been started with --skip-grant-tables option.
- */
- sctx->skip_grants();
- bzero((char*) mqh, sizeof(*mqh));
- DBUG_RETURN(0);
- }
-
- VOID(pthread_mutex_lock(&acl_cache->lock));
-
- /*
- Find acl entry in user database. Note, that find_acl_user is not the same,
- because it doesn't take into account the case when user is not empty,
- but acl_user->user is empty
- */
-
- for (uint i=0 ; i < acl_users.elements ; i++)
- {
- ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
- if (!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user))
- {
- if (compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip))
- {
- /* check password: it should be empty or valid */
- if (passwd_len == acl_user_tmp->salt_len)
- {
- if (acl_user_tmp->salt_len == 0 ||
- (acl_user_tmp->salt_len == SCRAMBLE_LENGTH ?
- check_scramble(passwd, thd->scramble, acl_user_tmp->salt) :
- check_scramble_323(passwd, thd->scramble,
- (ulong *) acl_user_tmp->salt)) == 0)
- {
- acl_user= acl_user_tmp;
- res= 0;
- }
- }
- else if (passwd_len == SCRAMBLE_LENGTH &&
- acl_user_tmp->salt_len == SCRAMBLE_LENGTH_323)
- res= -1;
- else if (passwd_len == SCRAMBLE_LENGTH_323 &&
- acl_user_tmp->salt_len == SCRAMBLE_LENGTH)
- res= 2;
- /* linear search complete: */
- break;
- }
- }
- }
- /*
- This was moved to separate tree because of heavy HAVE_OPENSSL case.
- If acl_user is not null, res is 0.
- */
-
- if (acl_user)
- {
- /* OK. User found and password checked continue validation */
-#ifdef HAVE_OPENSSL
- Vio *vio=thd->net.vio;
- SSL *ssl= (SSL*) vio->ssl_arg;
- X509 *cert;
-#endif
-
- /*
- At this point we know that user is allowed to connect
- from given host by given username/password pair. Now
- we check if SSL is required, if user is using SSL and
- if X509 certificate attributes are OK
- */
- switch (acl_user->ssl_type) {
- case SSL_TYPE_NOT_SPECIFIED: // Impossible
- case SSL_TYPE_NONE: // SSL is not required
- user_access= acl_user->access;
- break;
-#ifdef HAVE_OPENSSL
- case SSL_TYPE_ANY: // Any kind of SSL is ok
- if (vio_type(vio) == VIO_TYPE_SSL)
- user_access= acl_user->access;
- break;
- case SSL_TYPE_X509: /* Client should have any valid certificate. */
- /*
- Connections with non-valid certificates are dropped already
- in sslaccept() anyway, so we do not check validity here.
-
- We need to check for absence of SSL because without SSL
- we should reject connection.
- */
- if (vio_type(vio) == VIO_TYPE_SSL &&
- SSL_get_verify_result(ssl) == X509_V_OK &&
- (cert= SSL_get_peer_certificate(ssl)))
- {
- user_access= acl_user->access;
- X509_free(cert);
- }
- break;
- case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
- /*
- We do not check for absence of SSL because without SSL it does
- not pass all checks here anyway.
- If cipher name is specified, we compare it to actual cipher in
- use.
- */
- if (vio_type(vio) != VIO_TYPE_SSL ||
- SSL_get_verify_result(ssl) != X509_V_OK)
- break;
- if (acl_user->ssl_cipher)
- {
- DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
- acl_user->ssl_cipher,SSL_get_cipher(ssl)));
- if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl)))
- user_access= acl_user->access;
- else
- {
- if (global_system_variables.log_warnings)
- sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'",
- acl_user->ssl_cipher,
- SSL_get_cipher(ssl));
- break;
- }
- }
- /* Prepare certificate (if exists) */
- DBUG_PRINT("info",("checkpoint 1"));
- if (!(cert= SSL_get_peer_certificate(ssl)))
- {
- user_access=NO_ACCESS;
- break;
- }
- DBUG_PRINT("info",("checkpoint 2"));
- /* If X509 issuer is specified, we check it... */
- if (acl_user->x509_issuer)
- {
- DBUG_PRINT("info",("checkpoint 3"));
- char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
- DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
- acl_user->x509_issuer, ptr));
- if (strcmp(acl_user->x509_issuer, ptr))
- {
- if (global_system_variables.log_warnings)
- sql_print_information("X509 issuer mismatch: should be '%s' "
- "but is '%s'", acl_user->x509_issuer, ptr);
- free(ptr);
- X509_free(cert);
- user_access=NO_ACCESS;
- break;
- }
- user_access= acl_user->access;
- free(ptr);
- }
- DBUG_PRINT("info",("checkpoint 4"));
- /* X509 subject is specified, we check it .. */
- if (acl_user->x509_subject)
- {
- char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
- DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
- acl_user->x509_subject, ptr));
- if (strcmp(acl_user->x509_subject,ptr))
- {
- if (global_system_variables.log_warnings)
- sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
- acl_user->x509_subject, ptr);
- free(ptr);
- X509_free(cert);
- user_access=NO_ACCESS;
- break;
- }
- user_access= acl_user->access;
- free(ptr);
- }
- /* Deallocate the X509 certificate. */
- X509_free(cert);
- break;
-#else /* HAVE_OPENSSL */
- default:
- /*
- If we don't have SSL but SSL is required for this user the
- authentication should fail.
- */
- break;
-#endif /* HAVE_OPENSSL */
- }
- sctx->master_access= user_access;
- sctx->priv_user= acl_user->user ? sctx->user : (char *) "";
- *mqh= acl_user->user_resource;
-
- if (acl_user->host.hostname)
- strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME - 1);
- else
- *sctx->priv_host= 0;
- }
- VOID(pthread_mutex_unlock(&acl_cache->lock));
- DBUG_RETURN(res);
-}
-
-
-/*
- This is like acl_getroot() above, but it doesn't check password,
- and we don't care about the user resources.
-
- SYNOPSIS
- acl_getroot_no_password()
sctx Context which should be initialized
user user name
host host name
@@ -1093,13 +1300,13 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
TRUE Error
*/
-bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
- char *ip, char *db)
+bool acl_getroot(Security_context *sctx, char *user, char *host,
+ char *ip, char *db)
{
int res= 1;
uint i;
ACL_USER *acl_user= 0;
- DBUG_ENTER("acl_getroot_no_password");
+ DBUG_ENTER("acl_getroot");
DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
(host ? host : "(NULL)"), (ip ? ip : "(NULL)"),
@@ -1118,12 +1325,11 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
DBUG_RETURN(FALSE);
}
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_mutex_lock(&acl_cache->lock);
sctx->master_access= 0;
sctx->db_access= 0;
- sctx->priv_user= (char *) "";
- *sctx->priv_host= 0;
+ *sctx->priv_user= *sctx->priv_host= 0;
/*
Find acl entry in user database.
@@ -1165,14 +1371,18 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
}
}
sctx->master_access= acl_user->access;
- sctx->priv_user= acl_user->user ? user : (char *) "";
+
+ if (acl_user->user)
+ strmake(sctx->priv_user, user, USERNAME_LENGTH);
+ else
+ *sctx->priv_user= 0;
if (acl_user->host.hostname)
strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME - 1);
else
*sctx->priv_host= 0;
}
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
DBUG_RETURN(res);
}
@@ -1191,9 +1401,11 @@ static void acl_update_user(const char *user, const char *host,
const char *x509_issuer,
const char *x509_subject,
USER_RESOURCES *mqh,
- ulong privileges)
+ ulong privileges,
+ const LEX_STRING *plugin,
+ const LEX_STRING *auth)
{
- safe_mutex_assert_owner(&acl_cache->lock);
+ mysql_mutex_assert_owner(&acl_cache->lock);
for (uint i=0 ; i < acl_users.elements ; i++)
{
@@ -1205,6 +1417,14 @@ static void acl_update_user(const char *user, const char *host,
(acl_user->host.hostname &&
!my_strcasecmp(system_charset_info, host, acl_user->host.hostname)))
{
+ if (plugin->str[0])
+ {
+ acl_user->plugin.str= strmake_root(&mem, plugin->str, plugin->length);
+ acl_user->plugin.length= plugin->length;
+ acl_user->auth_string.str= auth->str ?
+ strmake_root(&mem, auth->str, auth->length) : const_cast<char*>("");
+ acl_user->auth_string.length= auth->length;
+ }
acl_user->access=privileges;
if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
acl_user->user_resource.questions=mqh->questions;
@@ -1241,14 +1461,32 @@ static void acl_insert_user(const char *user, const char *host,
const char *x509_issuer,
const char *x509_subject,
USER_RESOURCES *mqh,
- ulong privileges)
+ ulong privileges,
+ const LEX_STRING *plugin,
+ const LEX_STRING *auth)
{
ACL_USER acl_user;
- safe_mutex_assert_owner(&acl_cache->lock);
+ mysql_mutex_assert_owner(&acl_cache->lock);
acl_user.user=*user ? strdup_root(&mem,user) : 0;
update_hostname(&acl_user.host, *host ? strdup_root(&mem, host): 0);
+ if (plugin->str[0])
+ {
+ acl_user.plugin.str= strmake_root(&mem, plugin->str, plugin->length);
+ acl_user.plugin.length= plugin->length;
+ acl_user.auth_string.str= auth->str ?
+ strmake_root(&mem, auth->str, auth->length) : const_cast<char*>("");
+ acl_user.auth_string.length= auth->length;
+ }
+ else
+ {
+ acl_user.plugin= password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323 ?
+ old_password_plugin_name : native_password_plugin_name;
+ acl_user.auth_string.str= strmake_root(&mem, password, password_len);
+ acl_user.auth_string.length= password_len;
+ }
+
acl_user.access=privileges;
acl_user.user_resource = *mqh;
acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
@@ -1261,7 +1499,7 @@ static void acl_insert_user(const char *user, const char *host,
set_user_salt(&acl_user, password, password_len);
- VOID(push_dynamic(&acl_users,(uchar*) &acl_user));
+ (void) push_dynamic(&acl_users,(uchar*) &acl_user);
if (!acl_user.host.hostname ||
(acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]))
allow_all_hosts=1; // Anyone can connect /* purecov: tested */
@@ -1276,7 +1514,7 @@ static void acl_insert_user(const char *user, const char *host,
static void acl_update_db(const char *user, const char *host, const char *db,
ulong privileges)
{
- safe_mutex_assert_owner(&acl_cache->lock);
+ mysql_mutex_assert_owner(&acl_cache->lock);
for (uint i=0 ; i < acl_dbs.elements ; i++)
{
@@ -1321,13 +1559,13 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
ulong privileges)
{
ACL_DB acl_db;
- safe_mutex_assert_owner(&acl_cache->lock);
+ mysql_mutex_assert_owner(&acl_cache->lock);
acl_db.user=strdup_root(&mem,user);
update_hostname(&acl_db.host, *host ? strdup_root(&mem,host) : 0);
acl_db.db=strdup_root(&mem,db);
acl_db.access=privileges;
acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
- VOID(push_dynamic(&acl_dbs,(uchar*) &acl_db));
+ (void) push_dynamic(&acl_dbs,(uchar*) &acl_db);
my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
sizeof(ACL_DB),(qsort_cmp) acl_compare);
}
@@ -1351,7 +1589,7 @@ ulong acl_get(const char *host, const char *ip,
acl_entry *entry;
DBUG_ENTER("acl_get");
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_mutex_lock(&acl_cache->lock);
end=strmov((tmp_db=strmov(strmov(key, ip ? ip : "")+1,user)+1),db);
if (lower_case_table_names)
{
@@ -1363,7 +1601,7 @@ ulong acl_get(const char *host, const char *ip,
key_length)))
{
db_access=entry->access;
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
DBUG_PRINT("exit", ("access: 0x%lx", db_access));
DBUG_RETURN(db_access);
}
@@ -1417,7 +1655,7 @@ exit:
memcpy((uchar*) entry->key,key,key_length);
acl_cache->add(entry);
}
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
DBUG_PRINT("exit", ("access: 0x%lx", db_access & host_access));
DBUG_RETURN(db_access & host_access);
}
@@ -1433,10 +1671,11 @@ exit:
static void init_check_host(void)
{
DBUG_ENTER("init_check_host");
- VOID(my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
- acl_users.elements,1));
- VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0,
- (hash_get_key) check_get_key,0,0));
+ (void) my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
+ acl_users.elements,1);
+ (void) my_hash_init(&acl_check_hosts,system_charset_info,
+ acl_users.elements, 0, 0,
+ (my_hash_get_key) check_get_key, 0, 0);
if (!allow_all_hosts)
{
for (uint i=0 ; i < acl_users.elements ; i++)
@@ -1458,8 +1697,9 @@ static void init_check_host(void)
if (j == acl_wild_hosts.elements) // If new
(void) push_dynamic(&acl_wild_hosts,(uchar*) &acl_user->host);
}
- else if (!hash_search(&acl_check_hosts,(uchar*) acl_user->host.hostname,
- strlen(acl_user->host.hostname)))
+ else if (!my_hash_search(&acl_check_hosts,(uchar*)
+ acl_user->host.hostname,
+ strlen(acl_user->host.hostname)))
{
if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user))
{ // End of memory
@@ -1486,7 +1726,7 @@ static void init_check_host(void)
void rebuild_check_host(void)
{
delete_dynamic(&acl_wild_hosts);
- hash_free(&acl_check_hosts);
+ my_hash_free(&acl_check_hosts);
init_check_host();
}
@@ -1497,12 +1737,12 @@ bool acl_check_host(const char *host, const char *ip)
{
if (allow_all_hosts)
return 0;
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_mutex_lock(&acl_cache->lock);
- if ((host && hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) ||
- (ip && hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip))))
+ if ((host && my_hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) ||
+ (ip && my_hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip))))
{
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
return 0; // Found host
}
for (uint i=0 ; i < acl_wild_hosts.elements ; i++)
@@ -1510,11 +1750,11 @@ bool acl_check_host(const char *host, const char *ip)
acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,i,acl_host_and_ip*);
if (compare_hostname(acl, host, ip))
{
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
return 0; // Host ok
}
}
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
return 1; // Host is not allowed
}
@@ -1550,7 +1790,7 @@ int check_change_password(THD *thd, const char *host, const char *user,
my_strcasecmp(system_charset_info, host,
thd->security_ctx->priv_host)))
{
- if (check_access(thd, UPDATE_ACL, "mysql",0,1,0,0))
+ if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 0))
return(1);
}
if (!thd->slave_thread && !thd->security_ctx->user[0])
@@ -1604,9 +1844,7 @@ bool change_password(THD *thd, const char *host, const char *user,
if (check_change_password(thd, host, user, new_password, new_password_len))
DBUG_RETURN(1);
- bzero((char*) &tables, sizeof(tables));
- tables.alias= tables.table_name= (char*) "user";
- tables.db= (char*) "mysql";
+ tables.init_one_table("mysql", 5, "user", 4, "user", TL_WRITE);
#ifdef HAVE_REPLICATION
/*
@@ -1625,8 +1863,7 @@ bool change_password(THD *thd, const char *host, const char *user,
DBUG_RETURN(0);
}
#endif
-
- if (!(table= open_ltable(thd, &tables, TL_WRITE, 0)))
+ if (!(table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
DBUG_RETURN(1);
/*
@@ -1634,31 +1871,41 @@ bool change_password(THD *thd, const char *host, const char *user,
row-based replication. The flag will be reset at the end of the
statement.
*/
- if ((save_binlog_row_based= thd->current_stmt_binlog_row_based))
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_mutex_lock(&acl_cache->lock);
ACL_USER *acl_user;
if (!(acl_user= find_acl_user(host, user, TRUE)))
{
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
goto end;
}
+
+ if (my_strcasecmp(system_charset_info, acl_user->plugin.str,
+ native_password_plugin_name.str) &&
+ my_strcasecmp(system_charset_info, acl_user->plugin.str,
+ old_password_plugin_name.str))
+ {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SET_PASSWORD_AUTH_PLUGIN, ER(ER_SET_PASSWORD_AUTH_PLUGIN));
+ }
/* update loaded acl entry: */
set_user_salt(acl_user, new_password, new_password_len);
+ set_user_plugin(acl_user, new_password_len);
if (update_user_table(thd, table,
acl_user->host.hostname ? acl_user->host.hostname : "",
acl_user->user ? acl_user->user : "",
new_password, new_password_len))
{
- VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
+ mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */
goto end;
}
acl_cache->clear(1); // Clear locked hostname cache
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
result= 0;
if (mysql_bin_log.is_open())
{
@@ -1667,16 +1914,16 @@ bool change_password(THD *thd, const char *host, const char *user,
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password);
thd->clear_error();
- result= thd->binlog_query(THD::MYSQL_QUERY_TYPE, buff, query_length,
- FALSE, FALSE, 0);
+ result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length,
+ FALSE, FALSE, FALSE, 0);
}
end:
- close_thread_tables(thd);
+ close_mysql_tables(thd);
/* Restore the state of binlog format */
- DBUG_ASSERT(!thd->current_stmt_binlog_row_based);
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
if (save_binlog_row_based)
- thd->set_current_stmt_binlog_row_based();
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result);
}
@@ -1703,9 +1950,9 @@ bool is_acl_user(const char *host, const char *user)
if (!initialized)
return TRUE;
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_mutex_lock(&acl_cache->lock);
res= find_acl_user(host, user, TRUE) != NULL;
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
return res;
}
@@ -1720,7 +1967,7 @@ find_acl_user(const char *host, const char *user, my_bool exact)
DBUG_ENTER("find_acl_user");
DBUG_PRINT("enter",("host: '%s' user: '%s'",host,user));
- safe_mutex_assert_owner(&acl_cache->lock);
+ mysql_mutex_assert_owner(&acl_cache->lock);
for (uint i=0 ; i < acl_users.elements ; i++)
{
@@ -1803,24 +2050,83 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
(ip && !wild_compare(ip, host->hostname, 0)));
}
+/**
+ Check if the given host name needs to be resolved or not.
+ Host name has to be resolved if it actually contains *name*.
+
+ For example:
+ 192.168.1.1 --> FALSE
+ 192.168.1.0/255.255.255.0 --> FALSE
+ % --> FALSE
+ 192.168.1.% --> FALSE
+ AB% --> FALSE
+
+ AAAAFFFF --> TRUE (Hostname)
+ AAAA:FFFF:1234:5678 --> FALSE
+ ::1 --> FALSE
+
+ This function does not check if the given string is a valid host name or
+ not. It assumes that the argument is a valid host name.
+
+ @param hostname the string to check.
+
+ @return a flag telling if the argument needs to be resolved or not.
+ @retval TRUE the argument is a host name and needs to be resolved.
+ @retval FALSE the argument is either an IP address, or a patter and
+ should not be resolved.
+*/
+
bool hostname_requires_resolving(const char *hostname)
{
- char cur;
if (!hostname)
return FALSE;
- size_t namelen= strlen(hostname);
- size_t lhlen= strlen(my_localhost);
- if ((namelen == lhlen) &&
- !my_strnncoll(system_charset_info, (const uchar *)hostname, namelen,
- (const uchar *)my_localhost, strlen(my_localhost)))
+
+ /* Check if hostname is the localhost. */
+
+ size_t hostname_len= strlen(hostname);
+ size_t localhost_len= strlen(my_localhost);
+
+ if (hostname == my_localhost ||
+ (hostname_len == localhost_len &&
+ !my_strnncoll(system_charset_info,
+ (const uchar *) hostname, hostname_len,
+ (const uchar *) my_localhost, strlen(my_localhost))))
+ {
return FALSE;
- for (; (cur=*hostname); hostname++)
+ }
+
+ /*
+ If the string contains any of {':', '%', '_', '/'}, it is definitely
+ not a host name:
+ - ':' means that the string is an IPv6 address;
+ - '%' or '_' means that the string is a pattern;
+ - '/' means that the string is an IPv4 network address;
+ */
+
+ for (const char *p= hostname; *p; ++p)
{
- if ((cur != '%') && (cur != '_') && (cur != '.') && (cur != '/') &&
- ((cur < '0') || (cur > '9')))
- return TRUE;
+ switch (*p) {
+ case ':':
+ case '%':
+ case '_':
+ case '/':
+ return FALSE;
+ }
}
- return FALSE;
+
+ /*
+ Now we have to tell a host name (ab.cd, 12.ab) from an IPv4 address
+ (12.34.56.78). The assumption is that if the string contains only
+ digits and dots, it is an IPv4 address. Otherwise -- a host name.
+ */
+
+ for (const char *p= hostname; *p; ++p)
+ {
+ if (*p != '.' && !my_isdigit(&my_charset_latin1, *p))
+ return TRUE; /* a "letter" has been found. */
+ }
+
+ return FALSE; /* all characters are either dots or digits. */
}
@@ -1889,16 +2195,15 @@ static bool test_if_create_new_users(THD *thd)
{
TABLE_LIST tl;
ulong db_access;
- bzero((char*) &tl,sizeof(tl));
- tl.db= (char*) "mysql";
- tl.table_name= (char*) "user";
+ tl.init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("user"), "user", TL_WRITE);
create_new_users= 1;
db_access=acl_get(sctx->host, sctx->ip,
sctx->priv_user, tl.db, 0);
if (!(db_access & INSERT_ACL))
{
- if (check_grant(thd, INSERT_ACL, &tl, 0, UINT_MAX, 1))
+ if (check_grant(thd, INSERT_ACL, &tl, FALSE, UINT_MAX, TRUE))
create_new_users=0;
}
}
@@ -1923,7 +2228,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
LEX *lex= thd->lex;
DBUG_ENTER("replace_user_table");
- safe_mutex_assert_owner(&acl_cache->lock);
+ mysql_mutex_assert_owner(&acl_cache->lock);
if (combo.password.str && combo.password.str[0])
{
@@ -1968,7 +2273,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
see also test_if_create_new_users()
*/
- else if (!password_len && no_auto_create)
+ else if (!password_len && !combo.plugin.length && no_auto_create)
{
my_error(ER_PASSWORD_NO_MATCH, MYF(0), combo.user.str, combo.host.str);
goto end;
@@ -1979,6 +2284,15 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
thd->security_ctx->user, thd->security_ctx->host_or_ip);
goto end;
}
+ else if (combo.plugin.str[0])
+ {
+ if (!plugin_is_ready(&combo.plugin, MYSQL_AUTHENTICATION_PLUGIN))
+ {
+ my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), combo.plugin.str);
+ goto end;
+ }
+ }
+
old_row_exists = 0;
restore_record(table,s->default_values);
table->field[0]->store(combo.host.str,combo.host.length,
@@ -1992,7 +2306,14 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
{
old_row_exists = 1;
store_record(table,record[1]); // Save copy for update
- if (combo.password.str) // If password given
+ /* what == 'N' means revoke */
+ if (combo.plugin.length && what != 'N')
+ {
+ my_error(ER_GRANT_PLUGIN_USER_EXISTS, MYF(0), combo.user.length,
+ combo.user.str);
+ goto end;
+ }
+ if (combo.password.str) // If password given
table->field[2]->store(password, password_len, system_charset_info);
else if (!rights && !revoke_grant &&
lex->ssl_type == SSL_TYPE_NOT_SPECIFIED &&
@@ -2073,7 +2394,25 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
(mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
table->field[next_field+3]->store((longlong) mqh.user_conn, TRUE);
mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour;
+
+ next_field+= 4;
+ if (combo.plugin.str[0])
+ {
+ if (table->s->fields >= 41 && combo.plugin.str[0])
+ {
+ table->field[next_field]->store(combo.plugin.str, combo.plugin.length,
+ system_charset_info);
+ table->field[next_field + 1]->store(combo.auth.str, combo.auth.length,
+ system_charset_info);
+ }
+ else
+ {
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), "plugin", "mysql.user");
+ goto end;
+ }
+ }
}
+
if (old_row_exists)
{
/*
@@ -2117,7 +2456,9 @@ end:
lex->x509_issuer,
lex->x509_subject,
&lex->mqh,
- rights);
+ rights,
+ &combo.plugin,
+ &combo.auth);
else
acl_insert_user(combo.user.str, combo.host.str, password, password_len,
lex->ssl_type,
@@ -2125,7 +2466,9 @@ end:
lex->x509_issuer,
lex->x509_subject,
&lex->mqh,
- rights);
+ rights,
+ &combo.plugin,
+ &combo.auth);
}
DBUG_RETURN(error);
}
@@ -2240,6 +2583,164 @@ abort:
}
+static void
+acl_update_proxy_user(ACL_PROXY_USER *new_value, bool is_revoke)
+{
+ mysql_mutex_assert_owner(&acl_cache->lock);
+
+ DBUG_ENTER("acl_update_proxy_user");
+ for (uint i= 0; i < acl_proxy_users.elements; i++)
+ {
+ ACL_PROXY_USER *acl_user=
+ dynamic_element(&acl_proxy_users, i, ACL_PROXY_USER *);
+
+ if (acl_user->pk_equals(new_value))
+ {
+ if (is_revoke)
+ {
+ DBUG_PRINT("info", ("delting ACL_PROXY_USER"));
+ delete_dynamic_element(&acl_proxy_users, i);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("updating ACL_PROXY_USER"));
+ acl_user->set_data(new_value);
+ }
+ break;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+static void
+acl_insert_proxy_user(ACL_PROXY_USER *new_value)
+{
+ DBUG_ENTER("acl_insert_proxy_user");
+ mysql_mutex_assert_owner(&acl_cache->lock);
+ (void) push_dynamic(&acl_proxy_users, (uchar *) new_value);
+ my_qsort((uchar*) dynamic_element(&acl_proxy_users, 0, ACL_PROXY_USER *),
+ acl_proxy_users.elements,
+ sizeof(ACL_PROXY_USER), (qsort_cmp) acl_compare);
+ DBUG_VOID_RETURN;
+}
+
+
+static int
+replace_proxies_priv_table(THD *thd, TABLE *table, const LEX_USER *user,
+ const LEX_USER *proxied_user, bool with_grant_arg,
+ bool revoke_grant)
+{
+ bool old_row_exists= 0;
+ int error;
+ uchar user_key[MAX_KEY_LENGTH];
+ ACL_PROXY_USER new_grant;
+ char grantor[USER_HOST_BUFF_SIZE];
+
+ DBUG_ENTER("replace_proxies_priv_table");
+
+ if (!initialized)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
+ DBUG_RETURN(-1);
+ }
+
+ /* Check if there is such a user in user table in memory? */
+ if (!find_acl_user(user->host.str,user->user.str, FALSE))
+ {
+ my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ table->use_all_columns();
+ ACL_PROXY_USER::store_pk (table, &user->host, &user->user,
+ &proxied_user->host, &proxied_user->user);
+
+ key_copy(user_key, table->record[0], table->key_info,
+ table->key_info->key_length);
+
+ get_grantor(thd, grantor);
+
+ table->file->ha_index_init(0, 1);
+ if (table->file->index_read_map(table->record[0], user_key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
+ {
+ DBUG_PRINT ("info", ("Row not found"));
+ if (revoke_grant)
+ { // no row, no revoke
+ my_error(ER_NONEXISTING_GRANT, MYF(0), user->user.str, user->host.str);
+ goto abort;
+ }
+ old_row_exists= 0;
+ restore_record(table, s->default_values);
+ ACL_PROXY_USER::store_data_record(table, &user->host, &user->user,
+ &proxied_user->host,
+ &proxied_user->user,
+ with_grant_arg,
+ grantor);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Row found"));
+ old_row_exists= 1;
+ store_record(table, record[1]);
+ }
+
+ if (old_row_exists)
+ {
+ /* update old existing row */
+ if (!revoke_grant)
+ {
+ if ((error= table->file->ha_update_row(table->record[1],
+ table->record[0])) &&
+ error != HA_ERR_RECORD_IS_THE_SAME)
+ goto table_error; /* purecov: inspected */
+ }
+ else
+ {
+ if ((error= table->file->ha_delete_row(table->record[1])))
+ goto table_error; /* purecov: inspected */
+ }
+ }
+ else if ((error= table->file->ha_write_row(table->record[0])))
+ {
+ DBUG_PRINT("info", ("error inserting the row"));
+ if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
+ goto table_error; /* purecov: inspected */
+ }
+
+ acl_cache->clear(1); // Clear privilege cache
+ if (old_row_exists)
+ {
+ new_grant.init(user->host.str, user->user.str,
+ proxied_user->host.str, proxied_user->user.str,
+ with_grant_arg);
+ acl_update_proxy_user(&new_grant, revoke_grant);
+ }
+ else
+ {
+ new_grant.init(&mem, user->host.str, user->user.str,
+ proxied_user->host.str, proxied_user->user.str,
+ with_grant_arg);
+ acl_insert_proxy_user(&new_grant);
+ }
+
+ table->file->ha_index_end();
+ DBUG_RETURN(0);
+
+ /* This could only happen if the grant tables got corrupted */
+table_error:
+ DBUG_PRINT("info", ("table error"));
+ table->file->print_error(error, MYF(0)); /* purecov: inspected */
+
+abort:
+ DBUG_PRINT("info", ("aborting replace_proxies_priv_table"));
+ table->file->ha_index_end();
+ DBUG_RETURN(-1);
+}
+
+
class GRANT_COLUMN :public Sql_alloc
{
public:
@@ -2330,8 +2831,8 @@ GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
const char *t, ulong p, ulong c)
:GRANT_NAME(h,d,u,t,p, FALSE), cols(c)
{
- (void) hash_init2(&hash_columns,4,system_charset_info,
- 0,0,0, (hash_get_key) get_key_column,0,0);
+ (void) my_hash_init2(&hash_columns,4,system_charset_info,
+ 0,0,0, (my_hash_get_key) get_key_column,0,0);
}
@@ -2374,15 +2875,15 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
if (!db || !tname)
{
/* Wrong table row; Ignore it */
- hash_clear(&hash_columns); /* allow for destruction */
+ my_hash_clear(&hash_columns); /* allow for destruction */
cols= 0;
return;
}
cols= (ulong) form->field[7]->val_int();
cols = fix_rights_for_column(cols);
- (void) hash_init2(&hash_columns,4,system_charset_info,
- 0,0,0, (hash_get_key) get_key_column,0,0);
+ (void) my_hash_init2(&hash_columns,4,system_charset_info,
+ 0,0,0, (my_hash_get_key) get_key_column,0,0);
if (cols)
{
uint key_prefix_len;
@@ -2439,7 +2940,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
GRANT_TABLE::~GRANT_TABLE()
{
- hash_free(&hash_columns);
+ my_hash_free(&hash_columns);
}
@@ -2453,7 +2954,7 @@ static uchar* get_grant_table(GRANT_NAME *buff, size_t *length,
void free_grant_table(GRANT_TABLE *grant_table)
{
- hash_free(&grant_table->hash_columns);
+ my_hash_free(&grant_table->hash_columns);
}
@@ -2474,11 +2975,11 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
len = (uint) (strmov(name_ptr, tname) - helping) + 1;
if (name_tolower)
my_casedn_str(files_charset_info, name_ptr);
- for (grant_name= (GRANT_NAME*) hash_first(name_hash, (uchar*) helping,
- len, &state);
+ for (grant_name= (GRANT_NAME*) my_hash_first(name_hash, (uchar*) helping,
+ len, &state);
grant_name ;
- grant_name= (GRANT_NAME*) hash_next(name_hash,(uchar*) helping,
- len, &state))
+ grant_name= (GRANT_NAME*) my_hash_next(name_hash,(uchar*) helping,
+ len, &state))
{
if (exact)
{
@@ -2522,7 +3023,8 @@ table_hash_search(const char *host, const char *ip, const char *db,
inline GRANT_COLUMN *
column_hash_search(GRANT_TABLE *t, const char *cname, uint length)
{
- return (GRANT_COLUMN*) hash_search(&t->hash_columns, (uchar*) cname,length);
+ return (GRANT_COLUMN*) my_hash_search(&t->hash_columns,
+ (uchar*) cname, length);
}
@@ -2706,7 +3208,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
goto end; /* purecov: deadcode */
}
if (grant_column)
- hash_delete(&g_t->hash_columns,(uchar*) grant_column);
+ my_hash_delete(&g_t->hash_columns,(uchar*) grant_column);
}
}
} while (!table->file->index_next(table->record[0]) &&
@@ -2844,7 +3346,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
else
{
- hash_delete(&column_priv_hash,(uchar*) grant_table);
+ my_hash_delete(&column_priv_hash,(uchar*) grant_table);
}
DBUG_RETURN(0);
@@ -2963,7 +3465,8 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
}
else
{
- hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*) grant_name);
+ my_hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*)
+ grant_name);
}
DBUG_RETURN(0);
@@ -3025,7 +3528,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
class LEX_COLUMN *column;
List_iterator <LEX_COLUMN> column_iter(columns);
- if (open_and_lock_tables(thd, table_list))
+ if (open_normal_and_derived_tables(thd, table_list, 0))
DBUG_RETURN(TRUE);
while ((column = column_iter++))
@@ -3047,7 +3550,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(TRUE);
column_priv|= column->rights;
}
- close_thread_tables(thd);
+ close_mysql_tables(thd);
}
else
{
@@ -3079,27 +3582,26 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
/* open the mysql.tables_priv and mysql.columns_priv tables */
- bzero((char*) &tables,sizeof(tables));
- tables[0].alias=tables[0].table_name= (char*) "user";
- tables[1].alias=tables[1].table_name= (char*) "tables_priv";
- tables[2].alias=tables[2].table_name= (char*) "columns_priv";
+ tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("user"), "user", TL_WRITE);
+ tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("tables_priv"),
+ "tables_priv", TL_WRITE);
+ tables[2].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("columns_priv"),
+ "columns_priv", TL_WRITE);
tables[0].next_local= tables[0].next_global= tables+1;
/* Don't open column table if we don't need it ! */
- tables[1].next_local=
- tables[1].next_global= ((column_priv ||
- (revoke_grant &&
- ((rights & COL_ACLS) || columns.elements)))
- ? tables+2 : 0);
- tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
- tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
+ if (column_priv || (revoke_grant && ((rights & COL_ACLS) || columns.elements)))
+ tables[1].next_local= tables[1].next_global= tables+2;
/*
This statement will be replicated as a statement, even when using
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
#ifdef HAVE_REPLICATION
/*
@@ -3116,7 +3618,9 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(FALSE);
}
}
@@ -3128,19 +3632,26 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
*/
Query_tables_list backup;
thd->lex->reset_n_backup_query_tables_list(&backup);
- if (simple_open_n_lock_tables(thd,tables))
+ /*
+ Restore Query_tables_list::sql_command value, which was reset
+ above, as the code writing query to the binary log assumes that
+ this value corresponds to the statement being executed.
+ */
+ thd->lex->sql_command= backup.sql_command;
+ if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{ // Should never happen
- close_thread_tables(thd); /* purecov: deadcode */
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(TRUE); /* purecov: deadcode */
}
if (!revoke_grant)
create_new_users= test_if_create_new_users(thd);
bool result= FALSE;
- rw_wrlock(&LOCK_grant);
- pthread_mutex_lock(&acl_cache->lock);
+ mysql_rwlock_wrlock(&LOCK_grant);
+ mysql_mutex_lock(&acl_cache->lock);
MEM_ROOT *old_root= thd->mem_root;
thd->mem_root= &memex;
grant_version++;
@@ -3212,8 +3723,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
column_priv= 0;
for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++)
{
- grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns,
- idx);
+ grant_column= (GRANT_COLUMN*)
+ my_hash_element(&grant_table->hash_columns, idx);
grant_column->rights&= ~rights; // Fix other columns
column_priv|= grant_column->rights;
}
@@ -3245,14 +3756,14 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
}
}
thd->mem_root= old_root;
- pthread_mutex_unlock(&acl_cache->lock);
+ mysql_mutex_unlock(&acl_cache->lock);
if (!result) /* success */
{
result= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
if (!result) /* success */
my_ok(thd);
@@ -3260,7 +3771,9 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
/* Tables are automatically closed */
thd->lex->restore_backup_query_tables_list(&backup);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result);
}
@@ -3313,20 +3826,19 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
/* open the mysql.user and mysql.procs_priv tables */
- bzero((char*) &tables,sizeof(tables));
- tables[0].alias=tables[0].table_name= (char*) "user";
- tables[1].alias=tables[1].table_name= (char*) "procs_priv";
+ tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("user"), "user", TL_WRITE);
+ tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("procs_priv"), "procs_priv", TL_WRITE);
tables[0].next_local= tables[0].next_global= tables+1;
- tables[0].lock_type=tables[1].lock_type=TL_WRITE;
- tables[0].db=tables[1].db=(char*) "mysql";
/*
This statement will be replicated as a statement, even when using
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
#ifdef HAVE_REPLICATION
/*
@@ -3343,24 +3855,27 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(FALSE);
}
}
#endif
- if (simple_open_n_lock_tables(thd,tables))
+ if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{ // Should never happen
- close_thread_tables(thd);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(TRUE);
}
if (!revoke_grant)
create_new_users= test_if_create_new_users(thd);
- rw_wrlock(&LOCK_grant);
- pthread_mutex_lock(&acl_cache->lock);
+ mysql_rwlock_wrlock(&LOCK_grant);
+ mysql_mutex_lock(&acl_cache->lock);
MEM_ROOT *old_root= thd->mem_root;
thd->mem_root= &memex;
@@ -3421,7 +3936,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
}
}
thd->mem_root= old_root;
- pthread_mutex_unlock(&acl_cache->lock);
+ mysql_mutex_unlock(&acl_cache->lock);
if (write_to_binlog)
{
@@ -3429,9 +3944,11 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
result= TRUE;
}
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
/* Tables are automatically closed */
DBUG_RETURN(result);
@@ -3439,10 +3956,10 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
- ulong rights, bool revoke_grant)
+ ulong rights, bool revoke_grant, bool is_proxy)
{
List_iterator <LEX_USER> str_list (list);
- LEX_USER *Str, *tmp_Str;
+ LEX_USER *Str, *tmp_Str, *proxied_user= NULL;
char tmp_db[NAME_LEN+1];
bool create_new_users=0;
TABLE_LIST tables[2];
@@ -3462,21 +3979,35 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
db=tmp_db;
}
- /* open the mysql.user and mysql.db tables */
- bzero((char*) &tables,sizeof(tables));
- tables[0].alias=tables[0].table_name=(char*) "user";
- tables[1].alias=tables[1].table_name=(char*) "db";
+ if (is_proxy)
+ {
+ DBUG_ASSERT(!db);
+ proxied_user= str_list++;
+ }
+
+ /* open the mysql.user and mysql.db or mysql.proxies_priv tables */
+ tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("user"), "user", TL_WRITE);
+ if (is_proxy)
+
+ tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("proxies_priv"),
+ "proxies_priv",
+ TL_WRITE);
+ else
+ tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("db"),
+ "db",
+ TL_WRITE);
tables[0].next_local= tables[0].next_global= tables+1;
- tables[0].lock_type=tables[1].lock_type=TL_WRITE;
- tables[0].db=tables[1].db=(char*) "mysql";
/*
This statement will be replicated as a statement, even when using
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
#ifdef HAVE_REPLICATION
/*
@@ -3493,17 +4024,20 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(FALSE);
}
}
#endif
- if (simple_open_n_lock_tables(thd,tables))
+ if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{ // This should never happen
- close_thread_tables(thd); /* purecov: deadcode */
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(TRUE); /* purecov: deadcode */
}
@@ -3511,8 +4045,8 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
create_new_users= test_if_create_new_users(thd);
/* go through users in user_list */
- rw_wrlock(&LOCK_grant);
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_rwlock_wrlock(&LOCK_grant);
+ mysql_mutex_lock(&acl_cache->lock);
grant_version++;
int result=0;
@@ -3550,21 +4084,29 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
result= -1;
}
}
+ else if (is_proxy)
+ {
+ if (replace_proxies_priv_table (thd, tables[1].table, Str, proxied_user,
+ rights & GRANT_ACL ? TRUE : FALSE,
+ revoke_grant))
+ result= -1;
+ }
}
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
if (!result)
{
result= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
- rw_unlock(&LOCK_grant);
- close_thread_tables(thd);
+ mysql_rwlock_unlock(&LOCK_grant);
if (!result)
my_ok(thd);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result);
}
@@ -3575,9 +4117,9 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
void grant_free(void)
{
DBUG_ENTER("grant_free");
- hash_free(&column_priv_hash);
- hash_free(&proc_priv_hash);
- hash_free(&func_priv_hash);
+ my_hash_free(&column_priv_hash);
+ my_hash_free(&proc_priv_hash);
+ my_hash_free(&func_priv_hash);
free_root(&memex,MYF(0));
DBUG_VOID_RETURN;
}
@@ -3602,7 +4144,6 @@ my_bool grant_init()
DBUG_RETURN(1); /* purecov: deadcode */
thd->thread_stack= (char*) &thd;
thd->store_globals();
- lex_start(thd);
return_val= grant_reload(thd);
delete thd;
/* Remember that we don't have a THD */
@@ -3634,12 +4175,12 @@ static my_bool grant_load_procs_priv(TABLE *p_table)
MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,
THR_MALLOC);
DBUG_ENTER("grant_load_procs_priv");
- (void) hash_init(&proc_priv_hash, &my_charset_utf8_bin,
- 0,0,0, (hash_get_key) get_grant_table,
- 0,0);
- (void) hash_init(&func_priv_hash, &my_charset_utf8_bin,
- 0,0,0, (hash_get_key) get_grant_table,
- 0,0);
+ (void) my_hash_init(&proc_priv_hash, &my_charset_utf8_bin,
+ 0,0,0, (my_hash_get_key) get_grant_table,
+ 0,0);
+ (void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin,
+ 0,0,0, (my_hash_get_key) get_grant_table,
+ 0,0);
p_table->file->ha_index_init(0, 1);
p_table->use_all_columns();
@@ -3735,9 +4276,9 @@ static my_bool grant_load(THD *thd, TABLE_LIST *tables)
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
- (void) hash_init(&column_priv_hash, &my_charset_utf8_bin,
- 0,0,0, (hash_get_key) get_grant_table,
- (hash_free_key) free_grant_table,0);
+ (void) my_hash_init(&column_priv_hash, &my_charset_utf8_bin,
+ 0,0,0, (my_hash_get_key) get_grant_table,
+ (my_hash_free_key) free_grant_table,0);
t_table = tables[0].table;
c_table = tables[1].table;
@@ -3813,19 +4354,15 @@ static my_bool grant_reload_procs_priv(THD *thd)
my_bool return_val= FALSE;
DBUG_ENTER("grant_reload_procs_priv");
- bzero((char*) &table, sizeof(table));
- table.alias= table.table_name= (char*) "procs_priv";
- table.db= (char *) "mysql";
- table.lock_type= TL_READ;
- table.skip_temporary= 1;
+ table.init_one_table("mysql", 5, "procs_priv",
+ strlen("procs_priv"), "procs_priv",
+ TL_READ);
+ table.open_type= OT_BASE_ONLY;
- if (simple_open_n_lock_tables(thd, &table))
- {
- close_thread_tables(thd);
+ if (open_and_lock_tables(thd, &table, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
DBUG_RETURN(TRUE);
- }
- rw_wrlock(&LOCK_grant);
+ mysql_rwlock_wrlock(&LOCK_grant);
/* Save a copy of the current hash if we need to undo the grant load */
old_proc_priv_hash= proc_priv_hash;
old_func_priv_hash= func_priv_hash;
@@ -3840,12 +4377,12 @@ static my_bool grant_reload_procs_priv(THD *thd)
}
else
{
- hash_free(&old_proc_priv_hash);
- hash_free(&old_func_priv_hash);
+ my_hash_free(&old_proc_priv_hash);
+ my_hash_free(&old_func_priv_hash);
}
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
- close_thread_tables(thd);
+ close_mysql_tables(thd);
DBUG_RETURN(return_val);
}
@@ -3877,21 +4414,23 @@ my_bool grant_reload(THD *thd)
if (!initialized)
DBUG_RETURN(0);
- bzero((char*) tables, sizeof(tables));
- tables[0].alias= tables[0].table_name= (char*) "tables_priv";
- tables[1].alias= tables[1].table_name= (char*) "columns_priv";
- tables[0].db= tables[1].db= (char *) "mysql";
+ tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("tables_priv"),
+ "tables_priv", TL_READ);
+ tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("columns_priv"),
+ "columns_priv", TL_READ);
tables[0].next_local= tables[0].next_global= tables+1;
- tables[0].lock_type= tables[1].lock_type= TL_READ;
- tables[0].skip_temporary= tables[1].skip_temporary= TRUE;
+ tables[0].open_type= tables[1].open_type= OT_BASE_ONLY;
+
/*
To avoid deadlocks we should obtain table locks before
obtaining LOCK_grant rwlock.
*/
- if (simple_open_n_lock_tables(thd, tables))
+ if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
goto end;
- rw_wrlock(&LOCK_grant);
+ mysql_rwlock_wrlock(&LOCK_grant);
old_column_priv_hash= column_priv_hash;
/*
@@ -3910,11 +4449,11 @@ my_bool grant_reload(THD *thd)
}
else
{
- hash_free(&old_column_priv_hash);
+ my_hash_free(&old_column_priv_hash);
free_root(&old_mem,MYF(0));
}
- rw_unlock(&LOCK_grant);
- close_thread_tables(thd);
+ mysql_rwlock_unlock(&LOCK_grant);
+ close_mysql_tables(thd);
/*
It is OK failing to load procs_priv table because we may be
@@ -3923,45 +4462,59 @@ my_bool grant_reload(THD *thd)
if (grant_reload_procs_priv(thd))
return_val= 1;
- rw_wrlock(&LOCK_grant);
+ mysql_rwlock_wrlock(&LOCK_grant);
grant_version++;
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
end:
DBUG_RETURN(return_val);
}
-/****************************************************************************
- Check table level grants
- SYNOPSIS
- bool check_grant()
- thd Thread handler
- want_access Bits of privileges user needs to have
- tables List of tables to check. The user should have 'want_access'
- to all tables in list.
- show_table <> 0 if we are in show table. In this case it's enough to have
- any privilege for the table
- number Check at most this number of tables.
- no_errors If 0 then we write an error. The error is sent directly to
- the client
+/**
+ @brief Check table level grants
- RETURN
- 0 ok
- 1 Error: User did not have the requested privileges
+ @param thd Thread handler
+ @param want_access Bits of privileges user needs to have.
+ @param tables List of tables to check. The user should have
+ 'want_access' to all tables in list.
+ @param any_combination_will_do TRUE if it's enough to have any privilege for
+ any combination of the table columns.
+ @param number Check at most this number of tables.
+ @param no_errors TRUE if no error should be sent directly to the client.
+
+ If table->grant.want_privilege != 0 then the requested privileges where
+ in the set of COL_ACLS but access was not granted on the table level. As
+ a consequence an extra check of column privileges is required.
+
+ Specifically if this function returns FALSE the user has some kind of
+ privilege on a combination of columns in each table.
- NOTE
- This functions assumes that either number of tables to be inspected
+ This function is usually preceeded by check_access which establish the
+ User-, Db- and Host access rights.
+
+ @see check_access
+ @see check_table_access
+
+ @note This functions assumes that either number of tables to be inspected
by it is limited explicitly (i.e. is is not UINT_MAX) or table list
used and thd->lex->query_tables_own_last value correspond to each
other (the latter should be either 0 or point to next_global member
of one of elements of this table list).
-****************************************************************************/
+
+ @return Access status
+ @retval FALSE Access granted; But column privileges might need to be
+ checked.
+ @retval TRUE The user did not have the requested privileges on any of the
+ tables.
+
+*/
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
- uint show_table, uint number, bool no_errors)
+ bool any_combination_will_do, uint number, bool no_errors)
{
- TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table();
+ TABLE_LIST *tl;
+ TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
Security_context *sctx= thd->security_ctx;
uint i;
ulong orig_want_access= want_access;
@@ -3978,76 +4531,111 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
the given table list refers to the list for prelocking (contains tables
of other queries). For simple queries first_not_own_table is 0.
*/
- for (i= 0, table= tables;
- i < number && table != first_not_own_table;
- table= table->next_global, i++)
+ for (i= 0, tl= tables;
+ i < number && tl != first_not_own_table;
+ tl= tl->next_global, i++)
{
- /* Remove SHOW_VIEW_ACL, because it will be checked during making view */
- table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
+ /*
+ Save a copy of the privileges without the SHOW_VIEW_ACL attribute.
+ It will be checked during making view.
+ */
+ tl->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
}
- rw_rdlock(&LOCK_grant);
- for (table= tables;
- table && number-- && table != first_not_own_table;
- table= table->next_global)
+ mysql_rwlock_rdlock(&LOCK_grant);
+ for (tl= tables;
+ tl && number-- && tl != first_not_own_table;
+ tl= tl->next_global)
{
- GRANT_TABLE *grant_table;
- sctx = test(table->security_ctx) ?
- table->security_ctx : thd->security_ctx;
+ sctx = test(tl->security_ctx) ? tl->security_ctx : thd->security_ctx;
+
+ const ACL_internal_table_access *access=
+ get_cached_table_access(&tl->grant.m_internal,
+ tl->get_db_name(),
+ tl->get_table_name());
+
+ if (access)
+ {
+ switch(access->check(orig_want_access, &tl->grant.privilege))
+ {
+ case ACL_INTERNAL_ACCESS_GRANTED:
+ /*
+ Currently,
+ - the information_schema does not subclass ACL_internal_table_access,
+ there are no per table privilege checks for I_S,
+ - the performance schema does use per tables checks, but at most
+ returns 'CHECK_GRANT', and never 'ACCESS_GRANTED'.
+ so this branch is not used.
+ */
+ DBUG_ASSERT(0);
+ case ACL_INTERNAL_ACCESS_DENIED:
+ goto err;
+ case ACL_INTERNAL_ACCESS_CHECK_GRANT:
+ break;
+ }
+ }
want_access= orig_want_access;
want_access&= ~sctx->master_access;
if (!want_access)
continue; // ok
- if (!(~table->grant.privilege & want_access) ||
- table->is_anonymous_derived_table() || table->schema_table)
+ if (!(~tl->grant.privilege & want_access) ||
+ tl->is_anonymous_derived_table() || tl->schema_table)
{
/*
- It is subquery in the FROM clause. VIEW set table->derived after
+ It is subquery in the FROM clause. VIEW set tl->derived after
table opening, but this function always called before table opening.
*/
- if (!table->referencing_view)
+ if (!tl->referencing_view)
{
/*
If it's a temporary table created for a subquery in the FROM
clause, or an INFORMATION_SCHEMA table, drop the request for
a privilege.
*/
- table->grant.want_privilege= 0;
+ tl->grant.want_privilege= 0;
}
continue;
}
- if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
- table->get_db_name(), sctx->priv_user,
- table->get_table_name(), FALSE)))
+ GRANT_TABLE *grant_table= table_hash_search(sctx->host, sctx->ip,
+ tl->get_db_name(),
+ sctx->priv_user,
+ tl->get_table_name(),
+ FALSE);
+
+ if (!grant_table)
{
- want_access &= ~table->grant.privilege;
+ want_access &= ~tl->grant.privilege;
goto err; // No grants
}
- if (show_table)
- continue; // We have some priv on this
- table->grant.grant_table=grant_table; // Remember for column test
- table->grant.version=grant_version;
- table->grant.privilege|= grant_table->privs;
- table->grant.want_privilege= ((want_access & COL_ACLS)
- & ~table->grant.privilege);
+ /*
+ For SHOW COLUMNS, SHOW INDEX it is enough to have some
+ privileges on any column combination on the table.
+ */
+ if (any_combination_will_do)
+ continue;
- if (!(~table->grant.privilege & want_access))
+ tl->grant.grant_table= grant_table; // Remember for column test
+ tl->grant.version= grant_version;
+ tl->grant.privilege|= grant_table->privs;
+ tl->grant.want_privilege= ((want_access & COL_ACLS) & ~tl->grant.privilege);
+
+ if (!(~tl->grant.privilege & want_access))
continue;
- if (want_access & ~(grant_table->cols | table->grant.privilege))
+ if (want_access & ~(grant_table->cols | tl->grant.privilege))
{
- want_access &= ~(grant_table->cols | table->grant.privilege);
+ want_access &= ~(grant_table->cols | tl->grant.privilege);
goto err; // impossible
}
}
- rw_unlock(&LOCK_grant);
- DBUG_RETURN(0);
+ mysql_rwlock_unlock(&LOCK_grant);
+ DBUG_RETURN(FALSE);
err:
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
if (!no_errors) // Not a silent skip of table
{
char command[128];
@@ -4056,9 +4644,9 @@ err:
command,
sctx->priv_user,
sctx->host_or_ip,
- table ? table->get_table_name() : "unknown");
+ tl ? tl->get_table_name() : "unknown");
}
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
@@ -4093,7 +4681,7 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant,
if (!want_access)
DBUG_RETURN(0); // Already checked
- rw_rdlock(&LOCK_grant);
+ mysql_rwlock_rdlock(&LOCK_grant);
/* reload table if someone has modified any grants */
@@ -4111,12 +4699,12 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant,
grant_column=column_hash_search(grant_table, name, length);
if (grant_column && !(~grant_column->rights & want_access))
{
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
DBUG_RETURN(0);
}
err:
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
char command[128];
get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
@@ -4231,7 +4819,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg,
*/
bool using_column_privileges= FALSE;
- rw_rdlock(&LOCK_grant);
+ mysql_rwlock_rdlock(&LOCK_grant);
for (; !fields->end_of_fields(); fields->next())
{
@@ -4272,11 +4860,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg,
goto err;
}
}
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
return 0;
err:
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
char command[128];
get_privilege_desc(command, sizeof(command), want_access);
@@ -4305,7 +4893,7 @@ static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash)
for (uint idx= 0; idx < hash->records; ++idx)
{
- GRANT_NAME *item= (GRANT_NAME*) hash_element(hash, idx);
+ GRANT_NAME *item= (GRANT_NAME*) my_hash_element(hash, idx);
if (strcmp(item->user, sctx->priv_user) == 0 &&
strcmp(item->db, db) == 0 &&
@@ -4334,12 +4922,13 @@ bool check_grant_db(THD *thd,const char *db)
len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1;
- rw_rdlock(&LOCK_grant);
+ mysql_rwlock_rdlock(&LOCK_grant);
for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
{
- GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
- idx);
+ GRANT_TABLE *grant_table= (GRANT_TABLE*)
+ my_hash_element(&column_priv_hash,
+ idx);
if (len < grant_table->key_length &&
!memcmp(grant_table->hash_key,helping,len) &&
compare_hostname(&grant_table->host, sctx->host, sctx->ip))
@@ -4353,7 +4942,7 @@ bool check_grant_db(THD *thd,const char *db)
error= check_grant_db_routine(thd, db, &proc_priv_hash) &&
check_grant_db_routine(thd, db, &func_priv_hash);
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
return error;
}
@@ -4389,7 +4978,7 @@ bool check_grant_routine(THD *thd, ulong want_access,
if (!want_access)
DBUG_RETURN(0); // ok
- rw_rdlock(&LOCK_grant);
+ mysql_rwlock_rdlock(&LOCK_grant);
for (table= procs; table; table= table->next_global)
{
GRANT_NAME *grant_proc;
@@ -4403,10 +4992,10 @@ bool check_grant_routine(THD *thd, ulong want_access,
goto err;
}
}
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
DBUG_RETURN(0);
err:
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
if (!no_errors)
{
char buff[1024];
@@ -4447,13 +5036,13 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
bool no_routine_acl= 1;
GRANT_NAME *grant_proc;
Security_context *sctx= thd->security_ctx;
- rw_rdlock(&LOCK_grant);
+ mysql_rwlock_rdlock(&LOCK_grant);
if ((grant_proc= routine_hash_search(sctx->priv_host,
sctx->ip, db,
sctx->priv_user,
name, is_proc, 0)))
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
return no_routine_acl;
}
@@ -4469,7 +5058,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
const char *db = table->db ? table->db : thd->db;
GRANT_TABLE *grant_table;
- rw_rdlock(&LOCK_grant);
+ mysql_rwlock_rdlock(&LOCK_grant);
#ifdef EMBEDDED_LIBRARY
grant_table= NULL;
#else
@@ -4481,7 +5070,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
if (grant_table)
table->grant.privilege|= grant_table->privs;
privilege= table->grant.privilege;
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
return privilege;
}
@@ -4512,7 +5101,7 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant,
GRANT_COLUMN *grant_column;
ulong priv;
- rw_rdlock(&LOCK_grant);
+ mysql_rwlock_rdlock(&LOCK_grant);
/* reload table if someone has modified any grants */
if (grant->version != grant_version)
{
@@ -4535,7 +5124,7 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant,
else
priv= (grant->privilege | grant_table->privs | grant_column->rights);
}
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
return priv;
}
@@ -4562,13 +5151,13 @@ static const char *command_array[]=
"ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES",
"LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT",
"CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE",
- "CREATE USER", "EVENT", "TRIGGER"
+ "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE"
};
static uint command_lengths[]=
{
6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9,
- 14, 13, 11, 5, 7
+ 14, 13, 11, 5, 7, 17
};
@@ -4602,14 +5191,14 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
DBUG_RETURN(TRUE);
}
- rw_rdlock(&LOCK_grant);
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_rwlock_rdlock(&LOCK_grant);
+ mysql_mutex_lock(&acl_cache->lock);
acl_user= find_acl_user(lex_user->host.str, lex_user->user.str, TRUE);
if (!acl_user)
{
- VOID(pthread_mutex_unlock(&acl_cache->lock));
- rw_unlock(&LOCK_grant);
+ mysql_mutex_unlock(&acl_cache->lock);
+ mysql_rwlock_unlock(&LOCK_grant);
my_error(ER_NONEXISTING_GRANT, MYF(0),
lex_user->user.str, lex_user->host.str);
@@ -4623,11 +5212,11 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
strxmov(buff,"Grants for ",lex_user->user.str,"@",
lex_user->host.str,NullS);
field_list.push_back(field);
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
{
- VOID(pthread_mutex_unlock(&acl_cache->lock));
- rw_unlock(&LOCK_grant);
+ mysql_mutex_unlock(&acl_cache->lock);
+ mysql_rwlock_unlock(&LOCK_grant);
DBUG_RETURN(TRUE);
}
@@ -4811,8 +5400,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
for (index=0 ; index < column_priv_hash.records ; index++)
{
const char *user, *host;
- GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
- index);
+ GRANT_TABLE *grant_table= (GRANT_TABLE*)
+ my_hash_element(&column_priv_hash, index);
if (!(user=grant_table->user))
user= "";
@@ -4865,7 +5454,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
col_index++)
{
GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
- hash_element(&grant_table->hash_columns,col_index);
+ my_hash_element(&grant_table->hash_columns,col_index);
if (grant_column->rights & j)
{
if (!found_col)
@@ -4936,9 +5525,15 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
goto end;
}
+ if (show_proxy_grants(thd, lex_user, buff, sizeof(buff)))
+ {
+ error= -1;
+ goto end;
+ }
+
end:
- VOID(pthread_mutex_unlock(&acl_cache->lock));
- rw_unlock(&LOCK_grant);
+ mysql_mutex_unlock(&acl_cache->lock);
+ mysql_rwlock_unlock(&LOCK_grant);
my_eof(thd);
DBUG_RETURN(error);
@@ -4955,7 +5550,7 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash,
for (index=0 ; index < hash->records ; index++)
{
const char *user, *host;
- GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, index);
+ GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, index);
if (!(user=grant_proc->user))
user= "";
@@ -5062,14 +5657,14 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc)
{
ACL_USER *acl_user;
- pthread_mutex_lock(&acl_cache->lock);
+ mysql_mutex_lock(&acl_cache->lock);
if (initialized && (acl_user= find_acl_user(host,user, FALSE)))
uc->user_resources= acl_user->user_resource;
else
bzero((char*) &uc->user_resources, sizeof(uc->user_resources));
- pthread_mutex_unlock(&acl_cache->lock);
+ mysql_mutex_unlock(&acl_cache->lock);
}
/*
@@ -5093,7 +5688,7 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc)
< 0 Error.
*/
-#define GRANT_TABLES 5
+#define GRANT_TABLES 6
int open_grant_tables(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("open_grant_tables");
@@ -5104,21 +5699,29 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
DBUG_RETURN(-1);
}
- bzero((char*) tables, GRANT_TABLES*sizeof(*tables));
- tables->alias= tables->table_name= (char*) "user";
- (tables+1)->alias= (tables+1)->table_name= (char*) "db";
- (tables+2)->alias= (tables+2)->table_name= (char*) "tables_priv";
- (tables+3)->alias= (tables+3)->table_name= (char*) "columns_priv";
- (tables+4)->alias= (tables+4)->table_name= (char*) "procs_priv";
- tables->next_local= tables->next_global= tables+1;
- (tables+1)->next_local= (tables+1)->next_global= tables+2;
- (tables+2)->next_local= (tables+2)->next_global= tables+3;
- (tables+3)->next_local= (tables+3)->next_global= tables+4;
- tables->lock_type= (tables+1)->lock_type=
- (tables+2)->lock_type= (tables+3)->lock_type=
- (tables+4)->lock_type= TL_WRITE;
- tables->db= (tables+1)->db= (tables+2)->db=
- (tables+3)->db= (tables+4)->db= (char*) "mysql";
+ tables->init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("user"), "user", TL_WRITE);
+ (tables+1)->init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("db"), "db", TL_WRITE);
+ (tables+2)->init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("tables_priv"),
+ "tables_priv", TL_WRITE);
+ (tables+3)->init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("columns_priv"),
+ "columns_priv", TL_WRITE);
+ (tables+4)->init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("procs_priv"),
+ "procs_priv", TL_WRITE);
+ (tables+5)->init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("proxies_priv"),
+ "proxies_priv", TL_WRITE);
+ tables[5].open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
+
+ tables->next_local= tables->next_global= tables + 1;
+ (tables+1)->next_local= (tables+1)->next_global= tables + 2;
+ (tables+2)->next_local= (tables+2)->next_global= tables + 3;
+ (tables+3)->next_local= (tables+3)->next_global= tables + 4;
+ (tables+4)->next_local= (tables+4)->next_global= tables + 5;
#ifdef HAVE_REPLICATION
/*
@@ -5131,18 +5734,17 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
The tables must be marked "updating" so that tables_ok() takes them into
account in tests.
*/
- tables[0].updating=tables[1].updating=tables[2].updating=
- tables[3].updating=tables[4].updating=1;
+ tables[0].updating= tables[1].updating= tables[2].updating=
+ tables[3].updating= tables[4].updating= tables[5].updating= 1;
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
DBUG_RETURN(1);
- tables[0].updating=tables[1].updating=tables[2].updating=
- tables[3].updating=tables[4].updating=0;;
+ tables[0].updating= tables[1].updating= tables[2].updating=
+ tables[3].updating= tables[4].updating= tables[5].updating= 0;
}
#endif
- if (simple_open_n_lock_tables(thd, tables))
+ if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{ // This should never happen
- close_thread_tables(thd);
DBUG_RETURN(-1);
}
@@ -5155,7 +5757,7 @@ ACL_USER *check_acl_user(LEX_USER *user_name,
ACL_USER *acl_user= 0;
uint counter;
- safe_mutex_assert_owner(&acl_cache->lock);
+ mysql_mutex_assert_owner(&acl_cache->lock);
for (counter= 0 ; counter < acl_users.elements ; counter++)
{
@@ -5266,7 +5868,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
int error;
TABLE *table= tables[table_no].table;
Field *host_field= table->field[0];
- Field *user_field= table->field[table_no ? 2 : 1];
+ Field *user_field= table->field[table_no && table_no != 5 ? 2 : 1];
char *host_str= user_from->host.str;
char *user_str= user_from->user.str;
const char *host;
@@ -5349,12 +5951,15 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
user= "";
#ifdef EXTRA_DEBUG
- DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'",
- user, host,
- get_field(thd->mem_root, table->field[1]) /*db*/,
- get_field(thd->mem_root, table->field[3]) /*table*/,
- get_field(thd->mem_root,
- table->field[4]) /*column*/));
+ if (table_no != 5)
+ {
+ DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'",
+ user, host,
+ get_field(thd->mem_root, table->field[1]) /*db*/,
+ get_field(thd->mem_root, table->field[3]) /*table*/,
+ get_field(thd->mem_root,
+ table->field[4]) /*column*/));
+ }
#endif
if (strcmp(user_str, user) ||
my_strcasecmp(system_charset_info, host_str, host))
@@ -5416,6 +6021,7 @@ static int handle_grant_struct(uint struct_no, bool drop,
const char *host;
ACL_USER *acl_user= NULL;
ACL_DB *acl_db= NULL;
+ ACL_PROXY_USER *acl_proxy_user= NULL;
GRANT_NAME *grant_name= NULL;
DBUG_ENTER("handle_grant_struct");
DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'",
@@ -5424,7 +6030,7 @@ static int handle_grant_struct(uint struct_no, bool drop,
LINT_INIT(user);
LINT_INIT(host);
- safe_mutex_assert_owner(&acl_cache->lock);
+ mysql_mutex_assert_owner(&acl_cache->lock);
/* Get the number of elements in the in-memory structure. */
switch (struct_no) {
@@ -5440,6 +6046,9 @@ static int handle_grant_struct(uint struct_no, bool drop,
case 3:
elements= proc_priv_hash.records;
break;
+ case 5:
+ elements= acl_proxy_users.elements;
+ break;
default:
return -1;
}
@@ -5468,16 +6077,21 @@ static int handle_grant_struct(uint struct_no, bool drop,
break;
case 2:
- grant_name= (GRANT_NAME*) hash_element(&column_priv_hash, idx);
+ grant_name= (GRANT_NAME*) my_hash_element(&column_priv_hash, idx);
user= grant_name->user;
host= grant_name->host.hostname;
break;
case 3:
- grant_name= (GRANT_NAME*) hash_element(&proc_priv_hash, idx);
+ grant_name= (GRANT_NAME*) my_hash_element(&proc_priv_hash, idx);
user= grant_name->user;
host= grant_name->host.hostname;
break;
+ case 5:
+ acl_proxy_user= dynamic_element(&acl_proxy_users, idx, ACL_PROXY_USER*);
+ user= acl_proxy_user->get_user();
+ host= acl_proxy_user->get_host();
+ break;
default:
MY_ASSERT_UNREACHABLE();
}
@@ -5507,12 +6121,17 @@ static int handle_grant_struct(uint struct_no, bool drop,
break;
case 2:
- hash_delete(&column_priv_hash, (uchar*) grant_name);
+ my_hash_delete(&column_priv_hash, (uchar*) grant_name);
break;
case 3:
- hash_delete(&proc_priv_hash, (uchar*) grant_name);
+ my_hash_delete(&proc_priv_hash, (uchar*) grant_name);
break;
+
+ case 5:
+ delete_dynamic_element(&acl_proxy_users, idx);
+ break;
+
}
elements--;
idx--;
@@ -5545,9 +6164,15 @@ static int handle_grant_struct(uint struct_no, bool drop,
is renamed, the hash key is changed. Update the hash to
ensure that the position matches the new hash key value
*/
- hash_update(&column_priv_hash, (uchar*) grant_name,
- (uchar*) grant_name->hash_key, grant_name->key_length);
+ my_hash_update(&column_priv_hash, (uchar*) grant_name,
+ (uchar*) grant_name->hash_key, grant_name->key_length);
break;
+
+ case 5:
+ acl_proxy_user->set_user (&mem, user_to->user.str);
+ acl_proxy_user->set_host (&mem, user_to->host.str);
+ break;
+
}
}
else
@@ -5682,6 +6307,23 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop,
result= 1; /* At least one record/element found. */
}
}
+
+ /* Handle proxies_priv table. */
+ if (tables[5].table)
+ {
+ if ((found= handle_grant_table(tables, 5, drop, user_from, user_to)) < 0)
+ {
+ /* Handle of table failed, don't touch the in-memory array. */
+ result= -1;
+ }
+ else
+ {
+ /* Handle proxies_priv array. */
+ if ((handle_grant_struct(5, drop, user_from, user_to) && !result) ||
+ found)
+ result= 1; /* At least one record/element found. */
+ }
+ }
end:
DBUG_RETURN(result);
}
@@ -5728,19 +6370,21 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
/* CREATE USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result != 1);
}
- rw_wrlock(&LOCK_grant);
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_rwlock_wrlock(&LOCK_grant);
+ mysql_mutex_lock(&acl_cache->lock);
while ((tmp_user_name= user_list++))
{
@@ -5769,7 +6413,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
}
}
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
if (result)
my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());
@@ -5777,10 +6421,11 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
if (some_users_created)
result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
- rw_unlock(&LOCK_grant);
- close_thread_tables(thd);
+ mysql_rwlock_unlock(&LOCK_grant);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result);
}
@@ -5815,21 +6460,23 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
/* DROP USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result != 1);
}
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
- rw_wrlock(&LOCK_grant);
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_rwlock_wrlock(&LOCK_grant);
+ mysql_mutex_lock(&acl_cache->lock);
while ((tmp_user_name= user_list++))
{
@@ -5850,7 +6497,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
rebuild_check_host();
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
if (result)
my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe());
@@ -5858,11 +6505,12 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
if (some_users_deleted)
result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
- rw_unlock(&LOCK_grant);
- close_thread_tables(thd);
+ mysql_rwlock_unlock(&LOCK_grant);
thd->variables.sql_mode= old_sql_mode;
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result);
}
@@ -5897,19 +6545,21 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
/* RENAME USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result != 1);
}
- rw_wrlock(&LOCK_grant);
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_rwlock_wrlock(&LOCK_grant);
+ mysql_mutex_lock(&acl_cache->lock);
while ((tmp_user_from= user_list++))
{
@@ -5943,7 +6593,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
rebuild_check_host();
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
if (result)
my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe());
@@ -5951,10 +6601,11 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
if (some_users_renamed && mysql_bin_log.is_open())
result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
- rw_unlock(&LOCK_grant);
- close_thread_tables(thd);
+ mysql_rwlock_unlock(&LOCK_grant);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result);
}
@@ -5987,18 +6638,20 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
if ((result= open_grant_tables(thd, tables)))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result != 1);
}
- rw_wrlock(&LOCK_grant);
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_rwlock_wrlock(&LOCK_grant);
+ mysql_mutex_lock(&acl_cache->lock);
LEX_USER *lex_user, *tmp_lex_user;
List_iterator <LEX_USER> user_list(list);
@@ -6065,8 +6718,8 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
for (counter= 0, revoked= 0 ; counter < column_priv_hash.records ; )
{
const char *user,*host;
- GRANT_TABLE *grant_table= (GRANT_TABLE*)hash_element(&column_priv_hash,
- counter);
+ GRANT_TABLE *grant_table=
+ (GRANT_TABLE*) my_hash_element(&column_priv_hash, counter);
if (!(user=grant_table->user))
user= "";
if (!(host=grant_table->host.hostname))
@@ -6112,7 +6765,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
for (counter= 0, revoked= 0 ; counter < hash->records ; )
{
const char *user,*host;
- GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter);
+ GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
if (!(user=grant_proc->user))
user= "";
if (!(host=grant_proc->host.hostname))
@@ -6137,7 +6790,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
} while (revoked);
}
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
if (result)
my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0));
@@ -6145,11 +6798,11 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
result= result |
write_bin_log(thd, FALSE, thd->query(), thd->query_length());
- rw_unlock(&LOCK_grant);
- close_thread_tables(thd);
-
+ mysql_rwlock_unlock(&LOCK_grant);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result);
}
@@ -6175,9 +6828,12 @@ public:
virtual ~Silence_routine_definer_errors()
{}
- virtual bool handle_error(uint sql_errno, const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd);
+ virtual bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl);
bool has_errors() { return is_grave; }
@@ -6186,18 +6842,23 @@ private:
};
bool
-Silence_routine_definer_errors::handle_error(uint sql_errno,
- const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd)
+Silence_routine_definer_errors::handle_condition(
+ THD *thd,
+ uint sql_errno,
+ const char*,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
{
+ *cond_hdl= NULL;
if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
{
switch (sql_errno)
{
case ER_NONEXISTING_PROC_GRANT:
/* Convert the error into a warning. */
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, message);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ sql_errno, msg);
return TRUE;
default:
is_grave= TRUE;
@@ -6242,23 +6903,23 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
/* Be sure to pop this before exiting this scope! */
thd->push_internal_handler(&error_handler);
- rw_wrlock(&LOCK_grant);
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_rwlock_wrlock(&LOCK_grant);
+ mysql_mutex_lock(&acl_cache->lock);
/*
This statement will be replicated as a statement, even when using
row-based replication. The flag will be reset at the end of the
statement.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
/* Remove procedure access */
do
{
for (counter= 0, revoked= 0 ; counter < hash->records ; )
{
- GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter);
+ GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
if (!my_strcasecmp(&my_charset_utf8_bin, grant_proc->db, sp_db) &&
!my_strcasecmp(system_charset_info, grant_proc->tname, sp_name))
{
@@ -6282,13 +6943,14 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
}
} while (revoked);
- VOID(pthread_mutex_unlock(&acl_cache->lock));
- rw_unlock(&LOCK_grant);
- close_thread_tables(thd);
+ mysql_mutex_unlock(&acl_cache->lock);
+ mysql_rwlock_unlock(&LOCK_grant);
thd->pop_internal_handler();
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(error_handler.has_errors());
}
@@ -6325,7 +6987,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
combo->user.str= sctx->user;
- VOID(pthread_mutex_lock(&acl_cache->lock));
+ mysql_mutex_lock(&acl_cache->lock);
if ((au= find_acl_user(combo->host.str=(char*)sctx->host_or_ip,combo->user.str,FALSE)))
goto found_acl;
@@ -6336,11 +6998,11 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
if((au= find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE)))
goto found_acl;
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
DBUG_RETURN(TRUE);
found_acl:
- VOID(pthread_mutex_unlock(&acl_cache->lock));
+ mysql_mutex_unlock(&acl_cache->lock);
bzero((char*)tables, sizeof(TABLE_LIST));
user_list.empty();
@@ -6348,38 +7010,44 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
tables->db= (char*)sp_db;
tables->table_name= tables->alias= (char*)sp_name;
- combo->host.length= strlen(combo->host.str);
- combo->user.length= strlen(combo->user.str);
- combo->host.str= thd->strmake(combo->host.str,combo->host.length);
- combo->user.str= thd->strmake(combo->user.str,combo->user.length);
+ thd->make_lex_string(&combo->user,
+ combo->user.str, strlen(combo->user.str), 0);
+ thd->make_lex_string(&combo->host,
+ combo->host.str, strlen(combo->host.str), 0);
+ combo->password= empty_lex_str;
+ combo->plugin= empty_lex_str;
+ combo->auth= empty_lex_str;
- if(au && au->salt_len)
+ if(au)
{
- if (au->salt_len == SCRAMBLE_LENGTH)
- {
- make_password_from_salt(passwd_buff, au->salt);
- combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
- }
- else if (au->salt_len == SCRAMBLE_LENGTH_323)
+ if (au->salt_len)
{
- make_password_from_salt_323(passwd_buff, (ulong *) au->salt);
- combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ if (au->salt_len == SCRAMBLE_LENGTH)
+ {
+ make_password_from_salt(passwd_buff, au->salt);
+ combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
+ }
+ else if (au->salt_len == SCRAMBLE_LENGTH_323)
+ {
+ make_password_from_salt_323(passwd_buff, (ulong *) au->salt);
+ combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ }
+ else
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_PASSWD_LENGTH,
+ ER(ER_PASSWD_LENGTH), SCRAMBLED_PASSWORD_CHAR_LENGTH);
+ return TRUE;
+ }
+ combo->password.str= passwd_buff;
}
- else
+
+ if (au->plugin.str != native_password_plugin_name.str &&
+ au->plugin.str != old_password_plugin_name.str)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_PASSWD_LENGTH,
- ER(ER_PASSWD_LENGTH),
- SCRAMBLED_PASSWORD_CHAR_LENGTH);
- return TRUE;
+ combo->plugin= au->plugin;
+ combo->auth= au->auth_string;
}
- combo->password.str= passwd_buff;
- }
- else
- {
- combo->password.str= (char*)"";
- combo->password.length= 0;
}
if (user_list.push_back(combo))
@@ -6412,6 +7080,129 @@ template class List<LEX_COLUMN>;
template class List<LEX_USER>;
#endif
+/**
+ Validate if a user can proxy as another user
+
+ @thd current thread
+ @param user the logged in user (proxy user)
+ @param authenticated_as the effective user a plugin is trying to
+ impersonate as (proxied user)
+ @return proxy user definition
+ @retval NULL proxy user definition not found or not applicable
+ @retval non-null the proxy user data
+*/
+
+static ACL_PROXY_USER *
+acl_find_proxy_user(const char *user, const char *host, const char *ip,
+ const char *authenticated_as, bool *proxy_used)
+{
+ uint i;
+ /* if the proxied and proxy user are the same return OK */
+ DBUG_ENTER("acl_find_proxy_user");
+ DBUG_PRINT("info", ("user=%s host=%s ip=%s authenticated_as=%s",
+ user, host, ip, authenticated_as));
+
+ if (!strcmp(authenticated_as, user))
+ {
+ DBUG_PRINT ("info", ("user is the same as authenticated_as"));
+ DBUG_RETURN (NULL);
+ }
+
+ *proxy_used= TRUE;
+ for (i=0; i < acl_proxy_users.elements; i++)
+ {
+ ACL_PROXY_USER *proxy= dynamic_element(&acl_proxy_users, i,
+ ACL_PROXY_USER *);
+ if (proxy->matches(host, user, ip, authenticated_as))
+ DBUG_RETURN(proxy);
+ }
+
+ DBUG_RETURN(NULL);
+}
+
+
+bool
+acl_check_proxy_grant_access(THD *thd, const char *host, const char *user,
+ bool with_grant)
+{
+ DBUG_ENTER("acl_check_proxy_grant_access");
+ DBUG_PRINT("info", ("user=%s host=%s with_grant=%d", user, host,
+ (int) with_grant));
+ if (!initialized)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
+ DBUG_RETURN(1);
+ }
+
+ /* replication slave thread can do anything */
+ if (thd->slave_thread)
+ {
+ DBUG_PRINT("info", ("replication slave"));
+ DBUG_RETURN(FALSE);
+ }
+
+ /* one can grant proxy to himself to others */
+ if (!strcmp(thd->security_ctx->user, user) &&
+ !my_strcasecmp(system_charset_info, host,
+ thd->security_ctx->host))
+ {
+ DBUG_PRINT("info", ("strcmp (%s, %s) my_casestrcmp (%s, %s) equal",
+ thd->security_ctx->user, user,
+ host, thd->security_ctx->host));
+ DBUG_RETURN(FALSE);
+ }
+
+ /* check for matching WITH PROXY rights */
+ for (uint i=0; i < acl_proxy_users.elements; i++)
+ {
+ ACL_PROXY_USER *proxy= dynamic_element(&acl_proxy_users, i,
+ ACL_PROXY_USER *);
+ if (proxy->matches(thd->security_ctx->host,
+ thd->security_ctx->user,
+ thd->security_ctx->ip,
+ user) &&
+ proxy->get_with_grant())
+ {
+ DBUG_PRINT("info", ("found"));
+ DBUG_RETURN(FALSE);
+ }
+ }
+
+ my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
+ thd->security_ctx->user,
+ thd->security_ctx->host_or_ip);
+ DBUG_RETURN(TRUE);
+}
+
+
+static bool
+show_proxy_grants(THD *thd, LEX_USER *user, char *buff, size_t buffsize)
+{
+ Protocol *protocol= thd->protocol;
+ int error= 0;
+
+ for (uint i=0; i < acl_proxy_users.elements; i++)
+ {
+ ACL_PROXY_USER *proxy= dynamic_element(&acl_proxy_users, i,
+ ACL_PROXY_USER *);
+ if (proxy->granted_on(user->host.str, user->user.str))
+ {
+ String global(buff, buffsize, system_charset_info);
+ global.length(0);
+ proxy->print_grant(&global);
+ protocol->prepare_for_resend();
+ protocol->store(global.ptr(), global.length(), global.charset());
+ if (protocol->write())
+ {
+ error= -1;
+ break;
+ }
+ }
+ }
+ return error;
+}
+
+
#endif /*NO_EMBEDDED_ACCESS_CHECKS */
@@ -6470,6 +7261,7 @@ static bool update_schema_privilege(THD *thd, TABLE *table, char *buff,
CHARSET_INFO *cs= system_charset_info;
restore_record(table, s->default_values);
table->field[0]->store(buff, (uint) strlen(buff), cs);
+ table->field[1]->store(STRING_WITH_LEN("def"), cs);
if (db)
table->field[i++]->store(db, (uint) strlen(db), cs);
if (t_name)
@@ -6492,13 +7284,14 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
ulong want_access;
char buff[100];
TABLE *table= tables->table;
- bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
+ bool no_global_access= check_access(thd, SELECT_ACL, "mysql",
+ NULL, NULL, 1, 1);
char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_user_privileges");
if (!initialized)
DBUG_RETURN(0);
- pthread_mutex_lock(&acl_cache->lock);
+ mysql_mutex_lock(&acl_cache->lock);
for (counter=0 ; counter < acl_users.elements ; counter++)
{
@@ -6548,7 +7341,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
}
}
err:
- pthread_mutex_unlock(&acl_cache->lock);
+ mysql_mutex_unlock(&acl_cache->lock);
DBUG_RETURN(error);
#else
@@ -6566,13 +7359,14 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
ulong want_access;
char buff[100];
TABLE *table= tables->table;
- bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
+ bool no_global_access= check_access(thd, SELECT_ACL, "mysql",
+ NULL, NULL, 1, 1);
char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_schema_privileges");
if (!initialized)
DBUG_RETURN(0);
- pthread_mutex_lock(&acl_cache->lock);
+ mysql_mutex_lock(&acl_cache->lock);
for (counter=0 ; counter < acl_dbs.elements ; counter++)
{
@@ -6625,7 +7419,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
}
}
err:
- pthread_mutex_unlock(&acl_cache->lock);
+ mysql_mutex_unlock(&acl_cache->lock);
DBUG_RETURN(error);
#else
@@ -6641,16 +7435,17 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
uint index;
char buff[100];
TABLE *table= tables->table;
- bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
+ bool no_global_access= check_access(thd, SELECT_ACL, "mysql",
+ NULL, NULL, 1, 1);
char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_table_privileges");
- rw_rdlock(&LOCK_grant);
+ mysql_rwlock_rdlock(&LOCK_grant);
for (index=0 ; index < column_priv_hash.records ; index++)
{
const char *user, *host, *is_grantable= "YES";
- GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
+ GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash,
index);
if (!(user=grant_table->user))
user= "";
@@ -6708,7 +7503,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
}
}
err:
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
DBUG_RETURN(error);
#else
@@ -6724,16 +7519,17 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
uint index;
char buff[100];
TABLE *table= tables->table;
- bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
+ bool no_global_access= check_access(thd, SELECT_ACL, "mysql",
+ NULL, NULL, 1, 1);
char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_table_privileges");
- rw_rdlock(&LOCK_grant);
+ mysql_rwlock_rdlock(&LOCK_grant);
for (index=0 ; index < column_priv_hash.records ; index++)
{
const char *user, *host, *is_grantable= "YES";
- GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
+ GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash,
index);
if (!(user=grant_table->user))
user= "";
@@ -6768,7 +7564,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
col_index++)
{
GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
- hash_element(&grant_table->hash_columns,col_index);
+ my_hash_element(&grant_table->hash_columns,col_index);
if ((grant_column->rights & j) && (table_access & j))
{
if (update_schema_privilege(thd, table, buff, grant_table->db,
@@ -6789,7 +7585,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
}
}
err:
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
DBUG_RETURN(error);
#else
@@ -6841,7 +7637,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
/* table privileges */
- rw_rdlock(&LOCK_grant);
+ mysql_rwlock_rdlock(&LOCK_grant);
if (grant->version != grant_version)
{
grant->grant_table=
@@ -6854,7 +7650,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
{
grant->privilege|= grant->grant_table->privs;
}
- rw_unlock(&LOCK_grant);
+ mysql_rwlock_unlock(&LOCK_grant);
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
DBUG_VOID_RETURN;
@@ -6873,3 +7669,1765 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
}
#endif
+
+struct ACL_internal_schema_registry_entry
+{
+ const LEX_STRING *m_name;
+ const ACL_internal_schema_access *m_access;
+};
+
+/**
+ Internal schema registered.
+ Currently, this is only:
+ - performance_schema
+ - information_schema,
+ This can be reused later for:
+ - mysql
+*/
+static ACL_internal_schema_registry_entry registry_array[2];
+static uint m_registry_array_size= 0;
+
+/**
+ Add an internal schema to the registry.
+ @param name the schema name
+ @param access the schema ACL specific rules
+*/
+void ACL_internal_schema_registry::register_schema
+ (const LEX_STRING *name, const ACL_internal_schema_access *access)
+{
+ DBUG_ASSERT(m_registry_array_size < array_elements(registry_array));
+
+ /* Not thread safe, and does not need to be. */
+ registry_array[m_registry_array_size].m_name= name;
+ registry_array[m_registry_array_size].m_access= access;
+ m_registry_array_size++;
+}
+
+/**
+ Search per internal schema ACL by name.
+ @param name a schema name
+ @return per schema rules, or NULL
+*/
+const ACL_internal_schema_access *
+ACL_internal_schema_registry::lookup(const char *name)
+{
+ DBUG_ASSERT(name != NULL);
+
+ uint i;
+
+ for (i= 0; i<m_registry_array_size; i++)
+ {
+ if (my_strcasecmp(system_charset_info, registry_array[i].m_name->str,
+ name) == 0)
+ return registry_array[i].m_access;
+ }
+ return NULL;
+}
+
+/**
+ Get a cached internal schema access.
+ @param grant_internal_info the cache
+ @param schema_name the name of the internal schema
+*/
+const ACL_internal_schema_access *
+get_cached_schema_access(GRANT_INTERNAL_INFO *grant_internal_info,
+ const char *schema_name)
+{
+ if (grant_internal_info)
+ {
+ if (! grant_internal_info->m_schema_lookup_done)
+ {
+ grant_internal_info->m_schema_access=
+ ACL_internal_schema_registry::lookup(schema_name);
+ grant_internal_info->m_schema_lookup_done= TRUE;
+ }
+ return grant_internal_info->m_schema_access;
+ }
+ return ACL_internal_schema_registry::lookup(schema_name);
+}
+
+/**
+ Get a cached internal table access.
+ @param grant_internal_info the cache
+ @param schema_name the name of the internal schema
+ @param table_name the name of the internal table
+*/
+const ACL_internal_table_access *
+get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info,
+ const char *schema_name,
+ const char *table_name)
+{
+ DBUG_ASSERT(grant_internal_info);
+ if (! grant_internal_info->m_table_lookup_done)
+ {
+ const ACL_internal_schema_access *schema_access;
+ schema_access= get_cached_schema_access(grant_internal_info, schema_name);
+ if (schema_access)
+ grant_internal_info->m_table_access= schema_access->lookup(table_name);
+ grant_internal_info->m_table_lookup_done= TRUE;
+ }
+ return grant_internal_info->m_table_access;
+}
+
+
+/****************************************************************************
+ AUTHENTICATION CODE
+ including initial connect handshake, invoking appropriate plugins,
+ client-server plugin negotiation, COM_CHANGE_USER, and native
+ MySQL authentication plugins.
+****************************************************************************/
+
+/* few defines to have less ifdef's in the code below */
+#ifdef EMBEDDED_LIBRARY
+#undef HAVE_OPENSSL
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+#define initialized 0
+#define decrease_user_connections(X) /* nothing */
+#define check_for_max_user_connections(X, Y) 0
+#endif
+#endif
+#ifndef HAVE_OPENSSL
+#define ssl_acceptor_fd 0
+#define sslaccept(A,B,C) 1
+#endif
+
+
+class Thd_charset_adapter
+{
+ THD *thd;
+public:
+ Thd_charset_adapter(THD *thd_arg) : thd (thd_arg) {}
+ bool init_client_charset(uint cs_number)
+ {
+ thd_init_client_charset(thd, cs_number);
+ thd->update_charset();
+ return thd->is_error();
+ }
+
+ CHARSET_INFO *charset() { return thd->charset(); }
+};
+
+
+/**
+ The internal version of what plugins know as MYSQL_PLUGIN_VIO,
+ basically the context of the authentication session
+*/
+struct MPVIO_EXT :public MYSQL_PLUGIN_VIO
+{
+ MYSQL_SERVER_AUTH_INFO auth_info;
+ const ACL_USER *acl_user;
+ plugin_ref plugin; ///< what plugin we're under
+ LEX_STRING db; ///< db name from the handshake packet
+ /** when restarting a plugin this caches the last client reply */
+ struct {
+ char *plugin, *pkt; ///< pointers into NET::buff
+ uint pkt_len;
+ } cached_client_reply;
+ /** this caches the first plugin packet for restart request on the client */
+ struct {
+ char *pkt;
+ uint pkt_len;
+ } cached_server_packet;
+ int packets_read, packets_written; ///< counters for send/received packets
+ uint connect_errors; ///< if there were connect errors for this host
+ /** when plugin returns a failure this tells us what really happened */
+ enum { SUCCESS, FAILURE, RESTART } status;
+
+ /* encapsulation members */
+ ulong client_capabilities;
+ char *scramble;
+ MEM_ROOT *mem_root;
+ struct rand_struct *rand;
+ my_thread_id thread_id;
+ uint *server_status;
+ NET *net;
+ ulong max_client_packet_length;
+ char *ip;
+ char *host;
+ Thd_charset_adapter *charset_adapter;
+ LEX_STRING acl_user_plugin;
+};
+
+/**
+ a helper function to report an access denied error in all the proper places
+*/
+static void login_failed_error(MPVIO_EXT *mpvio, int passwd_used)
+{
+ THD *thd= current_thd;
+ if (passwd_used == 2)
+ {
+ my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
+ mpvio->auth_info.user_name,
+ mpvio->auth_info.host_or_ip);
+ general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_NO_PASSWORD_ERROR),
+ mpvio->auth_info.user_name,
+ mpvio->auth_info.host_or_ip);
+ /*
+ Log access denied messages to the error log when log-warnings = 2
+ so that the overhead of the general query log is not required to track
+ failed connections.
+ */
+ if (global_system_variables.log_warnings > 1)
+ {
+ sql_print_warning(ER(ER_ACCESS_DENIED_NO_PASSWORD_ERROR),
+ mpvio->auth_info.user_name,
+ mpvio->auth_info.host_or_ip);
+ }
+ }
+ else
+ {
+ my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
+ mpvio->auth_info.user_name,
+ mpvio->auth_info.host_or_ip,
+ passwd_used ? ER(ER_YES) : ER(ER_NO));
+ general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
+ mpvio->auth_info.user_name,
+ mpvio->auth_info.host_or_ip,
+ passwd_used ? ER(ER_YES) : ER(ER_NO));
+ /*
+ Log access denied messages to the error log when log-warnings = 2
+ so that the overhead of the general query log is not required to track
+ failed connections.
+ */
+ if (global_system_variables.log_warnings > 1)
+ {
+ sql_print_warning(ER(ER_ACCESS_DENIED_ERROR),
+ mpvio->auth_info.user_name,
+ mpvio->auth_info.host_or_ip,
+ passwd_used ? ER(ER_YES) : ER(ER_NO));
+ }
+ }
+}
+
+/**
+ sends a server handshake initialization packet, the very first packet
+ after the connection was established
+
+ Packet format:
+
+ Bytes Content
+ ----- ----
+ 1 protocol version (always 10)
+ n server version string, \0-terminated
+ 4 thread id
+ 8 first 8 bytes of the plugin provided data (scramble)
+ 1 \0 byte, terminating the first part of a scramble
+ 2 server capabilities (two lower bytes)
+ 1 server character set
+ 2 server status
+ 2 server capabilities (two upper bytes)
+ 1 length of the scramble
+ 10 reserved, always 0
+ n rest of the plugin provided data (at least 12 bytes)
+ 1 \0 byte, terminating the second part of a scramble
+
+ @retval 0 ok
+ @retval 1 error
+*/
+static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
+ const char *data, uint data_len)
+{
+ DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE);
+ DBUG_ASSERT(data_len <= 255);
+
+ char *buff= (char *) my_alloca(1 + SERVER_VERSION_LENGTH + data_len + 64);
+ char scramble_buf[SCRAMBLE_LENGTH];
+ char *end= buff;
+
+ DBUG_ENTER("send_server_handshake_packet");
+ *end++= protocol_version;
+
+ mpvio->client_capabilities= CLIENT_BASIC_FLAGS;
+
+ if (opt_using_transactions)
+ mpvio->client_capabilities|= CLIENT_TRANSACTIONS;
+
+ mpvio->client_capabilities|= CAN_CLIENT_COMPRESS;
+
+ if (ssl_acceptor_fd)
+ {
+ mpvio->client_capabilities|= CLIENT_SSL;
+ mpvio->client_capabilities|= CLIENT_SSL_VERIFY_SERVER_CERT;
+ }
+
+ if (data_len)
+ {
+ mpvio->cached_server_packet.pkt= (char*) memdup_root(mpvio->mem_root,
+ data, data_len);
+ mpvio->cached_server_packet.pkt_len= data_len;
+ }
+
+ if (data_len < SCRAMBLE_LENGTH)
+ {
+ if (data_len)
+ {
+ /*
+ the first packet *must* have at least 20 bytes of a scramble.
+ if a plugin provided less, we pad it to 20 with zeros
+ */
+ memcpy(scramble_buf, data, data_len);
+ bzero(scramble_buf + data_len, SCRAMBLE_LENGTH - data_len);
+ data= scramble_buf;
+ }
+ else
+ {
+ /*
+ if the default plugin does not provide the data for the scramble at
+ all, we generate a scramble internally anyway, just in case the
+ user account (that will be known only later) uses a
+ native_password_plugin (which needs a scramble). If we don't send a
+ scramble now - wasting 20 bytes in the packet -
+ native_password_plugin will have to send it in a separate packet,
+ adding one more round trip.
+ */
+ create_random_string(mpvio->scramble, SCRAMBLE_LENGTH, mpvio->rand);
+ data= mpvio->scramble;
+ }
+ data_len= SCRAMBLE_LENGTH;
+ }
+
+ end= strnmov(end, server_version, SERVER_VERSION_LENGTH) + 1;
+ int4store((uchar*) end, mpvio->thread_id);
+ end+= 4;
+
+ /*
+ Old clients does not understand long scrambles, but can ignore packet
+ tail: that's why first part of the scramble is placed here, and second
+ part at the end of packet.
+ */
+ end= (char*) memcpy(end, data, SCRAMBLE_LENGTH_323);
+ end+= SCRAMBLE_LENGTH_323;
+ *end++= 0;
+
+ int2store(end, mpvio->client_capabilities);
+ /* write server characteristics: up to 16 bytes allowed */
+ end[2]= (char) default_charset_info->number;
+ int2store(end + 3, mpvio->server_status[0]);
+ int2store(end + 5, mpvio->client_capabilities >> 16);
+ end[7]= data_len;
+ bzero(end + 8, 10);
+ end+= 18;
+ /* write scramble tail */
+ end= (char*) memcpy(end, data + SCRAMBLE_LENGTH_323,
+ data_len - SCRAMBLE_LENGTH_323);
+ end+= data_len - SCRAMBLE_LENGTH_323;
+ end= strmake(end, plugin_name(mpvio->plugin)->str,
+ plugin_name(mpvio->plugin)->length);
+
+ int res= my_net_write(mpvio->net, (uchar*) buff, (size_t) (end - buff)) ||
+ net_flush(mpvio->net);
+ my_afree(buff);
+ DBUG_RETURN (res);
+}
+
+static bool secure_auth(MPVIO_EXT *mpvio)
+{
+ THD *thd;
+ if (!opt_secure_auth)
+ return 0;
+ /*
+ If the server is running in secure auth mode, short scrambles are
+ forbidden. Extra juggling to report the same error as the old code.
+ */
+
+ thd= current_thd;
+ if (mpvio->client_capabilities & CLIENT_PROTOCOL_41)
+ {
+ my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0),
+ mpvio->auth_info.user_name,
+ mpvio->auth_info.host_or_ip);
+ general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
+ mpvio->auth_info.user_name,
+ mpvio->auth_info.host_or_ip);
+ }
+ else
+ {
+ my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
+ general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ }
+ return 1;
+}
+
+/**
+ sends a "change plugin" packet, requesting a client to restart authentication
+ using a different authentication plugin
+
+ Packet format:
+
+ Bytes Content
+ ----- ----
+ 1 byte with the value 254
+ n client plugin to use, \0-terminated
+ n plugin provided data
+
+ In a special case of switching from native_password_plugin to
+ old_password_plugin, the packet contains only one - the first - byte,
+ plugin name is omitted, plugin data aren't needed as the scramble was
+ already sent. This one-byte packet is identical to the "use the short
+ scramble" packet in the protocol before plugins were introduced.
+
+ @retval 0 ok
+ @retval 1 error
+*/
+static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
+ const uchar *data, uint data_len)
+{
+ DBUG_ASSERT(mpvio->packets_written == 1);
+ DBUG_ASSERT(mpvio->packets_read == 1);
+ NET *net= mpvio->net;
+ static uchar switch_plugin_request_buf[]= { 254 };
+
+ DBUG_ENTER("send_plugin_request_packet");
+ mpvio->status= MPVIO_EXT::FAILURE; // the status is no longer RESTART
+
+ const char *client_auth_plugin=
+ ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
+
+ DBUG_ASSERT(client_auth_plugin);
+
+ /*
+ we send an old "short 4.0 scramble request", if we need to request a
+ client to use 4.0 auth plugin (short scramble) and the scramble was
+ already sent to the client
+
+ below, cached_client_reply.plugin is the plugin name that client has used,
+ client_auth_plugin is derived from mysql.user table, for the given
+ user account, it's the plugin that the client need to use to login.
+ */
+ bool switch_from_long_to_short_scramble=
+ native_password_plugin_name.str == mpvio->cached_client_reply.plugin &&
+ client_auth_plugin == old_password_plugin_name.str;
+
+ if (switch_from_long_to_short_scramble)
+ DBUG_RETURN (secure_auth(mpvio) ||
+ my_net_write(net, switch_plugin_request_buf, 1) ||
+ net_flush(net));
+
+ /*
+ We never request a client to switch from a short to long scramble.
+ Plugin-aware clients can do that, but traditionally it meant to
+ ask an old 4.0 client to use the new 4.1 authentication protocol.
+ */
+ bool switch_from_short_to_long_scramble=
+ old_password_plugin_name.str == mpvio->cached_client_reply.plugin &&
+ client_auth_plugin == native_password_plugin_name.str;
+
+ if (switch_from_short_to_long_scramble)
+ {
+ my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
+ general_log_print(current_thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ DBUG_RETURN (1);
+ }
+
+ /*
+ If we're dealing with an older client we can't just send a change plugin
+ packet to re-initiate the authentication handshake, because the client
+ won't understand it. The good thing is that we don't need to : the old client
+ expects us to just check the user credentials here, which we can do by just reading
+ the cached data that are placed there by parse_com_change_user_packet()
+ In this case we just do nothing and behave as if normal authentication
+ should continue.
+ */
+ if (!(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH))
+ {
+ DBUG_PRINT("info", ("old client sent a COM_CHANGE_USER"));
+ DBUG_ASSERT(mpvio->cached_client_reply.pkt);
+ /* get the status back so the read can process the cached result */
+ mpvio->status= MPVIO_EXT::RESTART;
+ DBUG_RETURN(0);
+ }
+
+ DBUG_PRINT("info", ("requesting client to use the %s plugin",
+ client_auth_plugin));
+ DBUG_RETURN(net_write_command(net, switch_plugin_request_buf[0],
+ (uchar*) client_auth_plugin,
+ strlen(client_auth_plugin) + 1,
+ (uchar*) data, data_len));
+}
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+/**
+ Finds acl entry in user database for authentication purposes.
+
+ Finds a user and copies it into mpvio. Reports an authentication
+ failure if a user is not found.
+
+ @note find_acl_user is not the same, because it doesn't take into
+ account the case when user is not empty, but acl_user->user is empty
+
+ @retval 0 found
+ @retval 1 not found
+*/
+static bool find_mpvio_user(MPVIO_EXT *mpvio)
+{
+ DBUG_ENTER("find_mpvio_user");
+ DBUG_PRINT("info", ("entry: %s", mpvio->auth_info.user_name));
+ DBUG_ASSERT(mpvio->acl_user == 0);
+ mysql_mutex_lock(&acl_cache->lock);
+ for (uint i=0; i < acl_users.elements; i++)
+ {
+ ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*);
+ if ((!acl_user_tmp->user ||
+ !strcmp(mpvio->auth_info.user_name, acl_user_tmp->user)) &&
+ compare_hostname(&acl_user_tmp->host, mpvio->host, mpvio->ip))
+ {
+ mpvio->acl_user= acl_user_tmp->copy(mpvio->mem_root);
+ if (acl_user_tmp->plugin.str == native_password_plugin_name.str ||
+ acl_user_tmp->plugin.str == old_password_plugin_name.str)
+ mpvio->acl_user_plugin= acl_user_tmp->plugin;
+ else
+ make_lex_string_root(mpvio->mem_root,
+ &mpvio->acl_user_plugin,
+ acl_user_tmp->plugin.str,
+ acl_user_tmp->plugin.length, 0);
+ break;
+ }
+ }
+ mysql_mutex_unlock(&acl_cache->lock);
+
+ if (!mpvio->acl_user)
+ {
+ login_failed_error(mpvio, 0);
+ DBUG_RETURN (1);
+ }
+
+ /* user account requires non-default plugin and the client is too old */
+ if (mpvio->acl_user->plugin.str != native_password_plugin_name.str &&
+ mpvio->acl_user->plugin.str != old_password_plugin_name.str &&
+ !(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH))
+ {
+ DBUG_ASSERT(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
+ native_password_plugin_name.str));
+ DBUG_ASSERT(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
+ old_password_plugin_name.str));
+ my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
+ general_log_print(current_thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ DBUG_RETURN (1);
+ }
+
+ mpvio->auth_info.auth_string= mpvio->acl_user->auth_string.str;
+ mpvio->auth_info.auth_string_length=
+ (unsigned long) mpvio->acl_user->auth_string.length;
+ strmake(mpvio->auth_info.authenticated_as, mpvio->acl_user->user ?
+ mpvio->acl_user->user : "", USERNAME_LENGTH);
+ DBUG_PRINT("info", ("exit: user=%s, auth_string=%s, authenticated as=%s"
+ "plugin=%s",
+ mpvio->auth_info.user_name,
+ mpvio->auth_info.auth_string,
+ mpvio->auth_info.authenticated_as,
+ mpvio->acl_user->plugin.str));
+ DBUG_RETURN(0);
+}
+#endif
+
+/* the packet format is described in send_change_user_packet() */
+static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
+{
+ NET *net= mpvio->net;
+
+ char *user= (char*) net->read_pos;
+ char *end= user + packet_length;
+ /* Safe because there is always a trailing \0 at the end of the packet */
+ char *passwd= strend(user) + 1;
+ uint user_len= passwd - user - 1;
+ char *db= passwd;
+ char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
+ char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
+ uint dummy_errors;
+
+ DBUG_ENTER ("parse_com_change_user_packet");
+ if (passwd >= end)
+ {
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
+ DBUG_RETURN (1);
+ }
+
+ /*
+ Old clients send null-terminated string as password; new clients send
+ the size (1 byte) + string (not null-terminated). Hence in case of empty
+ password both send '\0'.
+
+ This strlen() can't be easily deleted without changing protocol.
+
+ Cast *passwd to an unsigned char, so that it doesn't extend the sign for
+ *passwd > 127 and become 2**32-127+ after casting to uint.
+ */
+ uint passwd_len= (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION ?
+ (uchar) (*passwd++) : strlen(passwd));
+
+ db+= passwd_len + 1;
+ /*
+ Database name is always NUL-terminated, so in case of empty database
+ the packet must contain at least the trailing '\0'.
+ */
+ if (db >= end)
+ {
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
+ DBUG_RETURN (1);
+ }
+
+ uint db_len= strlen(db);
+
+ char *ptr= db + db_len + 1;
+
+ if (ptr + 1 < end)
+ {
+ if (mpvio->charset_adapter->init_client_charset(uint2korr(ptr)))
+ DBUG_RETURN(1);
+ }
+
+
+ /* Convert database and user names to utf8 */
+ db_len= copy_and_convert(db_buff, sizeof(db_buff) - 1, system_charset_info,
+ db, db_len, mpvio->charset_adapter->charset(),
+ &dummy_errors);
+ db_buff[db_len]= 0;
+
+ user_len= copy_and_convert(user_buff, sizeof(user_buff) - 1,
+ system_charset_info, user, user_len,
+ mpvio->charset_adapter->charset(),
+ &dummy_errors);
+ user_buff[user_len]= 0;
+
+ /* we should not free mpvio->user here: it's saved by dispatch_command() */
+ if (!(mpvio->auth_info.user_name= my_strndup(user_buff, user_len, MYF(MY_WME))))
+ return 1;
+ mpvio->auth_info.user_name_length= user_len;
+
+ if (make_lex_string_root(mpvio->mem_root,
+ &mpvio->db, db_buff, db_len, 0) == 0)
+ DBUG_RETURN(1); /* The error is set by make_lex_string(). */
+
+ if (!initialized)
+ {
+ // if mysqld's been started with --skip-grant-tables option
+ strmake(mpvio->auth_info.authenticated_as,
+ mpvio->auth_info.user_name, USERNAME_LENGTH);
+
+ mpvio->status= MPVIO_EXT::SUCCESS;
+ DBUG_RETURN(0);
+ }
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (find_mpvio_user(mpvio))
+ DBUG_RETURN(1);
+
+ char *client_plugin;
+ if (mpvio->client_capabilities & CLIENT_PLUGIN_AUTH)
+ {
+ client_plugin= ptr + 2;
+ if (client_plugin >= end)
+ {
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+ else
+ {
+ if (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION)
+ client_plugin= native_password_plugin_name.str;
+ else
+ {
+ client_plugin= old_password_plugin_name.str;
+ /*
+ For a passwordless accounts we use native_password_plugin.
+ But when an old 4.0 client connects to it, we change it to
+ old_password_plugin, otherwise MySQL will think that server
+ and client plugins don't match.
+ */
+ if (mpvio->acl_user->auth_string.length == 0)
+ mpvio->acl_user_plugin= old_password_plugin_name;
+ }
+ }
+
+ DBUG_PRINT("info", ("client_plugin=%s, restart", client_plugin));
+ /*
+ Remember the data part of the packet, to present it to plugin in
+ read_packet()
+ */
+ mpvio->cached_client_reply.pkt= passwd;
+ mpvio->cached_client_reply.pkt_len= passwd_len;
+ mpvio->cached_client_reply.plugin= client_plugin;
+ mpvio->status= MPVIO_EXT::RESTART;
+#endif
+
+ DBUG_RETURN (0);
+}
+
+/* the packet format is described in send_client_reply_packet() */
+static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
+ uchar **buff, ulong pkt_len)
+{
+#ifndef EMBEDDED_LIBRARY
+ NET *net= mpvio->net;
+ char *end;
+
+ DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE);
+
+ if (pkt_len < MIN_HANDSHAKE_SIZE)
+ return packet_error;
+
+ if (mpvio->connect_errors)
+ reset_host_errors(mpvio->ip);
+
+ ulong client_capabilities= uint2korr(net->read_pos);
+ if (client_capabilities & CLIENT_PROTOCOL_41)
+ {
+ client_capabilities|= ((ulong) uint2korr(net->read_pos + 2)) << 16;
+ mpvio->max_client_packet_length= uint4korr(net->read_pos + 4);
+ DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
+ if (mpvio->charset_adapter->init_client_charset((uint) net->read_pos[8]))
+ return packet_error;
+ end= (char*) net->read_pos + 32;
+ }
+ else
+ {
+ mpvio->max_client_packet_length= uint3korr(net->read_pos + 2);
+ end= (char*) net->read_pos + 5;
+ }
+
+ /* Disable those bits which are not supported by the client. */
+ mpvio->client_capabilities&= client_capabilities;
+
+
+#if defined(HAVE_OPENSSL)
+ DBUG_PRINT("info", ("client capabilities: %lu", mpvio->client_capabilities));
+ if (mpvio->client_capabilities & CLIENT_SSL)
+ {
+ char error_string[1024] __attribute__((unused));
+
+ /* Do the SSL layering. */
+ if (!ssl_acceptor_fd)
+ return packet_error;
+
+ DBUG_PRINT("info", ("IO layer change in progress..."));
+ if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
+ {
+ DBUG_PRINT("error", ("Failed to accept new SSL connection"));
+ return packet_error;
+ }
+
+ DBUG_PRINT("info", ("Reading user information over SSL layer"));
+ pkt_len= my_net_read(net);
+ if (pkt_len == packet_error || pkt_len < NORMAL_HANDSHAKE_SIZE)
+ {
+ DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
+ pkt_len));
+ return packet_error;
+ }
+ }
+#endif
+
+ if (end >= (char*) net->read_pos + pkt_len + 2)
+ return packet_error;
+
+ if ((mpvio->client_capabilities & CLIENT_TRANSACTIONS) &&
+ opt_using_transactions)
+ net->return_status= mpvio->server_status;
+
+ char *user= end;
+ char *passwd= strend(user) + 1;
+ uint user_len= passwd - user - 1, db_len;
+ char *db= passwd;
+ char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
+ char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
+ uint dummy_errors;
+
+ /*
+ Old clients send null-terminated string as password; new clients send
+ the size (1 byte) + string (not null-terminated). Hence in case of empty
+ password both send '\0'.
+
+ This strlen() can't be easily deleted without changing protocol.
+
+ Cast *passwd to an unsigned char, so that it doesn't extend the sign for
+ *passwd > 127 and become 2**32-127+ after casting to uint.
+ */
+ uint passwd_len= mpvio->client_capabilities & CLIENT_SECURE_CONNECTION ?
+ (uchar) (*passwd++) : strlen(passwd);
+
+ if (mpvio->client_capabilities & CLIENT_CONNECT_WITH_DB)
+ {
+ db= db + passwd_len + 1;
+ /* strlen() can't be easily deleted without changing protocol */
+ db_len= strlen(db);
+ }
+ else
+ {
+ db= 0;
+ db_len= 0;
+ }
+
+ if (passwd + passwd_len + db_len > (char *) net->read_pos + pkt_len)
+ return packet_error;
+
+ char *client_plugin= passwd + passwd_len + (db ? db_len + 1 : 0);
+
+ /* Since 4.1 all database names are stored in utf8 */
+ if (db)
+ {
+ db_len= copy_and_convert(db_buff, sizeof(db_buff) - 1, system_charset_info,
+ db, db_len, mpvio->charset_adapter->charset(),
+ &dummy_errors);
+ db= db_buff;
+ db_buff[db_len]= 0;
+ }
+
+ user_len= copy_and_convert(user_buff, sizeof(user_buff) - 1,
+ system_charset_info, user, user_len,
+ mpvio->charset_adapter->charset(),
+ &dummy_errors);
+ user= user_buff;
+ user_buff[user_len]= 0;
+
+ /* If username starts and ends in "'", chop them off */
+ if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
+ {
+ user[user_len - 1]= 0;
+ user++;
+ user_len-= 2;
+ }
+
+ if (make_lex_string_root(mpvio->mem_root,
+ &mpvio->db, db, db_len, 0) == 0)
+ return packet_error; /* The error is set by make_lex_string(). */
+ if (mpvio->auth_info.user_name)
+ my_free(mpvio->auth_info.user_name);
+ if (!(mpvio->auth_info.user_name= my_strndup(user, user_len, MYF(MY_WME))))
+ return packet_error; /* The error is set by my_strdup(). */
+ mpvio->auth_info.user_name_length= user_len;
+
+ if (!initialized)
+ {
+ // if mysqld's been started with --skip-grant-tables option
+ mpvio->status= MPVIO_EXT::SUCCESS;
+ return packet_error;
+ }
+
+ if (find_mpvio_user(mpvio))
+ return packet_error;
+
+ if (mpvio->client_capabilities & CLIENT_PLUGIN_AUTH)
+ {
+ if ((client_plugin + strlen(client_plugin)) >
+ (char *) net->read_pos + pkt_len)
+ return packet_error;
+ }
+ else
+ {
+ if (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION)
+ client_plugin= native_password_plugin_name.str;
+ else
+ {
+ client_plugin= old_password_plugin_name.str;
+ /*
+ For a passwordless accounts we use native_password_plugin.
+ But when an old 4.0 client connects to it, we change it to
+ old_password_plugin, otherwise MySQL will think that server
+ and client plugins don't match.
+ */
+ if (mpvio->acl_user->auth_string.length == 0)
+ mpvio->acl_user_plugin= old_password_plugin_name;
+ }
+ }
+
+ /*
+ if the acl_user needs a different plugin to authenticate
+ (specified in GRANT ... AUTHENTICATED VIA plugin_name ..)
+ we need to restart the authentication in the server.
+ But perhaps the client has already used the correct plugin -
+ in that case the authentication on the client may not need to be
+ restarted and a server auth plugin will read the data that the client
+ has just send. Cache them to return in the next server_mpvio_read_packet().
+ */
+ if (my_strcasecmp(system_charset_info, mpvio->acl_user_plugin.str,
+ plugin_name(mpvio->plugin)->str) != 0)
+ {
+ mpvio->cached_client_reply.pkt= passwd;
+ mpvio->cached_client_reply.pkt_len= passwd_len;
+ mpvio->cached_client_reply.plugin= client_plugin;
+ mpvio->status= MPVIO_EXT::RESTART;
+ return packet_error;
+ }
+
+ /*
+ ok, we don't need to restart the authentication on the server.
+ but if the client used the wrong plugin, we need to restart
+ the authentication on the client. Do it here, the server plugin
+ doesn't need to know.
+ */
+ const char *client_auth_plugin=
+ ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
+
+ if (client_auth_plugin &&
+ my_strcasecmp(system_charset_info, client_plugin, client_auth_plugin))
+ {
+ mpvio->cached_client_reply.plugin= client_plugin;
+ if (send_plugin_request_packet(mpvio,
+ (uchar*) mpvio->cached_server_packet.pkt,
+ mpvio->cached_server_packet.pkt_len))
+ return packet_error;
+
+ passwd_len= my_net_read(mpvio->net);
+ passwd = (char*) mpvio->net->read_pos;
+ }
+
+ *buff= (uchar*) passwd;
+ return passwd_len;
+#else
+ return 0;
+#endif
+}
+
+
+/**
+ Make sure that when sending plugin supplued data to the client they
+ are not considered a special out-of-band command, like e.g.
+ \255 (error) or \254 (change user request packet).
+ To avoid this we send plugin data packets starting with one of these
+ 2 bytes "wrapped" in a command \1.
+ For the above reason we have to wrap plugin data packets starting with
+ \1 as well.
+*/
+
+#define IS_OUT_OF_BAND_PACKET(packet,packet_len) \
+ ((packet_len) > 0 && \
+ (*(packet) == 1 || *(packet) == 255 || *(packet) == 254))
+
+static inline int
+wrap_plguin_data_into_proper_command(NET *net,
+ const uchar *packet, int packet_len)
+{
+ DBUG_ASSERT(IS_OUT_OF_BAND_PACKET(packet, packet_len));
+ return net_write_command(net, 1, (uchar *) "", 0, packet, packet_len);
+}
+
+
+/**
+ vio->write_packet() callback method for server authentication plugins
+
+ This function is called by a server authentication plugin, when it wants
+ to send data to the client.
+
+ It transparently wraps the data into a handshake packet,
+ and handles plugin negotiation with the client. If necessary,
+ it escapes the plugin data, if it starts with a mysql protocol packet byte.
+*/
+static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param,
+ const uchar *packet, int packet_len)
+{
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) param;
+ int res;
+
+ DBUG_ENTER("server_mpvio_write_packet");
+ /*
+ Reset cached_client_reply if not an old client doing mysql_change_user,
+ as this is where the password from COM_CHANGE_USER is stored.
+ */
+ if (!((!(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH)) &&
+ mpvio->status == MPVIO_EXT::RESTART &&
+ mpvio->cached_client_reply.plugin ==
+ ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin
+ ))
+ mpvio->cached_client_reply.pkt= 0;
+ /* for the 1st packet we wrap plugin data into the handshake packet */
+ if (mpvio->packets_written == 0)
+ res= send_server_handshake_packet(mpvio, (char*) packet, packet_len);
+ else if (mpvio->status == MPVIO_EXT::RESTART)
+ res= send_plugin_request_packet(mpvio, packet, packet_len);
+ else if (IS_OUT_OF_BAND_PACKET(packet, packet_len))
+ res= wrap_plguin_data_into_proper_command(mpvio->net, packet, packet_len);
+ else
+ {
+ res= my_net_write(mpvio->net, packet, packet_len) ||
+ net_flush(mpvio->net);
+ }
+ mpvio->packets_written++;
+ DBUG_RETURN(res);
+}
+
+/**
+ vio->read_packet() callback method for server authentication plugins
+
+ This function is called by a server authentication plugin, when it wants
+ to read data from the client.
+
+ It transparently extracts the client plugin data, if embedded into
+ a client authentication handshake packet, and handles plugin negotiation
+ with the client, if necessary.
+*/
+static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
+{
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) param;
+ ulong pkt_len;
+
+ DBUG_ENTER("server_mpvio_read_packet");
+ if (mpvio->packets_written == 0)
+ {
+ /*
+ plugin wants to read the data without sending anything first.
+ send an empty packet to force a server handshake packet to be sent
+ */
+ if (mpvio->write_packet(mpvio, 0, 0))
+ pkt_len= packet_error;
+ else
+ pkt_len= my_net_read(mpvio->net);
+ }
+ else if (mpvio->cached_client_reply.pkt)
+ {
+ DBUG_ASSERT(mpvio->status == MPVIO_EXT::RESTART);
+ DBUG_ASSERT(mpvio->packets_read > 0);
+ /*
+ if the have the data cached from the last server_mpvio_read_packet
+ (which can be the case if it's a restarted authentication)
+ and a client has used the correct plugin, then we can return the
+ cached data straight away and avoid one round trip.
+ */
+ const char *client_auth_plugin=
+ ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
+ if (client_auth_plugin == 0 ||
+ my_strcasecmp(system_charset_info, mpvio->cached_client_reply.plugin,
+ client_auth_plugin) == 0)
+ {
+ mpvio->status= MPVIO_EXT::FAILURE;
+ *buf= (uchar*) mpvio->cached_client_reply.pkt;
+ mpvio->cached_client_reply.pkt= 0;
+ mpvio->packets_read++;
+ DBUG_RETURN ((int) mpvio->cached_client_reply.pkt_len);
+ }
+
+ /* older clients don't support change of client plugin request */
+ if (!(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH))
+ {
+ mpvio->status= MPVIO_EXT::FAILURE;
+ pkt_len= packet_error;
+ goto err;
+ }
+
+ /*
+ But if the client has used the wrong plugin, the cached data are
+ useless. Furthermore, we have to send a "change plugin" request
+ to the client.
+ */
+ if (mpvio->write_packet(mpvio, 0, 0))
+ pkt_len= packet_error;
+ else
+ pkt_len= my_net_read(mpvio->net);
+ }
+ else
+ pkt_len= my_net_read(mpvio->net);
+
+ if (pkt_len == packet_error)
+ goto err;
+
+ mpvio->packets_read++;
+
+ /*
+ the 1st packet has the plugin data wrapped into the client authentication
+ handshake packet
+ */
+ if (mpvio->packets_read == 1)
+ {
+ pkt_len= parse_client_handshake_packet(mpvio, buf, pkt_len);
+ if (pkt_len == packet_error)
+ goto err;
+ }
+ else
+ *buf= mpvio->net->read_pos;
+
+ DBUG_RETURN((int)pkt_len);
+
+err:
+ if (mpvio->status == MPVIO_EXT::FAILURE)
+ {
+ inc_host_errors(mpvio->ip);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0), mpvio->auth_info.host_or_ip);
+ }
+ DBUG_RETURN(-1);
+}
+
+/**
+ fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
+ connection
+*/
+static void server_mpvio_info(MYSQL_PLUGIN_VIO *vio,
+ MYSQL_PLUGIN_VIO_INFO *info)
+{
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
+ mpvio_info(mpvio->net->vio, info);
+}
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user)
+{
+#if defined(HAVE_OPENSSL)
+ Vio *vio= thd->net.vio;
+ SSL *ssl= (SSL *) vio->ssl_arg;
+ X509 *cert;
+#endif
+
+ /*
+ At this point we know that user is allowed to connect
+ from given host by given username/password pair. Now
+ we check if SSL is required, if user is using SSL and
+ if X509 certificate attributes are OK
+ */
+ switch (acl_user->ssl_type) {
+ case SSL_TYPE_NOT_SPECIFIED: // Impossible
+ case SSL_TYPE_NONE: // SSL is not required
+ return 0;
+#if defined(HAVE_OPENSSL)
+ case SSL_TYPE_ANY: // Any kind of SSL is ok
+ return vio_type(vio) != VIO_TYPE_SSL;
+ case SSL_TYPE_X509: /* Client should have any valid certificate. */
+ /*
+ Connections with non-valid certificates are dropped already
+ in sslaccept() anyway, so we do not check validity here.
+
+ We need to check for absence of SSL because without SSL
+ we should reject connection.
+ */
+ if (vio_type(vio) == VIO_TYPE_SSL &&
+ SSL_get_verify_result(ssl) == X509_V_OK &&
+ (cert= SSL_get_peer_certificate(ssl)))
+ {
+ X509_free(cert);
+ return 0;
+ }
+ return 1;
+ case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
+ /* If a cipher name is specified, we compare it to actual cipher in use. */
+ if (vio_type(vio) != VIO_TYPE_SSL ||
+ SSL_get_verify_result(ssl) != X509_V_OK)
+ return 1;
+ if (acl_user->ssl_cipher)
+ {
+ DBUG_PRINT("info", ("comparing ciphers: '%s' and '%s'",
+ acl_user->ssl_cipher, SSL_get_cipher(ssl)));
+ if (strcmp(acl_user->ssl_cipher, SSL_get_cipher(ssl)))
+ {
+ if (global_system_variables.log_warnings)
+ sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'",
+ acl_user->ssl_cipher, SSL_get_cipher(ssl));
+ return 1;
+ }
+ }
+ /* Prepare certificate (if exists) */
+ if (!(cert= SSL_get_peer_certificate(ssl)))
+ return 1;
+ /* If X509 issuer is specified, we check it... */
+ if (acl_user->x509_issuer)
+ {
+ char *ptr= X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
+ DBUG_PRINT("info", ("comparing issuers: '%s' and '%s'",
+ acl_user->x509_issuer, ptr));
+ if (strcmp(acl_user->x509_issuer, ptr))
+ {
+ if (global_system_variables.log_warnings)
+ sql_print_information("X509 issuer mismatch: should be '%s' "
+ "but is '%s'", acl_user->x509_issuer, ptr);
+ free(ptr);
+ X509_free(cert);
+ return 1;
+ }
+ free(ptr);
+ }
+ /* X509 subject is specified, we check it .. */
+ if (acl_user->x509_subject)
+ {
+ char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
+ DBUG_PRINT("info", ("comparing subjects: '%s' and '%s'",
+ acl_user->x509_subject, ptr));
+ if (strcmp(acl_user->x509_subject, ptr))
+ {
+ if (global_system_variables.log_warnings)
+ sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
+ acl_user->x509_subject, ptr);
+ free(ptr);
+ X509_free(cert);
+ return 1;
+ }
+ free(ptr);
+ }
+ X509_free(cert);
+ return 0;
+#else /* HAVE_OPENSSL */
+ default:
+ /*
+ If we don't have SSL but SSL is required for this user the
+ authentication should fail.
+ */
+ return 1;
+#endif /* HAVE_OPENSSL */
+ }
+ return 1;
+}
+#endif
+
+
+static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name,
+ MPVIO_EXT *mpvio)
+{
+ int res= CR_OK, old_status= MPVIO_EXT::FAILURE;
+ bool unlock_plugin= false;
+ plugin_ref plugin;
+
+ if (auth_plugin_name->str == native_password_plugin_name.str)
+ plugin= native_password_plugin;
+ else
+#ifndef EMBEDDED_LIBRARY
+ if (auth_plugin_name->str == old_password_plugin_name.str)
+ plugin= old_password_plugin;
+ else if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
+ MYSQL_AUTHENTICATION_PLUGIN)))
+ unlock_plugin= true;
+ else
+#endif
+ plugin= NULL;
+
+ mpvio->plugin= plugin;
+ old_status= mpvio->status;
+
+ if (plugin)
+ {
+ st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
+ res= auth->authenticate_user(mpvio, &mpvio->auth_info);
+
+ if (unlock_plugin)
+ plugin_unlock(thd, plugin);
+ }
+ else
+ {
+ /* Server cannot load the required plugin. */
+ my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), auth_plugin_name->str);
+ res= CR_ERROR;
+ }
+
+ /*
+ If the status was MPVIO_EXT::RESTART before the authenticate_user() call
+ it can never be MPVIO_EXT::RESTART after the call, because any call
+ to write_packet() or read_packet() will reset the status.
+
+ But (!) if a plugin never called a read_packet() or write_packet(), the
+ status will stay unchanged. We'll fix it, by resetting the status here.
+ */
+ if (old_status == MPVIO_EXT::RESTART && mpvio->status == MPVIO_EXT::RESTART)
+ mpvio->status= MPVIO_EXT::FAILURE; // reset to the default
+
+ return res;
+}
+
+
+static void
+server_mpvio_initialize(THD *thd, MPVIO_EXT *mpvio, uint connect_errors,
+ Thd_charset_adapter *charset_adapter)
+{
+ memset(mpvio, 0, sizeof(MPVIO_EXT));
+ mpvio->read_packet= server_mpvio_read_packet;
+ mpvio->write_packet= server_mpvio_write_packet;
+ mpvio->info= server_mpvio_info;
+ mpvio->auth_info.host_or_ip= thd->security_ctx->host_or_ip;
+ mpvio->auth_info.host_or_ip_length=
+ (unsigned int) strlen(thd->security_ctx->host_or_ip);
+ mpvio->auth_info.user_name= thd->security_ctx->user;
+ mpvio->auth_info.user_name_length= thd->security_ctx->user ?
+ (unsigned int) strlen(thd->security_ctx->user) : 0;
+ mpvio->connect_errors= connect_errors;
+ mpvio->status= MPVIO_EXT::FAILURE;
+
+ mpvio->client_capabilities= thd->client_capabilities;
+ mpvio->mem_root= thd->mem_root;
+ mpvio->scramble= thd->scramble;
+ mpvio->rand= &thd->rand;
+ mpvio->thread_id= thd->thread_id;
+ mpvio->server_status= &thd->server_status;
+ mpvio->net= &thd->net;
+ mpvio->ip= thd->security_ctx->ip;
+ mpvio->host= thd->security_ctx->host;
+ mpvio->charset_adapter= charset_adapter;
+}
+
+
+static void
+server_mpvio_update_thd(THD *thd, MPVIO_EXT *mpvio)
+{
+ thd->client_capabilities= mpvio->client_capabilities;
+ thd->max_client_packet_length= mpvio->max_client_packet_length;
+ if (mpvio->client_capabilities & CLIENT_INTERACTIVE)
+ thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
+ thd->security_ctx->user= mpvio->auth_info.user_name;
+ if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
+ thd->variables.sql_mode|= MODE_IGNORE_SPACE;
+}
+
+/**
+ Perform the handshake, authorize the client and update thd sctx variables.
+
+ @param thd thread handle
+ @param connect_errors number of previous failed connect attemps
+ from this host
+ @param com_change_user_pkt_len size of the COM_CHANGE_USER packet
+ (without the first, command, byte) or 0
+ if it's not a COM_CHANGE_USER (that is, if
+ it's a new connection)
+
+ @retval 0 success, thd is updated.
+ @retval 1 error
+*/
+bool
+acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
+{
+ int res= CR_OK;
+ MPVIO_EXT mpvio;
+ Thd_charset_adapter charset_adapter(thd);
+
+ const LEX_STRING *auth_plugin_name= default_auth_plugin_name;
+ enum enum_server_command command= com_change_user_pkt_len ? COM_CHANGE_USER
+ : COM_CONNECT;
+
+ DBUG_ENTER("acl_authenticate");
+ compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
+
+ server_mpvio_initialize(thd, &mpvio, connect_errors, &charset_adapter);
+
+ DBUG_PRINT("info", ("com_change_user_pkt_len=%u", com_change_user_pkt_len));
+
+ /*
+ Clear thd->db as it points to something, that will be freed when
+ connection is closed. We don't want to accidentally free a wrong
+ pointer if connect failed.
+ */
+ thd->reset_db(NULL, 0);
+
+ if (command == COM_CHANGE_USER)
+ {
+ mpvio.packets_written++; // pretend that a server handshake packet was sent
+ mpvio.packets_read++; // take COM_CHANGE_USER packet into account
+
+ /* Clear variables that are allocated */
+ thd->user_connect= 0;
+
+ if (parse_com_change_user_packet(&mpvio, com_change_user_pkt_len))
+ {
+ server_mpvio_update_thd(thd, &mpvio);
+ DBUG_RETURN(1);
+ }
+
+ DBUG_ASSERT(mpvio.status == MPVIO_EXT::RESTART ||
+ mpvio.status == MPVIO_EXT::SUCCESS);
+ }
+ else
+ {
+ /* mark the thd as having no scramble yet */
+ mpvio.scramble[SCRAMBLE_LENGTH]= 1;
+
+ /*
+ perform the first authentication attempt, with the default plugin.
+ This sends the server handshake packet, reads the client reply
+ with a user name, and performs the authentication if everyone has used
+ the correct plugin.
+ */
+
+ res= do_auth_once(thd, auth_plugin_name, &mpvio);
+ }
+
+ /*
+ retry the authentication, if - after receiving the user name -
+ we found that we need to switch to a non-default plugin
+ */
+ if (mpvio.status == MPVIO_EXT::RESTART)
+ {
+ DBUG_ASSERT(mpvio.acl_user);
+ DBUG_ASSERT(command == COM_CHANGE_USER ||
+ my_strcasecmp(system_charset_info, auth_plugin_name->str,
+ mpvio.acl_user->plugin.str));
+ auth_plugin_name= &mpvio.acl_user->plugin;
+ res= do_auth_once(thd, auth_plugin_name, &mpvio);
+ }
+
+ server_mpvio_update_thd(thd, &mpvio);
+
+ Security_context *sctx= thd->security_ctx;
+ const ACL_USER *acl_user= mpvio.acl_user;
+
+ thd->password= mpvio.auth_info.password_used; // remember for error messages
+
+ /*
+ Log the command here so that the user can check the log
+ for the tried logins and also to detect break-in attempts.
+
+ if sctx->user is unset it's protocol failure, bad packet.
+ */
+ if (mpvio.auth_info.user_name)
+ {
+ if (strcmp(mpvio.auth_info.authenticated_as, mpvio.auth_info.user_name))
+ {
+ general_log_print(thd, command, "%s@%s as %s on %s",
+ mpvio.auth_info.user_name, mpvio.auth_info.host_or_ip,
+ mpvio.auth_info.authenticated_as ?
+ mpvio.auth_info.authenticated_as : "anonymous",
+ mpvio.db.str ? mpvio.db.str : (char*) "");
+ }
+ else
+ general_log_print(thd, command, (char*) "%s@%s on %s",
+ mpvio.auth_info.user_name, mpvio.auth_info.host_or_ip,
+ mpvio.db.str ? mpvio.db.str : (char*) "");
+ }
+
+ if (res > CR_OK && mpvio.status != MPVIO_EXT::SUCCESS)
+ {
+ DBUG_ASSERT(mpvio.status == MPVIO_EXT::FAILURE);
+
+ if (!thd->is_error())
+ login_failed_error(&mpvio, mpvio.auth_info.password_used);
+ DBUG_RETURN (1);
+ }
+
+ sctx->proxy_user[0]= 0;
+
+ if (initialized) // if not --skip-grant-tables
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ bool is_proxy_user= FALSE;
+ const char *auth_user = acl_user->user ? acl_user->user : "";
+ ACL_PROXY_USER *proxy_user;
+ /* check if the user is allowed to proxy as another user */
+ proxy_user= acl_find_proxy_user(auth_user, sctx->host, sctx->ip,
+ mpvio.auth_info.authenticated_as,
+ &is_proxy_user);
+ if (is_proxy_user)
+ {
+ ACL_USER *acl_proxy_user;
+
+ /* we need to find the proxy user, but there was none */
+ if (!proxy_user)
+ {
+ if (!thd->is_error())
+ login_failed_error(&mpvio, mpvio.auth_info.password_used);
+ DBUG_RETURN(1);
+ }
+
+ my_snprintf(sctx->proxy_user, sizeof(sctx->proxy_user) - 1,
+ "'%s'@'%s'", auth_user,
+ acl_user->host.hostname ? acl_user->host.hostname : "");
+
+ /* we're proxying : find the proxy user definition */
+ mysql_mutex_lock(&acl_cache->lock);
+ acl_proxy_user= find_acl_user(proxy_user->get_proxied_host() ?
+ proxy_user->get_proxied_host() : "",
+ mpvio.auth_info.authenticated_as, TRUE);
+ if (!acl_proxy_user)
+ {
+ if (!thd->is_error())
+ login_failed_error(&mpvio, mpvio.auth_info.password_used);
+ mysql_mutex_unlock(&acl_cache->lock);
+ DBUG_RETURN(1);
+ }
+ acl_user= acl_proxy_user->copy(thd->mem_root);
+ mysql_mutex_unlock(&acl_cache->lock);
+ }
+#endif
+
+ sctx->master_access= acl_user->access;
+ if (acl_user->user)
+ strmake(sctx->priv_user, acl_user->user, USERNAME_LENGTH - 1);
+ else
+ *sctx->priv_user= 0;
+
+ if (acl_user->host.hostname)
+ strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME - 1);
+ else
+ *sctx->priv_host= 0;
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ OK. Let's check the SSL. Historically it was checked after the password,
+ as an additional layer, not instead of the password
+ (in which case it would've been a plugin too).
+ */
+ if (acl_check_ssl(thd, acl_user))
+ {
+ if (!thd->is_error())
+ login_failed_error(&mpvio, thd->password);
+ DBUG_RETURN(1);
+ }
+
+ /* Don't allow the user to connect if he has done too many queries */
+ if ((acl_user->user_resource.questions || acl_user->user_resource.updates ||
+ acl_user->user_resource.conn_per_hour ||
+ acl_user->user_resource.user_conn ||
+ global_system_variables.max_user_connections) &&
+ get_or_create_user_conn(thd,
+ (opt_old_style_user_limits ? sctx->user : sctx->priv_user),
+ (opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host),
+ &acl_user->user_resource))
+ DBUG_RETURN(1); // The error is set by get_or_create_user_conn()
+
+#endif
+ }
+ else
+ sctx->skip_grants();
+
+ if (thd->user_connect &&
+ (thd->user_connect->user_resources.conn_per_hour ||
+ thd->user_connect->user_resources.user_conn ||
+ global_system_variables.max_user_connections) &&
+ check_for_max_user_connections(thd, thd->user_connect))
+ {
+ DBUG_RETURN(1); // The error is set in check_for_max_user_connections()
+ }
+
+ DBUG_PRINT("info",
+ ("Capabilities: %lu packet_length: %ld Host: '%s' "
+ "Login user: '%s' Priv_user: '%s' Using password: %s "
+ "Access: %lu db: '%s'",
+ thd->client_capabilities, thd->max_client_packet_length,
+ sctx->host_or_ip, sctx->user, sctx->priv_user,
+ thd->password ? "yes": "no",
+ sctx->master_access, mpvio.db.str));
+
+ if (command == COM_CONNECT &&
+ !(thd->main_security_ctx.master_access & SUPER_ACL))
+ {
+ mysql_mutex_lock(&LOCK_connection_count);
+ bool count_ok= (connection_count <= max_connections);
+ mysql_mutex_unlock(&LOCK_connection_count);
+ if (!count_ok)
+ { // too many connections
+ my_error(ER_CON_COUNT_ERROR, MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+
+ /*
+ This is the default access rights for the current database. It's
+ set to 0 here because we don't have an active database yet (and we
+ may not have an active database to set.
+ */
+ sctx->db_access=0;
+
+ /* Change a database if necessary */
+ if (mpvio.db.length)
+ {
+ if (mysql_change_db(thd, &mpvio.db, FALSE))
+ {
+ /* mysql_change_db() has pushed the error message. */
+ if (thd->user_connect)
+ {
+ decrease_user_connections(thd->user_connect);
+ thd->user_connect= 0;
+ }
+ DBUG_RETURN(1);
+ }
+ }
+
+ if (mpvio.auth_info.external_user[0])
+ sctx->external_user= my_strdup(mpvio.auth_info.external_user, MYF(0));
+
+ if (res == CR_OK_HANDSHAKE_COMPLETE)
+ thd->stmt_da->disable_status();
+ else
+ my_ok(thd);
+
+#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
+ /*
+ Allow the network layer to skip big packets. Although a malicious
+ authenticated session might use this to trick the server to read
+ big packets indefinitely, this is a previously established behavior
+ that needs to be preserved as to not break backwards compatibility.
+ */
+ thd->net.skip_big_packet= TRUE;
+#endif
+
+ /* Ready to handle queries */
+ DBUG_RETURN(0);
+}
+
+/**
+ MySQL Server Password Authentication Plugin
+
+ In the MySQL authentication protocol:
+ 1. the server sends the random scramble to the client
+ 2. client sends the encrypted password back to the server
+ 3. the server checks the password.
+*/
+static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
+ MYSQL_SERVER_AUTH_INFO *info)
+{
+ uchar *pkt;
+ int pkt_len;
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
+
+ DBUG_ENTER("native_password_authenticate");
+
+ /* generate the scramble, or reuse the old one */
+ if (mpvio->scramble[SCRAMBLE_LENGTH])
+ create_random_string(mpvio->scramble, SCRAMBLE_LENGTH, mpvio->rand);
+
+ /* send it to the client */
+ if (mpvio->write_packet(mpvio, (uchar*) mpvio->scramble, SCRAMBLE_LENGTH + 1))
+ DBUG_RETURN(CR_ERROR);
+
+ /* reply and authenticate */
+
+ /*
+ <digression>
+ This is more complex than it looks.
+
+ The plugin (we) may be called right after the client was connected -
+ and will need to send a scramble, read reply, authenticate.
+
+ Or the plugin may be called after another plugin has sent a scramble,
+ and read the reply. If the client has used the correct client-plugin,
+ we won't need to read anything here from the client, the client
+ has already sent a reply with everything we need for authentication.
+
+ Or the plugin may be called after another plugin has sent a scramble,
+ and read the reply, but the client has used the wrong client-plugin.
+ We'll need to sent a "switch to another plugin" packet to the
+ client and read the reply. "Use the short scramble" packet is a special
+ case of "switch to another plugin" packet.
+
+ Or, perhaps, the plugin may be called after another plugin has
+ done the handshake but did not send a useful scramble. We'll need
+ to send a scramble (and perhaps a "switch to another plugin" packet)
+ and read the reply.
+
+ Besides, a client may be an old one, that doesn't understand plugins.
+ Or doesn't even understand 4.0 scramble.
+
+ And we want to keep the same protocol on the wire unless non-native
+ plugins are involved.
+
+ Anyway, it still looks simple from a plugin point of view:
+ "send the scramble, read the reply and authenticate"
+ All the magic is transparently handled by the server.
+ </digression>
+ */
+
+ /* read the reply with the encrypted password */
+ if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
+ DBUG_RETURN(CR_ERROR);
+ DBUG_PRINT("info", ("reply read : pkt_len=%d", pkt_len));
+
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+ DBUG_RETURN(CR_OK);
+#endif
+
+ if (pkt_len == 0) /* no password */
+ DBUG_RETURN(info->auth_string[0] ? CR_ERROR : CR_OK);
+
+ info->password_used= PASSWORD_USED_YES;
+ if (pkt_len == SCRAMBLE_LENGTH)
+ {
+ if (!mpvio->acl_user->salt_len)
+ DBUG_RETURN(CR_ERROR);
+
+ DBUG_RETURN(check_scramble(pkt, mpvio->scramble, mpvio->acl_user->salt) ?
+ CR_ERROR : CR_OK);
+ }
+
+ inc_host_errors(mpvio->ip);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0), mpvio->auth_info.host_or_ip);
+ DBUG_RETURN(CR_ERROR);
+}
+
+static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
+ MYSQL_SERVER_AUTH_INFO *info)
+{
+ uchar *pkt;
+ int pkt_len;
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
+
+ /* generate the scramble, or reuse the old one */
+ if (mpvio->scramble[SCRAMBLE_LENGTH])
+ create_random_string(mpvio->scramble, SCRAMBLE_LENGTH, mpvio->rand);
+
+ /* send it to the client */
+ if (mpvio->write_packet(mpvio, (uchar*) mpvio->scramble, SCRAMBLE_LENGTH + 1))
+ return CR_ERROR;
+
+ /* read the reply and authenticate */
+ if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
+ return CR_ERROR;
+
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+ return CR_OK;
+#endif
+
+ /*
+ legacy: if switch_from_long_to_short_scramble,
+ the password is sent \0-terminated, the pkt_len is always 9 bytes.
+ We need to figure out the correct scramble length here.
+ */
+ if (pkt_len == SCRAMBLE_LENGTH_323 + 1)
+ pkt_len= strnlen((char*)pkt, pkt_len);
+
+ if (pkt_len == 0) /* no password */
+ return info->auth_string[0] ? CR_ERROR : CR_OK;
+
+ if (secure_auth(mpvio))
+ return CR_ERROR;
+
+ info->password_used= PASSWORD_USED_YES;
+
+ if (pkt_len == SCRAMBLE_LENGTH_323)
+ {
+ if (!mpvio->acl_user->salt_len)
+ return CR_ERROR;
+
+ return check_scramble_323(pkt, mpvio->scramble,
+ (ulong *) mpvio->acl_user->salt) ?
+ CR_ERROR : CR_OK;
+ }
+
+ inc_host_errors(mpvio->ip);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0), mpvio->auth_info.host_or_ip);
+ return CR_ERROR;
+}
+
+static struct st_mysql_auth native_password_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ native_password_plugin_name.str,
+ native_password_authenticate
+};
+
+static struct st_mysql_auth old_password_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ old_password_plugin_name.str,
+ old_password_authenticate
+};
+
+mysql_declare_plugin(mysql_password)
+{
+ MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
+ &native_password_handler, /* type descriptor */
+ native_password_plugin_name.str, /* Name */
+ "R.J.Silk, Sergei Golubchik", /* Author */
+ "Native MySQL authentication", /* Description */
+ PLUGIN_LICENSE_GPL, /* License */
+ NULL, /* Init function */
+ NULL, /* Deinit function */
+ 0x0100, /* Version (1.0) */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ NULL /* config options */
+},
+{
+ MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
+ &old_password_handler, /* type descriptor */
+ old_password_plugin_name.str, /* Name */
+ "R.J.Silk, Sergei Golubchik", /* Author */
+ "Old MySQL-4.0 authentication", /* Description */
+ PLUGIN_LICENSE_GPL, /* License */
+ NULL, /* Init function */
+ NULL, /* Deinit function */
+ 0x0100, /* Version (1.0) */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ NULL /* config options */
+}
+mysql_declare_plugin_end;
+
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 4c835e2718c..3a7eefa058c 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -1,4 +1,7 @@
-/* Copyright (C) 2000-2006 MySQL AB
+#ifndef SQL_ACL_INCLUDED
+#define SQL_ACL_INCLUDED
+
+/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -13,7 +16,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "slave.h" // for tables_ok(), rpl_filter
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "violite.h" /* SSL_type */
+#include "sql_class.h" /* LEX_COLUMN */
#define SELECT_ACL (1L << 0)
#define INSERT_ACL (1L << 1)
@@ -43,6 +48,7 @@
#define CREATE_USER_ACL (1L << 25)
#define EVENT_ACL (1L << 26)
#define TRIGGER_ACL (1L << 27)
+#define CREATE_TABLESPACE_ACL (1L << 28)
/*
don't forget to update
1. static struct show_privileges_st sys_privileges[]
@@ -51,7 +57,6 @@
4. acl_init() or whatever - to define behaviour for old privilege tables
5. sql_yacc.yy - for GRANT/REVOKE to work
*/
-#define EXTRA_ACL (1L << 29)
#define NO_ACCESS (1L << 30)
#define DB_ACLS \
(UPDATE_ACL | SELECT_ACL | INSERT_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
@@ -79,11 +84,17 @@
REFERENCES_ACL | INDEX_ACL | ALTER_ACL | SHOW_DB_ACL | SUPER_ACL | \
CREATE_TMP_ACL | LOCK_TABLES_ACL | REPL_SLAVE_ACL | REPL_CLIENT_ACL | \
EXECUTE_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | CREATE_PROC_ACL | \
- ALTER_PROC_ACL | CREATE_USER_ACL | EVENT_ACL | TRIGGER_ACL)
+ ALTER_PROC_ACL | CREATE_USER_ACL | EVENT_ACL | TRIGGER_ACL | \
+ CREATE_TABLESPACE_ACL)
#define DEFAULT_CREATE_PROC_ACLS \
(ALTER_PROC_ACL | EXECUTE_ACL)
+#define SHOW_CREATE_TABLE_ACLS \
+(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | \
+ CREATE_ACL | DROP_ACL | ALTER_ACL | INDEX_ACL | \
+ TRIGGER_ACL | REFERENCES_ACL | GRANT_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL)
+
/*
Defines to change the above bits to how things are stored in tables
This is needed as the 'host' and 'db' table is missing a few privileges
@@ -160,53 +171,7 @@ enum mysql_db_table_field
};
extern const TABLE_FIELD_DEF mysql_db_table_def;
-
-/* Classes */
-
-struct acl_host_and_ip
-{
- char *hostname;
- long ip,ip_mask; // Used with masked ip:s
-};
-
-
-class ACL_ACCESS {
-public:
- ulong sort;
- ulong access;
-};
-
-
-/* ACL_HOST is used if no host is specified */
-
-class ACL_HOST :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- char *db;
-};
-
-
-class ACL_USER :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- uint hostname_length;
- USER_RESOURCES user_resource;
- char *user;
- uint8 salt[SCRAMBLE_LENGTH+1]; // scrambled password in binary form
- uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 3.23, 20 - 4.1.1
- enum SSL_type ssl_type;
- const char *ssl_cipher, *x509_issuer, *x509_subject;
-};
-
-
-class ACL_DB :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- char *user,*db;
-};
+extern bool mysql_user_table_is_in_short_password_format;
/* prototypes */
@@ -216,17 +181,16 @@ my_bool acl_reload(THD *thd);
void acl_free(bool end=0);
ulong acl_get(const char *host, const char *ip,
const char *user, const char *db, my_bool db_is_pattern);
-int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
- uint passwd_len);
-bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
- char *ip, char *db);
+bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len);
+bool acl_getroot(Security_context *sctx, char *user, char *host,
+ char *ip, char *db);
bool acl_check_host(const char *host, const char *ip);
int check_change_password(THD *thd, const char *host, const char *user,
char *password, uint password_len);
bool change_password(THD *thd, const char *host, const char *user,
char *password);
bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
- ulong rights, bool revoke);
+ ulong rights, bool revoke, bool is_proxy);
int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
List <LEX_COLUMN> &column_list, ulong rights,
bool revoke);
@@ -237,7 +201,7 @@ my_bool grant_init();
void grant_free(void);
my_bool grant_reload(THD *thd);
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
- uint show_command, uint number, bool dont_print_error);
+ bool any_combination_will_do, uint number, bool no_errors);
bool check_grant_column (THD *thd, GRANT_INFO *grant,
const char *db_name, const char *table_name,
const char *name, uint length, Security_context *sctx);
@@ -268,7 +232,146 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
bool is_proc);
bool is_acl_user(const char *host, const char *user);
+int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
+int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
+int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
+int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
+int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
+
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define check_grant(A,B,C,D,E,F) 0
#define check_grant_db(A,B) 0
#endif
+
+/**
+ Result of an access check for an internal schema or table.
+ Internal ACL checks are always performed *before* using
+ the grant tables.
+ This mechanism enforces that the server implementation has full
+ control on its internal tables.
+ Depending on the internal check result, the server implementation
+ can choose to:
+ - always allow access,
+ - always deny access,
+ - delegate the decision to the database administrator,
+ by using the grant tables.
+*/
+enum ACL_internal_access_result
+{
+ /**
+ Access granted for all the requested privileges,
+ do not use the grant tables.
+ This flag is used only for the INFORMATION_SCHEMA privileges,
+ for compatibility reasons.
+ */
+ ACL_INTERNAL_ACCESS_GRANTED,
+ /** Access denied, do not use the grant tables. */
+ ACL_INTERNAL_ACCESS_DENIED,
+ /** No decision yet, use the grant tables. */
+ ACL_INTERNAL_ACCESS_CHECK_GRANT
+};
+
+/**
+ Per internal table ACL access rules.
+ This class is an interface.
+ Per table(s) specific access rule should be implemented in a subclass.
+ @sa ACL_internal_schema_access
+*/
+class ACL_internal_table_access
+{
+public:
+ ACL_internal_table_access()
+ {}
+
+ virtual ~ACL_internal_table_access()
+ {}
+
+ /**
+ Check access to an internal table.
+ When a privilege is granted, this method add the requested privilege
+ to save_priv.
+ @param want_access the privileges requested
+ @param [in, out] save_priv the privileges granted
+ @return
+ @retval ACL_INTERNAL_ACCESS_GRANTED All the requested privileges
+ are granted, and saved in save_priv.
+ @retval ACL_INTERNAL_ACCESS_DENIED At least one of the requested
+ privileges was denied.
+ @retval ACL_INTERNAL_ACCESS_CHECK_GRANT No requested privilege
+ was denied, and grant should be checked for at least one
+ privilege. Requested privileges that are granted, if any, are saved
+ in save_priv.
+ */
+ virtual ACL_internal_access_result check(ulong want_access,
+ ulong *save_priv) const= 0;
+};
+
+/**
+ Per internal schema ACL access rules.
+ This class is an interface.
+ Each per schema specific access rule should be implemented
+ in a different subclass, and registered.
+ Per schema access rules can control:
+ - every schema privileges on schema.*
+ - every table privileges on schema.table
+ @sa ACL_internal_schema_registry
+*/
+class ACL_internal_schema_access
+{
+public:
+ ACL_internal_schema_access()
+ {}
+
+ virtual ~ACL_internal_schema_access()
+ {}
+
+ /**
+ Check access to an internal schema.
+ @param want_access the privileges requested
+ @param [in, out] save_priv the privileges granted
+ @return
+ @retval ACL_INTERNAL_ACCESS_GRANTED All the requested privileges
+ are granted, and saved in save_priv.
+ @retval ACL_INTERNAL_ACCESS_DENIED At least one of the requested
+ privileges was denied.
+ @retval ACL_INTERNAL_ACCESS_CHECK_GRANT No requested privilege
+ was denied, and grant should be checked for at least one
+ privilege. Requested privileges that are granted, if any, are saved
+ in save_priv.
+ */
+ virtual ACL_internal_access_result check(ulong want_access,
+ ulong *save_priv) const= 0;
+
+ /**
+ Search for per table ACL access rules by table name.
+ @param name the table name
+ @return per table access rules, or NULL
+ */
+ virtual const ACL_internal_table_access *lookup(const char *name) const= 0;
+};
+
+/**
+ A registry for per internal schema ACL.
+ An 'internal schema' is a database schema maintained by the
+ server implementation, such as 'performance_schema' and 'INFORMATION_SCHEMA'.
+*/
+class ACL_internal_schema_registry
+{
+public:
+ static void register_schema(const LEX_STRING *name,
+ const ACL_internal_schema_access *access);
+ static const ACL_internal_schema_access *lookup(const char *name);
+};
+
+const ACL_internal_schema_access *
+get_cached_schema_access(GRANT_INTERNAL_INFO *grant_internal_info,
+ const char *schema_name);
+
+const ACL_internal_table_access *
+get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info,
+ const char *schema_name,
+ const char *table_name);
+
+bool acl_check_proxy_grant_access (THD *thd, const char *host, const char *user,
+ bool with_grant);
+#endif /* SQL_ACL_INCLUDED */
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
new file mode 100644
index 00000000000..f648d219fac
--- /dev/null
+++ b/sql/sql_admin.cc
@@ -0,0 +1,1033 @@
+/* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 */
+
+#include "sql_class.h" // THD
+#include "keycaches.h" // get_key_cache
+#include "sql_base.h" // Open_table_context
+#include "lock.h" // MYSQL_OPEN_*
+#include "sql_handler.h" // mysql_ha_rm_tables
+#include "partition_element.h" // PART_ADMIN
+#include "sql_partition.h" // set_part_state
+#include "transaction.h" // trans_rollback_stmt
+#include "sql_view.h" // view_checksum
+#include "sql_table.h" // mysql_recreate_table
+#include "debug_sync.h" // DEBUG_SYNC
+#include "sql_acl.h" // *_ACL
+#include "sp.h" // Sroutine_hash_entry
+#include "sql_parse.h" // check_table_access
+#include "sql_admin.h"
+
+static int send_check_errmsg(THD *thd, TABLE_LIST* table,
+ const char* operator_name, const char* errmsg)
+
+{
+ Protocol *protocol= thd->protocol;
+ protocol->prepare_for_resend();
+ protocol->store(table->alias, system_charset_info);
+ protocol->store((char*) operator_name, system_charset_info);
+ protocol->store(STRING_WITH_LEN("error"), system_charset_info);
+ protocol->store(errmsg, system_charset_info);
+ thd->clear_error();
+ if (protocol->write())
+ return -1;
+ return 1;
+}
+
+
+static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
+ HA_CHECK_OPT *check_opt)
+{
+ int error= 0;
+ TABLE tmp_table, *table;
+ TABLE_SHARE *share;
+ bool has_mdl_lock= FALSE;
+ char from[FN_REFLEN],tmp[FN_REFLEN+32];
+ const char **ext;
+ MY_STAT stat_info;
+ Open_table_context ot_ctx(thd, (MYSQL_OPEN_IGNORE_FLUSH |
+ MYSQL_OPEN_HAS_MDL_LOCK |
+ MYSQL_LOCK_IGNORE_TIMEOUT));
+ DBUG_ENTER("prepare_for_repair");
+
+ if (!(check_opt->sql_flags & TT_USEFRM))
+ DBUG_RETURN(0);
+
+ if (!(table= table_list->table))
+ {
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ /*
+ If the table didn't exist, we have a shared metadata lock
+ on it that is left from mysql_admin_table()'s attempt to
+ open it. Release the shared metadata lock before trying to
+ acquire the exclusive lock to satisfy MDL asserts and avoid
+ deadlocks.
+ */
+ thd->mdl_context.release_transactional_locks();
+ /*
+ Attempt to do full-blown table open in mysql_admin_table() has failed.
+ Let us try to open at least a .FRM for this table.
+ */
+ my_hash_value_type hash_value;
+
+ key_length= create_table_def_key(thd, key, table_list, 0);
+ table_list->mdl_request.init(MDL_key::TABLE,
+ table_list->db, table_list->table_name,
+ MDL_EXCLUSIVE, MDL_TRANSACTION);
+
+ if (lock_table_names(thd, table_list, table_list->next_global,
+ thd->variables.lock_wait_timeout,
+ MYSQL_OPEN_SKIP_TEMPORARY))
+ DBUG_RETURN(0);
+ has_mdl_lock= TRUE;
+
+ hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
+ mysql_mutex_lock(&LOCK_open);
+ share= get_table_share(thd, table_list, key, key_length, 0,
+ &error, hash_value);
+ mysql_mutex_unlock(&LOCK_open);
+ if (share == NULL)
+ DBUG_RETURN(0); // Can't open frm file
+
+ if (open_table_from_share(thd, share, "", 0, 0, 0, &tmp_table, FALSE))
+ {
+ mysql_mutex_lock(&LOCK_open);
+ release_table_share(share);
+ mysql_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(0); // Out of memory
+ }
+ table= &tmp_table;
+ }
+
+ /*
+ REPAIR TABLE ... USE_FRM for temporary tables makes little sense.
+ */
+ if (table->s->tmp_table)
+ {
+ error= send_check_errmsg(thd, table_list, "repair",
+ "Cannot repair temporary table from .frm file");
+ goto end;
+ }
+
+ /*
+ User gave us USE_FRM which means that the header in the index file is
+ trashed.
+ In this case we will try to fix the table the following way:
+ - Rename the data file to a temporary name
+ - Truncate the table
+ - Replace the new data file with the old one
+ - Run a normal repair using the new index file and the old data file
+ */
+
+ if (table->s->frm_version != FRM_VER_TRUE_VARCHAR)
+ {
+ error= send_check_errmsg(thd, table_list, "repair",
+ "Failed repairing incompatible .frm file");
+ goto end;
+ }
+
+ /*
+ Check if this is a table type that stores index and data separately,
+ like ISAM or MyISAM. We assume fixed order of engine file name
+ extentions array. First element of engine file name extentions array
+ is meta/index file extention. Second element - data file extention.
+ */
+ ext= table->file->bas_ext();
+ if (!ext[0] || !ext[1])
+ goto end; // No data file
+
+ /* A MERGE table must not come here. */
+ DBUG_ASSERT(table->file->ht->db_type != DB_TYPE_MRG_MYISAM);
+
+ // Name of data file
+ strxmov(from, table->s->normalized_path.str, ext[1], NullS);
+ if (!mysql_file_stat(key_file_misc, from, &stat_info, MYF(0)))
+ goto end; // Can't use USE_FRM flag
+
+ my_snprintf(tmp, sizeof(tmp), "%s-%lx_%lx",
+ from, current_pid, thd->thread_id);
+
+ if (table_list->table)
+ {
+ /*
+ Table was successfully open in mysql_admin_table(). Now we need
+ to close it, but leave it protected by exclusive metadata lock.
+ */
+ if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ goto end;
+ close_all_tables_for_name(thd, table_list->table->s, FALSE);
+ table_list->table= 0;
+ }
+ /*
+ After this point we have an exclusive metadata lock on our table
+ in both cases when table was successfully open in mysql_admin_table()
+ and when it was open in prepare_for_repair().
+ */
+
+ if (my_rename(from, tmp, MYF(MY_WME)))
+ {
+ error= send_check_errmsg(thd, table_list, "repair",
+ "Failed renaming data file");
+ goto end;
+ }
+ if (dd_recreate_table(thd, table_list->db, table_list->table_name))
+ {
+ error= send_check_errmsg(thd, table_list, "repair",
+ "Failed generating table from .frm file");
+ goto end;
+ }
+ /*
+ 'FALSE' for 'using_transactions' means don't postpone
+ invalidation till the end of a transaction, but do it
+ immediately.
+ */
+ query_cache_invalidate3(thd, table_list, FALSE);
+ if (mysql_file_rename(key_file_misc, tmp, from, MYF(MY_WME)))
+ {
+ error= send_check_errmsg(thd, table_list, "repair",
+ "Failed restoring .MYD file");
+ goto end;
+ }
+
+ if (thd->locked_tables_list.reopen_tables(thd))
+ goto end;
+
+ /*
+ Now we should be able to open the partially repaired table
+ to finish the repair in the handler later on.
+ */
+ if (open_table(thd, table_list, thd->mem_root, &ot_ctx))
+ {
+ error= send_check_errmsg(thd, table_list, "repair",
+ "Failed to open partially repaired table");
+ goto end;
+ }
+
+end:
+ thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
+ if (table == &tmp_table)
+ {
+ mysql_mutex_lock(&LOCK_open);
+ closefrm(table, 1); // Free allocated memory
+ mysql_mutex_unlock(&LOCK_open);
+ }
+ /* In case of a temporary table there will be no metadata lock. */
+ if (error && has_mdl_lock)
+ thd->mdl_context.release_transactional_locks();
+
+ DBUG_RETURN(error);
+}
+
+
+/**
+ Check if a given error is something that could occur during
+ open_and_lock_tables() that does not indicate table corruption.
+
+ @param sql_errno Error number to check.
+
+ @retval TRUE Error does not indicate table corruption.
+ @retval FALSE Error could indicate table corruption.
+*/
+
+static inline bool table_not_corrupt_error(uint sql_errno)
+{
+ return (sql_errno == ER_NO_SUCH_TABLE ||
+ sql_errno == ER_FILE_NOT_FOUND ||
+ sql_errno == ER_LOCK_WAIT_TIMEOUT ||
+ sql_errno == ER_LOCK_DEADLOCK ||
+ sql_errno == ER_CANT_LOCK_LOG_TABLE ||
+ sql_errno == ER_OPEN_AS_READONLY);
+}
+
+
+/*
+ RETURN VALUES
+ FALSE Message sent to net (admin operation went ok)
+ TRUE Message should be sent by caller
+ (admin operation or network communication failed)
+*/
+static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
+ HA_CHECK_OPT* check_opt,
+ const char *operator_name,
+ thr_lock_type lock_type,
+ bool open_for_modify,
+ bool no_warnings_for_error,
+ uint extra_open_options,
+ int (*prepare_func)(THD *, TABLE_LIST *,
+ HA_CHECK_OPT *),
+ int (handler::*operator_func)(THD *,
+ HA_CHECK_OPT *),
+ int (view_operator_func)(THD *, TABLE_LIST*))
+{
+ TABLE_LIST *table;
+ SELECT_LEX *select= &thd->lex->select_lex;
+ List<Item> field_list;
+ Item *item;
+ Protocol *protocol= thd->protocol;
+ LEX *lex= thd->lex;
+ int result_code;
+ DBUG_ENTER("mysql_admin_table");
+
+ field_list.push_back(item = new Item_empty_string("Table", NAME_CHAR_LEN*2));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Op", 10));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Msg_type", 10));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Msg_text", 255));
+ item->maybe_null = 1;
+ if (protocol->send_result_set_metadata(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
+
+ mysql_ha_rm_tables(thd, tables);
+
+ for (table= tables; table; table= table->next_local)
+ {
+ char table_name[NAME_LEN*2+2];
+ char* db = table->db;
+ bool fatal_error=0;
+ bool open_error;
+
+ DBUG_PRINT("admin", ("table: '%s'.'%s'", table->db, table->table_name));
+ DBUG_PRINT("admin", ("extra_open_options: %u", extra_open_options));
+ strxmov(table_name, db, ".", table->table_name, NullS);
+ thd->open_options|= extra_open_options;
+ table->lock_type= lock_type;
+ /*
+ To make code safe for re-execution we need to reset type of MDL
+ request as code below may change it.
+ To allow concurrent execution of read-only operations we acquire
+ weak metadata lock for them.
+ */
+ table->mdl_request.set_type((lock_type >= TL_WRITE_ALLOW_WRITE) ?
+ MDL_SHARED_NO_READ_WRITE : MDL_SHARED_READ);
+ /* open only one table from local list of command */
+ {
+ TABLE_LIST *save_next_global, *save_next_local;
+ save_next_global= table->next_global;
+ table->next_global= 0;
+ save_next_local= table->next_local;
+ table->next_local= 0;
+ select->table_list.first= table;
+ /*
+ Time zone tables and SP tables can be add to lex->query_tables list,
+ so it have to be prepared.
+ TODO: Investigate if we can put extra tables into argument instead of
+ using lex->query_tables
+ */
+ lex->query_tables= table;
+ lex->query_tables_last= &table->next_global;
+ lex->query_tables_own_last= 0;
+ /*
+ Under locked tables, we know that the table can be opened,
+ so any errors opening the table are logical errors.
+ In these cases it makes sense to report them.
+ */
+ if (!thd->locked_tables_mode)
+ thd->no_warnings_for_error= no_warnings_for_error;
+ if (view_operator_func == NULL)
+ table->required_type=FRMTYPE_TABLE;
+
+ open_error= open_and_lock_tables(thd, table, TRUE, 0);
+ thd->no_warnings_for_error= 0;
+ table->next_global= save_next_global;
+ table->next_local= save_next_local;
+ thd->open_options&= ~extra_open_options;
+
+ /*
+ If open_and_lock_tables() failed, close_thread_tables() will close
+ the table and table->table can therefore be invalid.
+ */
+ if (open_error)
+ table->table= NULL;
+
+ /*
+ Under locked tables, we know that the table can be opened,
+ so any errors opening the table are logical errors.
+ In these cases it does not make sense to try to repair.
+ */
+ if (open_error && thd->locked_tables_mode)
+ {
+ result_code= HA_ADMIN_FAILED;
+ goto send_result;
+ }
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (table->table)
+ {
+ /*
+ Set up which partitions that should be processed
+ if ALTER TABLE t ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION ..
+ CACHE INDEX/LOAD INDEX for specified partitions
+ */
+ Alter_info *alter_info= &lex->alter_info;
+
+ if (alter_info->flags & ALTER_ADMIN_PARTITION)
+ {
+ if (!table->table->part_info)
+ {
+ my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ uint num_parts_found;
+ uint num_parts_opt= alter_info->partition_names.elements;
+ num_parts_found= set_part_state(alter_info, table->table->part_info,
+ PART_ADMIN);
+ if (num_parts_found != num_parts_opt &&
+ (!(alter_info->flags & ALTER_ALL_PARTITION)))
+ {
+ char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE];
+ size_t length;
+ DBUG_PRINT("admin", ("sending non existent partition error"));
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store(operator_name, system_charset_info);
+ protocol->store(STRING_WITH_LEN("error"), system_charset_info);
+ length= my_snprintf(buff, sizeof(buff),
+ ER(ER_DROP_PARTITION_NON_EXISTENT),
+ table_name);
+ protocol->store(buff, length, system_charset_info);
+ if(protocol->write())
+ goto err;
+ my_eof(thd);
+ goto err;
+ }
+ }
+ }
+#endif
+ }
+ DBUG_PRINT("admin", ("table: 0x%lx", (long) table->table));
+
+ if (prepare_func)
+ {
+ DBUG_PRINT("admin", ("calling prepare_func"));
+ switch ((*prepare_func)(thd, table, check_opt)) {
+ case 1: // error, message written to net
+ trans_rollback_stmt(thd);
+ trans_rollback(thd);
+ close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
+ DBUG_PRINT("admin", ("simple error, admin next table"));
+ continue;
+ case -1: // error, message could be written to net
+ /* purecov: begin inspected */
+ DBUG_PRINT("admin", ("severe error, stop"));
+ goto err;
+ /* purecov: end */
+ default: // should be 0 otherwise
+ DBUG_PRINT("admin", ("prepare_func succeeded"));
+ ;
+ }
+ }
+
+ /*
+ CHECK TABLE command is only command where VIEW allowed here and this
+ command use only temporary teble method for VIEWs resolving => there
+ can't be VIEW tree substitition of join view => if opening table
+ succeed then table->table will have real TABLE pointer as value (in
+ case of join view substitution table->table can be 0, but here it is
+ impossible)
+ */
+ if (!table->table)
+ {
+ DBUG_PRINT("admin", ("open table failed"));
+ if (thd->warning_info->is_empty())
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE));
+ /* if it was a view will check md5 sum */
+ if (table->view &&
+ view_checksum(thd, table) == HA_ADMIN_WRONG_CHECKSUM)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_VIEW_CHECKSUM, ER(ER_VIEW_CHECKSUM));
+ if (thd->stmt_da->is_error() &&
+ table_not_corrupt_error(thd->stmt_da->sql_errno()))
+ result_code= HA_ADMIN_FAILED;
+ else
+ /* Default failure code is corrupt table */
+ result_code= HA_ADMIN_CORRUPT;
+ goto send_result;
+ }
+
+ if (table->view)
+ {
+ DBUG_PRINT("admin", ("calling view_operator_func"));
+ result_code= (*view_operator_func)(thd, table);
+ goto send_result;
+ }
+
+ if (table->schema_table)
+ {
+ result_code= HA_ADMIN_NOT_IMPLEMENTED;
+ goto send_result;
+ }
+
+ if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify)
+ {
+ /* purecov: begin inspected */
+ char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE];
+ size_t length;
+ enum_sql_command save_sql_command= lex->sql_command;
+ DBUG_PRINT("admin", ("sending error message"));
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store(operator_name, system_charset_info);
+ protocol->store(STRING_WITH_LEN("error"), system_charset_info);
+ length= my_snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
+ table_name);
+ protocol->store(buff, length, system_charset_info);
+ trans_commit_stmt(thd);
+ trans_commit(thd);
+ close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
+ lex->reset_query_tables_list(FALSE);
+ /*
+ Restore Query_tables_list::sql_command value to make statement
+ safe for re-execution.
+ */
+ lex->sql_command= save_sql_command;
+ table->table=0; // For query cache
+ if (protocol->write())
+ goto err;
+ thd->stmt_da->reset_diagnostics_area();
+ continue;
+ /* purecov: end */
+ }
+
+ /*
+ Close all instances of the table to allow MyISAM "repair"
+ to rename files.
+ @todo: This code does not close all instances of the table.
+ It only closes instances in other connections, but if this
+ connection has LOCK TABLE t1 a READ, t1 b WRITE,
+ both t1 instances will be kept open.
+ There is no need to execute this branch for InnoDB, which does
+ repair by recreate. There is no need to do it for OPTIMIZE,
+ which doesn't move files around.
+ Hence, this code should be moved to prepare_for_repair(),
+ and executed only for MyISAM engine.
+ */
+ if (lock_type == TL_WRITE && !table->table->s->tmp_table)
+ {
+ if (wait_while_table_is_used(thd, table->table,
+ HA_EXTRA_PREPARE_FOR_RENAME))
+ goto err;
+ DEBUG_SYNC(thd, "after_admin_flush");
+ /* Flush entries in the query cache involving this table. */
+ query_cache_invalidate3(thd, table->table, 0);
+ /*
+ XXX: hack: switch off open_for_modify to skip the
+ flush that is made later in the execution flow.
+ */
+ open_for_modify= 0;
+ }
+
+ if (table->table->s->crashed && operator_func == &handler::ha_check)
+ {
+ /* purecov: begin inspected */
+ DBUG_PRINT("admin", ("sending crashed warning"));
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store(operator_name, system_charset_info);
+ protocol->store(STRING_WITH_LEN("warning"), system_charset_info);
+ protocol->store(STRING_WITH_LEN("Table is marked as crashed"),
+ system_charset_info);
+ if (protocol->write())
+ goto err;
+ /* purecov: end */
+ }
+
+ if (operator_func == &handler::ha_repair &&
+ !(check_opt->sql_flags & TT_USEFRM))
+ {
+ if ((table->table->file->check_old_types() == HA_ADMIN_NEEDS_ALTER) ||
+ (table->table->file->ha_check_for_upgrade(check_opt) ==
+ HA_ADMIN_NEEDS_ALTER))
+ {
+ DBUG_PRINT("admin", ("recreating table"));
+ trans_rollback_stmt(thd);
+ trans_rollback(thd);
+ close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
+ tmp_disable_binlog(thd); // binlogging is done by caller if wanted
+ result_code= mysql_recreate_table(thd, table);
+ reenable_binlog(thd);
+ /*
+ mysql_recreate_table() can push OK or ERROR.
+ Clear 'OK' status. If there is an error, keep it:
+ we will store the error message in a result set row
+ and then clear.
+ */
+ if (thd->stmt_da->is_ok())
+ thd->stmt_da->reset_diagnostics_area();
+ table->table= NULL;
+ result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK;
+ goto send_result;
+ }
+ }
+
+ DBUG_PRINT("admin", ("calling operator_func '%s'", operator_name));
+ result_code = (table->table->file->*operator_func)(thd, check_opt);
+ DBUG_PRINT("admin", ("operator_func returned: %d", result_code));
+
+send_result:
+
+ lex->cleanup_after_one_table_open();
+ thd->clear_error(); // these errors shouldn't get client
+ {
+ List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
+ MYSQL_ERROR *err;
+ while ((err= it++))
+ {
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store((char*) operator_name, system_charset_info);
+ protocol->store(warning_level_names[err->get_level()].str,
+ warning_level_names[err->get_level()].length,
+ system_charset_info);
+ protocol->store(err->get_message_text(), system_charset_info);
+ if (protocol->write())
+ goto err;
+ }
+ thd->warning_info->clear_warning_info(thd->query_id);
+ }
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store(operator_name, system_charset_info);
+
+send_result_message:
+
+ DBUG_PRINT("info", ("result_code: %d", result_code));
+ switch (result_code) {
+ case HA_ADMIN_NOT_IMPLEMENTED:
+ {
+ char buf[MYSQL_ERRMSG_SIZE];
+ size_t length=my_snprintf(buf, sizeof(buf),
+ ER(ER_CHECK_NOT_IMPLEMENTED), operator_name);
+ protocol->store(STRING_WITH_LEN("note"), system_charset_info);
+ protocol->store(buf, length, system_charset_info);
+ }
+ break;
+
+ case HA_ADMIN_NOT_BASE_TABLE:
+ {
+ char buf[MYSQL_ERRMSG_SIZE];
+ size_t length= my_snprintf(buf, sizeof(buf),
+ ER(ER_BAD_TABLE_ERROR), table_name);
+ protocol->store(STRING_WITH_LEN("note"), system_charset_info);
+ protocol->store(buf, length, system_charset_info);
+ }
+ break;
+
+ case HA_ADMIN_OK:
+ protocol->store(STRING_WITH_LEN("status"), system_charset_info);
+ protocol->store(STRING_WITH_LEN("OK"), system_charset_info);
+ break;
+
+ case HA_ADMIN_FAILED:
+ protocol->store(STRING_WITH_LEN("status"), system_charset_info);
+ protocol->store(STRING_WITH_LEN("Operation failed"),
+ system_charset_info);
+ break;
+
+ case HA_ADMIN_REJECT:
+ protocol->store(STRING_WITH_LEN("status"), system_charset_info);
+ protocol->store(STRING_WITH_LEN("Operation need committed state"),
+ system_charset_info);
+ open_for_modify= FALSE;
+ break;
+
+ case HA_ADMIN_ALREADY_DONE:
+ protocol->store(STRING_WITH_LEN("status"), system_charset_info);
+ protocol->store(STRING_WITH_LEN("Table is already up to date"),
+ system_charset_info);
+ break;
+
+ case HA_ADMIN_CORRUPT:
+ protocol->store(STRING_WITH_LEN("error"), system_charset_info);
+ protocol->store(STRING_WITH_LEN("Corrupt"), system_charset_info);
+ fatal_error=1;
+ break;
+
+ case HA_ADMIN_INVALID:
+ protocol->store(STRING_WITH_LEN("error"), system_charset_info);
+ protocol->store(STRING_WITH_LEN("Invalid argument"),
+ system_charset_info);
+ break;
+
+ case HA_ADMIN_TRY_ALTER:
+ {
+ /*
+ This is currently used only by InnoDB. ha_innobase::optimize() answers
+ "try with alter", so here we close the table, do an ALTER TABLE,
+ reopen the table and do ha_innobase::analyze() on it.
+ We have to end the row, so analyze could return more rows.
+ */
+ trans_commit_stmt(thd);
+ trans_commit(thd);
+ close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
+ DEBUG_SYNC(thd, "ha_admin_try_alter");
+ protocol->store(STRING_WITH_LEN("note"), system_charset_info);
+ protocol->store(STRING_WITH_LEN(
+ "Table does not support optimize, doing recreate + analyze instead"),
+ system_charset_info);
+ if (protocol->write())
+ goto err;
+ DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze..."));
+ TABLE_LIST *save_next_local= table->next_local,
+ *save_next_global= table->next_global;
+ table->next_local= table->next_global= 0;
+ tmp_disable_binlog(thd); // binlogging is done by caller if wanted
+ result_code= mysql_recreate_table(thd, table);
+ reenable_binlog(thd);
+ /*
+ mysql_recreate_table() can push OK or ERROR.
+ Clear 'OK' status. If there is an error, keep it:
+ we will store the error message in a result set row
+ and then clear.
+ */
+ if (thd->stmt_da->is_ok())
+ thd->stmt_da->reset_diagnostics_area();
+ trans_commit_stmt(thd);
+ trans_commit(thd);
+ close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
+ table->table= NULL;
+ if (!result_code) // recreation went ok
+ {
+ /* Clear the ticket released above. */
+ table->mdl_request.ticket= NULL;
+ DEBUG_SYNC(thd, "ha_admin_open_ltable");
+ table->mdl_request.set_type(MDL_SHARED_WRITE);
+ if ((table->table= open_ltable(thd, table, lock_type, 0)))
+ {
+ result_code= table->table->file->ha_analyze(thd, check_opt);
+ if (result_code == HA_ADMIN_ALREADY_DONE)
+ result_code= HA_ADMIN_OK;
+ else if (result_code) // analyze failed
+ table->table->file->print_error(result_code, MYF(0));
+ }
+ else
+ result_code= -1; // open failed
+ }
+ /* Start a new row for the final status row */
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store(operator_name, system_charset_info);
+ if (result_code) // either mysql_recreate_table or analyze failed
+ {
+ DBUG_ASSERT(thd->is_error());
+ if (thd->is_error())
+ {
+ const char *err_msg= thd->stmt_da->message();
+ if (!thd->vio_ok())
+ {
+ sql_print_error("%s", err_msg);
+ }
+ else
+ {
+ /* Hijack the row already in-progress. */
+ protocol->store(STRING_WITH_LEN("error"), system_charset_info);
+ protocol->store(err_msg, system_charset_info);
+ if (protocol->write())
+ goto err;
+ /* Start off another row for HA_ADMIN_FAILED */
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store(operator_name, system_charset_info);
+ }
+ thd->clear_error();
+ }
+ }
+ result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK;
+ table->next_local= save_next_local;
+ table->next_global= save_next_global;
+ goto send_result_message;
+ }
+ case HA_ADMIN_WRONG_CHECKSUM:
+ {
+ protocol->store(STRING_WITH_LEN("note"), system_charset_info);
+ protocol->store(ER(ER_VIEW_CHECKSUM), strlen(ER(ER_VIEW_CHECKSUM)),
+ system_charset_info);
+ break;
+ }
+
+ case HA_ADMIN_NEEDS_UPGRADE:
+ case HA_ADMIN_NEEDS_ALTER:
+ {
+ char buf[MYSQL_ERRMSG_SIZE];
+ size_t length;
+
+ protocol->store(STRING_WITH_LEN("error"), system_charset_info);
+ length=my_snprintf(buf, sizeof(buf), ER(ER_TABLE_NEEDS_UPGRADE),
+ table->table_name);
+ protocol->store(buf, length, system_charset_info);
+ fatal_error=1;
+ break;
+ }
+
+ default: // Probably HA_ADMIN_INTERNAL_ERROR
+ {
+ char buf[MYSQL_ERRMSG_SIZE];
+ size_t length=my_snprintf(buf, sizeof(buf),
+ "Unknown - internal error %d during operation",
+ result_code);
+ protocol->store(STRING_WITH_LEN("error"), system_charset_info);
+ protocol->store(buf, length, system_charset_info);
+ fatal_error=1;
+ break;
+ }
+ }
+ if (table->table)
+ {
+ if (table->table->s->tmp_table)
+ {
+ /*
+ If the table was not opened successfully, do not try to get
+ status information. (Bug#47633)
+ */
+ if (open_for_modify && !open_error)
+ table->table->file->info(HA_STATUS_CONST);
+ }
+ else if (open_for_modify || fatal_error)
+ {
+ tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
+ table->db, table->table_name, FALSE);
+ /*
+ May be something modified. Consequently, we have to
+ invalidate the query cache.
+ */
+ table->table= 0; // For query cache
+ query_cache_invalidate3(thd, table, 0);
+ }
+ }
+ /* Error path, a admin command failed. */
+ trans_commit_stmt(thd);
+ trans_commit_implicit(thd);
+ close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
+
+ /*
+ If it is CHECK TABLE v1, v2, v3, and v1, v2, v3 are views, we will run
+ separate open_tables() for each CHECK TABLE argument.
+ Right now we do not have a separate method to reset the prelocking
+ state in the lex to the state after parsing, so each open will pollute
+ this state: add elements to lex->srotuines_list, TABLE_LISTs to
+ lex->query_tables. Below is a lame attempt to recover from this
+ pollution.
+ @todo: have a method to reset a prelocking context, or use separate
+ contexts for each open.
+ */
+ for (Sroutine_hash_entry *rt=
+ (Sroutine_hash_entry*)thd->lex->sroutines_list.first;
+ rt; rt= rt->next)
+ rt->mdl_request.ticket= NULL;
+
+ if (protocol->write())
+ goto err;
+ }
+
+ my_eof(thd);
+ DBUG_RETURN(FALSE);
+
+err:
+ trans_rollback_stmt(thd);
+ trans_rollback(thd);
+ close_thread_tables(thd); // Shouldn't be needed
+ thd->mdl_context.release_transactional_locks();
+ if (table)
+ table->table=0;
+ DBUG_RETURN(TRUE);
+}
+
+
+/*
+ Assigned specified indexes for a table into key cache
+
+ SYNOPSIS
+ mysql_assign_to_keycache()
+ thd Thread object
+ tables Table list (one table only)
+
+ RETURN VALUES
+ FALSE ok
+ TRUE error
+*/
+
+bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables,
+ LEX_STRING *key_cache_name)
+{
+ HA_CHECK_OPT check_opt;
+ KEY_CACHE *key_cache;
+ DBUG_ENTER("mysql_assign_to_keycache");
+
+ check_opt.init();
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ if (!(key_cache= get_key_cache(key_cache_name)))
+ {
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ my_error(ER_UNKNOWN_KEY_CACHE, MYF(0), key_cache_name->str);
+ DBUG_RETURN(TRUE);
+ }
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ check_opt.key_cache= key_cache;
+ DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt,
+ "assign_to_keycache", TL_READ_NO_INSERT, 0, 0,
+ 0, 0, &handler::assign_to_keycache, 0));
+}
+
+
+/*
+ Preload specified indexes for a table into key cache
+
+ SYNOPSIS
+ mysql_preload_keys()
+ thd Thread object
+ tables Table list (one table only)
+
+ RETURN VALUES
+ FALSE ok
+ TRUE error
+*/
+
+bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
+{
+ DBUG_ENTER("mysql_preload_keys");
+ /*
+ We cannot allow concurrent inserts. The storage engine reads
+ directly from the index file, bypassing the cache. It could read
+ outdated information if parallel inserts into cache blocks happen.
+ */
+ DBUG_RETURN(mysql_admin_table(thd, tables, 0,
+ "preload_keys", TL_READ_NO_INSERT, 0, 0, 0, 0,
+ &handler::preload_keys, 0));
+}
+
+
+bool Analyze_table_statement::execute(THD *thd)
+{
+ TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+ bool res= TRUE;
+ thr_lock_type lock_type = TL_READ_NO_INSERT;
+ DBUG_ENTER("Analyze_table_statement::execute");
+
+ if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
+ FALSE, UINT_MAX, FALSE))
+ goto error;
+ thd->enable_slow_log= opt_log_slow_admin_statements;
+ res= mysql_admin_table(thd, first_table, &m_lex->check_opt,
+ "analyze", lock_type, 1, 0, 0, 0,
+ &handler::ha_analyze, 0);
+ /* ! we write after unlocking the table */
+ if (!res && !m_lex->no_write_to_binlog)
+ {
+ /*
+ Presumably, ANALYZE and binlog writing doesn't require synchronization
+ */
+ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ }
+ m_lex->select_lex.table_list.first= first_table;
+ m_lex->query_tables= first_table;
+
+error:
+ DBUG_RETURN(res);
+}
+
+
+bool Check_table_statement::execute(THD *thd)
+{
+ TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+ thr_lock_type lock_type = TL_READ_NO_INSERT;
+ bool res= TRUE;
+ DBUG_ENTER("Check_table_statement::execute");
+
+ if (check_table_access(thd, SELECT_ACL, first_table,
+ TRUE, UINT_MAX, FALSE))
+ goto error; /* purecov: inspected */
+ thd->enable_slow_log= opt_log_slow_admin_statements;
+
+ res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "check",
+ lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0,
+ &handler::ha_check, &view_checksum);
+
+ m_lex->select_lex.table_list.first= first_table;
+ m_lex->query_tables= first_table;
+
+error:
+ DBUG_RETURN(res);
+}
+
+
+bool Optimize_table_statement::execute(THD *thd)
+{
+ TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+ bool res= TRUE;
+ DBUG_ENTER("Optimize_table_statement::execute");
+
+ if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
+ FALSE, UINT_MAX, FALSE))
+ goto error; /* purecov: inspected */
+ thd->enable_slow_log= opt_log_slow_admin_statements;
+ res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
+ mysql_recreate_table(thd, first_table) :
+ mysql_admin_table(thd, first_table, &m_lex->check_opt,
+ "optimize", TL_WRITE, 1, 0, 0, 0,
+ &handler::ha_optimize, 0);
+ /* ! we write after unlocking the table */
+ if (!res && !m_lex->no_write_to_binlog)
+ {
+ /*
+ Presumably, OPTIMIZE and binlog writing doesn't require synchronization
+ */
+ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ }
+ m_lex->select_lex.table_list.first= first_table;
+ m_lex->query_tables= first_table;
+
+error:
+ DBUG_RETURN(res);
+}
+
+
+bool Repair_table_statement::execute(THD *thd)
+{
+ TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+ bool res= TRUE;
+ DBUG_ENTER("Repair_table_statement::execute");
+
+ if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
+ FALSE, UINT_MAX, FALSE))
+ goto error; /* purecov: inspected */
+ thd->enable_slow_log= opt_log_slow_admin_statements;
+ res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair",
+ TL_WRITE, 1,
+ test(m_lex->check_opt.sql_flags & TT_USEFRM),
+ HA_OPEN_FOR_REPAIR, &prepare_for_repair,
+ &handler::ha_repair, 0);
+
+ /* ! we write after unlocking the table */
+ if (!res && !m_lex->no_write_to_binlog)
+ {
+ /*
+ Presumably, REPAIR and binlog writing doesn't require synchronization
+ */
+ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ }
+ m_lex->select_lex.table_list.first= first_table;
+ m_lex->query_tables= first_table;
+
+error:
+ DBUG_RETURN(res);
+}
diff --git a/sql/sql_admin.h b/sql/sql_admin.h
new file mode 100644
index 00000000000..fdfffec8361
--- /dev/null
+++ b/sql/sql_admin.h
@@ -0,0 +1,132 @@
+/* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 SQL_TABLE_MAINTENANCE_H
+#define SQL_TABLE_MAINTENANCE_H
+
+
+bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list,
+ LEX_STRING *key_cache_name);
+bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
+int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache,
+ KEY_CACHE *dst_cache);
+
+/**
+ Analyze_statement represents the ANALYZE TABLE statement.
+*/
+class Analyze_table_statement : public Sql_statement
+{
+public:
+ /**
+ Constructor, used to represent a ANALYZE TABLE statement.
+ @param lex the LEX structure for this statement.
+ */
+ Analyze_table_statement(LEX *lex)
+ : Sql_statement(lex)
+ {}
+
+ ~Analyze_table_statement()
+ {}
+
+ /**
+ Execute a ANALYZE TABLE statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+};
+
+
+
+/**
+ Check_table_statement represents the CHECK TABLE statement.
+*/
+class Check_table_statement : public Sql_statement
+{
+public:
+ /**
+ Constructor, used to represent a CHECK TABLE statement.
+ @param lex the LEX structure for this statement.
+ */
+ Check_table_statement(LEX *lex)
+ : Sql_statement(lex)
+ {}
+
+ ~Check_table_statement()
+ {}
+
+ /**
+ Execute a CHECK TABLE statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+};
+
+
+
+/**
+ Optimize_table_statement represents the OPTIMIZE TABLE statement.
+*/
+class Optimize_table_statement : public Sql_statement
+{
+public:
+ /**
+ Constructor, used to represent a OPTIMIZE TABLE statement.
+ @param lex the LEX structure for this statement.
+ */
+ Optimize_table_statement(LEX *lex)
+ : Sql_statement(lex)
+ {}
+
+ ~Optimize_table_statement()
+ {}
+
+ /**
+ Execute a OPTIMIZE TABLE statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+};
+
+
+
+/**
+ Repair_table_statement represents the REPAIR TABLE statement.
+*/
+class Repair_table_statement : public Sql_statement
+{
+public:
+ /**
+ Constructor, used to represent a REPAIR TABLE statement.
+ @param lex the LEX structure for this statement.
+ */
+ Repair_table_statement(LEX *lex)
+ : Sql_statement(lex)
+ {}
+
+ ~Repair_table_statement()
+ {}
+
+ /**
+ Execute a REPAIR TABLE statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+};
+
+#endif
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
new file mode 100644
index 00000000000..5af01523aa7
--- /dev/null
+++ b/sql/sql_alter.cc
@@ -0,0 +1,109 @@
+/* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 */
+
+#include "sql_parse.h" // check_access
+#include "sql_table.h" // mysql_alter_table,
+ // mysql_exchange_partition
+#include "sql_alter.h"
+
+bool Alter_table_statement::execute(THD *thd)
+{
+ LEX *lex= thd->lex;
+ /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
+ SELECT_LEX *select_lex= &lex->select_lex;
+ /* first table of first SELECT_LEX */
+ TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
+ /*
+ Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
+ so we have to use a copy of this structure to make execution
+ prepared statement- safe. A shallow copy is enough as no memory
+ referenced from this structure will be modified.
+ @todo move these into constructor...
+ */
+ HA_CREATE_INFO create_info(lex->create_info);
+ Alter_info alter_info(lex->alter_info, thd->mem_root);
+ ulong priv=0;
+ ulong priv_needed= ALTER_ACL;
+ bool result;
+
+ DBUG_ENTER("Alter_table_statement::execute");
+
+ if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
+ DBUG_RETURN(TRUE);
+ /*
+ We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
+ as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
+ */
+ if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
+ priv_needed|= DROP_ACL;
+
+ /* Must be set in the parser */
+ DBUG_ASSERT(select_lex->db);
+ DBUG_ASSERT(!(alter_info.flags & ALTER_ADMIN_PARTITION));
+ if (check_access(thd, priv_needed, first_table->db,
+ &first_table->grant.privilege,
+ &first_table->grant.m_internal,
+ 0, 0) ||
+ check_access(thd, INSERT_ACL | CREATE_ACL, select_lex->db,
+ &priv,
+ NULL, /* Don't use first_tab->grant with sel_lex->db */
+ 0, 0))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+
+ /* If it is a merge table, check privileges for merge children. */
+ if (create_info.merge_list.first &&
+ check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
+ create_info.merge_list.first, FALSE, UINT_MAX, FALSE))
+ DBUG_RETURN(TRUE);
+
+ if (check_grant(thd, priv_needed, first_table, FALSE, UINT_MAX, FALSE))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+
+ if (lex->name.str && !test_all_bits(priv, INSERT_ACL | CREATE_ACL))
+ {
+ // Rename of table
+ TABLE_LIST tmp_table;
+ bzero((char*) &tmp_table,sizeof(tmp_table));
+ tmp_table.table_name= lex->name.str;
+ tmp_table.db= select_lex->db;
+ tmp_table.grant.privilege= priv;
+ if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, FALSE,
+ UINT_MAX, FALSE))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+ }
+
+ /* Don't yet allow changing of symlinks with ALTER TABLE */
+ if (create_info.data_file_name)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
+ "DATA DIRECTORY");
+ if (create_info.index_file_name)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
+ "INDEX DIRECTORY");
+ create_info.data_file_name= create_info.index_file_name= NULL;
+
+ thd->enable_slow_log= opt_log_slow_admin_statements;
+
+ result= mysql_alter_table(thd, select_lex->db, lex->name.str,
+ &create_info,
+ first_table,
+ &alter_info,
+ select_lex->order_list.elements,
+ select_lex->order_list.first,
+ lex->ignore);
+
+ DBUG_RETURN(result);
+}
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
new file mode 100644
index 00000000000..6a17f87f5a4
--- /dev/null
+++ b/sql/sql_alter.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 SQL_ALTER_TABLE_H
+#define SQL_ALTER_TABLE_H
+
+/**
+ Alter_table_common represents the common properties of the ALTER TABLE
+ statements.
+ @todo move Alter_info and other ALTER generic structures from Lex here.
+*/
+class Alter_table_common : public Sql_statement
+{
+protected:
+ /**
+ Constructor.
+ @param lex the LEX structure for this statement.
+ */
+ Alter_table_common(LEX *lex)
+ : Sql_statement(lex)
+ {}
+
+ virtual ~Alter_table_common()
+ {}
+
+};
+
+/**
+ Alter_table_statement represents the generic ALTER TABLE statement.
+ @todo move Alter_info and other ALTER specific structures from Lex here.
+*/
+class Alter_table_statement : public Alter_table_common
+{
+public:
+ /**
+ Constructor, used to represent a ALTER TABLE statement.
+ @param lex the LEX structure for this statement.
+ */
+ Alter_table_statement(LEX *lex)
+ : Alter_table_common(lex)
+ {}
+
+ ~Alter_table_statement()
+ {}
+
+ /**
+ Execute a ALTER TABLE statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+};
+
+#endif
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 29ba956bf6c..4b6756188dd 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -28,7 +28,7 @@
#define MYSQL_LEX 1
-#include "mysql_priv.h"
+#include "sql_priv.h"
#include "procedure.h"
#include "sql_analyse.h"
#include <m_ctype.h>
diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h
index 8807b40857e..a1461247894 100644
--- a/sql/sql_analyse.h
+++ b/sql/sql_analyse.h
@@ -1,3 +1,6 @@
+#ifndef SQL_ANALYSE_INCLUDED
+#define SQL_ANALYSE_INCLUDED
+
/* Copyright (C) 2000-2003, 2005 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -20,6 +23,8 @@
#pragma interface /* gcc class implementation */
#endif
+#include "procedure.h" /* Procedure */
+
#define my_thd_charset default_charset_info
#define DEC_IN_AVG 4
@@ -355,3 +360,7 @@ public:
select_result *result,
List<Item> &field_list);
};
+
+bool append_escaped(String *to_str, String *from_str);
+
+#endif /* SQL_ANALYSE_INCLUDED */
diff --git a/sql/sql_array.h b/sql/sql_array.h
index e1b22921519..dfaa9b02947 100644
--- a/sql/sql_array.h
+++ b/sql/sql_array.h
@@ -1,3 +1,6 @@
+#ifndef SQL_ARRAY_INCLUDED
+#define SQL_ARRAY_INCLUDED
+
/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -66,3 +69,4 @@ public:
}
};
+#endif /* SQL_ARRAY_INCLUDED */
diff --git a/sql/sql_audit.cc b/sql/sql_audit.cc
new file mode 100644
index 00000000000..b7d363dc09a
--- /dev/null
+++ b/sql/sql_audit.cc
@@ -0,0 +1,494 @@
+/* Copyright (C) 2007 MySQL AB, 2008-2009 Sun Microsystems, Inc
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "sql_priv.h"
+#include "sql_audit.h"
+
+extern int initialize_audit_plugin(st_plugin_int *plugin);
+extern int finalize_audit_plugin(st_plugin_int *plugin);
+
+#ifndef EMBEDDED_LIBRARY
+
+unsigned long mysql_global_audit_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
+
+static mysql_mutex_t LOCK_audit_mask;
+
+static void event_class_dispatch(THD *thd, const struct mysql_event *event);
+
+
+static inline
+void set_audit_mask(unsigned long *mask, uint event_class)
+{
+ mask[0]= 1;
+ mask[0]<<= event_class;
+}
+
+static inline
+void add_audit_mask(unsigned long *mask, const unsigned long *rhs)
+{
+ mask[0]|= rhs[0];
+}
+
+static inline
+bool check_audit_mask(const unsigned long *lhs,
+ const unsigned long *rhs)
+{
+ return !(lhs[0] & rhs[0]);
+}
+
+
+typedef void (*audit_handler_t)(THD *thd, uint event_subtype, va_list ap);
+
+/**
+ MYSQL_AUDIT_GENERAL_CLASS handler
+
+ @param[in] thd
+ @param[in] event_subtype
+ @param[in] error_code
+ @param[in] ap
+
+*/
+
+static void general_class_handler(THD *thd, uint event_subtype, va_list ap)
+{
+ mysql_event_general event;
+ event.event_class= MYSQL_AUDIT_GENERAL_CLASS;
+ event.event_subclass= event_subtype;
+ event.general_error_code= va_arg(ap, int);
+ event.general_thread_id= thd ? thd->thread_id : 0;
+ event.general_time= va_arg(ap, time_t);
+ event.general_user= va_arg(ap, const char *);
+ event.general_user_length= va_arg(ap, unsigned int);
+ event.general_command= va_arg(ap, const char *);
+ event.general_command_length= va_arg(ap, unsigned int);
+ event.general_query= va_arg(ap, const char *);
+ event.general_query_length= va_arg(ap, unsigned int);
+ event.general_charset= va_arg(ap, struct charset_info_st *);
+ event.general_rows= (unsigned long long) va_arg(ap, ha_rows);
+ event_class_dispatch(thd, (const mysql_event*) &event);
+}
+
+
+static audit_handler_t audit_handlers[] =
+{
+ general_class_handler
+};
+
+static const uint audit_handlers_count=
+ (sizeof(audit_handlers) / sizeof(audit_handler_t));
+
+
+/**
+ Acquire and lock any additional audit plugins as required
+
+ @param[in] thd
+ @param[in] plugin
+ @param[in] arg
+
+ @retval FALSE Always
+*/
+
+static my_bool acquire_plugins(THD *thd, plugin_ref plugin, void *arg)
+{
+ uint event_class= *(uint*) arg;
+ unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
+ st_mysql_audit *data= plugin_data(plugin, struct st_mysql_audit *);
+
+ set_audit_mask(event_class_mask, event_class);
+
+ /* Check if this plugin is interested in the event */
+ if (check_audit_mask(data->class_mask, event_class_mask))
+ return 0;
+
+ /*
+ Check if this plugin may already be registered. This will fail to
+ acquire a newly installed plugin on a specific corner case where
+ one or more event classes already in use by the calling thread
+ are an event class of which the audit plugin has interest.
+ */
+ if (!check_audit_mask(data->class_mask, thd->audit_class_mask))
+ return 0;
+
+ /* Check if we need to initialize the array of acquired plugins */
+ if (unlikely(!thd->audit_class_plugins.buffer))
+ {
+ /* specify some reasonable initialization defaults */
+ my_init_dynamic_array(&thd->audit_class_plugins,
+ sizeof(plugin_ref), 16, 16);
+ }
+
+ /* lock the plugin and add it to the list */
+ plugin= my_plugin_lock(NULL, &plugin);
+ insert_dynamic(&thd->audit_class_plugins, (uchar*) &plugin);
+
+ return 0;
+}
+
+
+/**
+ @brief Acquire audit plugins
+
+ @param[in] thd MySQL thread handle
+ @param[in] event_class Audit event class
+
+ @details Ensure that audit plugins interested in given event
+ class are locked by current thread.
+*/
+void mysql_audit_acquire_plugins(THD *thd, uint event_class)
+{
+ unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
+ DBUG_ENTER("mysql_audit_acquire_plugins");
+ set_audit_mask(event_class_mask, event_class);
+ if (thd && !check_audit_mask(mysql_global_audit_mask, event_class_mask) &&
+ check_audit_mask(thd->audit_class_mask, event_class_mask))
+ {
+ plugin_foreach(thd, acquire_plugins, MYSQL_AUDIT_PLUGIN, &event_class);
+ add_audit_mask(thd->audit_class_mask, event_class_mask);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Notify the audit system of an event
+
+ @param[in] thd
+ @param[in] event_class
+ @param[in] event_subtype
+ @param[in] error_code
+
+*/
+
+void mysql_audit_notify(THD *thd, uint event_class, uint event_subtype, ...)
+{
+ va_list ap;
+ audit_handler_t *handlers= audit_handlers + event_class;
+ DBUG_ASSERT(event_class < audit_handlers_count);
+ mysql_audit_acquire_plugins(thd, event_class);
+ va_start(ap, event_subtype);
+ (*handlers)(thd, event_subtype, ap);
+ va_end(ap);
+}
+
+
+/**
+ Release any resources associated with the current thd.
+
+ @param[in] thd
+
+*/
+
+void mysql_audit_release(THD *thd)
+{
+ plugin_ref *plugins, *plugins_last;
+
+ if (!thd || !(thd->audit_class_plugins.elements))
+ return;
+
+ plugins= (plugin_ref*) thd->audit_class_plugins.buffer;
+ plugins_last= plugins + thd->audit_class_plugins.elements;
+ for (; plugins < plugins_last; plugins++)
+ {
+ st_mysql_audit *data= plugin_data(*plugins, struct st_mysql_audit *);
+
+ /* Check to see if the plugin has a release method */
+ if (!(data->release_thd))
+ continue;
+
+ /* Tell the plugin to release its resources */
+ data->release_thd(thd);
+ }
+
+ /* Now we actually unlock the plugins */
+ plugin_unlock_list(NULL, (plugin_ref*) thd->audit_class_plugins.buffer,
+ thd->audit_class_plugins.elements);
+
+ /* Reset the state of thread values */
+ reset_dynamic(&thd->audit_class_plugins);
+ bzero(thd->audit_class_mask, sizeof(thd->audit_class_mask));
+}
+
+
+/**
+ Initialize thd variables used by Audit
+
+ @param[in] thd
+
+*/
+
+void mysql_audit_init_thd(THD *thd)
+{
+ bzero(&thd->audit_class_plugins, sizeof(thd->audit_class_plugins));
+ bzero(thd->audit_class_mask, sizeof(thd->audit_class_mask));
+}
+
+
+/**
+ Free thd variables used by Audit
+
+ @param[in] thd
+ @param[in] plugin
+ @param[in] arg
+
+ @retval FALSE Always
+*/
+
+void mysql_audit_free_thd(THD *thd)
+{
+ mysql_audit_release(thd);
+ DBUG_ASSERT(thd->audit_class_plugins.elements == 0);
+ delete_dynamic(&thd->audit_class_plugins);
+}
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_LOCK_audit_mask;
+
+static PSI_mutex_info all_audit_mutexes[]=
+{
+ { &key_LOCK_audit_mask, "LOCK_audit_mask", PSI_FLAG_GLOBAL}
+};
+
+static void init_audit_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_audit_mutexes);
+ PSI_server->register_mutex(category, all_audit_mutexes, count);
+}
+#endif /* HAVE_PSI_INTERFACE */
+
+/**
+ Initialize Audit global variables
+*/
+
+void mysql_audit_initialize()
+{
+#ifdef HAVE_PSI_INTERFACE
+ init_audit_psi_keys();
+#endif
+
+ mysql_mutex_init(key_LOCK_audit_mask, &LOCK_audit_mask, MY_MUTEX_INIT_FAST);
+ bzero(mysql_global_audit_mask, sizeof(mysql_global_audit_mask));
+}
+
+
+/**
+ Finalize Audit global variables
+*/
+
+void mysql_audit_finalize()
+{
+ mysql_mutex_destroy(&LOCK_audit_mask);
+}
+
+
+/**
+ Initialize an Audit plug-in
+
+ @param[in] plugin
+
+ @retval FALSE OK
+ @retval TRUE There was an error.
+*/
+
+int initialize_audit_plugin(st_plugin_int *plugin)
+{
+ st_mysql_audit *data= (st_mysql_audit*) plugin->plugin->info;
+
+ if (!data->class_mask || !data->event_notify ||
+ !data->class_mask[0])
+ {
+ sql_print_error("Plugin '%s' has invalid data.",
+ plugin->name.str);
+ return 1;
+ }
+
+ if (plugin->plugin->init && plugin->plugin->init(NULL))
+ {
+ sql_print_error("Plugin '%s' init function returned error.",
+ plugin->name.str);
+ return 1;
+ }
+
+ /* Make the interface info more easily accessible */
+ plugin->data= plugin->plugin->info;
+
+ /* Add the bits the plugin is interested in to the global mask */
+ mysql_mutex_lock(&LOCK_audit_mask);
+ add_audit_mask(mysql_global_audit_mask, data->class_mask);
+ mysql_mutex_unlock(&LOCK_audit_mask);
+
+ return 0;
+}
+
+
+/**
+ Performs a bitwise OR of the installed plugins event class masks
+
+ @param[in] thd
+ @param[in] plugin
+ @param[in] arg
+
+ @retval FALSE always
+*/
+static my_bool calc_class_mask(THD *thd, plugin_ref plugin, void *arg)
+{
+ st_mysql_audit *data= plugin_data(plugin, struct st_mysql_audit *);
+ if ((data= plugin_data(plugin, struct st_mysql_audit *)))
+ add_audit_mask((unsigned long *) arg, data->class_mask);
+ return 0;
+}
+
+
+/**
+ Finalize an Audit plug-in
+
+ @param[in] plugin
+
+ @retval FALSE OK
+ @retval TRUE There was an error.
+*/
+int finalize_audit_plugin(st_plugin_int *plugin)
+{
+ unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
+
+ if (plugin->plugin->deinit && plugin->plugin->deinit(NULL))
+ {
+ DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
+ plugin->name.str));
+ DBUG_EXECUTE("finalize_audit_plugin", return 1; );
+ }
+
+ plugin->data= NULL;
+ bzero(&event_class_mask, sizeof(event_class_mask));
+
+ /* Iterate through all the installed plugins to create new mask */
+
+ /*
+ LOCK_audit_mask/LOCK_plugin order is not fixed, but serialized with table
+ lock on mysql.plugin.
+ */
+ mysql_mutex_lock(&LOCK_audit_mask);
+ plugin_foreach(current_thd, calc_class_mask, MYSQL_AUDIT_PLUGIN,
+ &event_class_mask);
+
+ /* Set the global audit mask */
+ bmove(mysql_global_audit_mask, event_class_mask, sizeof(event_class_mask));
+ mysql_mutex_unlock(&LOCK_audit_mask);
+
+ return 0;
+}
+
+
+/**
+ Dispatches an event by invoking the plugin's event_notify method.
+
+ @param[in] thd
+ @param[in] plugin
+ @param[in] arg
+
+ @retval FALSE always
+*/
+
+static my_bool plugins_dispatch(THD *thd, plugin_ref plugin, void *arg)
+{
+ const struct mysql_event *event= (const struct mysql_event *) arg;
+ unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
+ st_mysql_audit *data= plugin_data(plugin, struct st_mysql_audit *);
+
+ set_audit_mask(event_class_mask, event->event_class);
+
+ /* Check to see if the plugin is interested in this event */
+ if (check_audit_mask(data->class_mask, event_class_mask))
+ return 0;
+
+ /* Actually notify the plugin */
+ data->event_notify(thd, event);
+
+ return 0;
+}
+
+
+/**
+ Distributes an audit event to plug-ins
+
+ @param[in] thd
+ @param[in] event
+*/
+
+static void event_class_dispatch(THD *thd, const struct mysql_event *event)
+{
+ /*
+ Check if we are doing a slow global dispatch. This event occurs when
+ thd == NULL as it is not associated with any particular thread.
+ */
+ if (unlikely(!thd))
+ {
+ plugin_foreach(thd, plugins_dispatch, MYSQL_AUDIT_PLUGIN, (void*) event);
+ }
+ else
+ {
+ plugin_ref *plugins, *plugins_last;
+
+ /* Use the cached set of audit plugins */
+ plugins= (plugin_ref*) thd->audit_class_plugins.buffer;
+ plugins_last= plugins + thd->audit_class_plugins.elements;
+
+ for (; plugins < plugins_last; plugins++)
+ plugins_dispatch(thd, *plugins, (void*) event);
+ }
+}
+
+
+#else /* EMBEDDED_LIBRARY */
+
+
+void mysql_audit_acquire_plugins(THD *thd, uint event_class)
+{
+}
+
+
+void mysql_audit_initialize()
+{
+}
+
+
+void mysql_audit_finalize()
+{
+}
+
+
+int initialize_audit_plugin(st_plugin_int *plugin)
+{
+ return 1;
+}
+
+
+int finalize_audit_plugin(st_plugin_int *plugin)
+{
+ return 0;
+}
+
+
+void mysql_audit_release(THD *thd)
+{
+}
+
+
+#endif /* EMBEDDED_LIBRARY */
diff --git a/sql/sql_audit.h b/sql/sql_audit.h
new file mode 100644
index 00000000000..cbc4c7a7232
--- /dev/null
+++ b/sql/sql_audit.h
@@ -0,0 +1,130 @@
+#ifndef SQL_AUDIT_INCLUDED
+#define SQL_AUDIT_INCLUDED
+
+/* Copyright (C) 2007 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <mysql/plugin_audit.h>
+#include "sql_class.h"
+
+extern unsigned long mysql_global_audit_mask[];
+
+
+extern void mysql_audit_initialize();
+extern void mysql_audit_finalize();
+
+
+extern void mysql_audit_init_thd(THD *thd);
+extern void mysql_audit_free_thd(THD *thd);
+extern void mysql_audit_acquire_plugins(THD *thd, uint event_class);
+
+
+extern void mysql_audit_notify(THD *thd, uint event_class,
+ uint event_subtype, ...);
+extern void mysql_audit_release(THD *thd);
+
+#define MAX_USER_HOST_SIZE 512
+static inline uint make_user_name(THD *thd, char *buf)
+{
+ Security_context *sctx= thd->security_ctx;
+ return strxnmov(buf, MAX_USER_HOST_SIZE,
+ sctx->priv_user[0] ? sctx->priv_user : "", "[",
+ sctx->user ? sctx->user : "", "] @ ",
+ sctx->host ? sctx->host : "", " [",
+ sctx->ip ? sctx->ip : "", "]", NullS) - buf;
+}
+
+/**
+ Call audit plugins of GENERAL audit class, MYSQL_AUDIT_GENERAL_LOG subtype.
+
+ @param[in] thd
+ @param[in] time time that event occurred
+ @param[in] user User name
+ @param[in] userlen User name length
+ @param[in] cmd Command name
+ @param[in] cmdlen Command name length
+ @param[in] query Query string
+ @param[in] querylen Query string length
+*/
+
+static inline
+void mysql_audit_general_log(THD *thd, time_t time,
+ const char *user, uint userlen,
+ const char *cmd, uint cmdlen,
+ const char *query, uint querylen)
+{
+#ifndef EMBEDDED_LIBRARY
+ if (mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK)
+ {
+ CHARSET_INFO *clientcs= thd ? thd->variables.character_set_client
+ : global_system_variables.character_set_client;
+
+ mysql_audit_notify(thd, MYSQL_AUDIT_GENERAL_CLASS, MYSQL_AUDIT_GENERAL_LOG,
+ 0, time, user, userlen, cmd, cmdlen,
+ query, querylen, clientcs, 0);
+ }
+#endif
+}
+
+/**
+ Call audit plugins of GENERAL audit class.
+ event_subtype should be set to one of:
+ MYSQL_AUDIT_GENERAL_ERROR
+ MYSQL_AUDIT_GENERAL_RESULT
+
+ @param[in] thd
+ @param[in] event_subtype Type of general audit event.
+ @param[in] error_code Error code
+ @param[in] msg Message
+*/
+static inline
+void mysql_audit_general(THD *thd, uint event_subtype,
+ int error_code, const char *msg)
+{
+#ifndef EMBEDDED_LIBRARY
+ if (mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK)
+ {
+ time_t time= my_time(0);
+ uint msglen= msg ? strlen(msg) : 0;
+ const char *user;
+ uint userlen;
+ char user_buff[MAX_USER_HOST_SIZE];
+ CSET_STRING query;
+ ha_rows rows;
+
+ if (thd)
+ {
+ query= thd->query_string;
+ user= user_buff;
+ userlen= make_user_name(thd, user_buff);
+ rows= thd->warning_info->current_row_for_warning();
+ }
+ else
+ {
+ user= 0;
+ userlen= 0;
+ rows= 0;
+ }
+
+ mysql_audit_notify(thd, MYSQL_AUDIT_GENERAL_CLASS, event_subtype,
+ error_code, time, user, userlen, msg, msglen,
+ query.str(), query.length(), query.charset(), rows);
+ }
+#endif
+}
+
+
+#endif /* SQL_AUDIT_INCLUDED */
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 3766ff18293..60c32a1a376 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -16,54 +16,58 @@
/* Basic functions needed by many modules */
-#include "mysql_priv.h"
+#include "sql_base.h" // setup_table_map
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h"
#include "debug_sync.h"
+#include "lock.h" // mysql_lock_remove,
+ // mysql_unlock_tables,
+ // mysql_lock_have_duplicate
+#include "sql_show.h" // append_identifier
+#include "strfunc.h" // find_type
+#include "parse_file.h" // sql_parse_prepare, File_parser
+#include "sql_view.h" // mysql_make_view, VIEW_ANY_ACL
+#include "sql_parse.h" // check_table_access
+#include "sql_insert.h" // kill_delayed_threads
+#include "sql_acl.h" // *_ACL, check_grant_all_columns,
+ // check_column_grant_in_table_ref,
+ // get_column_grant
+#include "sql_partition.h" // ALTER_PARTITION_PARAM_TYPE
+#include "sql_derived.h" // mysql_derived_prepare,
+ // mysql_handle_derived,
+ // mysql_derived_filling
+#include "sql_handler.h" // mysql_ha_flush
+#include "sql_partition.h" // ALTER_PARTITION_PARAM_TYPE
+#include "log_event.h" // Query_log_event
#include "sql_select.h"
#include "sp_head.h"
#include "sp.h"
+#include "sp_cache.h"
#include "sql_trigger.h"
+#include "transaction.h"
+#include "sql_prepare.h"
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
#include "rpl_filter.h"
+#include "sql_table.h" // build_table_filename
+#include "datadict.h" // dd_frm_type()
+#include "sql_hset.h" // Hash_set
#ifdef __WIN__
#include <io.h>
#endif
-#define FLAGSTR(S,F) ((S) & (F) ? #F " " : "")
-
-/**
- This internal handler is used to trap internally
- errors that can occur when executing open table
- during the prelocking phase.
-*/
-class Prelock_error_handler : public Internal_error_handler
-{
-public:
- Prelock_error_handler()
- : m_handled_errors(0), m_unhandled_errors(0)
- {}
-
- virtual ~Prelock_error_handler() {}
-
- virtual bool handle_error(uint sql_errno, const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd);
-
- bool safely_trapped_errors();
-
-private:
- int m_handled_errors;
- int m_unhandled_errors;
-};
-
bool
-Prelock_error_handler::handle_error(uint sql_errno,
- const char * /* message */,
- MYSQL_ERROR::enum_warning_level /* level */,
- THD * /* thd */)
+No_such_table_error_handler::handle_condition(THD *,
+ uint sql_errno,
+ const char*,
+ MYSQL_ERROR::enum_warning_level,
+ const char*,
+ MYSQL_ERROR ** cond_hdl)
{
+ *cond_hdl= NULL;
if (sql_errno == ER_NO_SUCH_TABLE)
{
m_handled_errors++;
@@ -75,7 +79,7 @@ Prelock_error_handler::handle_error(uint sql_errno,
}
-bool Prelock_error_handler::safely_trapped_errors()
+bool No_such_table_error_handler::safely_trapped_errors()
{
/*
If m_unhandled_errors != 0, something else, unanticipated, happened,
@@ -89,59 +93,69 @@ bool Prelock_error_handler::safely_trapped_errors()
@defgroup Data_Dictionary Data Dictionary
@{
*/
-TABLE *unused_tables; /* Used by mysql_test */
-HASH open_cache; /* Used by mysql_test */
-static HASH table_def_cache;
-static TABLE_SHARE *oldest_unused_share, end_of_unused_share;
-static pthread_mutex_t LOCK_table_share;
-static bool table_def_inited= 0;
-static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list,
- const char *alias,
- char *cache_key, uint cache_key_length,
- MEM_ROOT *mem_root, uint flags);
-static void free_cache_entry(TABLE *entry);
-static bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
- uint db_stat, uint prgflag,
- uint ha_open_flags, TABLE *outparam,
- TABLE_LIST *table_desc, MEM_ROOT *mem_root);
-static void close_old_data_files(THD *thd, TABLE *table, bool morph_locks,
- bool send_refresh);
-static bool
-has_write_table_with_auto_increment(TABLE_LIST *tables);
+/**
+ Protects table_def_hash, used and unused lists in the
+ TABLE_SHARE object, LRU lists of used TABLEs and used
+ TABLE_SHAREs, refresh_version and the table id counter.
+*/
+mysql_mutex_t LOCK_open;
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_LOCK_open;
+static PSI_mutex_info all_tdc_mutexes[]= {
+ { &key_LOCK_open, "LOCK_open", PSI_FLAG_GLOBAL }
+};
+/**
+ Initialize performance schema instrumentation points
+ used by the table cache.
+*/
-extern "C" uchar *table_cache_key(const uchar *record, size_t *length,
- my_bool not_used __attribute__((unused)))
+static void init_tdc_psi_keys(void)
{
- TABLE *entry=(TABLE*) record;
- *length= entry->s->table_cache_key.length;
- return (uchar*) entry->s->table_cache_key.str;
-}
+ const char *category= "sql";
+ int count;
+ if (PSI_server == NULL)
+ return;
-bool table_cache_init(void)
-{
- return hash_init(&open_cache, &my_charset_bin, table_cache_size+16,
- 0, 0, table_cache_key,
- (hash_free_key) free_cache_entry, 0) != 0;
+ count= array_elements(all_tdc_mutexes);
+ PSI_server->register_mutex(category, all_tdc_mutexes, count);
}
+#endif /* HAVE_PSI_INTERFACE */
+
+
+/**
+ Total number of TABLE instances for tables in the table definition cache
+ (both in use by threads and not in use). This value is accessible to user
+ as "Open_tables" status variable.
+*/
+uint table_cache_count= 0;
+/**
+ List that contains all TABLE instances for tables in the table definition
+ cache that are not in use by any thread. Recently used TABLE instances are
+ appended to the end of the list. Thus the beginning of the list contains
+ tables which have been least recently used.
+*/
+TABLE *unused_tables;
+HASH table_def_cache;
+static TABLE_SHARE *oldest_unused_share, end_of_unused_share;
+static bool table_def_inited= 0;
+static bool table_def_shutdown_in_progress= 0;
+
+static bool check_and_update_table_version(THD *thd, TABLE_LIST *tables,
+ TABLE_SHARE *table_share);
+static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry);
+static bool auto_repair_table(THD *thd, TABLE_LIST *table_list);
+static void free_cache_entry(TABLE *entry);
+static bool
+has_write_table_with_auto_increment(TABLE_LIST *tables);
-void table_cache_free(void)
-{
- DBUG_ENTER("table_cache_free");
- if (table_def_inited)
- {
- close_cached_tables(NULL, NULL, FALSE, FALSE, FALSE);
- if (!open_cache.records) // Safety first
- hash_free(&open_cache);
- }
- DBUG_VOID_RETURN;
-}
uint cached_open_tables(void)
{
- return open_cache.records;
+ return table_cache_count;
}
@@ -149,7 +163,8 @@ uint cached_open_tables(void)
static void check_unused(void)
{
uint count= 0, open_files= 0, idx= 0;
- TABLE *cur_link,*start_link;
+ TABLE *cur_link, *start_link, *entry;
+ TABLE_SHARE *share;
if ((start_link=cur_link=unused_tables))
{
@@ -160,45 +175,47 @@ static void check_unused(void)
DBUG_PRINT("error",("Unused_links aren't linked properly")); /* purecov: inspected */
return; /* purecov: inspected */
}
- } while (count++ < open_cache.records &&
+ } while (count++ < table_cache_count &&
(cur_link=cur_link->next) != start_link);
if (cur_link != start_link)
{
DBUG_PRINT("error",("Unused_links aren't connected")); /* purecov: inspected */
}
}
- for (idx=0 ; idx < open_cache.records ; idx++)
+ for (idx=0 ; idx < table_def_cache.records ; idx++)
{
- TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
- if (!entry->in_use)
+ share= (TABLE_SHARE*) my_hash_element(&table_def_cache, idx);
+
+ I_P_List_iterator<TABLE, TABLE_share> it(share->free_tables);
+ while ((entry= it++))
+ {
+ /* We must not have TABLEs in the free list that have their file closed. */
+ DBUG_ASSERT(entry->db_stat && entry->file);
+ /* Merge children should be detached from a merge parent */
+ DBUG_ASSERT(! entry->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
+
+ if (entry->in_use)
+ {
+ DBUG_PRINT("error",("Used table is in share's list of unused tables")); /* purecov: inspected */
+ }
count--;
- if (entry->file)
open_files++;
+ }
+ it.init(share->used_tables);
+ while ((entry= it++))
+ {
+ if (!entry->in_use)
+ {
+ DBUG_PRINT("error",("Unused table is in share's list of used tables")); /* purecov: inspected */
+ }
+ open_files++;
+ }
}
if (count != 0)
{
DBUG_PRINT("error",("Unused_links doesn't match open_cache: diff: %d", /* purecov: inspected */
count)); /* purecov: inspected */
}
-
-#ifdef NOT_SAFE_FOR_REPAIR
- /*
- check that open cache and table definition cache has same number of
- aktive tables
- */
- count= 0;
- for (idx=0 ; idx < table_def_cache.records ; idx++)
- {
- TABLE_SHARE *entry= (TABLE_SHARE*) hash_element(&table_def_cache,idx);
- count+= entry->ref_count;
- }
- if (count != open_files)
- {
- DBUG_PRINT("error", ("table_def ref_count: %u open_cache: %u",
- count, open_files));
- DBUG_ASSERT(count == open_files);
- }
-#endif
}
#else
#define check_unused()
@@ -230,7 +247,8 @@ static void check_unused(void)
Length of key
*/
-uint create_table_def_key(THD *thd, char *key, TABLE_LIST *table_list,
+uint create_table_def_key(THD *thd, char *key,
+ const TABLE_LIST *table_list,
bool tmp_table)
{
uint key_length= (uint) (strmov(strmov(key, table_list->db)+1,
@@ -262,13 +280,12 @@ extern "C" uchar *table_def_key(const uchar *record, size_t *length,
static void table_def_free_entry(TABLE_SHARE *share)
{
DBUG_ENTER("table_def_free_entry");
+ mysql_mutex_assert_owner(&LOCK_open);
if (share->prev)
{
/* remove from old_unused_share list */
- pthread_mutex_lock(&LOCK_table_share);
*share->prev= share->next;
share->next->prev= share->prev;
- pthread_mutex_unlock(&LOCK_table_share);
}
free_table_share(share);
DBUG_VOID_RETURN;
@@ -278,13 +295,42 @@ static void table_def_free_entry(TABLE_SHARE *share)
bool table_def_init(void)
{
table_def_inited= 1;
- pthread_mutex_init(&LOCK_table_share, MY_MUTEX_INIT_FAST);
+#ifdef HAVE_PSI_INTERFACE
+ init_tdc_psi_keys();
+#endif
+ mysql_mutex_init(key_LOCK_open, &LOCK_open, MY_MUTEX_INIT_FAST);
oldest_unused_share= &end_of_unused_share;
end_of_unused_share.prev= &oldest_unused_share;
- return hash_init(&table_def_cache, &my_charset_bin, table_def_size,
- 0, 0, table_def_key,
- (hash_free_key) table_def_free_entry, 0) != 0;
+
+ return my_hash_init(&table_def_cache, &my_charset_bin, table_def_size,
+ 0, 0, table_def_key,
+ (my_hash_free_key) table_def_free_entry, 0) != 0;
+}
+
+
+/**
+ Notify table definition cache that process of shutting down server
+ has started so it has to keep number of TABLE and TABLE_SHARE objects
+ minimal in order to reduce number of references to pluggable engines.
+*/
+
+void table_def_start_shutdown(void)
+{
+ if (table_def_inited)
+ {
+ mysql_mutex_lock(&LOCK_open);
+ /*
+ Ensure that TABLE and TABLE_SHARE objects which are created for
+ tables that are open during process of plugins' shutdown are
+ immediately released. This keeps number of references to engine
+ plugins minimal and allows shutdown to proceed smoothly.
+ */
+ table_def_shutdown_in_progress= TRUE;
+ mysql_mutex_unlock(&LOCK_open);
+ /* Free all cached but unused TABLEs and TABLE_SHAREs. */
+ close_cached_tables(NULL, NULL, FALSE, LONG_TIMEOUT);
+ }
}
@@ -294,8 +340,9 @@ void table_def_free(void)
if (table_def_inited)
{
table_def_inited= 0;
- pthread_mutex_destroy(&LOCK_table_share);
- hash_free(&table_def_cache);
+ /* Free table definitions. */
+ my_hash_free(&table_def_cache);
+ mysql_mutex_destroy(&LOCK_open);
}
DBUG_VOID_RETURN;
}
@@ -308,6 +355,121 @@ uint cached_table_definitions(void)
/*
+ Auxiliary routines for manipulating with per-share used/unused and
+ global unused lists of TABLE objects and table_cache_count counter.
+ Responsible for preserving invariants between those lists, counter
+ and TABLE::in_use member.
+ In fact those routines implement sort of implicit table cache as
+ part of table definition cache.
+*/
+
+
+/**
+ Add newly created TABLE object for table share which is going
+ to be used right away.
+*/
+
+static void table_def_add_used_table(THD *thd, TABLE *table)
+{
+ DBUG_ASSERT(table->in_use == thd);
+ table->s->used_tables.push_front(table);
+ table_cache_count++;
+}
+
+
+/**
+ Prepare used or unused TABLE instance for destruction by removing
+ it from share's and global list.
+*/
+
+static void table_def_remove_table(TABLE *table)
+{
+ if (table->in_use)
+ {
+ /* Remove from per-share chain of used TABLE objects. */
+ table->s->used_tables.remove(table);
+ }
+ else
+ {
+ /* Remove from per-share chain of unused TABLE objects. */
+ table->s->free_tables.remove(table);
+
+ /* And global unused chain. */
+ table->next->prev=table->prev;
+ table->prev->next=table->next;
+ if (table == unused_tables)
+ {
+ unused_tables=unused_tables->next;
+ if (table == unused_tables)
+ unused_tables=0;
+ }
+ check_unused();
+ }
+ table_cache_count--;
+}
+
+
+/**
+ Mark already existing TABLE instance as used.
+*/
+
+static void table_def_use_table(THD *thd, TABLE *table)
+{
+ DBUG_ASSERT(!table->in_use);
+
+ /* Unlink table from list of unused tables for this share. */
+ table->s->free_tables.remove(table);
+ /* Unlink able from global unused tables list. */
+ if (table == unused_tables)
+ { // First unused
+ unused_tables=unused_tables->next; // Remove from link
+ if (table == unused_tables)
+ unused_tables=0;
+ }
+ table->prev->next=table->next; /* Remove from unused list */
+ table->next->prev=table->prev;
+ check_unused();
+ /* Add table to list of used tables for this share. */
+ table->s->used_tables.push_front(table);
+ table->in_use= thd;
+ /* The ex-unused table must be fully functional. */
+ DBUG_ASSERT(table->db_stat && table->file);
+ /* The children must be detached from the table. */
+ DBUG_ASSERT(! table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
+}
+
+
+/**
+ Mark already existing used TABLE instance as unused.
+*/
+
+static void table_def_unuse_table(TABLE *table)
+{
+ DBUG_ASSERT(table->in_use);
+
+ /* We shouldn't put the table to 'unused' list if the share is old. */
+ DBUG_ASSERT(! table->s->has_old_version());
+
+ table->in_use= 0;
+ /* Remove table from the list of tables used in this share. */
+ table->s->used_tables.remove(table);
+ /* Add table to the list of unused TABLE objects for this share. */
+ table->s->free_tables.push_front(table);
+ /* Also link it last in the global list of unused TABLE objects. */
+ if (unused_tables)
+ {
+ table->next=unused_tables;
+ table->prev=unused_tables->prev;
+ unused_tables->prev=table;
+ table->prev->next=table;
+ }
+ else
+ unused_tables=table->next=table->prev=table;
+ check_unused();
+}
+
+
+/*
Get TABLE_SHARE for a table.
get_table_share()
@@ -333,16 +495,26 @@ uint cached_table_definitions(void)
*/
TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
- uint key_length, uint db_flags, int *error)
+ uint key_length, uint db_flags, int *error,
+ my_hash_value_type hash_value)
{
TABLE_SHARE *share;
DBUG_ENTER("get_table_share");
*error= 0;
+ /*
+ To be able perform any operation on table we should own
+ some kind of metadata lock on it.
+ */
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ table_list->db,
+ table_list->table_name,
+ MDL_SHARED));
+
/* Read table definition from cache */
- if ((share= (TABLE_SHARE*) hash_search(&table_def_cache,(uchar*) key,
- key_length)))
+ if ((share= (TABLE_SHARE*) my_hash_search_using_hash_value(&table_def_cache,
+ hash_value, (uchar*) key, key_length)))
goto found;
if (!(share= alloc_table_share(table_list, key, key_length)))
@@ -351,16 +523,10 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
}
/*
- Lock mutex to be able to read table definition from file without
- conflicts
- */
- (void) pthread_mutex_lock(&share->mutex);
-
- /*
- We assign a new table id under the protection of the LOCK_open and
- the share's own mutex. We do this insted of creating a new mutex
+ We assign a new table id under the protection of LOCK_open.
+ We do this instead of creating a new mutex
and using it for the sole purpose of serializing accesses to a
- static variable, we assign the table id here. We assign it to the
+ static variable, we assign the table id here. We assign it to the
share before inserting it into the table_def_cache to be really
sure that it cannot be read from the cache without having a table
id assigned.
@@ -379,60 +545,50 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
if (open_table_def(thd, share, db_flags))
{
*error= share->error;
- (void) hash_delete(&table_def_cache, (uchar*) share);
+ (void) my_hash_delete(&table_def_cache, (uchar*) share);
DBUG_RETURN(0);
}
share->ref_count++; // Mark in use
DBUG_PRINT("exit", ("share: 0x%lx ref_count: %u",
(ulong) share, share->ref_count));
- (void) pthread_mutex_unlock(&share->mutex);
DBUG_RETURN(share);
found:
- /*
+ /*
We found an existing table definition. Return it if we didn't get
an error when reading the table definition from file.
*/
-
- /* We must do a lock to ensure that the structure is initialized */
- (void) pthread_mutex_lock(&share->mutex);
if (share->error)
{
/* Table definition contained an error */
open_table_error(share, share->error, share->open_errno, share->errarg);
- (void) pthread_mutex_unlock(&share->mutex);
DBUG_RETURN(0);
}
if (share->is_view && !(db_flags & OPEN_VIEW))
{
open_table_error(share, 1, ENOENT, 0);
- (void) pthread_mutex_unlock(&share->mutex);
DBUG_RETURN(0);
}
- if (!share->ref_count++ && share->prev)
+ ++share->ref_count;
+
+ if (share->ref_count == 1 && share->prev)
{
/*
Share was not used before and it was in the old_unused_share list
Unlink share from this list
*/
DBUG_PRINT("info", ("Unlinking from not used list"));
- pthread_mutex_lock(&LOCK_table_share);
*share->prev= share->next;
share->next->prev= share->prev;
share->next= 0;
share->prev= 0;
- pthread_mutex_unlock(&LOCK_table_share);
}
- (void) pthread_mutex_unlock(&share->mutex);
/* Free cache if too big */
while (table_def_cache.records > table_def_size &&
oldest_unused_share->next)
- {
- pthread_mutex_lock(&oldest_unused_share->mutex);
- VOID(hash_delete(&table_def_cache, (uchar*) oldest_unused_share));
- }
+ my_hash_delete(&table_def_cache, (uchar*) oldest_unused_share);
DBUG_PRINT("exit", ("share: 0x%lx ref_count: %u",
(ulong) share, share->ref_count));
@@ -440,22 +596,25 @@ found:
}
-/*
+/**
Get a table share. If it didn't exist, try creating it from engine
- For arguments and return values, see get_table_from_share()
+ For arguments and return values, see get_table_share()
*/
-static TABLE_SHARE
-*get_table_share_with_create(THD *thd, TABLE_LIST *table_list,
- char *key, uint key_length,
- uint db_flags, int *error)
+static TABLE_SHARE *
+get_table_share_with_discover(THD *thd, TABLE_LIST *table_list,
+ char *key, uint key_length,
+ uint db_flags, int *error,
+ my_hash_value_type hash_value)
+
{
TABLE_SHARE *share;
- int tmp;
+ bool exists;
DBUG_ENTER("get_table_share_with_create");
- share= get_table_share(thd, table_list, key, key_length, db_flags, error);
+ share= get_table_share(thd, table_list, key, key_length, db_flags, error,
+ hash_value);
/*
If share is not NULL, we found an existing share.
@@ -465,31 +624,41 @@ static TABLE_SHARE
from the pre-locking list. In this case we still need to try
auto-discover before returning a NULL share.
+ Or, we're inside SHOW CREATE VIEW, which
+ also installs a silencer for ER_NO_SUCH_TABLE error.
+
If share is NULL and the error is ER_NO_SUCH_TABLE, this is
- the same as above, only that the error was not silenced by
- pre-locking. Once again, we need to try to auto-discover
- the share.
+ the same as above, only that the error was not silenced by
+ pre-locking or SHOW CREATE VIEW.
+
+ In both these cases it won't harm to try to discover the
+ table.
Finally, if share is still NULL, it's a real error and we need
to abort.
@todo Rework alternative ways to deal with ER_NO_SUCH TABLE.
*/
- if (share || (thd->is_error() && thd->main_da.sql_errno() != ER_NO_SUCH_TABLE))
-
+ if (share || (thd->is_error() && thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE))
DBUG_RETURN(share);
+ *error= 0;
+
/* Table didn't exist. Check if some engine can provide it */
- tmp= ha_create_table_from_engine(thd, table_list->db,
- table_list->table_name);
- if (tmp < 0)
+ if (ha_check_if_table_exists(thd, table_list->db, table_list->table_name,
+ &exists))
+ {
+ thd->clear_error();
+ /* Conventionally, the storage engine API does not report errors. */
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ }
+ else if (! exists)
{
/*
No such table in any engine.
Hide "Table doesn't exist" errors if the table belongs to a view.
The check for thd->is_error() is necessary to not push an
- unwanted error in case of pre-locking, which silences
- "no such table" errors.
+ unwanted error in case the error was already silenced.
@todo Rework the alternative ways to deal with ER_NO_SUCH TABLE.
*/
if (thd->is_error())
@@ -507,89 +676,60 @@ static TABLE_SHARE
view->view_db.str, view->view_name.str);
}
}
- DBUG_RETURN(0);
}
- if (tmp)
+ else
{
- /* Give right error message */
thd->clear_error();
- DBUG_PRINT("error", ("Discovery of %s/%s failed", table_list->db,
- table_list->table_name));
- my_printf_error(ER_UNKNOWN_ERROR,
- "Failed to open '%-.64s', error while "
- "unpacking from engine",
- MYF(0), table_list->table_name);
- DBUG_RETURN(0);
+ *error= 7; /* Run auto-discover. */
}
- /* Table existed in engine. Let's open it */
- mysql_reset_errors(thd, 1); // Clear warnings
- thd->clear_error(); // Clear error message
- DBUG_RETURN(get_table_share(thd, table_list, key, key_length,
- db_flags, error));
+ DBUG_RETURN(NULL);
}
-/*
- Mark that we are not using table share anymore.
+/**
+ Mark that we are not using table share anymore.
- SYNOPSIS
- release_table_share()
- share Table share
- release_type How the release should be done:
- RELEASE_NORMAL
- - Release without checking
- RELEASE_WAIT_FOR_DROP
- - Don't return until we get a signal that the
- table is deleted or the thread is killed.
-
- IMPLEMENTATION
- If ref_count goes to zero and (we have done a refresh or if we have
- already too many open table shares) then delete the definition.
-
- If type == RELEASE_WAIT_FOR_DROP then don't return until we get a signal
- that the table is deleted or the thread is killed.
+ @param share Table share
+
+ If the share has no open tables and (we have done a refresh or
+ if we have already too many open table shares) then delete the
+ definition.
*/
-void release_table_share(TABLE_SHARE *share, enum release_type type)
+void release_table_share(TABLE_SHARE *share)
{
- bool to_be_deleted= 0;
DBUG_ENTER("release_table_share");
DBUG_PRINT("enter",
("share: 0x%lx table: %s.%s ref_count: %u version: %lu",
(ulong) share, share->db.str, share->table_name.str,
share->ref_count, share->version));
- safe_mutex_assert_owner(&LOCK_open);
+ mysql_mutex_assert_owner(&LOCK_open);
- pthread_mutex_lock(&share->mutex);
+ DBUG_ASSERT(share->ref_count);
if (!--share->ref_count)
{
- if (share->version != refresh_version)
- to_be_deleted=1;
+ if (share->has_old_version() || table_def_shutdown_in_progress)
+ my_hash_delete(&table_def_cache, (uchar*) share);
else
{
/* Link share last in used_table_share list */
DBUG_PRINT("info",("moving share to unused list"));
DBUG_ASSERT(share->next == 0);
- pthread_mutex_lock(&LOCK_table_share);
share->prev= end_of_unused_share.prev;
*end_of_unused_share.prev= share;
end_of_unused_share.prev= &share->next;
share->next= &end_of_unused_share;
- pthread_mutex_unlock(&LOCK_table_share);
- to_be_deleted= (table_def_cache.records > table_def_size);
+ if (table_def_cache.records > table_def_size)
+ {
+ /* Delete the least used share to preserve LRU order. */
+ my_hash_delete(&table_def_cache, (uchar*) oldest_unused_share);
+ }
}
}
- if (to_be_deleted)
- {
- DBUG_PRINT("info", ("Deleting share"));
- hash_delete(&table_def_cache, (uchar*) share);
- DBUG_VOID_RETURN;
- }
- pthread_mutex_unlock(&share->mutex);
DBUG_VOID_RETURN;
}
@@ -612,76 +752,17 @@ TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name)
char key[NAME_LEN*2+2];
TABLE_LIST table_list;
uint key_length;
- safe_mutex_assert_owner(&LOCK_open);
+ mysql_mutex_assert_owner(&LOCK_open);
table_list.db= (char*) db;
table_list.table_name= (char*) table_name;
key_length= create_table_def_key((THD*) 0, key, &table_list, 0);
- return (TABLE_SHARE*) hash_search(&table_def_cache,(uchar*) key, key_length);
+ return (TABLE_SHARE*) my_hash_search(&table_def_cache,
+ (uchar*) key, key_length);
}
/*
- Close file handle, but leave the table in the table cache
-
- SYNOPSIS
- close_handle_and_leave_table_as_lock()
- table Table handler
-
- NOTES
- By leaving the table in the table cache, it disallows any other thread
- to open the table
-
- thd->killed will be set if we run out of memory
-
- If closing a MERGE child, the calling function has to take care for
- closing the parent too, if necessary.
-*/
-
-
-void close_handle_and_leave_table_as_lock(TABLE *table)
-{
- TABLE_SHARE *share, *old_share= table->s;
- char *key_buff;
- MEM_ROOT *mem_root= &table->mem_root;
- DBUG_ENTER("close_handle_and_leave_table_as_lock");
-
- DBUG_ASSERT(table->db_stat);
-
- /*
- Make a local copy of the table share and free the current one.
- This has to be done to ensure that the table share is removed from
- the table defintion cache as soon as the last instance is removed
- */
- if (multi_alloc_root(mem_root,
- &share, sizeof(*share),
- &key_buff, old_share->table_cache_key.length,
- NULL))
- {
- bzero((char*) share, sizeof(*share));
- share->set_table_cache_key(key_buff, old_share->table_cache_key.str,
- old_share->table_cache_key.length);
- share->tmp_table= INTERNAL_TMP_TABLE; // for intern_close_table()
- }
-
- /*
- When closing a MERGE parent or child table, detach the children first.
- Do not clear child table references to allow for reopen.
- */
- if (table->child_l || table->parent)
- detach_merge_children(table, FALSE);
- table->file->close();
- table->db_stat= 0; // Mark file closed
- release_table_share(table->s, RELEASE_NORMAL);
- table->s= share;
- table->file->change_table_ptr(table, table->s);
-
- DBUG_VOID_RETURN;
-}
-
-
-
-/*
Create a list for all open tables matching SQL expression
SYNOPSIS
@@ -706,16 +787,14 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild)
TABLE_LIST table_list;
DBUG_ENTER("list_open_tables");
- VOID(pthread_mutex_lock(&LOCK_open));
+ mysql_mutex_lock(&LOCK_open);
bzero((char*) &table_list,sizeof(table_list));
start_list= &open_list;
open_list=0;
- for (uint idx=0 ; result == 0 && idx < open_cache.records; idx++)
+ for (uint idx=0 ; result == 0 && idx < table_def_cache.records; idx++)
{
- OPEN_TABLE_LIST *table;
- TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
- TABLE_SHARE *share= entry->s;
+ TABLE_SHARE *share= (TABLE_SHARE *)my_hash_element(&table_def_cache, idx);
if (db && my_strcasecmp(system_charset_info, db, share->db.str))
continue;
@@ -727,23 +806,9 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild)
table_list.table_name= share->table_name.str;
table_list.grant.privilege=0;
- if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list, 1, TRUE))
- continue;
- /* need to check if we haven't already listed it */
- for (table= open_list ; table ; table=table->next)
- {
- if (!strcmp(table->table, share->table_name.str) &&
- !strcmp(table->db, share->db.str))
- {
- if (entry->in_use)
- table->in_use++;
- if (entry->locked_by_name)
- table->locked++;
- break;
- }
- }
- if (table)
+ if (check_table_access(thd,SELECT_ACL,&table_list, TRUE, 1, TRUE))
continue;
+
if (!(*start_list = (OPEN_TABLE_LIST *)
sql_alloc(sizeof(**start_list)+share->table_cache_key.length)))
{
@@ -754,12 +819,15 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild)
strmov(((*start_list)->db= (char*) ((*start_list)+1)),
share->db.str)+1,
share->table_name.str);
- (*start_list)->in_use= entry->in_use ? 1 : 0;
- (*start_list)->locked= entry->locked_by_name ? 1 : 0;
+ (*start_list)->in_use= 0;
+ I_P_List_iterator<TABLE, TABLE_share> it(share->used_tables);
+ while (it++)
+ ++(*start_list)->in_use;
+ (*start_list)->locked= 0; /* Obsolete. */
start_list= &(*start_list)->next;
*start_list=0;
}
- VOID(pthread_mutex_unlock(&LOCK_open));
+ mysql_mutex_unlock(&LOCK_open);
DBUG_RETURN(open_list);
}
@@ -778,8 +846,8 @@ void intern_close_table(TABLE *table)
free_io_cache(table);
delete table->triggers;
- if (table->file) // Not true if name lock
- VOID(closefrm(table, 1)); // close file
+ if (table->file) // Not true if placeholder
+ (void) closefrm(table, 1); // close file
DBUG_VOID_RETURN;
}
@@ -798,23 +866,12 @@ static void free_cache_entry(TABLE *table)
{
DBUG_ENTER("free_cache_entry");
- /* Assert that MERGE children are not attached before final close. */
- DBUG_ASSERT(!table->is_children_attached());
+ /* This should be done before releasing table share. */
+ table_def_remove_table(table);
intern_close_table(table);
- if (!table->in_use)
- {
- table->next->prev=table->prev; /* remove from used chain */
- table->prev->next=table->next;
- if (table == unused_tables)
- {
- unused_tables=unused_tables->next;
- if (table == unused_tables)
- unused_tables=0;
- }
- check_unused(); // consisty check
- }
- my_free((uchar*) table,MYF(0));
+
+ my_free(table);
DBUG_VOID_RETURN;
}
@@ -826,211 +883,251 @@ void free_io_cache(TABLE *table)
if (table->sort.io_cache)
{
close_cached_file(table->sort.io_cache);
- my_free((uchar*) table->sort.io_cache,MYF(0));
+ my_free(table->sort.io_cache);
table->sort.io_cache=0;
}
DBUG_VOID_RETURN;
}
+/**
+ Auxiliary function which allows to kill delayed threads for
+ particular table identified by its share.
+
+ @param share Table share.
+
+ @pre Caller should have LOCK_open mutex.
+*/
+
+static void kill_delayed_threads_for_table(TABLE_SHARE *share)
+{
+ I_P_List_iterator<TABLE, TABLE_share> it(share->used_tables);
+ TABLE *tab;
+
+ mysql_mutex_assert_owner(&LOCK_open);
+
+ while ((tab= it++))
+ {
+ THD *in_use= tab->in_use;
+
+ if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
+ ! in_use->killed)
+ {
+ in_use->killed= THD::KILL_CONNECTION;
+ mysql_mutex_lock(&in_use->mysys_var->mutex);
+ if (in_use->mysys_var->current_cond)
+ {
+ mysql_mutex_lock(in_use->mysys_var->current_mutex);
+ mysql_cond_broadcast(in_use->mysys_var->current_cond);
+ mysql_mutex_unlock(in_use->mysys_var->current_mutex);
+ }
+ mysql_mutex_unlock(&in_use->mysys_var->mutex);
+ }
+ }
+}
+
+
/*
Close all tables which aren't in use by any thread
@param thd Thread context
@param tables List of tables to remove from the cache
- @param have_lock If LOCK_open is locked
@param wait_for_refresh Wait for a impending flush
- @param wait_for_placeholders Wait for tables being reopened so that the GRL
- won't proceed while write-locked tables are being reopened by other
- threads.
+ @param timeout Timeout for waiting for flush to be completed.
- @remark THD can be NULL, but then wait_for_refresh must be FALSE
- and tables must be NULL.
+ @note THD can be NULL, but then wait_for_refresh must be FALSE
+ and tables must be NULL.
+
+ @note When called as part of FLUSH TABLES WITH READ LOCK this function
+ ignores metadata locks held by other threads. In order to avoid
+ situation when FLUSH TABLES WITH READ LOCK sneaks in at the moment
+ when some write-locked table is being reopened (by FLUSH TABLES or
+ ALTER TABLE) we have to rely on additional global shared metadata
+ lock taken by thread trying to obtain global read lock.
*/
-bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock,
- bool wait_for_refresh, bool wait_for_placeholders)
+bool close_cached_tables(THD *thd, TABLE_LIST *tables,
+ bool wait_for_refresh, ulong timeout)
{
- bool result=0;
+ bool result= FALSE;
+ bool found= TRUE;
+ struct timespec abstime;
DBUG_ENTER("close_cached_tables");
DBUG_ASSERT(thd || (!wait_for_refresh && !tables));
- if (!have_lock)
- VOID(pthread_mutex_lock(&LOCK_open));
+ mysql_mutex_lock(&LOCK_open);
if (!tables)
{
- refresh_version++; // Force close of open tables
- while (unused_tables)
- {
-#ifdef EXTRA_DEBUG
- if (hash_delete(&open_cache,(uchar*) unused_tables))
- printf("Warning: Couldn't delete open table from hash\n");
-#else
- VOID(hash_delete(&open_cache,(uchar*) unused_tables));
-#endif
- }
- /* Free table shares */
- while (oldest_unused_share->next)
- {
- pthread_mutex_lock(&oldest_unused_share->mutex);
- VOID(hash_delete(&table_def_cache, (uchar*) oldest_unused_share));
- }
+ /*
+ Force close of all open tables.
+
+ Note that code in TABLE_SHARE::wait_for_old_version() assumes that
+ incrementing of refresh_version and removal of unused tables and
+ shares from TDC happens atomically under protection of LOCK_open,
+ or putting it another way that TDC does not contain old shares
+ which don't have any tables used.
+ */
+ refresh_version++;
DBUG_PRINT("tcache", ("incremented global refresh_version to: %lu",
refresh_version));
- if (wait_for_refresh)
- {
- /*
- Other threads could wait in a loop in open_and_lock_tables(),
- trying to lock one or more of our tables.
-
- If they wait for the locks in thr_multi_lock(), their lock
- request is aborted. They loop in open_and_lock_tables() and
- enter open_table(). Here they notice the table is refreshed and
- wait for COND_refresh. Then they loop again in
- open_and_lock_tables() and this time open_table() succeeds. At
- this moment, if we (the FLUSH TABLES thread) are scheduled and
- on another FLUSH TABLES enter close_cached_tables(), they could
- awake while we sleep below, waiting for others threads (us) to
- close their open tables. If this happens, the other threads
- would find the tables unlocked. They would get the locks, one
- after the other, and could do their destructive work. This is an
- issue if we have LOCK TABLES in effect.
-
- The problem is that the other threads passed all checks in
- open_table() before we refresh the table.
-
- The fix for this problem is to set some_tables_deleted for all
- threads with open tables. These threads can still get their
- locks, but will immediately release them again after checking
- this variable. They will then loop in open_and_lock_tables()
- again. There they will wait until we update all tables version
- below.
-
- Setting some_tables_deleted is done by remove_table_from_cache()
- in the other branch.
-
- In other words (reviewer suggestion): You need this setting of
- some_tables_deleted for the case when table was opened and all
- related checks were passed before incrementing refresh_version
- (which you already have) but attempt to lock the table happened
- after the call to close_old_data_files() i.e. after removal of
- current thread locks.
- */
- for (uint idx=0 ; idx < open_cache.records ; idx++)
- {
- TABLE *table=(TABLE*) hash_element(&open_cache,idx);
- if (table->in_use)
- table->in_use->some_tables_deleted= 1;
- }
- }
+ kill_delayed_threads();
+ /*
+ Get rid of all unused TABLE and TABLE_SHARE instances. By doing
+ this we automatically close all tables which were marked as "old".
+ */
+ while (unused_tables)
+ free_cache_entry(unused_tables);
+ /* Free table shares which were not freed implicitly by loop above. */
+ while (oldest_unused_share->next)
+ (void) my_hash_delete(&table_def_cache, (uchar*) oldest_unused_share);
}
else
{
bool found=0;
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
- if (remove_table_from_cache(thd, table->db, table->table_name,
- RTFC_OWNED_BY_THD_FLAG))
+ TABLE_SHARE *share= get_cached_table_share(table->db, table->table_name);
+
+ if (share)
+ {
+ kill_delayed_threads_for_table(share);
+ /* tdc_remove_table() also sets TABLE_SHARE::version to 0. */
+ tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED, table->db,
+ table->table_name, TRUE);
found=1;
+ }
}
if (!found)
wait_for_refresh=0; // Nothing to wait for
}
-#ifndef EMBEDDED_LIBRARY
- if (!tables)
- kill_delayed_threads();
-#endif
- if (wait_for_refresh)
+
+ mysql_mutex_unlock(&LOCK_open);
+
+ if (!wait_for_refresh)
+ DBUG_RETURN(result);
+
+ set_timespec(abstime, timeout);
+
+ if (thd->locked_tables_mode)
{
/*
- If there is any table that has a lower refresh_version, wait until
- this is closed (or this thread is killed) before returning
+ If we are under LOCK TABLES, we need to reopen the tables without
+ opening a door for any concurrent threads to sneak in and get
+ lock on our tables. To achieve this we use exclusive metadata
+ locks.
*/
- thd->mysys_var->current_mutex= &LOCK_open;
- thd->mysys_var->current_cond= &COND_refresh;
- thd_proc_info(thd, "Flushing tables");
+ TABLE_LIST *tables_to_reopen= (tables ? tables :
+ thd->locked_tables_list.locked_tables());
- close_old_data_files(thd,thd->open_tables,1,1);
- mysql_ha_flush(thd);
- DEBUG_SYNC(thd, "after_flush_unlock");
+ /* Close open HANLER instances to avoid self-deadlock. */
+ mysql_ha_flush_tables(thd, tables_to_reopen);
- bool found=1;
- /* Wait until all threads has closed all the tables we had locked */
- DBUG_PRINT("info",
- ("Waiting for other threads to close their open tables"));
- while (found && ! thd->killed)
+ for (TABLE_LIST *table_list= tables_to_reopen; table_list;
+ table_list= table_list->next_global)
{
- found=0;
- for (uint idx=0 ; idx < open_cache.records ; idx++)
+ /* A check that the table was locked for write is done by the caller. */
+ TABLE *table= find_table_for_mdl_upgrade(thd->open_tables, table_list->db,
+ table_list->table_name, TRUE);
+
+ /* May return NULL if this table has already been closed via an alias. */
+ if (! table)
+ continue;
+
+ if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
{
- TABLE *table=(TABLE*) hash_element(&open_cache,idx);
- /* Avoid a self-deadlock. */
- if (table->in_use == thd)
- continue;
- /*
- Note that we wait here only for tables which are actually open, and
- not for placeholders with TABLE::open_placeholder set. Waiting for
- latter will cause deadlock in the following scenario, for example:
-
- conn1: lock table t1 write;
- conn2: lock table t2 write;
- conn1: flush tables;
- conn2: flush tables;
-
- It also does not make sense to wait for those of placeholders that
- are employed by CREATE TABLE as in this case table simply does not
- exist yet.
- */
- if (table->needs_reopen_or_name_lock() && (table->db_stat ||
- (table->open_placeholder && wait_for_placeholders)))
- {
- found=1;
- DBUG_PRINT("signal", ("Waiting for COND_refresh"));
- pthread_cond_wait(&COND_refresh,&LOCK_open);
- break;
- }
+ result= TRUE;
+ goto err_with_reopen;
}
+ close_all_tables_for_name(thd, table->s, FALSE);
}
+ }
+
+ /* Wait until all threads have closed all the tables we are flushing. */
+ DBUG_PRINT("info", ("Waiting for other threads to close their open tables"));
+
+ while (found && ! thd->killed)
+ {
+ TABLE_SHARE *share;
+ found= FALSE;
/*
- No other thread has the locked tables open; reopen them and get the
- old locks. This should always succeed (unless some external process
- has removed the tables)
+ To a self-deadlock or deadlocks with other FLUSH threads
+ waiting on our open HANDLERs, we have to flush them.
*/
- thd->in_lock_tables=1;
- result=reopen_tables(thd,1,1);
- thd->in_lock_tables=0;
- /* Set version for table */
- for (TABLE *table=thd->open_tables; table ; table= table->next)
+ mysql_ha_flush(thd);
+ DEBUG_SYNC(thd, "after_flush_unlock");
+
+ mysql_mutex_lock(&LOCK_open);
+
+ if (!tables)
+ {
+ for (uint idx=0 ; idx < table_def_cache.records ; idx++)
+ {
+ share= (TABLE_SHARE*) my_hash_element(&table_def_cache, idx);
+ if (share->has_old_version())
+ {
+ found= TRUE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (TABLE_LIST *table= tables; table; table= table->next_local)
+ {
+ share= get_cached_table_share(table->db, table->table_name);
+ if (share && share->has_old_version())
+ {
+ found= TRUE;
+ break;
+ }
+ }
+ }
+
+ if (found)
{
/*
- Preserve the version (0) of write locked tables so that a impending
- global read lock won't sneak in.
+ The method below temporarily unlocks LOCK_open and frees
+ share's memory.
*/
- if (table->reginfo.lock_type < TL_WRITE_ALLOW_WRITE)
- table->s->version= refresh_version;
+ if (share->wait_for_old_version(thd, &abstime,
+ MDL_wait_for_subgraph::DEADLOCK_WEIGHT_DDL))
+ {
+ mysql_mutex_unlock(&LOCK_open);
+ result= TRUE;
+ goto err_with_reopen;
+ }
}
+
+ mysql_mutex_unlock(&LOCK_open);
}
- if (!have_lock)
- VOID(pthread_mutex_unlock(&LOCK_open));
- if (wait_for_refresh)
+
+err_with_reopen:
+ if (thd->locked_tables_mode)
{
- pthread_mutex_lock(&thd->mysys_var->mutex);
- thd->mysys_var->current_mutex= 0;
- thd->mysys_var->current_cond= 0;
- thd_proc_info(thd, 0);
- pthread_mutex_unlock(&thd->mysys_var->mutex);
+ /*
+ No other thread has the locked tables open; reopen them and get the
+ old locks. This should always succeed (unless some external process
+ has removed the tables)
+ */
+ thd->locked_tables_list.reopen_tables(thd);
+ /*
+ Since downgrade_exclusive_lock() won't do anything with shared
+ metadata lock it is much simpler to go through all open tables rather
+ than picking only those tables that were flushed.
+ */
+ for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
+ tab->mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
}
DBUG_RETURN(result);
}
-/*
+/**
Close all tables which match specified connection string or
if specified string is NULL, then any table with a connection string.
*/
-bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh,
- LEX_STRING *connection, bool have_lock)
+bool close_cached_connection_tables(THD *thd, LEX_STRING *connection)
{
uint idx;
TABLE_LIST tmp, *tables= NULL;
@@ -1040,12 +1137,11 @@ bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh,
bzero(&tmp, sizeof(TABLE_LIST));
- if (!have_lock)
- VOID(pthread_mutex_lock(&LOCK_open));
+ mysql_mutex_lock(&LOCK_open);
for (idx= 0; idx < table_def_cache.records; idx++)
{
- TABLE_SHARE *share= (TABLE_SHARE *) hash_element(&table_def_cache, idx);
+ TABLE_SHARE *share= (TABLE_SHARE *) my_hash_element(&table_def_cache, idx);
/* Ignore if table is not open or does not have a connect_string */
if (!share->connect_string.length || !share->ref_count)
@@ -1069,21 +1165,10 @@ bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh,
tables= (TABLE_LIST *) memdup_root(thd->mem_root, (char*)&tmp,
sizeof(TABLE_LIST));
}
+ mysql_mutex_unlock(&LOCK_open);
if (tables)
- result= close_cached_tables(thd, tables, TRUE, FALSE, FALSE);
-
- if (!have_lock)
- VOID(pthread_mutex_unlock(&LOCK_open));
-
- if (if_wait_for_refresh)
- {
- pthread_mutex_lock(&thd->mysys_var->mutex);
- thd->mysys_var->current_mutex= 0;
- thd->mysys_var->current_cond= 0;
- thd->proc_info=0;
- pthread_mutex_unlock(&thd->mysys_var->mutex);
- }
+ result= close_cached_tables(thd, tables, FALSE, LONG_TIMEOUT);
DBUG_RETURN(result);
}
@@ -1104,43 +1189,54 @@ static void mark_temp_tables_as_free_for_reuse(THD *thd)
for (TABLE *table= thd->temporary_tables ; table ; table= table->next)
{
if ((table->query_id == thd->query_id) && ! table->open_by_handler)
- {
- table->query_id= 0;
- table->file->ha_reset();
- /*
- Detach temporary MERGE children from temporary parent to allow new
- attach at next open. Do not do the detach, if close_thread_tables()
- is called from a sub-statement. The temporary table might still be
- used in the top-level statement.
- */
- if (table->child_l || table->parent)
- detach_merge_children(table, TRUE);
- /*
- Reset temporary table lock type to it's default value (TL_WRITE).
-
- Statements such as INSERT INTO .. SELECT FROM tmp, CREATE TABLE
- .. SELECT FROM tmp and UPDATE may under some circumstances modify
- the lock type of the tables participating in the statement. This
- isn't a problem for non-temporary tables since their lock type is
- reset at every open, but the same does not occur for temporary
- tables for historical reasons.
-
- Furthermore, the lock type of temporary tables is not really that
- important because they can only be used by one query at a time and
- not even twice in a query -- a temporary table is represented by
- only one TABLE object. Nonetheless, it's safer from a maintenance
- point of view to reset the lock type of this singleton TABLE object
- as to not cause problems when the table is reused.
-
- Even under LOCK TABLES mode its okay to reset the lock type as
- LOCK TABLES is allowed (but ignored) for a temporary table.
- */
- table->reginfo.lock_type= TL_WRITE;
- }
+ mark_tmp_table_for_reuse(table);
}
}
+/**
+ Reset a single temporary table.
+ Effectively this "closes" one temporary table,
+ in a session.
+
+ @param table Temporary table.
+*/
+
+void mark_tmp_table_for_reuse(TABLE *table)
+{
+ DBUG_ASSERT(table->s->tmp_table);
+
+ table->query_id= 0;
+ table->file->ha_reset();
+
+ /* Detach temporary MERGE children from temporary parent. */
+ DBUG_ASSERT(table->file);
+ table->file->extra(HA_EXTRA_DETACH_CHILDREN);
+
+ /*
+ Reset temporary table lock type to it's default value (TL_WRITE).
+
+ Statements such as INSERT INTO .. SELECT FROM tmp, CREATE TABLE
+ .. SELECT FROM tmp and UPDATE may under some circumstances modify
+ the lock type of the tables participating in the statement. This
+ isn't a problem for non-temporary tables since their lock type is
+ reset at every open, but the same does not occur for temporary
+ tables for historical reasons.
+
+ Furthermore, the lock type of temporary tables is not really that
+ important because they can only be used by one query at a time and
+ not even twice in a query -- a temporary table is represented by
+ only one TABLE object. Nonetheless, it's safer from a maintenance
+ point of view to reset the lock type of this singleton TABLE object
+ as to not cause problems when the table is reused.
+
+ Even under LOCK TABLES mode its okay to reset the lock type as
+ LOCK TABLES is allowed (but ignored) for a temporary table.
+ */
+ table->reginfo.lock_type= TL_WRITE;
+}
+
+
/*
Mark all tables in the list which were used by current substatement
as free for reuse.
@@ -1168,6 +1264,8 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
{
for (; table ; table= table->next)
{
+ DBUG_ASSERT(table->pos_in_locked_tables == NULL ||
+ table->pos_in_locked_tables->table == table);
if (table->query_id == thd->query_id)
{
table->query_id= 0;
@@ -1187,29 +1285,77 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
static void close_open_tables(THD *thd)
{
- bool found_old_table= 0;
-
- safe_mutex_assert_not_owner(&LOCK_open);
-
- VOID(pthread_mutex_lock(&LOCK_open));
+ mysql_mutex_assert_not_owner(&LOCK_open);
DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables));
while (thd->open_tables)
- found_old_table|= close_thread_table(thd, &thd->open_tables);
- thd->some_tables_deleted= 0;
+ (void) close_thread_table(thd, &thd->open_tables);
+}
- /* Free tables to hold down open files */
- while (open_cache.records > table_cache_size && unused_tables)
- VOID(hash_delete(&open_cache,(uchar*) unused_tables)); /* purecov: tested */
- check_unused();
- if (found_old_table)
+
+/**
+ Close all open instances of the table but keep the MDL lock.
+
+ Works both under LOCK TABLES and in the normal mode.
+ Removes all closed instances of the table from the table cache.
+
+ @param thd thread handle
+ @param[in] share table share, but is just a handy way to
+ access the table cache key
+
+ @param[in] remove_from_locked_tables
+ TRUE if the table is being dropped or renamed.
+ In that case the documented behaviour is to
+ implicitly remove the table from LOCK TABLES
+ list.
+
+ @pre Must be called with an X MDL lock on the table.
+*/
+
+void
+close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
+ bool remove_from_locked_tables)
+{
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length= share->table_cache_key.length;
+ const char *db= key;
+ const char *table_name= db + share->db.length + 1;
+
+ memcpy(key, share->table_cache_key.str, key_length);
+
+ mysql_mutex_assert_not_owner(&LOCK_open);
+ for (TABLE **prev= &thd->open_tables; *prev; )
{
- /* Tell threads waiting for refresh that something has happened */
- broadcast_refresh();
- }
+ TABLE *table= *prev;
+
+ if (table->s->table_cache_key.length == key_length &&
+ !memcmp(table->s->table_cache_key.str, key, key_length))
+ {
+ thd->locked_tables_list.unlink_from_list(thd,
+ table->pos_in_locked_tables,
+ remove_from_locked_tables);
+ /*
+ Does nothing if the table is not locked.
+ This allows one to use this function after a table
+ has been unlocked, e.g. in partition management.
+ */
+ mysql_lock_remove(thd, thd->lock, table);
- VOID(pthread_mutex_unlock(&LOCK_open));
+ /* Inform handler that table will be dropped after close */
+ if (table->db_stat) /* Not true for partitioned tables. */
+ table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
+ close_thread_table(thd, prev);
+ }
+ else
+ {
+ /* Step to next entry in open_tables list. */
+ prev= &table->next;
+ }
+ }
+ /* Remove the table share from the cache. */
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db, table_name,
+ FALSE);
}
@@ -1234,7 +1380,6 @@ static void close_open_tables(THD *thd)
void close_thread_tables(THD *thd)
{
TABLE *table;
- prelocked_mode_type prelocked_mode= thd->prelocked_mode;
DBUG_ENTER("close_thread_tables");
#ifdef EXTRA_DEBUG
@@ -1250,6 +1395,23 @@ void close_thread_tables(THD *thd)
DEBUG_SYNC(thd, "before_close_thread_tables");
#endif
+ DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt ||
+ (thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
+
+ /* Detach MERGE children after every statement. Even under LOCK TABLES. */
+ for (table= thd->open_tables; table; table= table->next)
+ {
+ /* Table might be in use by some outer statement. */
+ DBUG_PRINT("tcache", ("table: '%s' query_id: %lu",
+ table->s->table_name.str, (ulong) table->query_id));
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES ||
+ table->query_id == thd->query_id)
+ {
+ DBUG_ASSERT(table->file);
+ table->file->extra(HA_EXTRA_DETACH_CHILDREN);
+ }
+ }
+
/*
We are assuming here that thd->derived_tables contains ONLY derived
tables for this substatement. i.e. instead of approach which uses
@@ -1280,29 +1442,8 @@ void close_thread_tables(THD *thd)
Mark all temporary tables used by this statement as free for reuse.
*/
mark_temp_tables_as_free_for_reuse(thd);
- /*
- Let us commit transaction for statement. Since in 5.0 we only have
- one statement transaction and don't allow several nested statement
- transactions this call will do nothing if we are inside of stored
- function or trigger (i.e. statement transaction is already active and
- does not belong to statement for which we do close_thread_tables()).
- TODO: This should be fixed in later releases.
- */
- if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
- {
- thd->main_da.can_overwrite_status= TRUE;
- ha_autocommit_or_rollback(thd, thd->is_error());
- thd->main_da.can_overwrite_status= FALSE;
-
- /*
- Reset transaction state, but only if we're not inside a
- sub-statement of a prelocked statement.
- */
- if (! prelocked_mode || thd->lex->requires_prelocking())
- thd->transaction.stmt.reset();
- }
- if (thd->locked_tables || prelocked_mode)
+ if (thd->locked_tables_mode)
{
/* Ensure we are calling ha_reset() for all used tables */
@@ -1311,8 +1452,13 @@ void close_thread_tables(THD *thd)
/*
We are under simple LOCK TABLES or we're inside a sub-statement
of a prelocked statement, so should not do anything else.
+
+ Note that even if we are in LTM_LOCK_TABLES mode and statement
+ requires prelocking (e.g. when we are closing tables after
+ failing ot "open" all tables required for statement execution)
+ we will exit this function a few lines below.
*/
- if (!prelocked_mode || !thd->lex->requires_prelocking())
+ if (! thd->lex->requires_prelocking())
DBUG_VOID_RETURN;
/*
@@ -1320,14 +1466,14 @@ void close_thread_tables(THD *thd)
so we have to leave the prelocked mode now with doing implicit
UNLOCK TABLES if needed.
*/
- DBUG_PRINT("info",("thd->prelocked_mode= NON_PRELOCKED"));
- thd->prelocked_mode= NON_PRELOCKED;
+ if (thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
+ thd->locked_tables_mode= LTM_LOCK_TABLES;
- if (prelocked_mode == PRELOCKED_UNDER_LOCK_TABLES)
+ if (thd->locked_tables_mode == LTM_LOCK_TABLES)
DBUG_VOID_RETURN;
- thd->lock= thd->locked_tables;
- thd->locked_tables= 0;
+ thd->leave_locked_tables_mode();
+
/* Fallthrough */
}
@@ -1347,25 +1493,12 @@ void close_thread_tables(THD *thd)
thd->lock=0;
}
/*
- Note that we need to hold LOCK_open while changing the
- open_tables list. Another thread may work on it.
- (See: remove_table_from_cache(), mysql_wait_completed_table())
Closing a MERGE child before the parent would be fatal if the
other thread tries to abort the MERGE lock in between.
*/
if (thd->open_tables)
close_open_tables(thd);
- if (prelocked_mode == PRELOCKED)
- {
- /*
- If we are here then we are leaving normal prelocked mode, so it is
- good idea to turn off OPTION_TABLE_LOCK flag.
- */
- DBUG_ASSERT(thd->lex->requires_prelocking());
- thd->options&= ~(OPTION_TABLE_LOCK);
- }
-
DBUG_VOID_RETURN;
}
@@ -1379,49 +1512,50 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
DBUG_ENTER("close_thread_table");
DBUG_ASSERT(table->key_read == 0);
DBUG_ASSERT(!table->file || table->file->inited == handler::NONE);
- DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
- table->s->table_name.str, (long) table));
-
- *table_ptr=table->next;
+ mysql_mutex_assert_not_owner(&LOCK_open);
/*
- When closing a MERGE parent or child table, detach the children first.
- Clear child table references to force new assignment at next open.
+ The metadata lock must be released after giving back
+ the table to the table cache.
*/
- if (table->child_l || table->parent)
- detach_merge_children(table, TRUE);
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ table->s->db.str,
+ table->s->table_name.str,
+ MDL_SHARED));
+ table->mdl_ticket= NULL;
- if (table->needs_reopen_or_name_lock() ||
- thd->version != refresh_version || !table->db_stat)
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ *table_ptr=table->next;
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+
+ if (! table->needs_reopen())
+ {
+ /* Avoid having MERGE tables with attached children in unused_tables. */
+ table->file->extra(HA_EXTRA_DETACH_CHILDREN);
+ /* Free memory and reset for next loop. */
+ free_field_buffers_larger_than(table, MAX_TDC_BLOB_SIZE);
+ table->file->ha_reset();
+ }
+
+ mysql_mutex_lock(&LOCK_open);
+
+ if (table->s->has_old_version() || table->needs_reopen() ||
+ table_def_shutdown_in_progress)
{
- VOID(hash_delete(&open_cache,(uchar*) table));
- found_old_table=1;
+ free_cache_entry(table);
+ found_old_table= 1;
}
else
{
+ DBUG_ASSERT(table->file);
+ table_def_unuse_table(table);
/*
- Open placeholders have TABLE::db_stat set to 0, so they should be
- handled by the first alternative.
+ We free the least used table, not the subject table,
+ to keep the LRU order.
*/
- DBUG_ASSERT(!table->open_placeholder);
-
- /* Assert that MERGE children are not attached in unused_tables. */
- DBUG_ASSERT(!table->is_children_attached());
-
- /* Free memory and reset for next loop */
- free_field_buffers_larger_than(table,MAX_TDC_BLOB_SIZE);
-
- table->file->ha_reset();
- table->in_use=0;
- if (unused_tables)
- {
- table->next=unused_tables; /* Link in last */
- table->prev=unused_tables->prev;
- unused_tables->prev=table;
- table->prev->next=table;
- }
- else
- unused_tables=table->next=table->prev=table;
+ if (table_cache_count > table_cache_size)
+ free_cache_entry(unused_tables);
}
+ mysql_mutex_unlock(&LOCK_open);
DBUG_RETURN(found_old_table);
}
@@ -1438,19 +1572,20 @@ static inline uint tmpkeyval(THD *thd, TABLE *table)
creates one DROP TEMPORARY TABLE binlog event for each pseudo-thread
*/
-void close_temporary_tables(THD *thd)
+bool close_temporary_tables(THD *thd)
{
+ DBUG_ENTER("close_temporary_tables");
TABLE *table;
TABLE *next= NULL;
TABLE *prev_table;
- /* Assume thd->options has OPTION_QUOTE_SHOW_CREATE */
+ /* Assume thd->variables.option_bits has OPTION_QUOTE_SHOW_CREATE */
bool was_quote_show= TRUE;
+ bool error= 0;
if (!thd->temporary_tables)
- return;
+ DBUG_RETURN(FALSE);
- if (!mysql_bin_log.is_open() ||
- (thd->current_stmt_binlog_row_based && thd->variables.binlog_format == BINLOG_FORMAT_ROW))
+ if (!mysql_bin_log.is_open())
{
TABLE *tmp_next;
for (table= thd->temporary_tables; table; table= tmp_next)
@@ -1459,7 +1594,7 @@ void close_temporary_tables(THD *thd)
close_temporary(table, 1, 1);
}
thd->temporary_tables= 0;
- return;
+ DBUG_RETURN(FALSE);
}
/* Better add "if exists", in case a RESET MASTER has been done */
@@ -1511,9 +1646,9 @@ void close_temporary_tables(THD *thd)
/* We always quote db,table names though it is slight overkill */
if (found_user_tables &&
- !(was_quote_show= test(thd->options & OPTION_QUOTE_SHOW_CREATE)))
+ !(was_quote_show= test(thd->variables.option_bits & OPTION_QUOTE_SHOW_CREATE)))
{
- thd->options |= OPTION_QUOTE_SHOW_CREATE;
+ thd->variables.option_bits |= OPTION_QUOTE_SHOW_CREATE;
}
/* scan sorted tmps to generate sequence of DROP */
@@ -1554,15 +1689,31 @@ void close_temporary_tables(THD *thd)
thd->thread_specific_used= TRUE;
Query_log_event qinfo(thd, s_query.ptr(),
s_query.length() - 1 /* to remove trailing ',' */,
- 0, FALSE, 0);
+ FALSE, TRUE, FALSE, 0);
qinfo.db= db.ptr();
qinfo.db_len= db.length();
thd->variables.character_set_client= cs_save;
- if (mysql_bin_log.write(&qinfo))
+
+ thd->stmt_da->can_overwrite_status= TRUE;
+ if ((error= (mysql_bin_log.write(&qinfo) || error)))
{
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, MYF(0),
- "Failed to write the DROP statement for temporary tables to binary log");
+ /*
+ If we're here following THD::cleanup, thence the connection
+ has been closed already. So lets print a message to the
+ error log instead of pushing yet another error into the
+ stmt_da.
+
+ Also, we keep the error flag so that we propagate the error
+ up in the stack. This way, if we're the SQL thread we notice
+ that close_temporary_tables failed. (Actually, the SQL
+ thread only calls close_temporary_tables while applying old
+ Start_log_event_v3 events.)
+ */
+ sql_print_error("Failed to write the DROP statement for "
+ "temporary tables to binary log");
}
+ thd->stmt_da->can_overwrite_status= FALSE;
+
thd->variables.pseudo_thread_id= save_pseudo_thread_id;
thd->thread_specific_used= save_thread_specific_used;
}
@@ -1573,8 +1724,10 @@ void close_temporary_tables(THD *thd)
}
}
if (!was_quote_show)
- thd->options&= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */
+ thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */
thd->temporary_tables=0;
+
+ DBUG_RETURN(error);
}
/*
@@ -1612,15 +1765,13 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
}
-/*
+/**
Test that table is unique (It's only exists once in the table list)
- SYNOPSIS
- unique_table()
- thd thread handle
- table table which should be checked
- table_list list of tables
- check_alias whether to check tables' aliases
+ @param thd thread handle
+ @param table table which should be checked
+ @param table_list list of tables
+ @param check_alias whether to check tables' aliases
NOTE: to exclude derived tables from check we use following mechanism:
a) during derived table processing set THD::derived_tables_processing
@@ -1631,7 +1782,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
processing loop, because multi-update call fix_fields() for some its
items (which mean JOIN::prepare for subqueries) before unique_table
call to detect which tables should be locked for write).
- c) unique_table skip all tables which belong to SELECT with
+ c) find_dup_table skip all tables which belong to SELECT with
SELECT::exclude_from_table_unique_test set.
Also SELECT::exclude_from_table_unique_test used to exclude from check
tables of main SELECT of multi-delete and multi-update
@@ -1643,17 +1794,17 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
TODO: when we will have table/view change detection we can do this check
only once for PS/SP
- RETURN
- found duplicate
- 0 if table is unique
+ @retval !=0 found duplicate
+ @retval 0 if table is unique
*/
-TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
- bool check_alias)
+static
+TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
+ bool check_alias)
{
TABLE_LIST *res;
const char *d_name, *t_name, *t_alias;
- DBUG_ENTER("unique_table");
+ DBUG_ENTER("find_dup_table");
DBUG_PRINT("enter", ("table alias: %s", table->alias));
/*
@@ -1668,6 +1819,9 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
*/
if (table->table)
{
+ /* All MyISAMMRG children are plain MyISAM tables. */
+ DBUG_ASSERT(table->table->file->ht->db_type != DB_TYPE_MRG_MYISAM);
+
/* temporary table is always unique */
if (table->table && table->table->s->tmp_table != NO_TMP_TABLE)
DBUG_RETURN(0);
@@ -1685,20 +1839,41 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
for (;;)
{
- if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) &&
- (! (res= mysql_lock_have_duplicate(thd, table, table_list)))) ||
- ((!res->table || res->table != table->table) &&
- (!check_alias || !(lower_case_table_names ?
+ /*
+ Table is unique if it is present only once in the global list
+ of tables and once in the list of table locks.
+ */
+ if (! (res= find_table_in_global_list(table_list, d_name, t_name)))
+ break;
+
+ /* Skip if same underlying table. */
+ if (res->table && (res->table == table->table))
+ goto next;
+
+ /* Skip if table alias does not match. */
+ if (check_alias)
+ {
+ if (lower_case_table_names ?
my_strcasecmp(files_charset_info, t_alias, res->alias) :
- strcmp(t_alias, res->alias))) &&
- res->select_lex && !res->select_lex->exclude_from_table_unique_test &&
- !res->prelocking_placeholder))
+ strcmp(t_alias, res->alias))
+ goto next;
+ }
+
+ /*
+ Skip if marked to be excluded (could be a derived table) or if
+ entry is a prelocking placeholder.
+ */
+ if (res->select_lex &&
+ !res->select_lex->exclude_from_table_unique_test &&
+ !res->prelocking_placeholder)
break;
+
/*
If we found entry of this table or table of SELECT which already
processed in derived table or top select of multi-update/multi-delete
(exclude_from_table_unique_test) or prelocking placeholder.
*/
+next:
table_list= res->next_global;
DBUG_PRINT("info",
("found same copy of table or table which we should skip"));
@@ -1707,6 +1882,42 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
}
+/**
+ Test that the subject table of INSERT/UPDATE/DELETE/CREATE
+ or (in case of MyISAMMRG) one of its children are not used later
+ in the query.
+
+ For MyISAMMRG tables, it is assumed that all the underlying
+ tables of @c table (if any) are listed right after it and that
+ their @c parent_l field points at the main table.
+
+
+ @retval non-NULL The table list element for the table that
+ represents the duplicate.
+ @retval NULL No duplicates found.
+*/
+
+TABLE_LIST*
+unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
+ bool check_alias)
+{
+ TABLE_LIST *dup;
+ if (table->table && table->table->file->ht->db_type == DB_TYPE_MRG_MYISAM)
+ {
+ TABLE_LIST *child;
+ dup= NULL;
+ /* Check duplicates of all merge children. */
+ for (child= table->next_global; child && child->parent_l == table;
+ child= child->next_global)
+ {
+ if ((dup= find_dup_table(thd, child, child->next_global, check_alias)))
+ break;
+ }
+ }
+ else
+ dup= find_dup_table(thd, table, table_list, check_alias);
+ return dup;
+}
/*
Issue correct error message in case we found 2 duplicate tables which
prevent some update operation
@@ -1764,39 +1975,60 @@ void update_non_unique_table_error(TABLE_LIST *update,
}
+/**
+ Find temporary table specified by database and table names in the
+ THD::temporary_tables list.
+
+ @return TABLE instance if a temporary table has been found; NULL otherwise.
+*/
+
TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name)
{
- TABLE_LIST table_list;
+ TABLE_LIST tl;
- table_list.db= (char*) db;
- table_list.table_name= (char*) table_name;
- return find_temporary_table(thd, &table_list);
+ tl.db= (char*) db;
+ tl.table_name= (char*) table_name;
+
+ return find_temporary_table(thd, &tl);
}
-TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list)
+/**
+ Find a temporary table specified by TABLE_LIST instance in the
+ THD::temporary_tables list.
+
+ @return TABLE instance if a temporary table has been found; NULL otherwise.
+*/
+
+TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl)
{
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
- TABLE *table;
- DBUG_ENTER("find_temporary_table");
- DBUG_PRINT("enter", ("table: '%s'.'%s'",
- table_list->db, table_list->table_name));
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length= create_table_def_key(thd, key, tl, 1);
+
+ return find_temporary_table(thd, key, key_length);
+}
+
- key_length= create_table_def_key(thd, key, table_list, 1);
- for (table=thd->temporary_tables ; table ; table= table->next)
+/**
+ Find a temporary table specified by a key in the THD::temporary_tables list.
+
+ @return TABLE instance if a temporary table has been found; NULL otherwise.
+*/
+
+TABLE *find_temporary_table(THD *thd,
+ const char *table_key,
+ uint table_key_length)
+{
+ for (TABLE *table= thd->temporary_tables; table; table= table->next)
{
- if (table->s->table_cache_key.length == key_length &&
- !memcmp(table->s->table_cache_key.str, key, key_length))
+ if (table->s->table_cache_key.length == table_key_length &&
+ !memcmp(table->s->table_cache_key.str, table_key, table_key_length))
{
- DBUG_PRINT("info",
- ("Found table. server_id: %u pseudo_thread_id: %lu",
- (uint) thd->server_id,
- (ulong) thd->variables.pseudo_thread_id));
- DBUG_RETURN(table);
+ return table;
}
}
- DBUG_RETURN(0); // Not a temporary table
+
+ return NULL;
}
@@ -1806,9 +2038,10 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list)
Try to locate the table in the list of thd->temporary_tables.
If the table is found:
- if the table is being used by some outer statement, fail.
- - if the table is in thd->locked_tables, unlock it and
- remove it from the list of locked tables. Currently only transactional
- temporary tables are present in the locked_tables list.
+ - if the table is locked with LOCK TABLES or by prelocking,
+ unlock it and remove it from the list of locked tables
+ (THD::lock). Currently only transactional temporary tables
+ are locked.
- Close the temporary table, remove its .FRM
- remove the table from the list of temporary tables
@@ -1820,13 +2053,17 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list)
thd->temporary_tables list, it's impossible to tell here whether
we're dealing with an internal or a user temporary table.
+ If is_trans is not null, we return the type of the table:
+ either transactional (e.g. innodb) as TRUE or non-transactional
+ (e.g. myisam) as FALSE.
+
@retval 0 the table was found and dropped successfully.
@retval 1 the table was not found in the list of temporary tables
of this thread
@retval -1 the table is in use by a outer query
*/
-int drop_temporary_table(THD *thd, TABLE_LIST *table_list)
+int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans)
{
TABLE *table;
DBUG_ENTER("drop_temporary_table");
@@ -1843,11 +2080,14 @@ int drop_temporary_table(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(-1);
}
+ if (is_trans != NULL)
+ *is_trans= table->file->has_transactions();
+
/*
If LOCK TABLES list is not empty and contains this table,
unlock the table and remove the table from this list.
*/
- mysql_lock_remove(thd, thd->locked_tables, table, FALSE);
+ mysql_lock_remove(thd, thd->lock, table);
close_temporary_table(thd, table, 1, 1);
DBUG_RETURN(0);
}
@@ -1864,19 +2104,6 @@ void close_temporary_table(THD *thd, TABLE *table,
table->s->db.str, table->s->table_name.str,
(long) table, table->alias));
- /*
- When closing a MERGE parent or child table, detach the children
- first. Clear child table references as MERGE table cannot be
- reopened after final close of one of its tables.
-
- This is necessary here because it is sometimes called with attached
- tables and without prior close_thread_tables(). E.g. in
- mysql_alter_table(), mysql_rm_table_part2(), mysql_truncate(),
- drop_open_table().
- */
- if (table->child_l || table->parent)
- detach_merge_children(table, TRUE);
-
if (table->prev)
{
table->prev->next= table->next;
@@ -1929,7 +2156,7 @@ void close_temporary(TABLE *table, bool free_share, bool delete_table)
if (free_share)
{
free_table_share(table->s);
- my_free((char*) table,MYF(0));
+ my_free(table);
}
DBUG_VOID_RETURN;
}
@@ -1963,535 +2190,364 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
}
- /* move table first in unused links */
-
-static void relink_unused(TABLE *table)
-{
- /* Assert that MERGE children are not attached in unused_tables. */
- DBUG_ASSERT(!table->is_children_attached());
-
- if (table != unused_tables)
- {
- table->prev->next=table->next; /* Remove from unused list */
- table->next->prev=table->prev;
- table->next=unused_tables; /* Link in unused tables */
- table->prev=unused_tables->prev;
- unused_tables->prev->next=table;
- unused_tables->prev=table;
- unused_tables=table;
- check_unused();
- }
-}
-
-
/**
- Prepare an open merge table for close.
-
- @param[in] thd thread context
- @param[in] table table to prepare
- @param[in,out] prev_pp pointer to pointer of previous table
-
- @detail
- If the table is a MERGE parent, just detach the children.
- If the table is a MERGE child, close the parent (incl. detach).
-*/
-
-static void unlink_open_merge(THD *thd, TABLE *table, TABLE ***prev_pp)
-{
- DBUG_ENTER("unlink_open_merge");
-
- if (table->parent)
- {
- /*
- If MERGE child, close parent too. Closing includes detaching.
-
- This is used for example in ALTER TABLE t1 RENAME TO t5 under
- LOCK TABLES where t1 is a MERGE child:
- CREATE TABLE t1 (c1 INT);
- CREATE TABLE t2 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1);
- LOCK TABLES t1 WRITE, t2 WRITE;
- ALTER TABLE t1 RENAME TO t5;
- */
- TABLE *parent= table->parent;
- TABLE **prv_p;
-
- /* Find parent in open_tables list. */
- for (prv_p= &thd->open_tables;
- *prv_p && (*prv_p != parent);
- prv_p= &(*prv_p)->next) {}
- if (*prv_p)
- {
- /* Special treatment required if child follows parent in list. */
- if (*prev_pp == &parent->next)
- *prev_pp= prv_p;
- /*
- Remove parent from open_tables list and close it.
- This includes detaching and hence clearing parent references.
- */
- close_thread_table(thd, prv_p);
- }
- }
- else if (table->child_l)
- {
- /*
- When closing a MERGE parent, detach the children first. It is
- not necessary to clear the child or parent table reference of
- this table because the TABLE is freed. But we need to clear
- the child or parent references of the other belonging tables
- so that they cannot be moved into the unused_tables chain with
- these pointers set.
-
- This is used for example in ALTER TABLE t2 RENAME TO t5 under
- LOCK TABLES where t2 is a MERGE parent:
- CREATE TABLE t1 (c1 INT);
- CREATE TABLE t2 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1);
- LOCK TABLES t1 WRITE, t2 WRITE;
- ALTER TABLE t2 RENAME TO t5;
- */
- detach_merge_children(table, TRUE);
- }
+ Force all other threads to stop using the table by upgrading
+ metadata lock on it and remove unused TABLE instances from cache.
- DBUG_VOID_RETURN;
-}
+ @param thd Thread handler
+ @param table Table to remove from cache
+ @param function HA_EXTRA_PREPARE_FOR_DROP if table is to be deleted
+ HA_EXTRA_FORCE_REOPEN if table is not be used
+ HA_EXTRA_PREPARE_FOR_RENAME if table is to be renamed
+ @note When returning, the table will be unusable for other threads
+ until metadata lock is downgraded.
-/**
- Remove all instances of table from thread's open list and
- table cache.
-
- @param thd Thread context
- @param find Table to remove
- @param unlock TRUE - free all locks on tables removed that are
- done with LOCK TABLES
- FALSE - otherwise
-
- @note When unlock parameter is FALSE or current thread doesn't have
- any tables locked with LOCK TABLES, tables are assumed to be
- not locked (for example already unlocked).
+ @retval FALSE Success.
+ @retval TRUE Failure (e.g. because thread was killed).
*/
-void unlink_open_table(THD *thd, TABLE *find, bool unlock)
+bool wait_while_table_is_used(THD *thd, TABLE *table,
+ enum ha_extra_function function)
{
- char key[MAX_DBKEY_LENGTH];
- uint key_length= find->s->table_cache_key.length;
- TABLE *list, **prev;
- DBUG_ENTER("unlink_open_table");
-
- safe_mutex_assert_owner(&LOCK_open);
-
- memcpy(key, find->s->table_cache_key.str, key_length);
- /*
- Note that we need to hold LOCK_open while changing the
- open_tables list. Another thread may work on it.
- (See: remove_table_from_cache(), mysql_wait_completed_table())
- Closing a MERGE child before the parent would be fatal if the
- other thread tries to abort the MERGE lock in between.
- */
- for (prev= &thd->open_tables; *prev; )
- {
- list= *prev;
+ DBUG_ENTER("wait_while_table_is_used");
+ DBUG_PRINT("enter", ("table: '%s' share: 0x%lx db_stat: %u version: %lu",
+ table->s->table_name.str, (ulong) table->s,
+ table->db_stat, table->s->version));
- if (list->s->table_cache_key.length == key_length &&
- !memcmp(list->s->table_cache_key.str, key, key_length))
- {
- if (unlock && thd->locked_tables)
- mysql_lock_remove(thd, thd->locked_tables,
- list->parent ? list->parent : list, TRUE);
-
- /* Prepare MERGE table for close. Close parent if necessary. */
- unlink_open_merge(thd, list, &prev);
-
- /* Remove table from open_tables list. */
- *prev= list->next;
- /* Close table. */
- VOID(hash_delete(&open_cache,(uchar*) list)); // Close table
- }
- else
- {
- /* Step to next entry in open_tables list. */
- prev= &list->next;
- }
- }
+ if (thd->mdl_context.upgrade_shared_lock_to_exclusive(
+ table->mdl_ticket, thd->variables.lock_wait_timeout))
+ DBUG_RETURN(TRUE);
- // Notify any 'refresh' threads
- broadcast_refresh();
- DBUG_VOID_RETURN;
+ tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN,
+ table->s->db.str, table->s->table_name.str,
+ FALSE);
+ /* extra() call must come only after all instances above are closed */
+ (void) table->file->extra(function);
+ DBUG_RETURN(FALSE);
}
/**
- Auxiliary routine which closes and drops open table.
-
- @param thd Thread handle
- @param table TABLE object for table to be dropped
- @param db_name Name of database for this table
- @param table_name Name of this table
-
- @note This routine assumes that table to be closed is open only
- by calling thread so we needn't wait until other threads
- will close the table. Also unless called under implicit or
- explicit LOCK TABLES mode it assumes that table to be
- dropped is already unlocked. In the former case it will
- also remove lock on the table. But one should not rely on
- this behaviour as it may change in future.
- Currently, however, this function is never called for a
- table that was locked with LOCK TABLES.
+ Close a and drop a just created table in CREATE TABLE ... SELECT.
+
+ @param thd Thread handle
+ @param table TABLE object for the table to be dropped
+ @param db_name Name of database for this table
+ @param table_name Name of this table
+
+ This routine assumes that the table to be closed is open only
+ by the calling thread, so we needn't wait until other threads
+ close the table. It also assumes that the table is first
+ in thd->open_ables and a data lock on it, if any, has been
+ released. To sum up, it's tuned to work with
+ CREATE TABLE ... SELECT and CREATE TABLE .. SELECT only.
+ Note, that currently CREATE TABLE ... SELECT is not supported
+ under LOCK TABLES. This function, still, can be called in
+ prelocked mode, e.g. if we do CREATE TABLE .. SELECT f1();
*/
void drop_open_table(THD *thd, TABLE *table, const char *db_name,
const char *table_name)
{
+ DBUG_ENTER("drop_open_table");
if (table->s->tmp_table)
close_temporary_table(thd, table, 1, 1);
else
{
+ DBUG_ASSERT(table == thd->open_tables);
+
handlerton *table_type= table->s->db_type();
- VOID(pthread_mutex_lock(&LOCK_open));
- /*
- unlink_open_table() also tells threads waiting for refresh or close
- that something has happened.
- */
- unlink_open_table(thd, table, FALSE);
+
+ table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
+ close_thread_table(thd, &thd->open_tables);
+ /* Remove the table share from the table cache. */
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db_name, table_name,
+ FALSE);
+ /* Remove the table from the storage engine and rm the .frm. */
quick_rm_table(table_type, db_name, table_name, 0);
- VOID(pthread_mutex_unlock(&LOCK_open));
}
-}
-
-
-/*
- Wait for condition but allow the user to send a kill to mysqld
-
- SYNOPSIS
- wait_for_condition()
- thd Thread handler
- mutex mutex that is currently hold that is associated with condition
- Will be unlocked on return
- cond Condition to wait for
-*/
-
-void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond)
-{
- /* Wait until the current table is up to date */
- const char *proc_info;
- thd->mysys_var->current_mutex= mutex;
- thd->mysys_var->current_cond= cond;
- proc_info=thd->proc_info;
- thd_proc_info(thd, "Waiting for table");
- DBUG_ENTER("wait_for_condition");
- DEBUG_SYNC(thd, "waiting_for_table");
- if (!thd->killed)
- (void) pthread_cond_wait(cond, mutex);
-
- /*
- We must unlock mutex first to avoid deadlock becasue conditions are
- sent to this thread by doing locks in the following order:
- lock(mysys_var->mutex)
- lock(mysys_var->current_mutex)
-
- One by effect of this that one can only use wait_for_condition with
- condition variables that are guranteed to not disapper (freed) even if this
- mutex is unlocked
- */
-
- pthread_mutex_unlock(mutex);
- pthread_mutex_lock(&thd->mysys_var->mutex);
- thd->mysys_var->current_mutex= 0;
- thd->mysys_var->current_cond= 0;
- thd_proc_info(thd, proc_info);
- pthread_mutex_unlock(&thd->mysys_var->mutex);
DBUG_VOID_RETURN;
}
/**
- Exclusively name-lock a table that is already write-locked by the
- current thread.
-
- @param thd current thread context
- @param tables table list containing one table to open.
-
- @return FALSE on success, TRUE otherwise.
-*/
-
-bool name_lock_locked_table(THD *thd, TABLE_LIST *tables)
-{
- DBUG_ENTER("name_lock_locked_table");
-
- /* Under LOCK TABLES we must only accept write locked tables. */
- tables->table= find_locked_table(thd, tables->db, tables->table_name);
-
- if (!tables->table)
- my_error(ER_TABLE_NOT_LOCKED, MYF(0), tables->alias);
- else if (tables->table->reginfo.lock_type < TL_WRITE_LOW_PRIORITY)
- my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), tables->alias);
- else
- {
- /*
- Ensures that table is opened only by this thread and that no
- other statement will open this table.
- */
- wait_while_table_is_used(thd, tables->table, HA_EXTRA_FORCE_REOPEN);
- DBUG_RETURN(FALSE);
- }
-
- DBUG_RETURN(TRUE);
-}
-
+ Check that table exists in table definition cache, on disk
+ or in some storage engine.
-/*
- Open table which is already name-locked by this thread.
+ @param thd Thread context
+ @param table Table list element
+ @param[out] exists Out parameter which is set to TRUE if table
+ exists and to FALSE otherwise.
- SYNOPSIS
- reopen_name_locked_table()
- thd Thread handle
- table_list TABLE_LIST object for table to be open, TABLE_LIST::table
- member should point to TABLE object which was used for
- name-locking.
- link_in TRUE - if TABLE object for table to be opened should be
- linked into THD::open_tables list.
- FALSE - placeholder used for name-locking is already in
- this list so we only need to preserve TABLE::next
- pointer.
+ @note This function acquires LOCK_open internally.
- NOTE
- This function assumes that its caller already acquired LOCK_open mutex.
+ @note If there is no .FRM file for the table but it exists in one
+ of engines (e.g. it was created on another node of NDB cluster)
+ this function will fetch and create proper .FRM file for it.
- RETURN VALUE
- FALSE - Success
- TRUE - Error
+ @retval TRUE Some error occurred
+ @retval FALSE No error. 'exists' out parameter set accordingly.
*/
-bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in)
+bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
{
- TABLE *table= table_list->table;
+ char path[FN_REFLEN + 1];
TABLE_SHARE *share;
- char *table_name= table_list->table_name;
- TABLE orig_table;
- DBUG_ENTER("reopen_name_locked_table");
+ DBUG_ENTER("check_if_table_exists");
- safe_mutex_assert_owner(&LOCK_open);
+ *exists= TRUE;
- if (thd->killed || !table)
- DBUG_RETURN(TRUE);
+ DBUG_ASSERT(thd->mdl_context.
+ is_lock_owner(MDL_key::TABLE, table->db,
+ table->table_name, MDL_SHARED));
- orig_table= *table;
+ mysql_mutex_lock(&LOCK_open);
+ share= get_cached_table_share(table->db, table->table_name);
+ mysql_mutex_unlock(&LOCK_open);
- if (open_unireg_entry(thd, table, table_list, table_name,
- table->s->table_cache_key.str,
- table->s->table_cache_key.length, thd->mem_root, 0))
- {
- intern_close_table(table);
- /*
- If there was an error during opening of table (for example if it
- does not exist) '*table' object can be wiped out. To be able
- properly release name-lock in this case we should restore this
- object to its original state.
- */
- *table= orig_table;
- DBUG_RETURN(TRUE);
- }
+ if (share)
+ goto end;
- share= table->s;
- /*
- We want to prevent other connections from opening this table until end
- of statement as it is likely that modifications of table's metadata are
- not yet finished (for example CREATE TRIGGER have to change .TRG file,
- or we might want to drop table if CREATE TABLE ... SELECT fails).
- This also allows us to assume that no other connection will sneak in
- before we will get table-level lock on this table.
- */
- share->version=0;
- table->in_use = thd;
- check_unused();
+ build_table_filename(path, sizeof(path) - 1, table->db, table->table_name,
+ reg_ext, 0);
- if (link_in)
- {
- table->next= thd->open_tables;
- thd->open_tables= table;
- }
- else
+ if (!access(path, F_OK))
+ goto end;
+
+ /* .FRM file doesn't exist. Check if some engine can provide it. */
+ if (ha_check_if_table_exists(thd, table->db, table->table_name, exists))
{
- /*
- TABLE object should be already in THD::open_tables list so we just
- need to set TABLE::next correctly.
- */
- table->next= orig_table.next;
+ my_printf_error(ER_OUT_OF_RESOURCES, "Failed to open '%-.64s', error while "
+ "unpacking from engine", MYF(0), table->table_name);
+ DBUG_RETURN(TRUE);
}
-
- table->tablenr=thd->current_tablenr++;
- table->used_fields=0;
- table->const_table=0;
- table->null_row= table->maybe_null= 0;
- table->force_index= table->force_index_order= table->force_index_group= 0;
- table->status=STATUS_NO_RECORD;
+end:
DBUG_RETURN(FALSE);
}
/**
- Create and insert into table cache placeholder for table
- which will prevent its opening (or creation) (a.k.a lock
- table name).
-
- @param thd Thread context
- @param key Table cache key for name to be locked
- @param key_length Table cache key length
-
- @return Pointer to TABLE object used for name locking or 0 in
- case of failure.
+ An error handler which converts, if possible, ER_LOCK_DEADLOCK error
+ that can occur when we are trying to acquire a metadata lock to
+ a request for back-off and re-start of open_tables() process.
*/
-TABLE *table_cache_insert_placeholder(THD *thd, const char *key,
- uint key_length)
+class MDL_deadlock_handler : public Internal_error_handler
{
- TABLE *table;
- TABLE_SHARE *share;
- char *key_buff;
- DBUG_ENTER("table_cache_insert_placeholder");
+public:
+ MDL_deadlock_handler(Open_table_context *ot_ctx_arg)
+ : m_ot_ctx(ot_ctx_arg), m_is_active(FALSE)
+ {}
- safe_mutex_assert_owner(&LOCK_open);
+ virtual ~MDL_deadlock_handler() {}
- /*
- Create a table entry with the right key and with an old refresh version
- Note that we must use my_multi_malloc() here as this is freed by the
- table cache
+ virtual bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl);
+
+private:
+ /** Open table context to be used for back-off request. */
+ Open_table_context *m_ot_ctx;
+ /**
+ Indicates that we are already in the process of handling
+ ER_LOCK_DEADLOCK error. Allows to re-emit the error from
+ the error handler without falling into infinite recursion.
*/
- if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &table, sizeof(*table),
- &share, sizeof(*share),
- &key_buff, key_length,
- NULL))
- DBUG_RETURN(NULL);
+ bool m_is_active;
+};
- table->s= share;
- share->set_table_cache_key(key_buff, key, key_length);
- share->tmp_table= INTERNAL_TMP_TABLE; // for intern_close_table
- table->in_use= thd;
- table->locked_by_name=1;
- if (my_hash_insert(&open_cache, (uchar*)table))
- {
- my_free((uchar*) table, MYF(0));
- DBUG_RETURN(NULL);
+bool MDL_deadlock_handler::handle_condition(THD *,
+ uint sql_errno,
+ const char*,
+ MYSQL_ERROR::enum_warning_level,
+ const char*,
+ MYSQL_ERROR ** cond_hdl)
+{
+ *cond_hdl= NULL;
+ if (! m_is_active && sql_errno == ER_LOCK_DEADLOCK)
+ {
+ /* Disable the handler to avoid infinite recursion. */
+ m_is_active= TRUE;
+ (void) m_ot_ctx->request_backoff_action(
+ Open_table_context::OT_BACKOFF_AND_RETRY,
+ NULL);
+ m_is_active= FALSE;
+ /*
+ If the above back-off request failed, a new instance of
+ ER_LOCK_DEADLOCK error was emitted. Thus the current
+ instance of error condition can be treated as handled.
+ */
+ return TRUE;
}
-
- DBUG_RETURN(table);
+ return FALSE;
}
/**
- Obtain an exclusive name lock on the table if it is not cached
- in the table cache.
-
- @param thd Thread context
- @param db Name of database
- @param table_name Name of table
- @param[out] table Out parameter which is either:
- - set to NULL if table cache contains record for
- the table or
- - set to point to the TABLE instance used for
- name-locking.
-
- @note This function takes into account all records for table in table
- cache, even placeholders used for name-locking. This means that
- 'table' parameter can be set to NULL for some situations when
- table does not really exist.
-
- @retval TRUE Error occured (OOM)
- @retval FALSE Success. 'table' parameter set according to above rules.
+ Try to acquire an MDL lock for a table being opened.
+
+ @param[in,out] thd Session context, to report errors.
+ @param[out] ot_ctx Open table context, to hold the back off
+ state. If we failed to acquire a lock
+ due to a lock conflict, we add the
+ failed request to the open table context.
+ @param[in,out] mdl_request A request for an MDL lock.
+ If we managed to acquire a ticket
+ (no errors or lock conflicts occurred),
+ contains a reference to it on
+ return. However, is not modified if MDL
+ lock type- modifying flags were provided.
+ @param[in] flags flags MYSQL_OPEN_FORCE_SHARED_MDL,
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL or
+ MYSQL_OPEN_FAIL_ON_MDL_CONFLICT
+ @sa open_table().
+ @param[out] mdl_ticket Only modified if there was no error.
+ If we managed to acquire an MDL
+ lock, contains a reference to the
+ ticket, otherwise is set to NULL.
+
+ @retval TRUE An error occurred.
+ @retval FALSE No error, but perhaps a lock conflict, check mdl_ticket.
*/
-bool lock_table_name_if_not_cached(THD *thd, const char *db,
- const char *table_name, TABLE **table)
+static bool
+open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx,
+ MDL_request *mdl_request,
+ uint flags,
+ MDL_ticket **mdl_ticket)
{
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
- DBUG_ENTER("lock_table_name_if_not_cached");
+ MDL_request mdl_request_shared;
- key_length= (uint)(strmov(strmov(key, db) + 1, table_name) - key) + 1;
- VOID(pthread_mutex_lock(&LOCK_open));
+ if (flags & (MYSQL_OPEN_FORCE_SHARED_MDL |
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
+ {
+ /*
+ MYSQL_OPEN_FORCE_SHARED_MDL flag means that we are executing
+ PREPARE for a prepared statement and want to override
+ the type-of-operation aware metadata lock which was set
+ in the parser/during view opening with a simple shared
+ metadata lock.
+ This is necessary to allow concurrent execution of PREPARE
+ and LOCK TABLES WRITE statement against the same table.
+
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL flag means that we open
+ the table in order to get information about it for one of I_S
+ queries and also want to override the type-of-operation aware
+ shared metadata lock which was set earlier (e.g. during view
+ opening) with a high-priority shared metadata lock.
+ This is necessary to avoid unnecessary waiting and extra
+ ER_WARN_I_S_SKIPPED_TABLE warnings when accessing I_S tables.
+
+ These two flags are mutually exclusive.
+ */
+ DBUG_ASSERT(!(flags & MYSQL_OPEN_FORCE_SHARED_MDL) ||
+ !(flags & MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL));
+
+ mdl_request_shared.init(&mdl_request->key,
+ (flags & MYSQL_OPEN_FORCE_SHARED_MDL) ?
+ MDL_SHARED : MDL_SHARED_HIGH_PRIO,
+ MDL_TRANSACTION);
+ mdl_request= &mdl_request_shared;
+ }
- if (hash_search(&open_cache, (uchar *)key, key_length))
+ if (flags & MYSQL_OPEN_FAIL_ON_MDL_CONFLICT)
{
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_PRINT("info", ("Table is cached, name-lock is not obtained"));
- *table= 0;
- DBUG_RETURN(FALSE);
+ /*
+ When table is being open in order to get data for I_S table,
+ we might have some tables not only open but also locked (e.g. when
+ this happens under LOCK TABLES or in a stored function).
+ As a result by waiting on a conflicting metadata lock to go away
+ we may create a deadlock which won't entirely belong to the
+ MDL subsystem and thus won't be detectable by this subsystem's
+ deadlock detector.
+ To avoid such situation we skip the trouble-making table if
+ there is a conflicting lock.
+ */
+ if (thd->mdl_context.try_acquire_lock(mdl_request))
+ return TRUE;
+ if (mdl_request->ticket == NULL)
+ {
+ my_error(ER_WARN_I_S_SKIPPED_TABLE, MYF(0),
+ mdl_request->key.db_name(), mdl_request->key.name());
+ return TRUE;
+ }
}
- if (!(*table= table_cache_insert_placeholder(thd, key, key_length)))
+ else
{
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(TRUE);
+ /*
+ We are doing a normal table open. Let us try to acquire a metadata
+ lock on the table. If there is a conflicting lock, acquire_lock()
+ will wait for it to go away. Sometimes this waiting may lead to a
+ deadlock, with the following results:
+ 1) If a deadlock is entirely within MDL subsystem, it is
+ detected by the deadlock detector of this subsystem.
+ ER_LOCK_DEADLOCK error is produced. Then, the error handler
+ that is installed prior to the call to acquire_lock() attempts
+ to request a back-off and retry. Upon success, ER_LOCK_DEADLOCK
+ error is suppressed, otherwise propagated up the calling stack.
+ 2) Otherwise, a deadlock may occur when the wait-for graph
+ includes edges not visible to the MDL deadlock detector.
+ One such example is a wait on an InnoDB row lock, e.g. when:
+ conn C1 gets SR MDL lock on t1 with SELECT * FROM t1
+ conn C2 gets a row lock on t2 with SELECT * FROM t2 FOR UPDATE
+ conn C3 gets in and waits on C1 with DROP TABLE t0, t1
+ conn C2 continues and blocks on C3 with SELECT * FROM t0
+ conn C1 deadlocks by waiting on C2 by issuing SELECT * FROM
+ t2 LOCK IN SHARE MODE.
+ Such circular waits are currently only resolved by timeouts,
+ e.g. @@innodb_lock_wait_timeout or @@lock_wait_timeout.
+ */
+ MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);
+
+ thd->push_internal_handler(&mdl_deadlock_handler);
+ bool result= thd->mdl_context.acquire_lock(mdl_request,
+ ot_ctx->get_timeout());
+ thd->pop_internal_handler();
+
+ if (result && !ot_ctx->can_recover_from_failed_open())
+ return TRUE;
}
- (*table)->open_placeholder= 1;
- (*table)->next= thd->open_tables;
- thd->open_tables= *table;
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(FALSE);
+ *mdl_ticket= mdl_request->ticket;
+ return FALSE;
}
/**
- Check that table exists in table definition cache, on disk
- or in some storage engine.
-
- @param thd Thread context
- @param table Table list element
- @param[out] exists Out parameter which is set to TRUE if table
- exists and to FALSE otherwise.
-
- @note This function assumes that caller owns LOCK_open mutex.
- It also assumes that the fact that there are no name-locks
- on the table was checked beforehand.
+ Check if table's share is being removed from the table definition
+ cache and, if yes, wait until the flush is complete.
- @note If there is no .FRM file for the table but it exists in one
- of engines (e.g. it was created on another node of NDB cluster)
- this function will fetch and create proper .FRM file for it.
+ @param thd Thread context.
+ @param table_list Table which share should be checked.
+ @param timeout Timeout for waiting.
+ @param deadlock_weight Weight of this wait for deadlock detector.
- @retval TRUE Some error occured
- @retval FALSE No error. 'exists' out parameter set accordingly.
+ @retval FALSE Success. Share is up to date or has been flushed.
+ @retval TRUE Error (OOM, our was killed, the wait resulted
+ in a deadlock or timeout). Reported.
*/
-bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
+static bool
+tdc_wait_for_old_version(THD *thd, const char *db, const char *table_name,
+ ulong wait_timeout, uint deadlock_weight)
{
- char path[FN_REFLEN + 1];
- int rc;
- DBUG_ENTER("check_if_table_exists");
-
- safe_mutex_assert_owner(&LOCK_open);
-
- *exists= TRUE;
-
- if (get_cached_table_share(table->db, table->table_name))
- DBUG_RETURN(FALSE);
-
- build_table_filename(path, sizeof(path) - 1, table->db, table->table_name,
- reg_ext, 0);
-
- if (!access(path, F_OK))
- DBUG_RETURN(FALSE);
-
- /* .FRM file doesn't exist. Check if some engine can provide it. */
-
- rc= ha_create_table_from_engine(thd, table->db, table->table_name);
+ TABLE_SHARE *share;
+ bool res= FALSE;
- if (rc < 0)
- {
- /* Table does not exists in engines as well. */
- *exists= FALSE;
- DBUG_RETURN(FALSE);
- }
- else if (!rc)
- {
- /* Table exists in some engine and .FRM for it was created. */
- DBUG_RETURN(FALSE);
- }
- else /* (rc > 0) */
+ mysql_mutex_lock(&LOCK_open);
+ if ((share= get_cached_table_share(db, table_name)) &&
+ share->has_old_version())
{
- my_printf_error(ER_UNKNOWN_ERROR, "Failed to open '%-.64s', error while "
- "unpacking from engine", MYF(0), table->table_name);
- DBUG_RETURN(TRUE);
+ struct timespec abstime;
+ set_timespec(abstime, wait_timeout);
+ res= share->wait_for_old_version(thd, &abstime, deadlock_weight);
}
+ mysql_mutex_unlock(&LOCK_open);
+ return res;
}
@@ -2502,55 +2558,59 @@ bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
open_table()
thd Thread context.
table_list Open first table in list.
- refresh INOUT Pointer to memory that will be set to 1 if
- we need to close all tables and reopen them.
- If this is a NULL pointer, then the table is not
- put in the thread-open-list.
+ action INOUT Pointer to variable of enum_open_table_action type
+ which will be set according to action which is
+ required to remedy problem appeared during attempt
+ to open table.
flags Bitmap of flags to modify how open works:
- MYSQL_LOCK_IGNORE_FLUSH - Open table even if
- someone has done a flush on it.
+ MYSQL_OPEN_IGNORE_FLUSH - Open table even if
+ someone has done a flush or there is a pending
+ exclusive metadata lock requests against it
+ (i.e. request high priority metadata lock).
No version number checking is done.
MYSQL_OPEN_TEMPORARY_ONLY - Open only temporary
table not the base table or view.
+ MYSQL_OPEN_TAKE_UPGRADABLE_MDL - Obtain upgradable
+ metadata lock for tables on which we are going to
+ take some kind of write table-level lock.
IMPLEMENTATION
Uses a cache of open tables to find a table not in use.
- If table list element for the table to be opened has "create" flag
- set and table does not exist, this function will automatically insert
- a placeholder for exclusive name lock into the open tables cache and
- will return the TABLE instance that corresponds to this placeholder.
+ If TABLE_LIST::open_strategy is set to OPEN_IF_EXISTS, the table is opened
+ only if it exists. If the open strategy is OPEN_STUB, the underlying table
+ is never opened. In both cases, metadata locks are always taken according
+ to the lock strategy.
RETURN
- NULL Open failed. If refresh is set then one should close
- all other tables and retry the open.
- # Success. Pointer to TABLE object for open table.
+ TRUE Open failed. "action" parameter may contain type of action
+ needed to remedy problem before retrying again.
+ FALSE Success. Members of TABLE_LIST structure are filled properly (e.g.
+ TABLE_LIST::table is set for real tables and TABLE_LIST::view is
+ set for views).
*/
-TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
- bool *refresh, uint flags)
+bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
+ Open_table_context *ot_ctx)
{
reg1 TABLE *table;
char key[MAX_DBKEY_LENGTH];
uint key_length;
char *alias= table_list->alias;
- HASH_SEARCH_STATE state;
+ uint flags= ot_ctx->get_flags();
+ MDL_ticket *mdl_ticket;
+ int error;
+ TABLE_SHARE *share;
+ my_hash_value_type hash_value;
DBUG_ENTER("open_table");
- /* Parsing of partitioning information from .frm needs thd->lex set up. */
- DBUG_ASSERT(thd->lex->is_lex_started);
-
- /* find a unused table in the open table cache */
- if (refresh)
- *refresh=0;
-
/* an open table operation needs a lot of the stack space */
if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
if (thd->killed)
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
key_length= (create_table_def_key(thd, key, table_list, 1) -
TMP_TABLE_KEY_EXTRA);
@@ -2562,7 +2622,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
same name. This block implements the behaviour.
TODO: move this block into a separate function.
*/
- if (!table_list->skip_temporary)
+ if (table_list->open_type != OT_BASE_ONLY &&
+ ! (flags & MYSQL_OPEN_SKIP_TEMPORARY))
{
for (table= thd->temporary_tables; table ; table=table->next)
{
@@ -2584,7 +2645,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
(ulong) table->query_id, (uint) thd->server_id,
(ulong) thd->variables.pseudo_thread_id));
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
}
table->query_id= thd->query_id;
thd->thread_specific_used= TRUE;
@@ -2594,10 +2655,16 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
}
- if (flags & MYSQL_OPEN_TEMPORARY_ONLY)
+ if (table_list->open_type == OT_TEMPORARY_ONLY ||
+ (flags & MYSQL_OPEN_TEMPORARY_ONLY))
{
- my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
- DBUG_RETURN(0);
+ if (table_list->open_strategy == TABLE_LIST::OPEN_NORMAL)
+ {
+ my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
+ DBUG_RETURN(TRUE);
+ }
+ else
+ DBUG_RETURN(FALSE);
}
/*
@@ -2607,7 +2674,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
open not pre-opened tables in pre-locked/LOCK TABLES mode.
TODO: move this block into a separate function.
*/
- if (thd->locked_tables || thd->prelocked_mode)
+ if (thd->locked_tables_mode &&
+ ! (flags & MYSQL_OPEN_GET_NEW_TABLE))
{ // Using table locks
TABLE *best_table= 0;
int best_distance= INT_MIN;
@@ -2616,17 +2684,14 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (table->s->table_cache_key.length == key_length &&
!memcmp(table->s->table_cache_key.str, key, key_length))
{
- /*
- When looking for a usable TABLE, ignore MERGE children, as they
- belong to their parent and cannot be used explicitly.
- */
if (!my_strcasecmp(system_charset_info, table->alias, alias) &&
table->query_id != thd->query_id && /* skip tables already used */
- !(thd->prelocked_mode && table->query_id) &&
- !table->parent)
+ (thd->locked_tables_mode == LTM_LOCK_TABLES ||
+ table->query_id == 0))
{
int distance= ((int) table->reginfo.lock_type -
(int) table_list->lock_type);
+
/*
Find a table that either has the exact lock type requested,
or has the best suitable lock. In case there is no locked
@@ -2669,29 +2734,35 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
Is this table a view and not a base table?
(it is work around to allow to open view with locked tables,
real fix will be made after definition cache will be made)
+
+ Since opening of view which was not explicitly locked by LOCK
+ TABLES breaks metadata locking protocol (potentially can lead
+ to deadlocks) it should be disallowed.
*/
+ if (thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ table_list->db,
+ table_list->table_name,
+ MDL_SHARED))
{
char path[FN_REFLEN + 1];
enum legacy_db_type not_used;
build_table_filename(path, sizeof(path) - 1,
table_list->db, table_list->table_name, reg_ext, 0);
- if (mysql_frm_type(thd, path, &not_used) == FRMTYPE_VIEW)
+ /*
+ Note that we can't be 100% sure that it is a view since it's
+ possible that we either simply have not found unused TABLE
+ instance in THD::open_tables list or were unable to open table
+ during prelocking process (in this case in theory we still
+ should hold shared metadata lock on it).
+ */
+ if (dd_frm_type(thd, path, &not_used) == FRMTYPE_VIEW)
{
- /*
- Will not be used (because it's VIEW) but has to be passed.
- Also we will not free it (because it is a stack variable).
- */
- TABLE tab;
- table= &tab;
- VOID(pthread_mutex_lock(&LOCK_open));
- if (!open_unireg_entry(thd, table, table_list, alias,
- key, key_length, mem_root, 0))
+ if (!tdc_open_view(thd, table_list, alias, key, key_length,
+ mem_root, 0))
{
DBUG_ASSERT(table_list->view != 0);
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(0); // VIEW
+ DBUG_RETURN(FALSE); // VIEW
}
- VOID(pthread_mutex_unlock(&LOCK_open));
}
}
/*
@@ -2701,1001 +2772,713 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
so we may only end up here if the table did not exist when
locked tables list was created.
*/
- if (thd->prelocked_mode == PRELOCKED)
+ if (thd->locked_tables_mode == LTM_PRELOCKED)
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
else
my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
- DBUG_RETURN(0);
- }
-
- /*
- Non pre-locked/LOCK TABLES mode, and the table is not temporary:
- this is the normal use case.
- Now we should:
- - try to find the table in the table cache.
- - if one of the discovered TABLE instances is name-locked
- (table->s->version == 0) or some thread has started FLUSH TABLES
- (refresh_version > table->s->version), back off -- we have to wait
- until no one holds a name lock on the table.
- - if there is no such TABLE in the name cache, read the table definition
- and insert it into the cache.
- We perform all of the above under LOCK_open which currently protects
- the open cache (also known as table cache) and table definitions stored
- on disk.
- */
-
- VOID(pthread_mutex_lock(&LOCK_open));
-
- /*
- If it's the first table from a list of tables used in a query,
- remember refresh_version (the version of open_cache state).
- If the version changes while we're opening the remaining tables,
- we will have to back off, close all the tables opened-so-far,
- and try to reopen them.
- Note: refresh_version is currently changed only during FLUSH TABLES.
- */
- if (!thd->open_tables)
- thd->version=refresh_version;
- else if ((thd->version != refresh_version) &&
- ! (flags & MYSQL_LOCK_IGNORE_FLUSH))
- {
- /* Someone did a refresh while thread was opening tables */
- if (refresh)
- *refresh=1;
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
}
/*
- In order for the back off and re-start process to work properly,
- handler tables having old versions (due to FLUSH TABLES or pending
- name-lock) MUST be closed. This is specially important if a name-lock
- is pending for any table of the handler_tables list, otherwise a
- deadlock may occur.
+ Non pre-locked/LOCK TABLES mode, and the table is not temporary.
+ This is the normal use case.
*/
- if (thd->handler_tables)
- mysql_ha_flush(thd);
- /*
- Actually try to find the table in the open_cache.
- The cache may contain several "TABLE" instances for the same
- physical table. The instances that are currently "in use" by
- some thread have their "in_use" member != NULL.
- There is no good reason for having more than one entry in the
- hash for the same physical table, except that we use this as
- an implicit "pending locks queue" - see
- wait_for_locked_table_names for details.
- */
- for (table= (TABLE*) hash_first(&open_cache, (uchar*) key, key_length,
- &state);
- table && table->in_use ;
- table= (TABLE*) hash_next(&open_cache, (uchar*) key, key_length,
- &state))
+ if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
{
- DBUG_PRINT("tcache", ("in_use table: '%s'.'%s' 0x%lx", table->s->db.str,
- table->s->table_name.str, (long) table));
/*
- Here we flush tables marked for flush.
- Normally, table->s->version contains the value of
- refresh_version from the moment when this table was
- (re-)opened and added to the cache.
- If since then we did (or just started) FLUSH TABLES
- statement, refresh_version has been increased.
- For "name-locked" TABLE instances, table->s->version is set
- to 0 (see lock_table_name for details).
- In case there is a pending FLUSH TABLES or a name lock, we
- need to back off and re-start opening tables.
- If we do not back off now, we may dead lock in case of lock
- order mismatch with some other thread:
- c1: name lock t1; -- sort of exclusive lock
- c2: open t2; -- sort of shared lock
- c1: name lock t2; -- blocks
- c2: open t1; -- blocks
+ We are not under LOCK TABLES and going to acquire write-lock/
+ modify the base table. We need to acquire protection against
+ global read lock until end of this statement in order to have
+ this statement blocked by active FLUSH TABLES WITH READ LOCK.
+
+ We don't block acquire this protection under LOCK TABLES as
+ such protection already acquired at LOCK TABLES time and
+ not released until UNLOCK TABLES.
+
+ We don't block statements which modify only temporary tables
+ as these tables are not preserved by backup by any form of
+ backup which uses FLUSH TABLES WITH READ LOCK.
+
+ TODO: The fact that we sometimes acquire protection against
+ GRL only when we encounter table to be write-locked
+ slightly increases probability of deadlock.
+ This problem will be solved once Alik pushes his
+ temporary table refactoring patch and we can start
+ pre-acquiring metadata locks at the beggining of
+ open_tables() call.
*/
- if (table->needs_reopen_or_name_lock())
+ if (table_list->mdl_request.type >= MDL_SHARED_WRITE &&
+ ! (flags & (MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
+ MYSQL_OPEN_FORCE_SHARED_MDL |
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
+ MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) &&
+ ! ot_ctx->has_protection_against_grl())
{
- DBUG_PRINT("note",
- ("Found table '%s.%s' with different refresh version",
- table_list->db, table_list->table_name));
+ MDL_request protection_request;
+ MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);
- /* Ignore FLUSH, but not name locks! */
- if (flags & MYSQL_LOCK_IGNORE_FLUSH && !table->open_placeholder)
- {
- DBUG_ASSERT(table->db_stat);
- /* Force close at once after usage */
- thd->version= table->s->version;
- continue;
- }
+ if (thd->global_read_lock.can_acquire_protection())
+ DBUG_RETURN(TRUE);
- /* Avoid self-deadlocks by detecting self-dependencies. */
- if (table->open_placeholder && table->in_use == thd)
- {
- VOID(pthread_mutex_unlock(&LOCK_open));
- my_error(ER_UPDATE_TABLE_USED, MYF(0), table->s->table_name.str);
- DBUG_RETURN(0);
- }
+ protection_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_STATEMENT);
/*
- Back off, part 1: mark the table as "unused" for the
- purpose of name-locking by setting table->db_stat to 0. Do
- that only for the tables in this thread that have an old
- table->s->version (this is an optimization (?)).
- table->db_stat == 0 signals wait_for_locked_table_names
- that the tables in question are not used any more. See
- table_is_used call for details.
-
- Notice that HANDLER tables were already taken care of by
- the earlier call to mysql_ha_flush() in this same critical
- section.
- */
- close_old_data_files(thd,thd->open_tables,0,0);
- /*
- Back-off part 2: try to avoid "busy waiting" on the table:
- if the table is in use by some other thread, we suspend
- and wait till the operation is complete: when any
- operation that juggles with table->s->version completes,
- it broadcasts COND_refresh condition variable.
- If 'old' table we met is in use by current thread we return
- without waiting since in this situation it's this thread
- which is responsible for broadcasting on COND_refresh
- (and this was done already in close_old_data_files()).
- Good example of such situation is when we have statement
- that needs two instances of table and FLUSH TABLES comes
- after we open first instance but before we open second
- instance.
- */
- if (table->in_use != thd)
- {
- /* wait_for_conditionwill unlock LOCK_open for us */
- wait_for_condition(thd, &LOCK_open, &COND_refresh);
- }
- else
- {
- VOID(pthread_mutex_unlock(&LOCK_open));
- }
- /*
- There is a refresh in progress for this table.
- Signal the caller that it has to try again.
+ Install error handler which if possible will convert deadlock error
+ into request to back-off and restart process of opening tables.
*/
- if (refresh)
- *refresh=1;
- DBUG_RETURN(0);
+ thd->push_internal_handler(&mdl_deadlock_handler);
+ bool result= thd->mdl_context.acquire_lock(&protection_request,
+ ot_ctx->get_timeout());
+ thd->pop_internal_handler();
+
+ if (result)
+ DBUG_RETURN(TRUE);
+
+ ot_ctx->set_has_protection_against_grl();
}
- }
- if (table)
- {
- DBUG_PRINT("tcache", ("unused table: '%s'.'%s' 0x%lx", table->s->db.str,
- table->s->table_name.str, (long) table));
- /* Unlink the table from "unused_tables" list. */
- if (table == unused_tables)
- { // First unused
- unused_tables=unused_tables->next; // Remove from link
- if (table == unused_tables)
- unused_tables=0;
+
+ if (open_table_get_mdl_lock(thd, ot_ctx, &table_list->mdl_request,
+ flags, &mdl_ticket) ||
+ mdl_ticket == NULL)
+ {
+ DEBUG_SYNC(thd, "before_open_table_wait_refresh");
+ DBUG_RETURN(TRUE);
}
- table->prev->next=table->next; /* Remove from unused list */
- table->next->prev=table->prev;
- table->in_use= thd;
+ DEBUG_SYNC(thd, "after_open_table_mdl_shared");
}
else
{
- /* Insert a new TABLE instance into the open cache */
- int error;
- DBUG_PRINT("tcache", ("opening new table"));
- /* Free cache if too big */
- while (open_cache.records > table_cache_size && unused_tables)
- VOID(hash_delete(&open_cache,(uchar*) unused_tables)); /* purecov: tested */
+ /*
+ Grab reference to the MDL lock ticket that was acquired
+ by the caller.
+ */
+ mdl_ticket= table_list->mdl_request.ticket;
+ }
- if (table_list->create)
- {
- bool exists;
+ hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
- if (check_if_table_exists(thd, table_list, &exists))
- {
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(NULL);
- }
- if (!exists)
- {
- /*
- Table to be created, so we need to create placeholder in table-cache.
- */
- if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
- {
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(NULL);
- }
- /*
- Link placeholder to the open tables list so it will be automatically
- removed once tables are closed. Also mark it so it won't be ignored
- by other trying to take name-lock.
- */
- table->open_placeholder= 1;
- table->next= thd->open_tables;
- thd->open_tables= table;
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(table);
- }
- /* Table exists. Let us try to open it. */
- }
+ if (table_list->open_strategy == TABLE_LIST::OPEN_IF_EXISTS)
+ {
+ bool exists;
- /* make a new table */
- if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))))
+ if (check_if_table_exists(thd, table_list, &exists))
+ DBUG_RETURN(TRUE);
+
+ if (!exists)
+ DBUG_RETURN(FALSE);
+
+ /* Table exists. Let us try to open it. */
+ }
+ else if (table_list->open_strategy == TABLE_LIST::OPEN_STUB)
+ DBUG_RETURN(FALSE);
+
+retry_share:
+
+ mysql_mutex_lock(&LOCK_open);
+
+ if (!(share= get_table_share_with_discover(thd, table_list, key,
+ key_length, OPEN_VIEW,
+ &error,
+ hash_value)))
+ {
+ mysql_mutex_unlock(&LOCK_open);
+ /*
+ If thd->is_error() is not set, we either need discover
+ (error == 7), or the error was silenced by the prelocking
+ handler (error == 0), in which case we should skip this
+ table.
+ */
+ if (error == 7 && !thd->is_error())
{
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(NULL);
+ (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER,
+ table_list);
}
+ DBUG_RETURN(TRUE);
+ }
- error= open_unireg_entry(thd, table, table_list, alias, key, key_length,
- mem_root, (flags & OPEN_VIEW_NO_PARSE));
- if (error > 0)
+ if (share->is_view)
+ {
+ /*
+ If parent_l of the table_list is non null then a merge table
+ has this view as child table, which is not supported.
+ */
+ if (table_list->parent_l)
{
- my_free((uchar*)table, MYF(0));
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(NULL);
+ my_error(ER_WRONG_MRG_TABLE, MYF(0));
+ goto err_unlock;
}
- if (table_list->view || error < 0)
- {
- /*
- VIEW not really opened, only frm were read.
- Set 1 as a flag here
- */
- if (error < 0)
- table_list->view= (st_lex*)1;
- my_free((uchar*)table, MYF(0));
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(0); // VIEW
- }
- DBUG_PRINT("info", ("inserting table '%s'.'%s' 0x%lx into the cache",
- table->s->db.str, table->s->table_name.str,
- (long) table));
- if (my_hash_insert(&open_cache,(uchar*) table))
+ /*
+ This table is a view. Validate its metadata version: in particular,
+ that it was a view when the statement was prepared.
+ */
+ if (check_and_update_table_version(thd, table_list, share))
+ goto err_unlock;
+ if (table_list->i_s_requested_object & OPEN_TABLE_ONLY)
{
- my_free(table, MYF(0));
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(NULL);
+ my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db,
+ table_list->table_name);
+ goto err_unlock;
}
- }
- check_unused(); // Debugging call
+ /* Open view */
+ if (open_new_frm(thd, share, alias,
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
+ HA_GET_INDEX | HA_TRY_READ_ONLY),
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+ thd->open_options,
+ 0, table_list, mem_root))
+ goto err_unlock;
- VOID(pthread_mutex_unlock(&LOCK_open));
- if (refresh)
- {
- table->next=thd->open_tables; /* Link into simple list */
- thd->open_tables=table;
- }
- table->reginfo.lock_type=TL_READ; /* Assume read */
+ /* TODO: Don't free this */
+ release_table_share(share);
- reset:
- DBUG_ASSERT(table->s->ref_count > 0 || table->s->tmp_table != NO_TMP_TABLE);
-
- if (thd->lex->need_correct_ident())
- table->alias_name_used= my_strcasecmp(table_alias_charset,
- table->s->table_name.str, alias);
- /* Fix alias if table name changes */
- if (strcmp(table->alias, alias))
- {
- uint length=(uint) strlen(alias)+1;
- table->alias= (char*) my_realloc((char*) table->alias, length,
- MYF(MY_WME));
- memcpy((char*) table->alias, alias, length);
- }
- /* These variables are also set in reopen_table() */
- table->tablenr=thd->current_tablenr++;
- table->used_fields=0;
- table->const_table=0;
- table->null_row= table->maybe_null= 0;
- table->force_index= table->force_index_order= table->force_index_group= 0;
- table->status=STATUS_NO_RECORD;
- table->insert_values= 0;
- table->fulltext_searched= 0;
- table->file->ft_handler= 0;
- table->reginfo.impossible_range= 0;
- /* Catch wrong handling of the auto_increment_field_not_null. */
- DBUG_ASSERT(!table->auto_increment_field_not_null);
- table->auto_increment_field_not_null= FALSE;
- if (table->timestamp_field)
- table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
- table->pos_in_table_list= table_list;
- table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
- table->clear_column_bitmaps();
- DBUG_ASSERT(table->key_read == 0);
- DBUG_RETURN(table);
-}
+ DBUG_ASSERT(table_list->view);
+ mysql_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(FALSE);
+ }
-TABLE *find_locked_table(THD *thd, const char *db,const char *table_name)
-{
- char key[MAX_DBKEY_LENGTH];
- uint key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
+ /*
+ Note that situation when we are trying to open a table for what
+ was a view during previous execution of PS will be handled in by
+ the caller. Here we should simply open our table even if
+ TABLE_LIST::view is true.
+ */
- for (TABLE *table=thd->open_tables; table ; table=table->next)
+ if (table_list->i_s_requested_object & OPEN_VIEW_ONLY)
{
- if (table->s->table_cache_key.length == key_length &&
- !memcmp(table->s->table_cache_key.str, key, key_length))
- return table;
+ my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db,
+ table_list->table_name);
+ goto err_unlock;
}
- return(0);
-}
+ if (!(flags & MYSQL_OPEN_IGNORE_FLUSH))
+ {
+ if (share->has_old_version())
+ {
+ /*
+ We already have an MDL lock. But we have encountered an old
+ version of table in the table definition cache which is possible
+ when someone changes the table version directly in the cache
+ without acquiring a metadata lock (e.g. this can happen during
+ "rolling" FLUSH TABLE(S)).
+ Release our reference to share, wait until old version of
+ share goes away and then try to get new version of table share.
+ */
+ MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);
+ bool wait_result;
-/*
- Reopen an table because the definition has changed.
-
- SYNOPSIS
- reopen_table()
- table Table object
-
- NOTES
- The data file for the table is already closed and the share is released
- The table has a 'dummy' share that mainly contains database and table name.
-
- RETURN
- 0 ok
- 1 error. The old table object is not changed.
-*/
+ release_table_share(share);
+ mysql_mutex_unlock(&LOCK_open);
-bool reopen_table(TABLE *table)
-{
- TABLE tmp;
- bool error= 1;
- Field **field;
- uint key,part;
- TABLE_LIST table_list;
- THD *thd= table->in_use;
- DBUG_ENTER("reopen_table");
- DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
- table->s->table_name.str, (long) table));
+ thd->push_internal_handler(&mdl_deadlock_handler);
+ wait_result= tdc_wait_for_old_version(thd, table_list->db,
+ table_list->table_name,
+ ot_ctx->get_timeout(),
+ mdl_ticket->get_deadlock_weight());
+ thd->pop_internal_handler();
- DBUG_ASSERT(table->s->ref_count == 0);
- DBUG_ASSERT(!table->sort.io_cache);
- DBUG_ASSERT(!table->children_attached);
+ if (wait_result)
+ DBUG_RETURN(TRUE);
-#ifdef EXTRA_DEBUG
- if (table->db_stat)
- sql_print_error("Table %s had a open data handler in reopen_table",
- table->alias);
-#endif
- bzero((char*) &table_list, sizeof(TABLE_LIST));
- table_list.db= table->s->db.str;
- table_list.table_name= table->s->table_name.str;
- table_list.table= table;
-
- if (wait_for_locked_table_names(thd, &table_list))
- DBUG_RETURN(1); // Thread was killed
-
- if (open_unireg_entry(thd, &tmp, &table_list,
- table->alias,
- table->s->table_cache_key.str,
- table->s->table_cache_key.length,
- thd->mem_root, 0))
- goto end;
+ goto retry_share;
+ }
- /* This list copies variables set by open_table */
- tmp.tablenr= table->tablenr;
- tmp.used_fields= table->used_fields;
- tmp.const_table= table->const_table;
- tmp.null_row= table->null_row;
- tmp.maybe_null= table->maybe_null;
- tmp.status= table->status;
-
- /* Get state */
- tmp.in_use= thd;
- tmp.reginfo.lock_type=table->reginfo.lock_type;
- tmp.grant= table->grant;
-
- /* Replace table in open list */
- tmp.next= table->next;
- tmp.prev= table->prev;
-
- /* Preserve MERGE parent. */
- tmp.parent= table->parent;
- /* Fix MERGE child list and check for unchanged union. */
- if ((table->child_l || tmp.child_l) &&
- fix_merge_after_open(table->child_l, table->child_last_l,
- tmp.child_l, tmp.child_last_l))
- {
- VOID(closefrm(&tmp, 1)); // close file, free everything
- goto end;
+ if (thd->open_tables && thd->open_tables->s->version != share->version)
+ {
+ /*
+ If the version changes while we're opening the tables,
+ we have to back off, close all the tables opened-so-far,
+ and try to reopen them. Note: refresh_version is currently
+ changed only during FLUSH TABLES.
+ */
+ release_table_share(share);
+ mysql_mutex_unlock(&LOCK_open);
+ (void)ot_ctx->request_backoff_action(Open_table_context::OT_REOPEN_TABLES,
+ NULL);
+ DBUG_RETURN(TRUE);
+ }
}
- delete table->triggers;
- if (table->file)
- VOID(closefrm(table, 1)); // close file, free everything
-
- *table= tmp;
- table->default_column_bitmaps();
- table->file->change_table_ptr(table, table->s);
-
- DBUG_ASSERT(table->alias != 0);
- for (field=table->field ; *field ; field++)
+ if (!share->free_tables.is_empty())
{
- (*field)->table= (*field)->orig_table= table;
- (*field)->table_name= &table->alias;
+ table= share->free_tables.front();
+ table_def_use_table(thd, table);
+ /* We need to release share as we have EXTRA reference to it in our hands. */
+ release_table_share(share);
}
- for (key=0 ; key < table->s->keys ; key++)
+ else
{
- for (part=0 ; part < table->key_info[key].usable_key_parts ; part++)
+ /* We have too many TABLE instances around let us try to get rid of them. */
+ while (table_cache_count > table_cache_size && unused_tables)
+ free_cache_entry(unused_tables);
+
+ mysql_mutex_unlock(&LOCK_open);
+
+ /* make a new table */
+ if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))))
+ goto err_lock;
+
+ error= open_table_from_share(thd, share, alias,
+ (uint) (HA_OPEN_KEYFILE |
+ HA_OPEN_RNDFILE |
+ HA_GET_INDEX |
+ HA_TRY_READ_ONLY),
+ (READ_KEYINFO | COMPUTE_TYPES |
+ EXTRA_RECORD),
+ thd->open_options, table, FALSE);
+
+ if (error)
{
- table->key_info[key].key_part[part].field->table= table;
- table->key_info[key].key_part[part].field->orig_table= table;
+ my_free(table);
+
+ if (error == 7)
+ (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER,
+ table_list);
+ else if (share->crashed)
+ (void) ot_ctx->request_backoff_action(Open_table_context::OT_REPAIR,
+ table_list);
+
+ goto err_lock;
}
- }
- if (table->triggers)
- table->triggers->set_table(table);
- /*
- Do not attach MERGE children here. The children might be reopened
- after the parent. Attach children after reopening all tables that
- require reopen. See for example reopen_tables().
- */
- broadcast_refresh();
- error=0;
+ if (open_table_entry_fini(thd, share, table))
+ {
+ closefrm(table, 0);
+ my_free(table);
+ goto err_lock;
+ }
- end:
- DBUG_RETURN(error);
-}
+ mysql_mutex_lock(&LOCK_open);
+ /* Add table to the share's used tables list. */
+ table_def_add_used_table(thd, table);
+ }
+ mysql_mutex_unlock(&LOCK_open);
-/**
- Close all instances of a table open by this thread and replace
- them with exclusive name-locks.
+ table->mdl_ticket= mdl_ticket;
- @param thd Thread context
- @param db Database name for the table to be closed
- @param table_name Name of the table to be closed
+ table->next= thd->open_tables; /* Link into simple list */
+ thd->set_open_tables(table);
- @note This function assumes that if we are not under LOCK TABLES,
- then there is only one table open and locked. This means that
- the function probably has to be adjusted before it can be used
- anywhere outside ALTER TABLE.
+ table->reginfo.lock_type=TL_READ; /* Assume read */
- @note Must not use TABLE_SHARE::table_name/db of the table being closed,
- the strings are used in a loop even after the share may be freed.
-*/
+ reset:
+ table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
+ table_list->table= table;
-void close_data_files_and_morph_locks(THD *thd, const char *db,
- const char *table_name)
-{
- TABLE *table;
- DBUG_ENTER("close_data_files_and_morph_locks");
+ table->init(thd, table_list);
- safe_mutex_assert_owner(&LOCK_open);
+ DBUG_RETURN(FALSE);
- if (thd->lock)
- {
- /*
- If we are not under LOCK TABLES we should have only one table
- open and locked so it makes sense to remove the lock at once.
- */
- mysql_unlock_tables(thd, thd->lock);
- thd->lock= 0;
- }
+err_lock:
+ mysql_mutex_lock(&LOCK_open);
+err_unlock:
+ release_table_share(share);
+ mysql_mutex_unlock(&LOCK_open);
- /*
- Note that open table list may contain a name-lock placeholder
- for target table name if we process ALTER TABLE ... RENAME.
- So loop below makes sense even if we are not under LOCK TABLES.
- */
- for (table=thd->open_tables; table ; table=table->next)
- {
- if (!strcmp(table->s->table_name.str, table_name) &&
- !strcmp(table->s->db.str, db))
- {
- if (thd->locked_tables)
- {
- if (table->parent)
- {
- /*
- If MERGE child, need to reopen parent too. This means that
- the first child to be closed will detach all children from
- the parent and close it. OTOH in most cases a MERGE table
- won't have multiple children with the same db.table_name.
- */
- mysql_lock_remove(thd, thd->locked_tables, table->parent, TRUE);
- table->parent->open_placeholder= 1;
- close_handle_and_leave_table_as_lock(table->parent);
- }
- else
- mysql_lock_remove(thd, thd->locked_tables, table, TRUE);
- }
- table->open_placeholder= 1;
- close_handle_and_leave_table_as_lock(table);
- }
- }
- DBUG_VOID_RETURN;
+ DBUG_RETURN(TRUE);
}
/**
- Reattach MERGE children after reopen.
+ Find table in the list of open tables.
- @param[in] thd thread context
- @param[in,out] err_tables_p pointer to pointer of tables in error
+ @param list List of TABLE objects to be inspected.
+ @param db Database name
+ @param table_name Table name
- @return status
- @retval FALSE OK, err_tables_p unchanged
- @retval TRUE Error, err_tables_p contains table(s)
+ @return Pointer to the TABLE object found, 0 if no table found.
*/
-static bool reattach_merge(THD *thd, TABLE **err_tables_p)
+TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name)
{
- TABLE *table;
- TABLE *next;
- TABLE **prv_p= &thd->open_tables;
- bool error= FALSE;
- DBUG_ENTER("reattach_merge");
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
- for (table= thd->open_tables; table; table= next)
+ for (TABLE *table= list; table ; table=table->next)
{
- next= table->next;
- DBUG_PRINT("tcache", ("check table: '%s'.'%s' 0x%lx next: 0x%lx",
- table->s->db.str, table->s->table_name.str,
- (long) table, (long) next));
- /* Reattach children for MERGE tables with "closed data files" only. */
- if (table->child_l && !table->children_attached)
- {
- DBUG_PRINT("tcache", ("MERGE parent, attach children"));
- if(table->file->extra(HA_EXTRA_ATTACH_CHILDREN))
- {
- my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
- error= TRUE;
- /* Remove table from open_tables. */
- *prv_p= next;
- if (next)
- prv_p= &next->next;
- /* Stack table on error list. */
- table->next= *err_tables_p;
- *err_tables_p= table;
- continue;
- }
- else
- {
- table->children_attached= TRUE;
- DBUG_PRINT("myrg", ("attached parent: '%s'.'%s' 0x%lx",
- table->s->db.str,
- table->s->table_name.str, (long) table));
- }
- }
- prv_p= &table->next;
+ if (table->s->table_cache_key.length == key_length &&
+ !memcmp(table->s->table_cache_key.str, key, key_length))
+ return table;
}
- DBUG_RETURN(error);
+ return(0);
}
/**
- Reopen all tables with closed data files.
-
- @param thd Thread context
- @param get_locks Should we get locks after reopening tables ?
- @param mark_share_as_old Mark share as old to protect from a impending
- global read lock.
-
- @note Since this function can't properly handle prelocking and
- create placeholders it should be used in very special
- situations like FLUSH TABLES or ALTER TABLE. In general
- case one should just repeat open_tables()/lock_tables()
- combination when one needs tables to be reopened (for
- example see open_and_lock_tables()).
-
- @note One should have lock on LOCK_open when calling this.
-
- @return FALSE in case of success, TRUE - otherwise.
+ Find instance of TABLE with upgradable or exclusive metadata
+ lock from the list of open tables, emit error if no such table
+ found.
+
+ @param list List of TABLE objects to be searched
+ @param db Database name.
+ @param table_name Name of table.
+ @param no_error Don't emit error if no suitable TABLE
+ instance were found.
+
+ @return Pointer to TABLE instance with MDL_SHARED_NO_WRITE,
+ MDL_SHARED_NO_READ_WRITE, or MDL_EXCLUSIVE metadata
+ lock, NULL otherwise.
*/
-bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old)
+TABLE *find_table_for_mdl_upgrade(TABLE *list, const char *db,
+ const char *table_name,
+ bool no_error)
{
- TABLE *table,*next,**prev;
- TABLE **tables,**tables_ptr; // For locks
- TABLE *err_tables= NULL;
- bool error=0, not_used;
- bool merge_table_found= FALSE;
- const uint flags= MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN |
- MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
- MYSQL_LOCK_IGNORE_FLUSH;
+ TABLE *tab= find_locked_table(list, db, table_name);
- DBUG_ENTER("reopen_tables");
-
- if (!thd->open_tables)
- DBUG_RETURN(0);
-
- safe_mutex_assert_owner(&LOCK_open);
- if (get_locks)
+ if (!tab)
{
- /*
- The ptr is checked later
- Do not handle locks of MERGE children.
- */
- uint opens=0;
- for (table= thd->open_tables; table ; table=table->next)
- if (!table->parent)
- opens++;
- DBUG_PRINT("tcache", ("open tables to lock: %u", opens));
- tables= (TABLE**) my_alloca(sizeof(TABLE*)*opens);
+ if (!no_error)
+ my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_name);
+ return NULL;
}
else
- tables= &thd->open_tables;
- tables_ptr =tables;
-
- prev= &thd->open_tables;
- for (table=thd->open_tables; table ; table=next)
- {
- uint db_stat=table->db_stat;
- next=table->next;
- DBUG_PRINT("tcache", ("open table: '%s'.'%s' 0x%lx "
- "parent: 0x%lx db_stat: %u",
- table->s->db.str, table->s->table_name.str,
- (long) table, (long) table->parent, db_stat));
- if (table->child_l && !db_stat)
- merge_table_found= TRUE;
- if (!tables || (!db_stat && reopen_table(table)))
- {
- my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
- /*
- If we could not allocate 'tables', we may close open tables
- here. If a MERGE table is affected, detach the children first.
- It is not necessary to clear the child or parent table reference
- of this table because the TABLE is freed. But we need to clear
- the child or parent references of the other belonging tables so
- that they cannot be moved into the unused_tables chain with
- these pointers set.
- */
- if (table->child_l || table->parent)
- detach_merge_children(table, TRUE);
- VOID(hash_delete(&open_cache,(uchar*) table));
- error=1;
- }
- else
- {
- DBUG_PRINT("tcache", ("opened. need lock: %d",
- get_locks && !db_stat && !table->parent));
- *prev= table;
- prev= &table->next;
- /* Do not handle locks of MERGE children. */
- if (get_locks && !db_stat && !table->parent)
- *tables_ptr++= table; // need new lock on this
- if (mark_share_as_old)
- {
- table->s->version=0;
- table->open_placeholder= 0;
- }
- }
- }
- *prev=0;
- /*
- When all tables are open again, we can re-attach MERGE children to
- their parents. All TABLE objects are still present.
- */
- DBUG_PRINT("tcache", ("re-attaching MERGE tables: %d", merge_table_found));
- if (!error && merge_table_found && reattach_merge(thd, &err_tables))
- {
- while (err_tables)
- {
- VOID(hash_delete(&open_cache, (uchar*) err_tables));
- err_tables= err_tables->next;
- }
- }
- DBUG_PRINT("tcache", ("open tables to lock: %u",
- (uint) (tables_ptr - tables)));
- if (tables != tables_ptr) // Should we get back old locks
{
- MYSQL_LOCK *lock;
- /*
- We should always get these locks. Anyway, we must not go into
- wait_for_tables() as it tries to acquire LOCK_open, which is
- already locked.
- */
- thd->some_tables_deleted=0;
- if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables),
- flags, &not_used)))
- {
- thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock);
- }
- else
+ while (tab->mdl_ticket != NULL &&
+ !tab->mdl_ticket->is_upgradable_or_exclusive() &&
+ (tab= find_locked_table(tab->next, db, table_name)))
+ continue;
+ if (!tab)
{
- /*
- This case should only happen if there is a bug in the reopen logic.
- Need to issue error message to have a reply for the application.
- Not exactly what happened though, but close enough.
- */
- my_error(ER_LOCK_DEADLOCK, MYF(0));
- error=1;
+ if (!no_error)
+ my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name);
+ return 0;
}
}
- if (get_locks && tables)
- {
- my_afree((uchar*) tables);
- }
- broadcast_refresh();
- DBUG_RETURN(error);
+ return tab;
}
+/***********************************************************************
+ class Locked_tables_list implementation. Declared in sql_class.h
+************************************************************************/
+
/**
- Close handlers for tables in list, but leave the TABLE structure
- intact so that we can re-open these quickly.
-
- @param thd Thread context
- @param table Head of the list of TABLE objects
- @param morph_locks TRUE - remove locks which we have on tables being closed
- but ensure that no DML or DDL will sneak in before
- we will re-open the table (i.e. temporarily morph
- our table-level locks into name-locks).
- FALSE - otherwise
- @param send_refresh Should we awake waiters even if we didn't close any tables?
+ Enter LTM_LOCK_TABLES mode.
+
+ Enter the LOCK TABLES mode using all the tables that are
+ currently open and locked in this connection.
+ Initializes a TABLE_LIST instance for every locked table.
+
+ @param thd thread handle
+
+ @return TRUE if out of memory.
*/
-static void close_old_data_files(THD *thd, TABLE *table, bool morph_locks,
- bool send_refresh)
+bool
+Locked_tables_list::init_locked_tables(THD *thd)
{
- bool found= send_refresh;
- DBUG_ENTER("close_old_data_files");
+ DBUG_ASSERT(thd->locked_tables_mode == LTM_NONE);
+ DBUG_ASSERT(m_locked_tables == NULL);
+ DBUG_ASSERT(m_reopen_array == NULL);
+ DBUG_ASSERT(m_locked_tables_count == 0);
+
+ for (TABLE *table= thd->open_tables; table;
+ table= table->next, m_locked_tables_count++)
+ {
+ TABLE_LIST *src_table_list= table->pos_in_table_list;
+ char *db, *table_name, *alias;
+ size_t db_len= src_table_list->db_length;
+ size_t table_name_len= src_table_list->table_name_length;
+ size_t alias_len= strlen(src_table_list->alias);
+ TABLE_LIST *dst_table_list;
+
+ if (! multi_alloc_root(&m_locked_tables_root,
+ &dst_table_list, sizeof(*dst_table_list),
+ &db, db_len + 1,
+ &table_name, table_name_len + 1,
+ &alias, alias_len + 1,
+ NullS))
+ {
+ unlock_locked_tables(0);
+ return TRUE;
+ }
- for (; table ; table=table->next)
- {
- DBUG_PRINT("tcache", ("checking table: '%s'.'%s' 0x%lx",
- table->s->db.str, table->s->table_name.str,
- (long) table));
- DBUG_PRINT("tcache", ("needs refresh: %d is open: %u",
- table->needs_reopen_or_name_lock(), table->db_stat));
- /*
- Reopen marked for flush.
+ memcpy(db, src_table_list->db, db_len + 1);
+ memcpy(table_name, src_table_list->table_name, table_name_len + 1);
+ memcpy(alias, src_table_list->alias, alias_len + 1);
+ /**
+ Sic: remember the *actual* table level lock type taken, to
+ acquire the exact same type in reopen_tables().
+ E.g. if the table was locked for write, src_table_list->lock_type is
+ TL_WRITE_DEFAULT, whereas reginfo.lock_type has been updated from
+ thd->update_lock_default.
*/
- if (table->needs_reopen_or_name_lock())
+ dst_table_list->init_one_table(db, db_len, table_name, table_name_len,
+ alias,
+ src_table_list->table->reginfo.lock_type);
+ dst_table_list->table= table;
+ dst_table_list->mdl_request.ticket= src_table_list->mdl_request.ticket;
+
+ /* Link last into the list of tables */
+ *(dst_table_list->prev_global= m_locked_tables_last)= dst_table_list;
+ m_locked_tables_last= &dst_table_list->next_global;
+ table->pos_in_locked_tables= dst_table_list;
+ }
+ if (m_locked_tables_count)
+ {
+ /**
+ Allocate an auxiliary array to pass to mysql_lock_tables()
+ in reopen_tables(). reopen_tables() is a critical
+ path and we don't want to complicate it with extra allocations.
+ */
+ m_reopen_array= (TABLE**)alloc_root(&m_locked_tables_root,
+ sizeof(TABLE*) *
+ (m_locked_tables_count+1));
+ if (m_reopen_array == NULL)
{
- found=1;
- if (table->db_stat)
- {
- if (morph_locks)
- {
- /*
- Forward lock handling to MERGE parent. But unlock parent
- once only.
- */
- TABLE *ulcktbl= table->parent ? table->parent : table;
- if (ulcktbl->lock_count)
- {
- /*
- Wake up threads waiting for table-level lock on this table
- so they won't sneak in when we will temporarily remove our
- lock on it. This will also give them a chance to close their
- instances of this table.
- */
- mysql_lock_abort(thd, ulcktbl, TRUE);
- mysql_lock_remove(thd, thd->locked_tables, ulcktbl, TRUE);
- ulcktbl->lock_count= 0;
- }
- if ((ulcktbl != table) && ulcktbl->db_stat)
- {
- /*
- Close the parent too. Note that parent can come later in
- the list of tables. It will then be noticed as closed and
- as a placeholder. When this happens, do not clear the
- placeholder flag. See the branch below ("***").
- */
- ulcktbl->open_placeholder= 1;
- close_handle_and_leave_table_as_lock(ulcktbl);
- }
- /*
- We want to protect the table from concurrent DDL operations
- (like RENAME TABLE) until we will re-open and re-lock it.
- */
- table->open_placeholder= 1;
- }
- close_handle_and_leave_table_as_lock(table);
- }
- else if (table->open_placeholder && !morph_locks)
- {
- /*
- We come here only in close-for-back-off scenario. So we have to
- "close" create placeholder here to avoid deadlocks (for example,
- in case of concurrent execution of CREATE TABLE t1 SELECT * FROM t2
- and RENAME TABLE t2 TO t1). In close-for-re-open scenario we will
- probably want to let it stay.
-
- Note "***": We must not enter this branch if the placeholder
- flag has been set because of a former close through a child.
- See above the comment that refers to this note.
- */
- table->open_placeholder= 0;
- }
+ unlock_locked_tables(0);
+ return TRUE;
}
}
- if (found)
- broadcast_refresh();
- DBUG_VOID_RETURN;
+ thd->enter_locked_tables_mode(LTM_LOCK_TABLES);
+
+ return FALSE;
}
-/*
- Wait until all threads has closed the tables in the list
- We have also to wait if there is thread that has a lock on this table even
- if the table is closed
+/**
+ Leave LTM_LOCK_TABLES mode if it's been entered.
+
+ Close all locked tables, free memory, and leave the mode.
+
+ @note This function is a no-op if we're not in LOCK TABLES.
*/
-bool table_is_used(TABLE *table, bool wait_for_name_lock)
+void
+Locked_tables_list::unlock_locked_tables(THD *thd)
+
{
- DBUG_ENTER("table_is_used");
- do
+ if (thd)
{
- char *key= table->s->table_cache_key.str;
- uint key_length= table->s->table_cache_key.length;
+ DBUG_ASSERT(!thd->in_sub_stmt &&
+ !(thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
+ /*
+ Sic: we must be careful to not close open tables if
+ we're not in LOCK TABLES mode: unlock_locked_tables() is
+ sometimes called implicitly, expecting no effect on
+ open tables, e.g. from begin_trans().
+ */
+ if (thd->locked_tables_mode != LTM_LOCK_TABLES)
+ return;
- DBUG_PRINT("loop", ("table_name: %s", table->alias));
- HASH_SEARCH_STATE state;
- for (TABLE *search= (TABLE*) hash_first(&open_cache, (uchar*) key,
- key_length, &state);
- search ;
- search= (TABLE*) hash_next(&open_cache, (uchar*) key,
- key_length, &state))
+ for (TABLE_LIST *table_list= m_locked_tables;
+ table_list; table_list= table_list->next_global)
{
- DBUG_PRINT("info", ("share: 0x%lx "
- "open_placeholder: %d locked_by_name: %d "
- "db_stat: %u version: %lu",
- (ulong) search->s,
- search->open_placeholder, search->locked_by_name,
- search->db_stat,
- search->s->version));
- if (search->in_use == table->in_use)
- continue; // Name locked by this thread
/*
- We can't use the table under any of the following conditions:
- - There is an name lock on it (Table is to be deleted or altered)
- - If we are in flush table and we didn't execute the flush
- - If the table engine is open and it's an old version
- (We must wait until all engines are shut down to use the table)
+ Clear the position in the list, the TABLE object will be
+ returned to the table cache.
*/
- if ( (search->locked_by_name && wait_for_name_lock) ||
- (search->is_name_opened() && search->needs_reopen_or_name_lock()))
- DBUG_RETURN(1);
+ table_list->table->pos_in_locked_tables= NULL;
}
- } while ((table=table->next));
- DBUG_RETURN(0);
+ thd->leave_locked_tables_mode();
+
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ close_thread_tables(thd);
+ /*
+ We rely on the caller to implicitly commit the
+ transaction and release transactional locks.
+ */
+ }
+ /*
+ After closing tables we can free memory used for storing lock
+ request for metadata locks and TABLE_LIST elements.
+ */
+ free_root(&m_locked_tables_root, MYF(0));
+ m_locked_tables= NULL;
+ m_locked_tables_last= &m_locked_tables;
+ m_reopen_array= NULL;
+ m_locked_tables_count= 0;
}
-/* Wait until all used tables are refreshed */
+/**
+ Unlink a locked table from the locked tables list, either
+ temporarily or permanently.
+
+ @param thd thread handle
+ @param table_list the element of locked tables list.
+ The implementation assumes that this argument
+ points to a TABLE_LIST element linked into
+ the locked tables list. Passing a TABLE_LIST
+ instance that is not part of locked tables
+ list will lead to a crash.
+ @param remove_from_locked_tables
+ TRUE if the table is removed from the list
+ permanently.
+
+ This function is a no-op if we're not under LOCK TABLES.
+
+ @sa Locked_tables_list::reopen_tables()
+*/
-bool wait_for_tables(THD *thd)
-{
- bool result;
- DBUG_ENTER("wait_for_tables");
- thd_proc_info(thd, "Waiting for tables");
- pthread_mutex_lock(&LOCK_open);
- while (!thd->killed)
- {
- thd->some_tables_deleted=0;
- close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0);
- mysql_ha_flush(thd);
- if (!table_is_used(thd->open_tables,1))
- break;
- (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
- }
- if (thd->killed)
- result= 1; // aborted
- else
- {
- /* Now we can open all tables without any interference */
- thd_proc_info(thd, "Reopen tables");
- thd->version= refresh_version;
- result=reopen_tables(thd,0,0);
- }
- pthread_mutex_unlock(&LOCK_open);
- thd_proc_info(thd, 0);
- DBUG_RETURN(result);
-}
+void Locked_tables_list::unlink_from_list(THD *thd,
+ TABLE_LIST *table_list,
+ bool remove_from_locked_tables)
+{
+ /*
+ If mode is not LTM_LOCK_TABLES, we needn't do anything. Moreover,
+ outside this mode pos_in_locked_tables value is not trustworthy.
+ */
+ if (thd->locked_tables_mode != LTM_LOCK_TABLES)
+ return;
+ /*
+ table_list must be set and point to pos_in_locked_tables of some
+ table.
+ */
+ DBUG_ASSERT(table_list->table->pos_in_locked_tables == table_list);
-/*
- drop tables from locked list
+ /* Clear the pointer, the table will be returned to the table cache. */
+ table_list->table->pos_in_locked_tables= NULL;
- SYNOPSIS
- drop_locked_tables()
- thd Thread thandler
- db Database
- table_name Table name
+ /* Mark the table as closed in the locked tables list. */
+ table_list->table= NULL;
- INFORMATION
- This is only called on drop tables
+ /*
+ If the table is being dropped or renamed, remove it from
+ the locked tables list (implicitly drop the LOCK TABLES lock
+ on it).
+ */
+ if (remove_from_locked_tables)
+ {
+ *table_list->prev_global= table_list->next_global;
+ if (table_list->next_global == NULL)
+ m_locked_tables_last= table_list->prev_global;
+ else
+ table_list->next_global->prev_global= table_list->prev_global;
+ }
+}
- The TABLE object for the dropped table is unlocked but still kept around
- as a name lock, which means that the table will be available for other
- thread as soon as we call unlock_table_names().
- If there is multiple copies of the table locked, all copies except
- the first, which acts as a name lock, is removed.
+/**
+ This is an attempt to recover (somewhat) in case of an error.
+ If we failed to reopen a closed table, let's unlink it from the
+ list and forget about it. From a user perspective that would look
+ as if the server "lost" the lock on one of the locked tables.
- RETURN
- # If table existed, return table
- 0 Table was not locked
+ @note This function is a no-op if we're not under LOCK TABLES.
*/
-
-TABLE *drop_locked_tables(THD *thd,const char *db, const char *table_name)
+void Locked_tables_list::
+unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count)
{
- TABLE *table,*next,**prev, *found= 0;
- prev= &thd->open_tables;
- DBUG_ENTER("drop_locked_tables");
-
+ /* If we managed to take a lock, unlock tables and free the lock. */
+ if (lock)
+ mysql_unlock_tables(thd, lock);
/*
- Note that we need to hold LOCK_open while changing the
- open_tables list. Another thread may work on it.
- (See: remove_table_from_cache(), mysql_wait_completed_table())
- Closing a MERGE child before the parent would be fatal if the
- other thread tries to abort the MERGE lock in between.
+ If a failure happened in reopen_tables(), we may have succeeded
+ reopening some tables, but not all.
+ This works when the connection was killed in mysql_lock_tables().
*/
- for (table= thd->open_tables; table ; table=next)
+ if (reopen_count)
{
- next=table->next;
- if (!strcmp(table->s->table_name.str, table_name) &&
- !strcmp(table->s->db.str, db))
+ while (reopen_count--)
{
- /* If MERGE child, forward lock handling to parent. */
- mysql_lock_remove(thd, thd->locked_tables,
- table->parent ? table->parent : table, TRUE);
/*
- When closing a MERGE parent or child table, detach the children first.
- Clear child table references in case this object is opened again.
+ When closing the table, we must remove it
+ from thd->open_tables list.
+ We rely on the fact that open_table() that was used
+ in reopen_tables() always links the opened table
+ to the beginning of the open_tables list.
*/
- if (table->child_l || table->parent)
- detach_merge_children(table, TRUE);
+ DBUG_ASSERT(thd->open_tables == m_reopen_array[reopen_count]);
- if (!found)
- {
- found= table;
- /* Close engine table, but keep object around as a name lock */
- if (table->db_stat)
- {
- table->db_stat= 0;
- table->file->close();
- }
- }
- else
- {
- /* We already have a name lock, remove copy */
- VOID(hash_delete(&open_cache,(uchar*) table));
- }
- }
- else
- {
- *prev=table;
- prev= &table->next;
+ thd->open_tables->pos_in_locked_tables->table= NULL;
+
+ close_thread_table(thd, &thd->open_tables);
}
}
- *prev=0;
- if (found)
- broadcast_refresh();
- if (thd->locked_tables && thd->locked_tables->table_count == 0)
+ /* Exclude all closed tables from the LOCK TABLES list. */
+ for (TABLE_LIST *table_list= m_locked_tables; table_list; table_list=
+ table_list->next_global)
{
- my_free((uchar*) thd->locked_tables,MYF(0));
- thd->locked_tables=0;
+ if (table_list->table == NULL)
+ {
+ /* Unlink from list. */
+ *table_list->prev_global= table_list->next_global;
+ if (table_list->next_global == NULL)
+ m_locked_tables_last= table_list->prev_global;
+ else
+ table_list->next_global->prev_global= table_list->prev_global;
+ }
}
- DBUG_RETURN(found);
}
-/*
- If we have the table open, which only happens when a LOCK TABLE has been
- done on the table, change the lock type to a lock that will abort all
- other threads trying to get the lock.
+/**
+ Reopen the tables locked with LOCK TABLES and temporarily closed
+ by a DDL statement or FLUSH TABLES.
+
+ @note This function is a no-op if we're not under LOCK TABLES.
+
+ @return TRUE if an error reopening the tables. May happen in
+ case of some fatal system error only, e.g. a disk
+ corruption, out of memory or a serious bug in the
+ locking.
*/
-void abort_locked_tables(THD *thd,const char *db, const char *table_name)
+bool
+Locked_tables_list::reopen_tables(THD *thd)
{
- TABLE *table;
- for (table= thd->open_tables; table ; table= table->next)
+ Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
+ size_t reopen_count= 0;
+ MYSQL_LOCK *lock;
+ MYSQL_LOCK *merged_lock;
+
+ for (TABLE_LIST *table_list= m_locked_tables;
+ table_list; table_list= table_list->next_global)
{
- if (!strcmp(table->s->table_name.str, table_name) &&
- !strcmp(table->s->db.str, db))
+ if (table_list->table) /* The table was not closed */
+ continue;
+
+ /* Links into thd->open_tables upon success */
+ if (open_table(thd, table_list, thd->mem_root, &ot_ctx))
{
- /* If MERGE child, forward lock handling to parent. */
- mysql_lock_abort(thd, table->parent ? table->parent : table, TRUE);
- break;
+ unlink_all_closed_tables(thd, 0, reopen_count);
+ return TRUE;
}
+ table_list->table->pos_in_locked_tables= table_list;
+ /* See also the comment on lock type in init_locked_tables(). */
+ table_list->table->reginfo.lock_type= table_list->lock_type;
+
+ DBUG_ASSERT(reopen_count < m_locked_tables_count);
+ m_reopen_array[reopen_count++]= table_list->table;
}
+ if (reopen_count)
+ {
+ thd->in_lock_tables= 1;
+ /*
+ We re-lock all tables with mysql_lock_tables() at once rather
+ than locking one table at a time because of the case
+ reported in Bug#45035: when the same table is present
+ in the list many times, thr_lock.c fails to grant READ lock
+ on a table that is already locked by WRITE lock, even if
+ WRITE lock is taken by the same thread. If READ and WRITE
+ lock are passed to thr_lock.c in the same list, everything
+ works fine. Patching legacy code of thr_lock.c is risking to
+ break something else.
+ */
+ lock= mysql_lock_tables(thd, m_reopen_array, reopen_count,
+ MYSQL_OPEN_REOPEN);
+ thd->in_lock_tables= 0;
+ if (lock == NULL || (merged_lock=
+ mysql_lock_merge(thd->lock, lock)) == NULL)
+ {
+ unlink_all_closed_tables(thd, lock, reopen_count);
+ if (! thd->killed)
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ return TRUE;
+ }
+ thd->lock= merged_lock;
+ }
+ return FALSE;
}
@@ -3716,7 +3499,7 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
PRE-CONDITION(S)
share is non-NULL
- The LOCK_open mutex is locked
+ The LOCK_open mutex is locked.
POST-CONDITION(S)
@@ -3737,7 +3520,7 @@ void assign_new_table_id(TABLE_SHARE *share)
/* Preconditions */
DBUG_ASSERT(share != NULL);
- safe_mutex_assert_owner(&LOCK_open);
+ mysql_mutex_assert_owner(&LOCK_open);
ulong tid= ++last_table_id; /* get next id */
/*
@@ -3801,7 +3584,7 @@ static bool inject_reprepare(THD *thd)
@retval FALSE success, version in TABLE_LIST has been updated
*/
-bool
+static bool
check_and_update_table_version(THD *thd,
TABLE_LIST *tables, TABLE_SHARE *table_share)
{
@@ -3823,210 +3606,137 @@ check_and_update_table_version(THD *thd,
}
DBUG_EXECUTE_IF("reprepare_each_statement", return inject_reprepare(thd););
+ return FALSE;
+}
+
+
+/**
+ Compares versions of a stored routine obtained from the sp cache
+ and the version used at prepare.
+
+ @details If the new and the old values mismatch, invoke
+ Metadata_version_observer.
+ At prepared statement prepare, all Sroutine_hash_entry version values
+ are NULL and we always have a mismatch. But there is no observer set
+ in THD, and therefore no error is reported. Instead, we update
+ the value in Sroutine_hash_entry, effectively recording the original
+ version.
+ At prepared statement execute, an observer may be installed. If
+ there is a version mismatch, we push an error and return TRUE.
+
+ For conventional execution (no prepared statements), the
+ observer is never installed.
+ @param[in] thd used to report errors
+ @param[in/out] rt pointer to stored routine entry in the
+ parse tree
+ @param[in] sp pointer to stored routine cache entry.
+ Can be NULL if there is no such routine.
+ @retval TRUE an error, which has been reported
+ @retval FALSE success, version in Sroutine_hash_entry has been updated
+*/
+
+static bool
+check_and_update_routine_version(THD *thd, Sroutine_hash_entry *rt,
+ sp_head *sp)
+{
+ ulong spc_version= sp_cache_version();
+ /* sp is NULL if there is no such routine. */
+ ulong version= sp ? sp->sp_cache_version() : spc_version;
+ /*
+ If the version in the parse tree is stale,
+ or the version in the cache is stale and sp is not used,
+ we need to reprepare.
+ Sic: version != spc_version <--> sp is not NULL.
+ */
+ if (rt->m_sp_cache_version != version ||
+ (version != spc_version && !sp->is_invoked()))
+ {
+ if (thd->m_reprepare_observer &&
+ thd->m_reprepare_observer->report_error(thd))
+ {
+ /*
+ Version of the sp cache is different from the
+ previous execution of the prepared statement, and it is
+ unacceptable for this SQLCOM. Error has been reported.
+ */
+ DBUG_ASSERT(thd->is_error());
+ return TRUE;
+ }
+ /* Always maintain the latest cache version. */
+ rt->m_sp_cache_version= version;
+ }
return FALSE;
}
-/*
- Load a table definition from file and open unireg table
- SYNOPSIS
- open_unireg_entry()
- thd Thread handle
- entry Store open table definition here
- table_list TABLE_LIST with db, table_name & belong_to_view
- alias Alias name
- cache_key Key for share_cache
- cache_key_length length of cache_key
- mem_root temporary mem_root for parsing
- flags the OPEN_VIEW_NO_PARSE flag to be passed to
- openfrm()/open_new_frm()
+/**
+ Open view by getting its definition from disk (and table cache in future).
- NOTES
- Extra argument for open is taken from thd->open_options
- One must have a lock on LOCK_open when calling this function
+ @param thd Thread handle
+ @param table_list TABLE_LIST with db, table_name & belong_to_view
+ @param alias Alias name
+ @param cache_key Key for table definition cache
+ @param cache_key_length Length of cache_key
+ @param mem_root Memory to be used for .frm parsing.
+ @param flags Flags which modify how we open the view
- RETURN
- 0 ok
- # Error
+ @todo This function is needed for special handling of views under
+ LOCK TABLES. We probably should get rid of it in long term.
+
+ @return FALSE if success, TRUE - otherwise.
*/
-static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list,
- const char *alias,
- char *cache_key, uint cache_key_length,
- MEM_ROOT *mem_root, uint flags)
+bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
+ char *cache_key, uint cache_key_length,
+ MEM_ROOT *mem_root, uint flags)
{
+ TABLE not_used;
int error;
+ my_hash_value_type hash_value;
TABLE_SHARE *share;
- uint discover_retry_count= 0;
- DBUG_ENTER("open_unireg_entry");
-
- safe_mutex_assert_owner(&LOCK_open);
-retry:
- if (!(share= get_table_share_with_create(thd, table_list, cache_key,
- cache_key_length,
- OPEN_VIEW |
- table_list->i_s_requested_object,
- &error)))
- DBUG_RETURN(1);
- if (share->is_view)
- {
- /*
- If parent_l of the table_list is non null then a merge table
- has this view as child table, which is not supported.
- */
- if (table_list->parent_l)
- {
- my_error(ER_WRONG_MRG_TABLE, MYF(0));
- goto err;
- }
+ hash_value= my_calc_hash(&table_def_cache, (uchar*) cache_key,
+ cache_key_length);
+ mysql_mutex_lock(&LOCK_open);
- /*
- This table is a view. Validate its metadata version: in particular,
- that it was a view when the statement was prepared.
- */
- if (check_and_update_table_version(thd, table_list, share))
- goto err;
- if (table_list->i_s_requested_object & OPEN_TABLE_ONLY)
- goto err;
+ if (!(share= get_table_share(thd, table_list, cache_key,
+ cache_key_length,
+ OPEN_VIEW, &error,
+ hash_value)))
+ goto err;
- /* Open view */
- error= (int) open_new_frm(thd, share, alias,
- (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
- HA_GET_INDEX | HA_TRY_READ_ONLY),
- READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD |
- (flags & OPEN_VIEW_NO_PARSE),
- thd->open_options, entry, table_list,
- mem_root);
- if (error)
- goto err;
- /* TODO: Don't free this */
- release_table_share(share, RELEASE_NORMAL);
- DBUG_RETURN((flags & OPEN_VIEW_NO_PARSE)? -1 : 0);
- }
- else if (table_list->view)
+ if (share->is_view &&
+ !open_new_frm(thd, share, alias,
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
+ HA_GET_INDEX | HA_TRY_READ_ONLY),
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD |
+ flags, thd->open_options, &not_used, table_list,
+ mem_root))
{
- /*
- We're trying to open a table for what was a view.
- This can only happen during (re-)execution.
- At prepared statement prepare the view has been opened and
- merged into the statement parse tree. After that, someone
- performed a DDL and replaced the view with a base table.
- Don't try to open the table inside a prepared statement,
- invalidate it instead.
-
- Note, the assert below is known to fail inside stored
- procedures (Bug#27011).
- */
- DBUG_ASSERT(thd->m_reprepare_observer);
- check_and_update_table_version(thd, table_list, share);
- /* Always an error. */
- DBUG_ASSERT(thd->is_error());
- goto err;
+ release_table_share(share);
+ mysql_mutex_unlock(&LOCK_open);
+ return FALSE;
}
- if (table_list->i_s_requested_object & OPEN_VIEW_ONLY)
- goto err;
+ my_error(ER_WRONG_OBJECT, MYF(0), share->db.str, share->table_name.str, "VIEW");
+ release_table_share(share);
+err:
+ mysql_mutex_unlock(&LOCK_open);
+ return TRUE;
+}
- while ((error= open_table_from_share(thd, share, alias,
- (uint) (HA_OPEN_KEYFILE |
- HA_OPEN_RNDFILE |
- HA_GET_INDEX |
- HA_TRY_READ_ONLY),
- (READ_KEYINFO | COMPUTE_TYPES |
- EXTRA_RECORD),
- thd->open_options, entry, FALSE)))
- {
- if (error == 7) // Table def changed
- {
- share->version= 0; // Mark share as old
- if (discover_retry_count++) // Retry once
- goto err;
- /*
- TODO:
- Here we should wait until all threads has released the table.
- For now we do one retry. This may cause a deadlock if there
- is other threads waiting for other tables used by this thread.
-
- Proper fix would be to if the second retry failed:
- - Mark that table def changed
- - Return from open table
- - Close all tables used by this thread
- - Start waiting that the share is released
- - Retry by opening all tables again
- */
- if (ha_create_table_from_engine(thd, table_list->db,
- table_list->table_name))
- goto err;
- /*
- TO BE FIXED
- To avoid deadlock, only wait for release if no one else is
- using the share.
- */
- if (share->ref_count != 1)
- goto err;
- /* Free share and wait until it's released by all threads */
- release_table_share(share, RELEASE_WAIT_FOR_DROP);
- if (!thd->killed)
- {
- mysql_reset_errors(thd, 1); // Clear warnings
- thd->clear_error(); // Clear error message
- goto retry;
- }
- DBUG_RETURN(1);
- }
- if (!entry->s || !entry->s->crashed)
- goto err;
- // Code below is for repairing a crashed file
- if ((error= lock_table_name(thd, table_list, TRUE)))
- {
- if (error < 0)
- goto err;
- if (wait_for_locked_table_names(thd, table_list))
- {
- unlock_table_name(thd, table_list);
- goto err;
- }
- }
- pthread_mutex_unlock(&LOCK_open);
- thd->clear_error(); // Clear error message
- error= 0;
- if (open_table_from_share(thd, share, alias,
- (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
- HA_GET_INDEX |
- HA_TRY_READ_ONLY),
- READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
- ha_open_options | HA_OPEN_FOR_REPAIR,
- entry, FALSE) || ! entry->file ||
- (entry->file->is_crashed() && entry->file->ha_check_and_repair(thd)))
- {
- /* Give right error message */
- thd->clear_error();
- my_error(ER_NOT_KEYFILE, MYF(0), share->table_name.str, my_errno);
- sql_print_error("Couldn't repair table: %s.%s", share->db.str,
- share->table_name.str);
- if (entry->file)
- closefrm(entry, 0);
- error=1;
- }
- else
- thd->clear_error(); // Clear error message
- pthread_mutex_lock(&LOCK_open);
- unlock_table_name(thd, table_list);
-
- if (error)
- goto err;
- break;
- }
+/**
+ Finalize the process of TABLE creation by loading table triggers
+ and taking action if a HEAP table content was emptied implicitly.
+*/
+static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry)
+{
if (Table_triggers_list::check_n_load(thd, share->db.str,
share->table_name.str, entry, 0))
- {
- closefrm(entry, 0);
- goto err;
- }
+ return TRUE;
/*
If we are here, there was no fatal error (but error may be still
@@ -4047,12 +3757,12 @@ retry:
int errcode= query_error_code(thd, TRUE);
if (thd->binlog_query(THD::STMT_QUERY_TYPE,
query, (ulong)(end-query),
- FALSE, FALSE, errcode))
+ FALSE, FALSE, FALSE, errcode))
{
- my_free(query, MYF(0));
- goto err;
+ my_free(query);
+ return TRUE;
}
- my_free(query, MYF(0));
+ my_free(query);
}
else
{
@@ -4063,445 +3773,939 @@ retry:
*/
sql_print_error("When opening HEAP table, could not allocate memory "
"to write 'DELETE FROM `%s`.`%s`' to the binary log",
- table_list->db, table_list->table_name);
+ share->db.str, share->table_name.str);
delete entry->triggers;
- closefrm(entry, 0);
- goto err;
+ return TRUE;
}
}
}
- DBUG_RETURN(0);
-
-err:
- release_table_share(share, RELEASE_NORMAL);
- DBUG_RETURN(1);
+ return FALSE;
}
/**
- @brief Add list of MERGE children to a TABLE_LIST list.
+ Auxiliary routine which is used for performing automatical table repair.
+*/
- @param[in] tlist the parent TABLE_LIST object just opened
+static bool auto_repair_table(THD *thd, TABLE_LIST *table_list)
+{
+ char cache_key[MAX_DBKEY_LENGTH];
+ uint cache_key_length;
+ TABLE_SHARE *share;
+ TABLE *entry;
+ int not_used;
+ bool result= TRUE;
+ my_hash_value_type hash_value;
- @return status
- @retval 0 OK
- @retval != 0 Error
+ cache_key_length= create_table_def_key(thd, cache_key, table_list, 0);
- @detail
- When a MERGE parent table has just been opened, insert the
- TABLE_LIST chain from the MERGE handle into the table list used for
- opening tables for this statement. This lets the children be opened
- too.
-*/
+ thd->clear_error();
-static int add_merge_table_list(TABLE_LIST *tlist)
-{
- TABLE *parent= tlist->table;
- TABLE_LIST *child_l;
- DBUG_ENTER("add_merge_table_list");
- DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx", parent->s->db.str,
- parent->s->table_name.str, (long) parent));
+ hash_value= my_calc_hash(&table_def_cache, (uchar*) cache_key,
+ cache_key_length);
+ mysql_mutex_lock(&LOCK_open);
+
+ if (!(share= get_table_share(thd, table_list, cache_key,
+ cache_key_length,
+ OPEN_VIEW, &not_used,
+ hash_value)))
+ goto end_unlock;
- /* Must not call this with attached children. */
- DBUG_ASSERT(!parent->children_attached);
- /* Must not call this with children list in place. */
- DBUG_ASSERT(tlist->next_global != parent->child_l);
- /* Prevent inclusion of another MERGE table. Could make infinite recursion. */
- if (tlist->parent_l)
+ if (share->is_view)
{
- my_error(ER_ADMIN_WRONG_MRG_TABLE, MYF(0), tlist->alias);
- DBUG_RETURN(1);
+ release_table_share(share);
+ goto end_unlock;
}
- /* Fix children.*/
- for (child_l= parent->child_l; ; child_l= child_l->next_global)
+ if (!(entry= (TABLE*)my_malloc(sizeof(TABLE), MYF(MY_WME))))
{
- /*
- Note: child_l->table may still be set if this parent was taken
- from the unused_tables chain. Ignore this fact here. The
- reference will be replaced by the handler in
- ::extra(HA_EXTRA_ATTACH_CHILDREN).
- */
+ release_table_share(share);
+ goto end_unlock;
+ }
+ mysql_mutex_unlock(&LOCK_open);
+
+ if (open_table_from_share(thd, share, table_list->alias,
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
+ HA_GET_INDEX |
+ HA_TRY_READ_ONLY),
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+ ha_open_options | HA_OPEN_FOR_REPAIR,
+ entry, FALSE) || ! entry->file ||
+ (entry->file->is_crashed() && entry->file->ha_check_and_repair(thd)))
+ {
+ /* Give right error message */
+ thd->clear_error();
+ my_error(ER_NOT_KEYFILE, MYF(0), share->table_name.str, my_errno);
+ sql_print_error("Couldn't repair table: %s.%s", share->db.str,
+ share->table_name.str);
+ if (entry->file)
+ closefrm(entry, 0);
+ }
+ else
+ {
+ thd->clear_error(); // Clear error message
+ closefrm(entry, 0);
+ result= FALSE;
+ }
+ my_free(entry);
+
+ mysql_mutex_lock(&LOCK_open);
+ release_table_share(share);
+ /* Remove the repaired share from the table cache. */
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
+ table_list->db, table_list->table_name,
+ TRUE);
+end_unlock:
+ mysql_mutex_unlock(&LOCK_open);
+ return result;
+}
- /* Set lock type. */
- child_l->lock_type= tlist->lock_type;
- /* Set parent reference. */
- child_l->parent_l= tlist;
+/** Open_table_context */
- /* Break when this was the last child. */
- if (&child_l->next_global == parent->child_last_l)
- break;
- }
+Open_table_context::Open_table_context(THD *thd, uint flags)
+ :m_failed_table(NULL),
+ m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()),
+ m_timeout(flags & MYSQL_LOCK_IGNORE_TIMEOUT ?
+ LONG_TIMEOUT : thd->variables.lock_wait_timeout),
+ m_flags(flags),
+ m_action(OT_NO_ACTION),
+ m_has_locks(thd->mdl_context.has_locks()),
+ m_has_protection_against_grl(FALSE)
+{}
- /* Insert children into the table list. */
- *parent->child_last_l= tlist->next_global;
- tlist->next_global= parent->child_l;
+/**
+ Check if we can back-off and set back off action if we can.
+ Otherwise report and return error.
+
+ @retval TRUE if back-off is impossible.
+ @retval FALSE if we can back off. Back off action has been set.
+*/
+
+bool
+Open_table_context::
+request_backoff_action(enum_open_table_action action_arg,
+ TABLE_LIST *table)
+{
/*
- Do not fix the prev_global pointers. We will remove the
- chain soon anyway.
+ A back off action may be one of three kinds:
+
+ * We met a broken table that needs repair, or a table that
+ is not present on this MySQL server and needs re-discovery.
+ To perform the action, we need an exclusive metadata lock on
+ the table. Acquiring an X lock while holding other shared
+ locks is very deadlock-prone. If this is a multi- statement
+ transaction that holds metadata locks for completed
+ statements, we don't do it, and report an error instead.
+ The action type in this case is OT_DISCOVER or OT_REPAIR.
+ * Our attempt to acquire an MDL lock lead to a deadlock,
+ detected by the MDL deadlock detector. The current
+ session was chosen a victim. If this is a multi-statement
+ transaction that holds metadata locks taken by completed
+ statements, restarting locking for the current statement
+ may lead to a livelock. Releasing locks of completed
+ statements can not be done as will lead to violation
+ of ACID. Thus, again, if m_has_locks is set,
+ we report an error. Otherwise, when there are no metadata
+ locks other than which belong to this statement, we can
+ try to recover from error by releasing all locks and
+ restarting the pre-locking.
+ Similarly, a deadlock error can occur when the
+ pre-locking process met a TABLE_SHARE that is being
+ flushed, and unsuccessfully waited for the flush to
+ complete. A deadlock in this case can happen, e.g.,
+ when our session is holding a metadata lock that
+ is being waited on by a session which is using
+ the table which is being flushed. The only way
+ to recover from this error is, again, to close all
+ open tables, release all locks, and retry pre-locking.
+ Action type name is OT_REOPEN_TABLES. Re-trying
+ while holding some locks may lead to a livelock,
+ and thus we don't do it.
+ * Finally, this session has open TABLEs from different
+ "generations" of the table cache. This can happen, e.g.,
+ when, after this session has successfully opened one
+ table used for a statement, FLUSH TABLES interfered and
+ expelled another table used in it. FLUSH TABLES then
+ blocks and waits on the table already opened by this
+ statement.
+ We detect this situation by ensuring that table cache
+ version of all tables used in a statement is the same.
+ If it isn't, all tables needs to be reopened.
+ Note, that we can always perform a reopen in this case,
+ even if we already have metadata locks, since we don't
+ keep tables open between statements and a livelock
+ is not possible.
*/
-
- DBUG_RETURN(0);
+ if (action_arg != OT_REOPEN_TABLES && m_has_locks)
+ {
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ return TRUE;
+ }
+ /*
+ If auto-repair or discovery are requested, a pointer to table
+ list element must be provided.
+ */
+ if (table)
+ {
+ DBUG_ASSERT(action_arg == OT_DISCOVER || action_arg == OT_REPAIR);
+ m_failed_table= (TABLE_LIST*) current_thd->alloc(sizeof(TABLE_LIST));
+ if (m_failed_table == NULL)
+ return TRUE;
+ m_failed_table->init_one_table(table->db, table->db_length,
+ table->table_name,
+ table->table_name_length,
+ table->alias, TL_WRITE);
+ m_failed_table->mdl_request.set_type(MDL_EXCLUSIVE);
+ }
+ m_action= action_arg;
+ return FALSE;
}
/**
- @brief Attach MERGE children to the parent.
+ Recover from failed attempt of open table by performing requested action.
- @param[in] tlist the child TABLE_LIST object just opened
+ @param thd Thread context
- @return status
- @retval 0 OK
- @retval != 0 Error
+ @pre This function should be called only with "action" != OT_NO_ACTION
+ and after having called @sa close_tables_for_reopen().
- @note
- This is called when the last MERGE child has just been opened, let
- the handler attach the MyISAM tables to the MERGE table. Remove
- MERGE TABLE_LIST chain from the statement list so that it cannot be
- changed or freed.
+ @retval FALSE - Success. One should try to open tables once again.
+ @retval TRUE - Error
*/
-static int attach_merge_children(TABLE_LIST *tlist)
+bool
+Open_table_context::
+recover_from_failed_open(THD *thd)
{
- TABLE *parent= tlist->parent_l->table;
- int error;
- DBUG_ENTER("attach_merge_children");
- DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx", parent->s->db.str,
- parent->s->table_name.str, (long) parent));
+ bool result= FALSE;
+ /* Execute the action. */
+ switch (m_action)
+ {
+ case OT_BACKOFF_AND_RETRY:
+ break;
+ case OT_REOPEN_TABLES:
+ break;
+ case OT_DISCOVER:
+ {
+ if ((result= lock_table_names(thd, m_failed_table, NULL,
+ get_timeout(),
+ MYSQL_OPEN_SKIP_TEMPORARY)))
+ break;
+
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
+ m_failed_table->table_name, FALSE);
+ ha_create_table_from_engine(thd, m_failed_table->db,
+ m_failed_table->table_name);
- /* Must not call this with attached children. */
- DBUG_ASSERT(!parent->children_attached);
- /* Must call this with children list in place. */
- DBUG_ASSERT(tlist->parent_l->next_global == parent->child_l);
+ thd->warning_info->clear_warning_info(thd->query_id);
+ thd->clear_error(); // Clear error message
+ thd->mdl_context.release_transactional_locks();
+ break;
+ }
+ case OT_REPAIR:
+ {
+ if ((result= lock_table_names(thd, m_failed_table, NULL,
+ get_timeout(),
+ MYSQL_OPEN_SKIP_TEMPORARY)))
+ break;
- /* Attach MyISAM tables to MERGE table. */
- error= parent->file->extra(HA_EXTRA_ATTACH_CHILDREN);
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
+ m_failed_table->table_name, FALSE);
+ result= auto_repair_table(thd, m_failed_table);
+ thd->mdl_context.release_transactional_locks();
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ }
/*
- Remove children from the table list. Even in case of an error.
- This should prevent tampering with them.
+ Reset the pointers to conflicting MDL request and the
+ TABLE_LIST element, set when we need auto-discovery or repair,
+ for safety.
*/
- tlist->parent_l->next_global= *parent->child_last_l;
-
+ m_failed_table= NULL;
/*
- Do not fix the last childs next_global pointer. It is needed for
- stepping to the next table in the enclosing loop in open_tables().
- Do not fix prev_global pointers. We did not set them.
+ Reset flag indicating that we have already acquired protection
+ against GRL. It is no longer valid as the corresponding lock was
+ released by close_tables_for_reopen().
*/
+ m_has_protection_against_grl= FALSE;
+ /* Prepare for possible another back-off. */
+ m_action= OT_NO_ACTION;
+ return result;
+}
- if (error)
- {
- DBUG_PRINT("error", ("attaching MERGE children failed: %d", my_errno));
- parent->file->print_error(error, MYF(0));
- DBUG_RETURN(1);
- }
- parent->children_attached= TRUE;
- DBUG_PRINT("myrg", ("attached parent: '%s'.'%s' 0x%lx", parent->s->db.str,
- parent->s->table_name.str, (long) parent));
+/*
+ Return a appropriate read lock type given a table object.
+
+ @param thd Thread context
+ @param prelocking_ctx Prelocking context.
+ @param table_list Table list element for table to be locked.
+ @remark Due to a statement-based replication limitation, statements such as
+ INSERT INTO .. SELECT FROM .. and CREATE TABLE .. SELECT FROM need
+ to grab a TL_READ_NO_INSERT lock on the source table in order to
+ prevent the replication of a concurrent statement that modifies the
+ source table. If such a statement gets applied on the slave before
+ the INSERT .. SELECT statement finishes, data on the master could
+ differ from data on the slave and end-up with a discrepancy between
+ the binary log and table state.
+ This also applies to SELECT/SET/DO statements which use stored
+ functions. Calls to such functions are going to be logged as a
+ whole and thus should be serialized against concurrent changes
+ to tables used by those functions. This can be avoided if functions
+ only read data but doing so requires more complex analysis than it
+ is done now.
+ Furthermore, this does not apply to I_S and log tables as it's
+ always unsafe to replicate such tables under statement-based
+ replication as the table on the slave might contain other data
+ (ie: general_log is enabled on the slave). The statement will
+ be marked as unsafe for SBR in decide_logging_format().
+ @remark Note that even in prelocked mode it is important to correctly
+ determine lock type value. In this mode lock type is passed to
+ handler::start_stmt() method and can be used by storage engine,
+ for example, to determine what kind of row locks it should acquire
+ when reading data from the table.
+*/
+
+thr_lock_type read_lock_type_for_table(THD *thd,
+ Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list)
+{
/*
- Note that we have the cildren in the thd->open_tables list at this
- point.
+ In cases when this function is called for a sub-statement executed in
+ prelocked mode we can't rely on OPTION_BIN_LOG flag in THD::options
+ bitmap to determine that binary logging is turned on as this bit can
+ be cleared before executing sub-statement. So instead we have to look
+ at THD::variables::sql_log_bin member.
*/
-
- DBUG_RETURN(0);
+ bool log_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin;
+ ulong binlog_format= thd->variables.binlog_format;
+ if ((log_on == FALSE) || (binlog_format == BINLOG_FORMAT_ROW) ||
+ (table_list->table->s->table_category == TABLE_CATEGORY_LOG) ||
+ (table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) ||
+ !(is_update_query(prelocking_ctx->sql_command) ||
+ table_list->prelocking_placeholder ||
+ (thd->locked_tables_mode > LTM_LOCK_TABLES)))
+ return TL_READ;
+ else
+ return TL_READ_NO_INSERT;
}
-/**
- @brief Detach MERGE children from the parent.
+/*
+ Handle element of prelocking set other than table. E.g. cache routine
+ and, if prelocking strategy prescribes so, extend the prelocking set
+ with tables and routines used by it.
+
+ @param[in] thd Thread context.
+ @param[in] prelocking_ctx Prelocking context.
+ @param[in] rt Element of prelocking set to be processed.
+ @param[in] prelocking_strategy Strategy which specifies how the
+ prelocking set should be extended when
+ one of its elements is processed.
+ @param[in] has_prelocking_list Indicates that prelocking set/list for
+ this statement has already been built.
+ @param[in] ot_ctx Context of open_table used to recover from
+ locking failures.
+ @param[out] need_prelocking Set to TRUE if it was detected that this
+ statement will require prelocked mode for
+ its execution, not touched otherwise.
+
+ @retval FALSE Success.
+ @retval TRUE Failure (Conflicting metadata lock, OOM, other errors).
+*/
- @note
- Call this before the first table of a MERGE table (parent or child)
- is closed.
+static bool
+open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
+ Sroutine_hash_entry *rt,
+ Prelocking_strategy *prelocking_strategy,
+ bool has_prelocking_list,
+ Open_table_context *ot_ctx,
+ bool *need_prelocking)
+{
+ MDL_key::enum_mdl_namespace mdl_type= rt->mdl_request.key.mdl_namespace();
+ DBUG_ENTER("open_and_process_routine");
+
+ switch (mdl_type)
+ {
+ case MDL_key::FUNCTION:
+ case MDL_key::PROCEDURE:
+ {
+ sp_head *sp;
+ /*
+ Try to get MDL lock on the routine.
+ Note that we do not take locks on top-level CALLs as this can
+ lead to a deadlock. Not locking top-level CALLs does not break
+ the binlog as only the statements in the called procedure show
+ up there, not the CALL itself.
+ */
+ if (rt != (Sroutine_hash_entry*)prelocking_ctx->sroutines_list.first ||
+ mdl_type != MDL_key::PROCEDURE)
+ {
+ /*
+ Since we acquire only shared lock on routines we don't
+ need to care about global intention exclusive locks.
+ */
+ DBUG_ASSERT(rt->mdl_request.type == MDL_SHARED);
+
+ /*
+ Waiting for a conflicting metadata lock to go away may
+ lead to a deadlock, detected by MDL subsystem.
+ If possible, we try to resolve such deadlocks by releasing all
+ metadata locks and restarting the pre-locking process.
+ To prevent the error from polluting the diagnostics area
+ in case of successful resolution, install a special error
+ handler for ER_LOCK_DEADLOCK error.
+ */
+ MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);
- When closing thread tables at end of statement, both parent and
- children are in thd->open_tables and will be closed. In most cases
- the children will be closed before the parent. They are opened after
- the parent and thus stacked into thd->open_tables before it.
+ thd->push_internal_handler(&mdl_deadlock_handler);
+ bool result= thd->mdl_context.acquire_lock(&rt->mdl_request,
+ ot_ctx->get_timeout());
+ thd->pop_internal_handler();
- To avoid that we touch a closed children in any way, we must detach
- the children from the parent when the first belonging table is
- closed (parent or child).
+ if (result)
+ DBUG_RETURN(TRUE);
- All references to the children should be removed on handler level
- and optionally on table level.
+ DEBUG_SYNC(thd, "after_shared_lock_pname");
- @note
- Assure that you call it for a MERGE parent or child only.
- Either table->child_l or table->parent must be set.
-
- @param[in] table the TABLE object of the parent
- @param[in] clear_refs if to clear TABLE references
- this must be true when called from
- close_thread_tables() to enable fresh
- open in open_tables()
- it must be false when called in preparation
- for reopen_tables()
+ /* Ensures the routine is up-to-date and cached, if exists. */
+ if (sp_cache_routine(thd, rt, has_prelocking_list, &sp))
+ DBUG_RETURN(TRUE);
+
+ /* Remember the version of the routine in the parse tree. */
+ if (check_and_update_routine_version(thd, rt, sp))
+ DBUG_RETURN(TRUE);
+
+ /* 'sp' is NULL when there is no such routine. */
+ if (sp && !has_prelocking_list)
+ {
+ prelocking_strategy->handle_routine(thd, prelocking_ctx, rt, sp,
+ need_prelocking);
+ }
+ }
+ else
+ {
+ /*
+ If it's a top level call, just make sure we have a recent
+ version of the routine, if it exists.
+ Validating routine version is unnecessary, since CALL
+ does not affect the prepared statement prelocked list.
+ */
+ if (sp_cache_routine(thd, rt, FALSE, &sp))
+ DBUG_RETURN(TRUE);
+ }
+ }
+ break;
+ case MDL_key::TRIGGER:
+ /**
+ We add trigger entries to lex->sroutines_list, but we don't
+ load them here. The trigger entry is only used when building
+ a transitive closure of objects used in a statement, to avoid
+ adding to this closure objects that are used in the trigger more
+ than once.
+ E.g. if a trigger trg refers to table t2, and the trigger table t1
+ is used multiple times in the statement (say, because it's used in
+ function f1() twice), we will only add t2 once to the list of
+ tables to prelock.
+
+ We don't take metadata locks on triggers either: they are protected
+ by a respective lock on the table, on which the trigger is defined.
+
+ The only two cases which give "trouble" are SHOW CREATE TRIGGER
+ and DROP TRIGGER statements. For these, statement syntax doesn't
+ specify the table on which this trigger is defined, so we have
+ to make a "dirty" read in the data dictionary to find out the
+ table name. Once we discover the table name, we take a metadata
+ lock on it, and this protects all trigger operations.
+ Of course the table, in theory, may disappear between the dirty
+ read and metadata lock acquisition, but in that case we just return
+ a run-time error.
+
+ Grammar of other trigger DDL statements (CREATE, DROP) requires
+ the table to be specified explicitly, so we use the table metadata
+ lock to protect trigger metadata in these statements. Similarly, in
+ DML we always use triggers together with their tables, and thus don't
+ need to take separate metadata locks on them.
+ */
+ break;
+ default:
+ /* Impossible type value. */
+ DBUG_ASSERT(0);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ Handle table list element by obtaining metadata lock, opening table or view
+ and, if prelocking strategy prescribes so, extending the prelocking set with
+ tables and routines used by it.
+
+ @param[in] thd Thread context.
+ @param[in] lex LEX structure for statement.
+ @param[in] tables Table list element to be processed.
+ @param[in,out] counter Number of tables which are open.
+ @param[in] flags Bitmap of flags to modify how the tables
+ will be open, see open_table() description
+ for details.
+ @param[in] prelocking_strategy Strategy which specifies how the
+ prelocking set should be extended
+ when table or view is processed.
+ @param[in] has_prelocking_list Indicates that prelocking set/list for
+ this statement has already been built.
+ @param[in] ot_ctx Context used to recover from a failed
+ open_table() attempt.
+ @param[in] new_frm_mem Temporary MEM_ROOT to be used for
+ parsing .FRMs for views.
+
+ @retval FALSE Success.
+ @retval TRUE Error, reported unless there is a chance to recover from it.
*/
-void detach_merge_children(TABLE *table, bool clear_refs)
+static bool
+open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
+ uint *counter, uint flags,
+ Prelocking_strategy *prelocking_strategy,
+ bool has_prelocking_list,
+ Open_table_context *ot_ctx,
+ MEM_ROOT *new_frm_mem)
{
- TABLE_LIST *child_l;
- TABLE *parent= table->child_l ? table : table->parent;
- bool first_detach;
- DBUG_ENTER("detach_merge_children");
+ bool error= FALSE;
+ bool safe_to_ignore_table= FALSE;
+ DBUG_ENTER("open_and_process_table");
+ DEBUG_SYNC(thd, "open_and_process_table");
+
/*
- Either table->child_l or table->parent must be set. Parent must have
- child_l set.
+ Ignore placeholders for derived tables. After derived tables
+ processing, link to created temporary table will be put here.
+ If this is derived table for view then we still want to process
+ routines used by this view.
*/
- DBUG_ASSERT(parent && parent->child_l);
- DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx clear_refs: %d",
- table->s->db.str, table->s->table_name.str,
- (long) table, clear_refs));
- DBUG_PRINT("myrg", ("parent: '%s'.'%s' 0x%lx", parent->s->db.str,
- parent->s->table_name.str, (long) parent));
-
+ if (tables->derived)
+ {
+ if (!tables->view)
+ goto end;
+ /*
+ We restore view's name and database wiped out by derived tables
+ processing and fall back to standard open process in order to
+ obtain proper metadata locks and do other necessary steps like
+ stored routine processing.
+ */
+ tables->db= tables->view_db.str;
+ tables->db_length= tables->view_db.length;
+ tables->table_name= tables->view_name.str;
+ tables->table_name_length= tables->view_name.length;
+ }
/*
- In a open_tables() loop it can happen that not all tables have their
- children attached yet. Also this is called for every child and the
- parent from close_thread_tables().
+ If this TABLE_LIST object is a placeholder for an information_schema
+ table, create a temporary table to represent the information_schema
+ table in the query. Do not fill it yet - will be filled during
+ execution.
*/
- if ((first_detach= parent->children_attached))
+ if (tables->schema_table)
{
- VOID(parent->file->extra(HA_EXTRA_DETACH_CHILDREN));
- parent->children_attached= FALSE;
- DBUG_PRINT("myrg", ("detached parent: '%s'.'%s' 0x%lx", parent->s->db.str,
- parent->s->table_name.str, (long) parent));
+ /*
+ If this information_schema table is merged into a mergeable
+ view, ignore it for now -- it will be filled when its respective
+ TABLE_LIST is processed. This code works only during re-execution.
+ */
+ if (tables->view)
+ {
+ MDL_ticket *mdl_ticket;
+ /*
+ We still need to take a MDL lock on the merged view to protect
+ it from concurrent changes.
+ */
+ if (!open_table_get_mdl_lock(thd, ot_ctx, &tables->mdl_request,
+ flags, &mdl_ticket) &&
+ mdl_ticket != NULL)
+ goto process_view_routines;
+ /* Fall-through to return error. */
+ }
+ else if (!mysql_schema_table(thd, lex, tables) &&
+ !check_and_update_table_version(thd, tables, tables->table->s))
+ {
+ goto end;
+ }
+ error= TRUE;
+ goto end;
+ }
+ DBUG_PRINT("tcache", ("opening table: '%s'.'%s' item: %p",
+ tables->db, tables->table_name, tables)); //psergey: invalid read of size 1 here
+ (*counter)++;
+
+ /* Not a placeholder: must be a base table or a view. Let us open it. */
+ DBUG_ASSERT(!tables->table);
+
+ if (tables->prelocking_placeholder)
+ {
+ /*
+ For the tables added by the pre-locking code, attempt to open
+ the table but fail silently if the table does not exist.
+ The real failure will occur when/if a statement attempts to use
+ that table.
+ */
+ No_such_table_error_handler no_such_table_handler;
+ thd->push_internal_handler(&no_such_table_handler);
+ error= open_table(thd, tables, new_frm_mem, ot_ctx);
+ thd->pop_internal_handler();
+ safe_to_ignore_table= no_such_table_handler.safely_trapped_errors();
}
else
- DBUG_PRINT("myrg", ("parent is already detached"));
+ error= open_table(thd, tables, new_frm_mem, ot_ctx);
+
+ free_root(new_frm_mem, MYF(MY_KEEP_PREALLOC));
+
+ if (error)
+ {
+ if (! ot_ctx->can_recover_from_failed_open() && safe_to_ignore_table)
+ {
+ DBUG_PRINT("info", ("open_table: ignoring table '%s'.'%s'",
+ tables->db, tables->alias));
+ error= FALSE;
+ }
+ goto end;
+ }
- if (clear_refs)
+ /*
+ We can't rely on simple check for TABLE_LIST::view to determine
+ that this is a view since during re-execution we might reopen
+ ordinary table in place of view and thus have TABLE_LIST::view
+ set from repvious execution and TABLE_LIST::table set from
+ current.
+ */
+ if (!tables->table && tables->view)
{
- /* In any case clear the own parent reference. (***) */
- table->parent= NULL;
+ /* VIEW placeholder */
+ (*counter)--;
/*
- On the first detach, clear all references. If this table is the
- parent, we still may need to clear the child references. The first
- detach might not have done this.
+ tables->next_global list consists of two parts:
+ 1) Query tables and underlying tables of views.
+ 2) Tables used by all stored routines that this statement invokes on
+ execution.
+ We need to know where the bound between these two parts is. If we've
+ just opened a view, which was the last table in part #1, and it
+ has added its base tables after itself, adjust the boundary pointer
+ accordingly.
*/
- if (first_detach || (table == parent))
- {
- /* Clear TABLE references to force new assignment at next open. */
- for (child_l= parent->child_l; ; child_l= child_l->next_global)
- {
- /*
- Do not DBUG_ASSERT(child_l->table); open_tables might be
- incomplete.
+ if (lex->query_tables_own_last == &(tables->next_global) &&
+ tables->view->query_tables)
+ lex->query_tables_own_last= tables->view->query_tables_last;
+ /*
+ Let us free memory used by 'sroutines' hash here since we never
+ call destructor for this LEX.
+ */
+ my_hash_free(&tables->view->sroutines);
+ goto process_view_routines;
+ }
- Clear the parent reference of the children only on the first
- detach. The children might already be closed. They will clear
- it themseves when this function is called for them with
- 'clear_refs' true. See above "(***)".
- */
- if (first_detach && child_l->table)
- child_l->table->parent= NULL;
+ /*
+ Special types of open can succeed but still don't set
+ TABLE_LIST::table to anything.
+ */
+ if (tables->open_strategy && !tables->table)
+ goto end;
- /* Clear the table reference to force new assignment at next open. */
- child_l->table= NULL;
+ /*
+ If we are not already in prelocked mode and extended table list is not
+ yet built we might have to build the prelocking set for this statement.
- /* Break when this was the last child. */
- if (&child_l->next_global == parent->child_last_l)
- break;
- }
- }
+ Since currently no prelocking strategy prescribes doing anything for
+ tables which are only read, we do below checks only if table is going
+ to be changed.
+ */
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+ ! has_prelocking_list &&
+ tables->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ bool need_prelocking= FALSE;
+ TABLE_LIST **save_query_tables_last= lex->query_tables_last;
+ /*
+ Extend statement's table list and the prelocking set with
+ tables and routines according to the current prelocking
+ strategy.
+
+ For example, for DML statements we need to add tables and routines
+ used by triggers which are going to be invoked for this element of
+ table list and also add tables required for handling of foreign keys.
+ */
+ error= prelocking_strategy->handle_table(thd, lex, tables,
+ &need_prelocking);
+
+ if (need_prelocking && ! lex->requires_prelocking())
+ lex->mark_as_requiring_prelocking(save_query_tables_last);
+
+ if (error)
+ goto end;
}
- DBUG_VOID_RETURN;
-}
+ if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables_mode)
+ {
+ if (tables->lock_type == TL_WRITE_DEFAULT)
+ tables->table->reginfo.lock_type= thd->update_lock_default;
+ else if (tables->lock_type == TL_READ_DEFAULT)
+ tables->table->reginfo.lock_type=
+ read_lock_type_for_table(thd, lex, tables);
+ else
+ tables->table->reginfo.lock_type= tables->lock_type;
+ }
+ tables->table->grant= tables->grant;
+ /* Check and update metadata version of a base table. */
+ error= check_and_update_table_version(thd, tables, tables->table->s);
-/**
- @brief Fix MERGE children after open.
+ if (error)
+ goto end;
+ /*
+ After opening a MERGE table add the children to the query list of
+ tables, so that they are opened too.
+ Note that placeholders don't have the handler open.
+ */
+ /* MERGE tables need to access parent and child TABLE_LISTs. */
+ DBUG_ASSERT(tables->table->pos_in_table_list == tables);
+ /* Non-MERGE tables ignore this call. */
+ if (tables->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
+ {
+ error= TRUE;
+ goto end;
+ }
- @param[in] old_child_list first list member from original table
- @param[in] old_last pointer to &next_global of last list member
- @param[in] new_child_list first list member from freshly opened table
- @param[in] new_last pointer to &next_global of last list member
+process_view_routines:
+ /*
+ Again we may need cache all routines used by this view and add
+ tables used by them to table list.
+ */
+ if (tables->view &&
+ thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+ ! has_prelocking_list)
+ {
+ bool need_prelocking= FALSE;
+ TABLE_LIST **save_query_tables_last= lex->query_tables_last;
- @return mismatch
- @retval FALSE OK, no mismatch
- @retval TRUE Error, lists mismatch
+ error= prelocking_strategy->handle_view(thd, lex, tables,
+ &need_prelocking);
- @detail
- Main action is to copy TABLE reference for each member of original
- child list to new child list. After a fresh open these references
- are NULL. Assign the old children to the new table. Some of them
- might also be reopened or will be reopened soon.
+ if (need_prelocking && ! lex->requires_prelocking())
+ lex->mark_as_requiring_prelocking(save_query_tables_last);
- Other action is to verify that the table definition with respect to
- the UNION list did not change.
+ if (error)
+ goto end;
+ }
- @note
- This function terminates the child list if the respective '*_last'
- pointer is non-NULL. Do not call it from a place where the list is
- embedded in another list and this would break it.
+end:
+ DBUG_RETURN(error);
+}
- Terminating the list is required for example in the first
- reopen_table() after open_tables(). open_tables() requires the end
- of the list not to be terminated because other tables could follow
- behind the child list.
+extern "C" uchar *schema_set_get_key(const uchar *record, size_t *length,
+ my_bool not_used __attribute__((unused)))
+{
+ TABLE_LIST *table=(TABLE_LIST*) record;
+ *length= table->db_length;
+ return (uchar*) table->db;
+}
- If a '*_last' pointer is NULL, the respective list is assumed to be
- NULL terminated.
+/**
+ Acquire upgradable (SNW, SNRW) metadata locks on tables used by
+ LOCK TABLES or by a DDL statement. Under LOCK TABLES, we can't take
+ new locks, so use open_tables_check_upgradable_mdl() instead.
+
+ @param thd Thread context.
+ @param tables_start Start of list of tables on which upgradable locks
+ should be acquired.
+ @param tables_end End of list of tables.
+ @param lock_wait_timeout Seconds to wait before timeout.
+ @param flags Bitmap of flags to modify how the tables will be
+ open, see open_table() description for details.
+
+ @retval FALSE Success.
+ @retval TRUE Failure (e.g. connection was killed)
*/
-bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last,
- TABLE_LIST *new_child_list, TABLE_LIST **new_last)
+bool
+lock_table_names(THD *thd,
+ TABLE_LIST *tables_start, TABLE_LIST *tables_end,
+ ulong lock_wait_timeout, uint flags)
{
- bool mismatch= FALSE;
- DBUG_ENTER("fix_merge_after_open");
- DBUG_PRINT("myrg", ("old last addr: 0x%lx new last addr: 0x%lx",
- (long) old_last, (long) new_last));
+ MDL_request_list mdl_requests;
+ TABLE_LIST *table;
+ MDL_request global_request;
+ Hash_set<TABLE_LIST, schema_set_get_key> schema_set;
- /* Terminate the lists for easier check of list end. */
- if (old_last)
- *old_last= NULL;
- if (new_last)
- *new_last= NULL;
+ DBUG_ASSERT(!thd->locked_tables_mode);
- for (;;)
+ for (table= tables_start; table && table != tables_end;
+ table= table->next_global)
+ {
+ if (table->mdl_request.type >= MDL_SHARED_NO_WRITE &&
+ !(table->open_type == OT_TEMPORARY_ONLY ||
+ (flags & MYSQL_OPEN_TEMPORARY_ONLY) ||
+ (table->open_type != OT_BASE_ONLY &&
+ ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) &&
+ find_temporary_table(thd, table))))
+ {
+ if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
+ schema_set.insert(table))
+ return TRUE;
+ mdl_requests.push_front(&table->mdl_request);
+ }
+ }
+
+ if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
+ ! mdl_requests.is_empty())
{
- DBUG_PRINT("myrg", ("old list item: 0x%lx new list item: 0x%lx",
- (long) old_child_list, (long) new_child_list));
- /* Break if one of the list is at its end. */
- if (!old_child_list || !new_child_list)
- break;
- /* Old table has references to child TABLEs. */
- DBUG_ASSERT(old_child_list->table);
- /* New table does not yet have references to child TABLEs. */
- DBUG_ASSERT(!new_child_list->table);
- DBUG_PRINT("myrg", ("old table: '%s'.'%s' new table: '%s'.'%s'",
- old_child_list->db, old_child_list->table_name,
- new_child_list->db, new_child_list->table_name));
- /* Child db.table names must match. */
- if (strcmp(old_child_list->table_name, new_child_list->table_name) ||
- strcmp(old_child_list->db, new_child_list->db))
- break;
/*
- Copy TABLE reference. Child TABLE objects are still in place
- though not necessarily open yet.
+ Scoped locks: Take intention exclusive locks on all involved
+ schemas.
*/
- DBUG_PRINT("myrg", ("old table ref: 0x%lx replaces new table ref: 0x%lx",
- (long) old_child_list->table,
- (long) new_child_list->table));
- new_child_list->table= old_child_list->table;
- /* Step both lists. */
- old_child_list= old_child_list->next_global;
- new_child_list= new_child_list->next_global;
- }
- DBUG_PRINT("myrg", ("end of list, mismatch: %d", mismatch));
- /*
- If the list pointers are not both NULL after the loop, then the
- lists differ. If the are both identical, but not NULL, then they
- have at least one table in common and hence the rest of the list
- would be identical too. But in this case the loop woul run until the
- list end, where both pointers would become NULL.
- */
- if (old_child_list != new_child_list)
- mismatch= TRUE;
- if (mismatch)
- my_error(ER_TABLE_DEF_CHANGED, MYF(0));
+ Hash_set<TABLE_LIST, schema_set_get_key>::Iterator it(schema_set);
+ while ((table= it++))
+ {
+ MDL_request *schema_request= new (thd->mem_root) MDL_request;
+ if (schema_request == NULL)
+ return TRUE;
+ schema_request->init(MDL_key::SCHEMA, table->db, "",
+ MDL_INTENTION_EXCLUSIVE,
+ MDL_TRANSACTION);
+ mdl_requests.push_front(schema_request);
+ }
- DBUG_RETURN(mismatch);
-}
+ /*
+ Protect this statement against concurrent global read lock
+ by acquiring global intention exclusive lock with statement
+ duration.
+ */
+ if (thd->global_read_lock.can_acquire_protection())
+ return TRUE;
+ global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_STATEMENT);
+ mdl_requests.push_front(&global_request);
+ }
+ if (thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout))
+ return TRUE;
-/*
- Return a appropriate read lock type given a table object.
+ return FALSE;
+}
- @param thd Thread context
- @param lex LEX for the current statement.
- @param table_list Table list element for table to be locked.
- @remark Due to a statement-based replication limitation, statements such as
- INSERT INTO .. SELECT FROM .. and CREATE TABLE .. SELECT FROM need
- to grab a TL_READ_NO_INSERT lock on the source table in order to
- prevent the replication of a concurrent statement that modifies the
- source table. If such a statement gets applied on the slave before
- the INSERT .. SELECT statement finishes, data on the master could
- differ from data on the slave and end-up with a discrepancy between
- the binary log and table state.
- This also applies to SELECT/SET/DO statements which use stored
- functions. Calls to such functions are going to be logged as a
- whole and thus should be serialized against concurrent changes
- to tables used by those functions. This can be avoided if functions
- only read data but doing so requires more complex analysis than it
- is done now (unfortunately, due to bug #53921 "Wrong locks for
- SELECTs used stored functions may lead to broken SBR" this rule
- is not followed in cases when stored function or trigger use
- simple SELECT and not a subselect in their body).
- Furthermore, this does not apply to I_S and log tables as it's
- always unsafe to replicate such tables under statement-based
- replication as the table on the slave might contain other data
- (ie: general_log is enabled on the slave). The statement will
- be marked as unsafe for SBR in decide_logging_format().
+/**
+ Check for upgradable (SNW, SNRW) metadata locks on tables to be opened
+ for a DDL statement. Under LOCK TABLES, we can't take new locks, so we
+ must check if appropriate locks were pre-acquired.
+
+ @param thd Thread context.
+ @param tables_start Start of list of tables on which upgradable locks
+ should be searched for.
+ @param tables_end End of list of tables.
+ @param flags Bitmap of flags to modify how the tables will be
+ open, see open_table() description for details.
+
+ @retval FALSE Success.
+ @retval TRUE Failure (e.g. connection was killed)
*/
-thr_lock_type read_lock_type_for_table(THD *thd, LEX *lex,
- TABLE_LIST *table_list)
+static bool
+open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
+ TABLE_LIST *tables_end, uint flags)
{
- bool log_on= mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG);
- ulong binlog_format= thd->variables.binlog_format;
- if ((log_on == FALSE) || (binlog_format == BINLOG_FORMAT_ROW) ||
- (table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) ||
- (lex->sql_command == SQLCOM_SELECT &&
- ! table_list->prelocking_placeholder))
- return TL_READ;
- else
- return TL_READ_NO_INSERT;
+ TABLE_LIST *table;
+
+ DBUG_ASSERT(thd->locked_tables_mode);
+
+ for (table= tables_start; table && table != tables_end;
+ table= table->next_global)
+ {
+ if (table->mdl_request.type >= MDL_SHARED_NO_WRITE &&
+ !(table->open_type == OT_TEMPORARY_ONLY ||
+ (flags & MYSQL_OPEN_TEMPORARY_ONLY) ||
+ (table->open_type != OT_BASE_ONLY &&
+ ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) &&
+ find_temporary_table(thd, table))))
+ {
+ /*
+ We don't need to do anything about the found TABLE instance as it
+ will be handled later in open_tables(), we only need to check that
+ an upgradable lock is already acquired. When we enter LOCK TABLES
+ mode, SNRW locks are acquired before all other locks. So if under
+ LOCK TABLES we find that there is TABLE instance with upgradeable
+ lock, all other instances of TABLE for the same table will have the
+ same ticket.
+
+ Note that this works OK even for CREATE TABLE statements which
+ request X type of metadata lock. This is because under LOCK TABLES
+ such statements don't create the table but only check if it exists
+ or, in most complex case, only insert into it.
+ Thus SNRW lock should be enough.
+
+ Note that find_table_for_mdl_upgrade() will report an error if
+ no suitable ticket is found.
+ */
+ if (!find_table_for_mdl_upgrade(thd->open_tables, table->db,
+ table->table_name, FALSE))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
-/*
+/**
Open all tables in list
- SYNOPSIS
- open_tables()
- thd - thread handler
- start - list of tables in/out
- counter - number of opened tables will be return using this parameter
- flags - bitmap of flags to modify how the tables will be open:
- MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has
- done a flush on it.
+ @param[in] thd Thread context.
+ @param[in,out] start List of tables to be open (it can be adjusted for
+ statement that uses tables only implicitly, e.g.
+ for "SELECT f1()").
+ @param[out] counter Number of tables which were open.
+ @param[in] flags Bitmap of flags to modify how the tables will be
+ open, see open_table() description for details.
+ @param[in] prelocking_strategy Strategy which specifies how prelocking
+ algorithm should work for this statement.
- NOTE
- Unless we are already in prelocked mode, this function will also precache
- all SP/SFs explicitly or implicitly (via views and triggers) used by the
- query and add tables needed for their execution to table list. If resulting
- tables list will be non empty it will mark query as requiring precaching.
+ @note
+ Unless we are already in prelocked mode and prelocking strategy prescribes
+ so this function will also precache all SP/SFs explicitly or implicitly
+ (via views and triggers) used by the query and add tables needed for their
+ execution to table list. Statement that uses SFs, invokes triggers or
+ requires foreign key checks will be marked as requiring prelocking.
Prelocked mode will be enabled for such query during lock_tables() call.
If query for which we are opening tables is already marked as requiring
prelocking it won't do such precaching and will simply reuse table list
which is already built.
- If any table has a trigger and start->trg_event_map is non-zero
- the final lock will end up in thd->locked_tables, otherwise, the
- lock will be placed in thd->lock. See also comments in
- st_lex::set_trg_event_type_for_tables().
-
- RETURN
- 0 - OK
- -1 - error
+ @retval FALSE Success.
+ @retval TRUE Error, reported.
*/
-int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
+bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
+ Prelocking_strategy *prelocking_strategy)
{
- TABLE_LIST *tables= NULL;
- bool refresh;
- int result=0;
+ /*
+ We use pointers to "next_global" member in the last processed TABLE_LIST
+ element and to the "next" member in the last processed Sroutine_hash_entry
+ element as iterators over, correspondingly, the table list and stored routines
+ list which stay valid and allow to continue iteration when new elements are
+ added to the tail of the lists.
+ */
+ TABLE_LIST **table_to_open;
+ Sroutine_hash_entry **sroutine_to_open;
+ TABLE_LIST *tables;
+ Open_table_context ot_ctx(thd, flags);
+ bool error= FALSE;
MEM_ROOT new_frm_mem;
- /* Also used for indicating that prelocking is need */
- TABLE_LIST **query_tables_last_own;
- bool safe_to_ignore_table;
-
+ bool has_prelocking_list;
DBUG_ENTER("open_tables");
+
/*
temporary mem_root for new .frm parsing.
TODO: variables for size
@@ -4509,356 +4713,482 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
init_sql_alloc(&new_frm_mem, 8024, 8024);
thd->current_tablenr= 0;
- restart:
- *counter= 0;
- query_tables_last_own= 0;
- thd_proc_info(thd, "Opening tables");
-
+restart:
/*
- If we are not already executing prelocked statement and don't have
- statement for which table list for prelocking is already built, let
- us cache routines and try to build such table list.
-
+ Close HANDLER tables which are marked for flush or against which there
+ are pending exclusive metadata locks. This is needed both in order to
+ avoid deadlocks and to have a point during statement execution at
+ which such HANDLERs are closed even if they don't create problems for
+ the current session (i.e. to avoid having a DDL blocked by HANDLERs
+ opened for a long time).
*/
+ if (thd->handler_tables_hash.records)
+ mysql_ha_flush(thd);
- if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
- thd->lex->uses_stored_routines())
- {
- bool first_no_prelocking, need_prelocking;
- TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last;
-
- DBUG_ASSERT(thd->lex->query_tables == *start);
- sp_get_prelocking_info(thd, &need_prelocking, &first_no_prelocking);
-
- if (sp_cache_routines_and_add_tables(thd, thd->lex, first_no_prelocking))
- {
- /*
- Serious error during reading stored routines from mysql.proc table.
- Something's wrong with the table or its contents, and an error has
- been emitted; we must abort.
- */
- result= -1;
- goto err;
- }
- else if (need_prelocking)
- {
- query_tables_last_own= save_query_tables_last;
- *start= thd->lex->query_tables;
- }
- }
+ has_prelocking_list= thd->lex->requires_prelocking();
+ table_to_open= start;
+ sroutine_to_open= (Sroutine_hash_entry**) &thd->lex->sroutines_list.first;
+ *counter= 0;
+ thd_proc_info(thd, "Opening tables");
/*
- For every table in the list of tables to open, try to find or open
- a table.
+ If we are executing LOCK TABLES statement or a DDL statement
+ (in non-LOCK TABLES mode) we might have to acquire upgradable
+ semi-exclusive metadata locks (SNW or SNRW) on some of the
+ tables to be opened.
+ When executing CREATE TABLE .. If NOT EXISTS .. SELECT, the
+ table may not yet exist, in which case we acquire an exclusive
+ lock.
+ We acquire all such locks at once here as doing this in one
+ by one fashion may lead to deadlocks or starvation. Later when
+ we will be opening corresponding table pre-acquired metadata
+ lock will be reused (thanks to the fact that in recursive case
+ metadata locks are acquired without waiting).
*/
- for (tables= *start; tables ;tables= tables->next_global)
+ if (! (flags & (MYSQL_OPEN_HAS_MDL_LOCK |
+ MYSQL_OPEN_FORCE_SHARED_MDL |
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)))
{
- DBUG_PRINT("tcache", ("opening table: '%s'.'%s' item: 0x%lx",
- tables->db, tables->table_name, (long) tables));
-
- safe_to_ignore_table= FALSE;
-
- /*
- Ignore placeholders for derived tables. After derived tables
- processing, link to created temporary table will be put here.
- If this is derived table for view then we still want to process
- routines used by this view.
- */
- if (tables->derived)
- {
- if (tables->view)
- goto process_view_routines;
- continue;
- }
- /*
- If this TABLE_LIST object is a placeholder for an information_schema
- table, create a temporary table to represent the information_schema
- table in the query. Do not fill it yet - will be filled during
- execution.
- */
- if (tables->schema_table)
+ if (thd->locked_tables_mode)
{
/*
- If this information_schema table is merged into a mergeable
- view, ignore it for now -- it will be filled when its respective
- TABLE_LIST is processed. This code works only during re-execution.
+ Under LOCK TABLES, we can't acquire new locks, so we instead
+ need to check if appropriate locks were pre-acquired.
*/
- if (tables->view)
- goto process_view_routines;
- if (!mysql_schema_table(thd, thd->lex, tables) &&
- !check_and_update_table_version(thd, tables, tables->table->s))
+ if (open_tables_check_upgradable_mdl(thd, *start,
+ thd->lex->first_not_own_table(),
+ flags))
{
- continue;
+ error= TRUE;
+ goto err;
}
- DBUG_RETURN(-1);
}
- (*counter)++;
-
- /*
- Not a placeholder: must be a base table or a view, and the table is
- not opened yet. Try to open the table.
- */
- if (!tables->table)
+ else
{
- if (tables->prelocking_placeholder)
+ TABLE_LIST *table;
+ if (lock_table_names(thd, *start, thd->lex->first_not_own_table(),
+ ot_ctx.get_timeout(), flags))
{
- /*
- For the tables added by the pre-locking code, attempt to open
- the table but fail silently if the table does not exist.
- The real failure will occur when/if a statement attempts to use
- that table.
- */
- Prelock_error_handler prelock_handler;
- thd->push_internal_handler(& prelock_handler);
- tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags);
- thd->pop_internal_handler();
- safe_to_ignore_table= prelock_handler.safely_trapped_errors();
+ error= TRUE;
+ goto err;
}
- else
+ for (table= *start; table && table != thd->lex->first_not_own_table();
+ table= table->next_global)
{
- tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags);
-
- /*
- Skip further processing if there has been a fatal error while
- trying to open a table. For example, this might happen due to
- stack shortage, unknown definer in views, etc.
- */
- if (!tables->table && thd->is_error())
- {
- result= -1;
- goto err;
- }
+ if (table->mdl_request.type >= MDL_SHARED_NO_WRITE)
+ table->mdl_request.ticket= NULL;
}
}
- else
- DBUG_PRINT("tcache", ("referenced table: '%s'.'%s' 0x%lx",
- tables->db, tables->table_name,
- (long) tables->table));
+ }
- if (!tables->table)
+ /*
+ Perform steps of prelocking algorithm until there are unprocessed
+ elements in prelocking list/set.
+ */
+ while (*table_to_open ||
+ (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+ *sroutine_to_open))
+ {
+ /*
+ For every table in the list of tables to open, try to find or open
+ a table.
+ */
+ for (tables= *table_to_open; tables;
+ table_to_open= &tables->next_global, tables= tables->next_global)
{
- free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
-
- if (tables->view)
- {
- /* VIEW placeholder */
- (*counter)--;
-
- /*
- tables->next_global list consists of two parts:
- 1) Query tables and underlying tables of views.
- 2) Tables used by all stored routines that this statement invokes on
- execution.
- We need to know where the bound between these two parts is. If we've
- just opened a view, which was the last table in part #1, and it
- has added its base tables after itself, adjust the boundary pointer
- accordingly.
- */
- if (query_tables_last_own == &(tables->next_global) &&
- tables->view->query_tables)
- query_tables_last_own= tables->view->query_tables_last;
- /*
- Let us free memory used by 'sroutines' hash here since we never
- call destructor for this LEX.
- */
- hash_free(&tables->view->sroutines);
- goto process_view_routines;
- }
+ error= open_and_process_table(thd, thd->lex, tables, counter,
+ flags, prelocking_strategy,
+ has_prelocking_list, &ot_ctx,
+ &new_frm_mem);
- /*
- If in a MERGE table open, we need to remove the children list
- from statement table list before restarting. Otherwise the list
- will be inserted another time.
- */
- if (tables->parent_l)
+ if (error)
{
- TABLE_LIST *parent_l= tables->parent_l;
- /* The parent table should be correctly open at this point. */
- DBUG_ASSERT(parent_l->table);
- parent_l->next_global= *parent_l->table->child_last_l;
- }
+ if (ot_ctx.can_recover_from_failed_open())
+ {
+ /*
+ We have met exclusive metadata lock or old version of table.
+ Now we have to close all tables and release metadata locks.
+ We also have to throw away set of prelocked tables (and thus
+ close tables from this set that were open by now) since it
+ is possible that one of tables which determined its content
+ was changed.
+
+ Instead of implementing complex/non-robust logic mentioned
+ above we simply close and then reopen all tables.
+
+ We have to save pointer to table list element for table which we
+ have failed to open since closing tables can trigger removal of
+ elements from the table list (if MERGE tables are involved),
+ */
+ close_tables_for_reopen(thd, start, ot_ctx.start_of_statement_svp());
- if (refresh) // Refresh in progress
- {
- /*
- We have met name-locked or old version of table. Now we have
- to close all tables which are not up to date. We also have to
- throw away set of prelocked tables (and thus close tables from
- this set that were open by now) since it possible that one of
- tables which determined its content was changed.
-
- Instead of implementing complex/non-robust logic mentioned
- above we simply close and then reopen all tables.
-
- In order to prepare for recalculation of set of prelocked tables
- we pretend that we have finished calculation which we were doing
- currently.
- */
- if (query_tables_last_own)
- thd->lex->mark_as_requiring_prelocking(query_tables_last_own);
- close_tables_for_reopen(thd, start);
- goto restart;
- }
+ /*
+ Here we rely on the fact that 'tables' still points to the valid
+ TABLE_LIST element. Altough currently this assumption is valid
+ it may change in future.
+ */
+ if (ot_ctx.recover_from_failed_open(thd))
+ goto err;
- if (safe_to_ignore_table)
- {
- DBUG_PRINT("info", ("open_table: ignoring table '%s'.'%s'",
- tables->db, tables->alias));
- continue;
+ error= FALSE;
+ goto restart;
+ }
+ goto err;
}
- result= -1; // Fatal error
- break;
+ DEBUG_SYNC(thd, "open_tables_after_open_and_process_table");
}
- else
+
+ /*
+ If we are not already in prelocked mode and extended table list is
+ not yet built for our statement we need to cache routines it uses
+ and build the prelocking list for it.
+ If we are not in prelocked mode but have built the extended table
+ list, we still need to call open_and_process_routine() to take
+ MDL locks on the routines.
+ */
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
{
+ bool need_prelocking= FALSE;
+ TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last;
/*
- If we are not already in prelocked mode and extended table list is not
- yet built and we have trigger for table being opened then we should
- cache all routines used by its triggers and add their tables to
- prelocking list.
- If we lock table for reading we won't update it so there is no need to
- process its triggers since they never will be activated.
+ Process elements of the prelocking set which are present there
+ since parsing stage or were added to it by invocations of
+ Prelocking_strategy methods in the above loop over tables.
+
+ For example, if element is a routine, cache it and then,
+ if prelocking strategy prescribes so, add tables it uses to the
+ table list and routines it might invoke to the prelocking set.
*/
- if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
- tables->trg_event_map && tables->table->triggers &&
- tables->lock_type >= TL_WRITE_ALLOW_WRITE)
+ for (Sroutine_hash_entry *rt= *sroutine_to_open; rt;
+ sroutine_to_open= &rt->next, rt= rt->next)
{
- if (!query_tables_last_own)
- query_tables_last_own= thd->lex->query_tables_last;
- if (sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex,
- tables))
+ error= open_and_process_routine(thd, thd->lex, rt, prelocking_strategy,
+ has_prelocking_list, &ot_ctx,
+ &need_prelocking);
+
+ if (error)
{
+ if (ot_ctx.can_recover_from_failed_open())
+ {
+ close_tables_for_reopen(thd, start,
+ ot_ctx.start_of_statement_svp());
+ if (ot_ctx.recover_from_failed_open(thd))
+ goto err;
+
+ error= FALSE;
+ goto restart;
+ }
/*
Serious error during reading stored routines from mysql.proc table.
- Something's wrong with the table or its contents, and an error has
+ Something is wrong with the table or its contents, and an error has
been emitted; we must abort.
*/
- result= -1;
goto err;
}
}
- free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
- }
- if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables)
- {
- if (tables->lock_type == TL_WRITE_DEFAULT)
- tables->table->reginfo.lock_type= thd->update_lock_default;
- else if (tables->lock_type == TL_READ_DEFAULT)
- tables->table->reginfo.lock_type=
- read_lock_type_for_table(thd, thd->lex, tables);
- else
- tables->table->reginfo.lock_type= tables->lock_type;
- }
- tables->table->grant= tables->grant;
+ if (need_prelocking && ! thd->lex->requires_prelocking())
+ thd->lex->mark_as_requiring_prelocking(save_query_tables_last);
- /* Check and update metadata version of a base table. */
- if (check_and_update_table_version(thd, tables, tables->table->s))
- {
- result= -1;
- goto err;
+ if (need_prelocking && ! *start)
+ *start= thd->lex->query_tables;
}
+ }
- /* Attach MERGE children if not locked already. */
- DBUG_PRINT("tcache", ("is parent: %d is child: %d",
- test(tables->table->child_l),
- test(tables->parent_l)));
- DBUG_PRINT("tcache", ("in lock tables: %d in prelock mode: %d",
- test(thd->locked_tables), test(thd->prelocked_mode)));
- if (((!thd->locked_tables && !thd->prelocked_mode) ||
- tables->table->s->tmp_table) &&
- ((tables->table->child_l &&
- add_merge_table_list(tables)) ||
- (tables->parent_l &&
- (&tables->next_global == tables->parent_l->table->child_last_l) &&
- attach_merge_children(tables))))
- {
- result= -1;
- goto err;
- }
+ /*
+ After successful open of all tables, including MERGE parents and
+ children, attach the children to their parents. At end of statement,
+ the children are detached. Attaching and detaching are always done,
+ even under LOCK TABLES.
+ */
+ for (tables= *start; tables; tables= tables->next_global)
+ {
+ TABLE *tbl= tables->table;
-process_view_routines:
- /*
- Again we may need cache all routines used by this view and add
- tables used by them to table list.
- */
- if (tables->view && !thd->prelocked_mode &&
- !thd->lex->requires_prelocking() &&
- tables->view->uses_stored_routines())
+ /* Schema tables may not have a TABLE object here. */
+ if (tbl && tbl->file->ht->db_type == DB_TYPE_MRG_MYISAM)
{
- /* We have at least one table in TL here. */
- if (!query_tables_last_own)
- query_tables_last_own= thd->lex->query_tables_last;
- if (sp_cache_routines_and_add_tables_for_view(thd, thd->lex, tables))
+ /* MERGE tables need to access parent and child TABLE_LISTs. */
+ DBUG_ASSERT(tbl->pos_in_table_list == tables);
+ if (tbl->file->extra(HA_EXTRA_ATTACH_CHILDREN))
{
- /*
- Serious error during reading stored routines from mysql.proc table.
- Something is wrong with the table or its contents, and an error has
- been emitted; we must abort.
- */
- result= -1;
+ error= TRUE;
goto err;
}
}
}
- err:
+err:
thd_proc_info(thd, 0);
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
- if (query_tables_last_own)
- thd->lex->mark_as_requiring_prelocking(query_tables_last_own);
+ if (error && *table_to_open)
+ {
+ (*table_to_open)->table= NULL;
+ }
+ DBUG_PRINT("open_tables", ("returning: %d", (int) error));
+ DBUG_RETURN(error);
+}
+
+
+/**
+ Defines how prelocking algorithm for DML statements should handle routines:
+ - For CALL statements we do unrolling (i.e. open and lock tables for each
+ sub-statement individually). So for such statements prelocking is enabled
+ only if stored functions are used in parameter list and only for period
+ during which we calculate values of parameters. Thus in this strategy we
+ ignore procedure which is directly called by such statement and extend
+ the prelocking set only with tables/functions used by SF called from the
+ parameter list.
+ - For any other statement any routine which is directly or indirectly called
+ by statement is going to be executed in prelocked mode. So in this case we
+ simply add all tables and routines used by it to the prelocking set.
+
+ @param[in] thd Thread context.
+ @param[in] prelocking_ctx Prelocking context of the statement.
+ @param[in] rt Prelocking set element describing routine.
+ @param[in] sp Routine body.
+ @param[out] need_prelocking Set to TRUE if method detects that prelocking
+ required, not changed otherwise.
+
+ @retval FALSE Success.
+ @retval TRUE Failure (OOM).
+*/
+
+bool DML_prelocking_strategy::
+handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
+ Sroutine_hash_entry *rt, sp_head *sp, bool *need_prelocking)
+{
+ /*
+ We assume that for any "CALL proc(...)" statement sroutines_list will
+ have 'proc' as first element (it may have several, consider e.g.
+ "proc(sp_func(...)))". This property is currently guaranted by the
+ parser.
+ */
- if (result && tables)
+ if (rt != (Sroutine_hash_entry*)prelocking_ctx->sroutines_list.first ||
+ rt->mdl_request.key.mdl_namespace() != MDL_key::PROCEDURE)
{
- /*
- Some functions determine success as (tables->table != NULL).
- tables->table is in thd->open_tables. It won't go lost. If the
- error happens on a MERGE child, clear the parents TABLE reference.
- */
- if (tables->parent_l)
+ *need_prelocking= TRUE;
+ sp_update_stmt_used_routines(thd, prelocking_ctx, &sp->m_sroutines,
+ rt->belong_to_view);
+ (void)sp->add_used_tables_to_table_list(thd,
+ &prelocking_ctx->query_tables_last,
+ rt->belong_to_view);
+ }
+ sp->propagate_attributes(prelocking_ctx);
+ return FALSE;
+}
+
+
+/**
+ Defines how prelocking algorithm for DML statements should handle table list
+ elements:
+ - If table has triggers we should add all tables and routines
+ used by them to the prelocking set.
+
+ We do not need to acquire metadata locks on trigger names
+ in DML statements, since all DDL statements
+ that change trigger metadata always lock their
+ subject tables.
+
+ @param[in] thd Thread context.
+ @param[in] prelocking_ctx Prelocking context of the statement.
+ @param[in] table_list Table list element for table.
+ @param[in] sp Routine body.
+ @param[out] need_prelocking Set to TRUE if method detects that prelocking
+ required, not changed otherwise.
+
+ @retval FALSE Success.
+ @retval TRUE Failure (OOM).
+*/
+
+bool DML_prelocking_strategy::
+handle_table(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking)
+{
+ /* We rely on a caller to check that table is going to be changed. */
+ DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE);
+
+ if (table_list->trg_event_map)
+ {
+ if (table_list->table->triggers)
{
- if (tables->parent_l->next_global == tables->parent_l->table->child_l)
- tables->parent_l->next_global= *tables->parent_l->table->child_last_l;
- tables->parent_l->table= NULL;
+ *need_prelocking= TRUE;
+
+ if (table_list->table->triggers->
+ add_tables_and_routines_for_triggers(thd, prelocking_ctx, table_list))
+ return TRUE;
}
- tables->table= NULL;
}
- DBUG_PRINT("tcache", ("returning: %d", result));
- DBUG_RETURN(result);
+
+ return FALSE;
}
-/*
+/**
+ Defines how prelocking algorithm for DML statements should handle view -
+ all view routines should be added to the prelocking set.
+
+ @param[in] thd Thread context.
+ @param[in] prelocking_ctx Prelocking context of the statement.
+ @param[in] table_list Table list element for view.
+ @param[in] sp Routine body.
+ @param[out] need_prelocking Set to TRUE if method detects that prelocking
+ required, not changed otherwise.
+
+ @retval FALSE Success.
+ @retval TRUE Failure (OOM).
+*/
+
+bool DML_prelocking_strategy::
+handle_view(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking)
+{
+ if (table_list->view->uses_stored_routines())
+ {
+ *need_prelocking= TRUE;
+
+ sp_update_stmt_used_routines(thd, prelocking_ctx,
+ &table_list->view->sroutines_list,
+ table_list->top_table());
+ }
+ return FALSE;
+}
+
+
+/**
+ Defines how prelocking algorithm for LOCK TABLES statement should handle
+ table list elements.
+
+ @param[in] thd Thread context.
+ @param[in] prelocking_ctx Prelocking context of the statement.
+ @param[in] table_list Table list element for table.
+ @param[in] sp Routine body.
+ @param[out] need_prelocking Set to TRUE if method detects that prelocking
+ required, not changed otherwise.
+
+ @retval FALSE Success.
+ @retval TRUE Failure (OOM).
+*/
+
+bool Lock_tables_prelocking_strategy::
+handle_table(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking)
+{
+ if (DML_prelocking_strategy::handle_table(thd, prelocking_ctx, table_list,
+ need_prelocking))
+ return TRUE;
+
+ /* We rely on a caller to check that table is going to be changed. */
+ DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE);
+
+ return FALSE;
+}
+
+
+/**
+ Defines how prelocking algorithm for ALTER TABLE statement should handle
+ routines - do nothing as this statement is not supposed to call routines.
+
+ We still can end up in this method when someone tries
+ to define a foreign key referencing a view, and not just
+ a simple view, but one that uses stored routines.
+*/
+
+bool Alter_table_prelocking_strategy::
+handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
+ Sroutine_hash_entry *rt, sp_head *sp, bool *need_prelocking)
+{
+ return FALSE;
+}
+
+
+/**
+ Defines how prelocking algorithm for ALTER TABLE statement should handle
+ table list elements.
+
+ Unlike in DML, we do not process triggers here.
+
+ @param[in] thd Thread context.
+ @param[in] prelocking_ctx Prelocking context of the statement.
+ @param[in] table_list Table list element for table.
+ @param[in] sp Routine body.
+ @param[out] need_prelocking Set to TRUE if method detects that prelocking
+ required, not changed otherwise.
+
+
+ @retval FALSE Success.
+ @retval TRUE Failure (OOM).
+*/
+
+bool Alter_table_prelocking_strategy::
+handle_table(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking)
+{
+ return FALSE;
+}
+
+
+/**
+ Defines how prelocking algorithm for ALTER TABLE statement
+ should handle view - do nothing. We don't need to add view
+ routines to the prelocking set in this case as view is not going
+ to be materialized.
+*/
+
+bool Alter_table_prelocking_strategy::
+handle_view(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking)
+{
+ return FALSE;
+}
+
+
+/**
Check that lock is ok for tables; Call start stmt if ok
- SYNOPSIS
- check_lock_and_start_stmt()
- thd Thread handle
- table_list Table to check
- lock_type Lock used for table
+ @param thd Thread handle.
+ @param prelocking_ctx Prelocking context.
+ @param table_list Table list element for table to be checked.
- RETURN VALUES
- 0 ok
- 1 error
+ @retval FALSE - Ok.
+ @retval TRUE - Error.
*/
-static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
- thr_lock_type lock_type)
+static bool check_lock_and_start_stmt(THD *thd,
+ Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list)
{
int error;
+ thr_lock_type lock_type;
DBUG_ENTER("check_lock_and_start_stmt");
- if ((int) lock_type >= (int) TL_WRITE_ALLOW_READ &&
- (int) table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ)
+ /*
+ TL_WRITE_DEFAULT and TL_READ_DEFAULT are supposed to be parser only
+ types of locks so they should be converted to appropriate other types
+ to be passed to storage engine. The exact lock type passed to the
+ engine is important as, for example, InnoDB uses it to determine
+ what kind of row locks should be acquired when executing statement
+ in prelocked mode or under LOCK TABLES with @@innodb_table_locks = 0.
+ */
+ if (table_list->lock_type == TL_WRITE_DEFAULT)
+ lock_type= thd->update_lock_default;
+ else if (table_list->lock_type == TL_READ_DEFAULT)
+ lock_type= read_lock_type_for_table(thd, prelocking_ctx, table_list);
+ else
+ lock_type= table_list->lock_type;
+
+ if ((int) lock_type > (int) TL_WRITE_ALLOW_WRITE &&
+ (int) table_list->table->reginfo.lock_type <= (int) TL_WRITE_ALLOW_WRITE)
{
- my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),table->alias);
+ my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias);
DBUG_RETURN(1);
}
- if ((error=table->file->start_stmt(thd, lock_type)))
+ if ((error= table_list->table->file->start_stmt(thd, lock_type)))
{
- table->file->print_error(error,MYF(0));
+ table_list->table->file->print_error(error, MYF(0));
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -4871,6 +5201,10 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
@param[in] thd thread handle
@param[in] table_l table to open is first table in this list
@param[in] lock_type lock to use for table
+ @param[in] flags options to be used while opening and locking
+ table (see open_table(), mysql_lock_tables())
+ @param[in] prelocking_strategy Strategy which specifies how prelocking
+ algorithm should work for this statement.
@return table
@retval != NULL OK, opened table returned
@@ -4891,12 +5225,13 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
There may be more differences between open_n_lock_single_table() and
open_ltable(). One known difference is that open_ltable() does
- neither call decide_logging_format() nor handle some other logging
+ neither call thd->decide_logging_format() nor handle some other logging
and locking issues because it does not call lock_tables().
*/
TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
- thr_lock_type lock_type)
+ thr_lock_type lock_type, uint flags,
+ Prelocking_strategy *prelocking_strategy)
{
TABLE_LIST *save_next_global;
DBUG_ENTER("open_n_lock_single_table");
@@ -4912,7 +5247,8 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
table_l->required_type= FRMTYPE_TABLE;
/* Open the table. */
- if (simple_open_n_lock_tables(thd, table_l))
+ if (open_and_lock_tables(thd, table_l, FALSE, flags,
+ prelocking_strategy))
table_l->table= NULL; /* Just to be sure. */
/* Restore list. */
@@ -4950,23 +5286,44 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
uint lock_flags)
{
TABLE *table;
- bool refresh;
+ Open_table_context ot_ctx(thd, lock_flags);
+ bool error;
DBUG_ENTER("open_ltable");
/* should not be used in a prelocked_mode context, see NOTE above */
- DBUG_ASSERT(!thd->prelocked_mode);
+ DBUG_ASSERT(thd->locked_tables_mode < LTM_PRELOCKED);
thd_proc_info(thd, "Opening table");
thd->current_tablenr= 0;
/* open_ltable can be used only for BASIC TABLEs */
table_list->required_type= FRMTYPE_TABLE;
- while (!(table= open_table(thd, table_list, thd->mem_root, &refresh, 0)) &&
- refresh)
- ;
- if (table)
+ /* This function can't properly handle requests for such metadata locks. */
+ DBUG_ASSERT(table_list->mdl_request.type < MDL_SHARED_NO_WRITE);
+
+ while ((error= open_table(thd, table_list, thd->mem_root, &ot_ctx)) &&
+ ot_ctx.can_recover_from_failed_open())
+ {
+ /*
+ Even though we have failed to open table we still need to
+ call release_transactional_locks() to release metadata locks which
+ might have been acquired successfully.
+ */
+ thd->mdl_context.rollback_to_savepoint(ot_ctx.start_of_statement_svp());
+ table_list->mdl_request.ticket= 0;
+ if (ot_ctx.recover_from_failed_open(thd))
+ break;
+ }
+
+ if (!error)
{
- if (table->child_l)
+ /*
+ We can't have a view or some special "open_strategy" in this function
+ so there should be a TABLE instance.
+ */
+ DBUG_ASSERT(table_list->table);
+ table= table_list->table;
+ if (table->file->ht->db_type == DB_TYPE_MRG_MYISAM)
{
/* A MERGE table must not come here. */
/* purecov: begin tested */
@@ -4978,11 +5335,10 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
}
table_list->lock_type= lock_type;
- table_list->table= table;
table->grant= table_list->grant;
- if (thd->locked_tables)
+ if (thd->locked_tables_mode)
{
- if (check_lock_and_start_stmt(thd, table, lock_type))
+ if (check_lock_and_start_stmt(thd, thd->lex, table_list))
table= 0;
}
else
@@ -4990,71 +5346,82 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1,
- lock_flags, &refresh)))
- table= 0;
+ lock_flags)))
+ {
+ table= 0;
+ }
}
}
+ else
+ table= 0;
- end:
+end:
+ if (table == NULL)
+ {
+ if (!thd->in_sub_stmt)
+ trans_rollback_stmt(thd);
+ close_thread_tables(thd);
+ }
thd_proc_info(thd, 0);
DBUG_RETURN(table);
}
-/*
+/**
Open all tables in list, locks them and optionally process derived tables.
- SYNOPSIS
- open_and_lock_tables_derived()
- thd - thread handler
- tables - list of tables for open&locking
- derived - if to handle derived tables
-
- RETURN
- FALSE - ok
- TRUE - error
+ @param thd Thread context.
+ @param tables List of tables for open and locking.
+ @param derived If to handle derived tables.
+ @param flags Bitmap of options to be used to open and lock
+ tables (see open_tables() and mysql_lock_tables()
+ for details).
+ @param prelocking_strategy Strategy which specifies how prelocking algorithm
+ should work for this statement.
- NOTE
- The lock will automaticaly be freed by close_thread_tables()
+ @note
+ The thr_lock locks will automatically be freed by
+ close_thread_tables().
- NOTE
- There are two convenience functions:
- - simple_open_n_lock_tables(thd, tables) without derived handling
- - open_and_lock_tables(thd, tables) with derived handling
- Both inline functions call open_and_lock_tables_derived() with
- the third argument set appropriately.
+ @retval FALSE OK.
+ @retval TRUE Error
*/
-int open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived)
+bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
+ bool derived, uint flags,
+ Prelocking_strategy *prelocking_strategy)
{
uint counter;
- bool need_reopen;
- DBUG_ENTER("open_and_lock_tables_derived");
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ DBUG_ENTER("open_and_lock_tables");
DBUG_PRINT("enter", ("derived handling: %d", derived));
- for ( ; ; )
- {
- if (open_tables(thd, &tables, &counter, 0))
- DBUG_RETURN(-1);
+ if (open_tables(thd, &tables, &counter, flags, prelocking_strategy))
+ goto err;
- DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", {
- const char *old_proc_info= thd->proc_info;
- thd->proc_info= "DBUG sleep";
- my_sleep(6000000);
- thd->proc_info= old_proc_info;});
+ DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", {
+ const char *old_proc_info= thd->proc_info;
+ thd->proc_info= "DBUG sleep";
+ my_sleep(6000000);
+ thd->proc_info= old_proc_info;});
+
+ if (lock_tables(thd, tables, counter, flags))
+ goto err;
- if (!lock_tables(thd, tables, counter, &need_reopen))
- break;
- if (!need_reopen)
- DBUG_RETURN(-1);
- close_tables_for_reopen(thd, &tables);
- }
if (derived &&
(mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
(thd->fill_derived_tables() &&
mysql_handle_derived(thd->lex, &mysql_derived_filling))))
- DBUG_RETURN(TRUE); /* purecov: inspected */
- DBUG_RETURN(0);
+ goto err;
+
+ DBUG_RETURN(FALSE);
+err:
+ if (! thd->in_sub_stmt)
+ trans_rollback_stmt(thd); /* Necessary if derived handling failed. */
+ close_thread_tables(thd);
+ /* Don't keep locks for a failed statement. */
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+ DBUG_RETURN(TRUE);
}
@@ -5080,13 +5447,30 @@ int open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived)
bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags)
{
+ DML_prelocking_strategy prelocking_strategy;
uint counter;
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("open_normal_and_derived_tables");
DBUG_ASSERT(!thd->fill_derived_tables());
- if (open_tables(thd, &tables, &counter, flags) ||
+ if (open_tables(thd, &tables, &counter, flags, &prelocking_strategy) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare))
- DBUG_RETURN(TRUE); /* purecov: inspected */
+ goto end;
+
DBUG_RETURN(0);
+end:
+ /*
+ No need to commit/rollback the statement transaction: it's
+ either not started or we're filling in an INFORMATION_SCHEMA
+ table on the fly, and thus mustn't manipulate with the
+ transaction of the enclosing statement.
+ */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
+ (thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
+ close_thread_tables(thd);
+ /* Don't keep locks for a failed statement. */
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+
+ DBUG_RETURN(TRUE); /* purecov: inspected */
}
@@ -5103,234 +5487,50 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags)
or schema tables) as free for reuse.
*/
-static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
+static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table_list)
{
- for (; table; table= table->next_global)
+ TABLE_LIST *table;
+ for (table= table_list; table; table= table->next_global)
if (!table->placeholder())
- table->table->query_id= 0;
-}
-
-
-/**
- Decide on logging format to use for the statement.
-
- Compute the capabilities vector for the involved storage engines
- and mask out the flags for the binary log. Right now, the binlog
- flags only include the capabilities of the storage engines, so this
- is safe.
-
- We now have three alternatives that prevent the statement from
- being loggable:
-
- 1. If there are no capabilities left (all flags are clear) it is
- not possible to log the statement at all, so we roll back the
- statement and report an error.
-
- 2. Statement mode is set, but the capabilities indicate that
- statement format is not possible.
-
- 3. Row mode is set, but the capabilities indicate that row
- format is not possible.
-
- 4. Statement is unsafe, but the capabilities indicate that row
- format is not possible.
-
- If we are in MIXED mode, we then decide what logging format to use:
-
- 1. If the statement is unsafe, row-based logging is used.
-
- 2. If statement-based logging is not possible, row-based logging is
- used.
-
- 3. Otherwise, statement-based logging is used.
-
- @param thd Client thread
- @param tables Tables involved in the query
- */
-
-int decide_logging_format(THD *thd, TABLE_LIST *tables)
-{
- /*
- In SBR mode, we are only proceeding if we are binlogging this
- statement, ie, the filtering rules won't later filter this out.
-
- This check here is needed to prevent some spurious error to be
- raised in some cases (See BUG#42829).
- */
- if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG) &&
- (thd->variables.binlog_format != BINLOG_FORMAT_STMT ||
- binlog_filter->db_ok(thd->db)))
- {
- /*
- Compute the starting vectors for the computations by creating a
- set with all the capabilities bits set and one with no
- capabilities bits set.
- */
- handler::Table_flags flags_write_some_set= 0;
- handler::Table_flags flags_access_some_set= 0;
- handler::Table_flags flags_write_all_set=
- HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
-
- /*
- If different types of engines are about to be updated.
- For example: Innodb and Falcon; Innodb and MyIsam.
- */
- my_bool multi_write_engine= FALSE;
- void* prev_write_ht= NULL;
-
- /*
- If different types of engines are about to be accessed
- and any of them is about to be updated. For example:
- Innodb and Falcon; Innodb and MyIsam.
- */
- my_bool multi_access_engine= FALSE;
- void* prev_access_ht= NULL;
- for (TABLE_LIST *table= tables; table; table= table->next_global)
{
- if (table->placeholder())
- continue;
- if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE)
- thd->lex->set_stmt_unsafe();
- ulonglong const flags= table->table->file->ha_table_flags();
- if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
- {
- DBUG_PRINT("info", ("table: %s; ha_table_flags: %s%s",
- table->table_name,
- FLAGSTR(flags, HA_BINLOG_STMT_CAPABLE),
- FLAGSTR(flags, HA_BINLOG_ROW_CAPABLE)));
- if (prev_write_ht && prev_write_ht != table->table->file->ht)
- multi_write_engine= TRUE;
- prev_write_ht= table->table->file->ht;
- flags_write_all_set &= flags;
- flags_write_some_set |= flags;
- }
- if (prev_access_ht && prev_access_ht != table->table->file->ht)
- multi_access_engine= TRUE;
- prev_access_ht= table->table->file->ht;
- flags_access_some_set |= flags;
- }
-
- DBUG_PRINT("info", ("flags_write_all_set: %s%s",
- FLAGSTR(flags_write_all_set, HA_BINLOG_STMT_CAPABLE),
- FLAGSTR(flags_write_all_set, HA_BINLOG_ROW_CAPABLE)));
- DBUG_PRINT("info", ("flags_write_some_set: %s%s",
- FLAGSTR(flags_write_some_set, HA_BINLOG_STMT_CAPABLE),
- FLAGSTR(flags_write_some_set, HA_BINLOG_ROW_CAPABLE)));
- DBUG_PRINT("info", ("flags_access_some_set: %s%s",
- FLAGSTR(flags_access_some_set, HA_BINLOG_STMT_CAPABLE),
- FLAGSTR(flags_access_some_set, HA_BINLOG_ROW_CAPABLE)));
- DBUG_PRINT("info", ("multi_write_engine: %s",
- multi_write_engine ? "TRUE" : "FALSE"));
- DBUG_PRINT("info", ("multi_access_engine: %s",
- multi_access_engine ? "TRUE" : "FALSE"));
- DBUG_PRINT("info", ("thd->variables.binlog_format: %ld",
- thd->variables.binlog_format));
-
- int error= 0;
- if (flags_write_all_set == 0)
- {
- my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
- "Statement cannot be logged to the binary log in"
- " row-based nor statement-based format");
- }
- else if (thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
- (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
- {
- my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
- "Statement-based format required for this statement,"
- " but not allowed by this combination of engines");
- }
- else if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW ||
- thd->lex->is_stmt_unsafe()) &&
- (flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
- {
- my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
- "Row-based format required for this statement,"
- " but not allowed by this combination of engines");
- }
-
- /*
- If more than one engine is involved in the statement and at
- least one is doing it's own logging (is *self-logging*), the
- statement cannot be logged atomically, so we generate an error
- rather than allowing the binlog to become corrupt.
- */
- if (multi_write_engine &&
- (flags_write_some_set & HA_HAS_OWN_BINLOGGING))
- {
- error= ER_BINLOG_LOGGING_IMPOSSIBLE;
- my_error(error, MYF(0),
- "Statement cannot be written atomically since more"
- " than one engine involved and at least one engine"
- " is self-logging");
+ table->table->query_id= 0;
}
- /*
- Reading from a self-logging engine and updating another engine
- generates changes that are written to the binary log in the
- statement format and may make slaves to diverge. In the mixed
- mode, such changes should be written to the binary log in the
- row format.
- */
- else if (multi_access_engine &&
- (flags_access_some_set & HA_HAS_OWN_BINLOGGING))
- thd->lex->set_stmt_unsafe();
-
- DBUG_PRINT("info", ("error: %d", error));
-
- if (error)
- return -1;
-
- /*
- We switch to row-based format if we are in mixed mode and one of
- the following are true:
-
- 1. If the statement is unsafe
- 2. If statement format cannot be used
-
- Observe that point to cannot be decided before the tables
- involved in a statement has been checked, i.e., we cannot put
- this code in reset_current_stmt_binlog_row_based(), it has to be
- here.
- */
- if (thd->lex->is_stmt_unsafe() ||
- (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
+ for (table= table_list; table; table= table->next_global)
+ if (!table->placeholder())
{
- thd->set_current_stmt_binlog_row_based_if_mixed();
+ /*
+ Detach children of MyISAMMRG tables used in
+ sub-statements, they will be reattached at open.
+ This has to be done in a separate loop to make sure
+ that children have had their query_id cleared.
+ */
+ table->table->file->extra(HA_EXTRA_DETACH_CHILDREN);
}
- }
-
- return 0;
}
-/*
- Lock all tables in list
- SYNOPSIS
- lock_tables()
- thd Thread handler
- tables Tables to lock
- count Number of opened tables
- need_reopen Out parameter which if TRUE indicates that some
- tables were dropped or altered during this call
- and therefore invoker should reopen tables and
- try to lock them once again (in this case
- lock_tables() will also return error).
+/**
+ Lock all tables in a list.
- NOTES
- You can't call lock_tables twice, as this would break the dead-lock-free
- handling thr_lock gives us. You most always get all needed locks at
- once.
+ @param thd Thread handler
+ @param tables Tables to lock
+ @param count Number of opened tables
+ @param flags Options (see mysql_lock_tables() for details)
- If query for which we are calling this function marked as requring
- prelocking, this function will do implicit LOCK TABLES and change
- thd::prelocked_mode accordingly.
+ You can't call lock_tables() while holding thr_lock locks, as
+ this would break the dead-lock-free handling thr_lock gives us.
+ You must always get all needed locks at once.
- RETURN VALUES
- 0 ok
- -1 Error
+ If the query for which we are calling this function is marked as
+ requiring prelocking, this function will change
+ locked_tables_mode to LTM_PRELOCKED.
+
+ @retval FALSE Success.
+ @retval TRUE A lock wait timeout, deadlock or out of memory.
*/
-int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
+bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
+ uint flags)
{
TABLE_LIST *table;
@@ -5339,29 +5539,29 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
We can't meet statement requiring prelocking if we already
in prelocked mode.
*/
- DBUG_ASSERT(!thd->prelocked_mode || !thd->lex->requires_prelocking());
- *need_reopen= FALSE;
+ DBUG_ASSERT(thd->locked_tables_mode <= LTM_LOCK_TABLES ||
+ !thd->lex->requires_prelocking());
if (!tables && !thd->lex->requires_prelocking())
- DBUG_RETURN(decide_logging_format(thd, tables));
+ DBUG_RETURN(thd->decide_logging_format(tables));
/*
- We need this extra check for thd->prelocked_mode because we want to avoid
- attempts to lock tables in substatements. Checking for thd->locked_tables
- is not enough in some situations. For example for SP containing
+ Check for thd->locked_tables_mode to avoid a redundant
+ and harmful attempt to lock the already locked tables again.
+ Checking for thd->lock is not enough in some situations. For example,
+ if a stored function contains
"drop table t3; create temporary t3 ..; insert into t3 ...;"
- thd->locked_tables may be 0 after drop tables, and without this extra
- check insert will try to lock temporary table t3, that will lead
- to memory leak...
+ thd->lock may be 0 after drop tables, whereas locked_tables_mode
+ is still on. In this situation an attempt to lock temporary
+ table t3 will lead to a memory leak.
*/
- if (!thd->locked_tables && !thd->prelocked_mode)
+ if (! thd->locked_tables_mode)
{
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
TABLE **start,**ptr;
- uint lock_flag= MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN;
if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count)))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
for (table= tables; table; table= table->next_global)
{
if (!table->placeholder())
@@ -5371,35 +5571,22 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
/* We have to emulate LOCK TABLES if we are statement needs prelocking. */
if (thd->lex->requires_prelocking())
{
- thd->in_lock_tables=1;
- thd->options|= OPTION_TABLE_LOCK;
/*
A query that modifies autoinc column in sub-statement can make the
master and slave inconsistent.
We can solve these problems in mixed mode by switching to binlogging
if at least one updated table is used by sub-statement
*/
- /* The BINLOG_FORMAT_MIXED judgement is saved for suppressing
- warnings, but it will be removed by fixing bug#45827 */
- if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED && tables &&
+ if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables &&
has_write_table_with_auto_increment(thd->lex->first_not_own_table()))
- {
- thd->lex->set_stmt_unsafe();
- }
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS);
}
DEBUG_SYNC(thd, "before_lock_tables_takes_lock");
if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start),
- lock_flag, need_reopen)))
- {
- if (thd->lex->requires_prelocking())
- {
- thd->options&= ~(OPTION_TABLE_LOCK);
- thd->in_lock_tables=0;
- }
- DBUG_RETURN(-1);
- }
+ flags)))
+ DBUG_RETURN(TRUE);
DEBUG_SYNC(thd, "after_lock_tables_takes_lock");
@@ -5411,17 +5598,6 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
We just have done implicit LOCK TABLES, and now we have
to emulate first open_and_lock_tables() after it.
- Note that "LOCK TABLES" can also be marked as requiring prelocking
- (e.g. if one locks view which uses functions). We should not emulate
- such open_and_lock_tables() in this case. We also should not set
- THD::prelocked_mode or first close_thread_tables() call will do
- "UNLOCK TABLES".
- */
- thd->locked_tables= thd->lock;
- thd->lock= 0;
- thd->in_lock_tables=0;
-
- /*
When open_and_lock_tables() is called for a single table out of
a table list, the 'next_global' chain is temporarily broken. We
may not find 'first_not_own' before the end of the "list".
@@ -5436,12 +5612,11 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
if (!table->placeholder())
{
table->table->query_id= thd->query_id;
- if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
+ if (check_lock_and_start_stmt(thd, thd->lex, table))
{
- mysql_unlock_tables(thd, thd->locked_tables);
- thd->locked_tables= 0;
- thd->options&= ~(OPTION_TABLE_LOCK);
- DBUG_RETURN(-1);
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock= 0;
+ DBUG_RETURN(TRUE);
}
}
}
@@ -5450,8 +5625,8 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
and was marked as occupied during open_tables() as free for reuse.
*/
mark_real_tables_as_free_for_reuse(first_not_own);
- DBUG_PRINT("info",("prelocked_mode= PRELOCKED"));
- thd->prelocked_mode= PRELOCKED;
+ DBUG_PRINT("info",("locked_tables_mode= LTM_PRELOCKED"));
+ thd->enter_locked_tables_mode(LTM_PRELOCKED);
}
}
else
@@ -5476,7 +5651,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
In a stored function or trigger we should ensure that we won't change
a table that is already used by the calling statement.
*/
- if (thd->prelocked_mode &&
+ if (thd->locked_tables_mode >= LTM_PRELOCKED &&
table->lock_type >= TL_WRITE_ALLOW_WRITE)
{
for (TABLE* opentab= thd->open_tables; opentab; opentab= opentab->next)
@@ -5486,14 +5661,14 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
{
my_error(ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG, MYF(0),
table->table->s->table_name.str);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
}
- if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
+ if (check_lock_and_start_stmt(thd, thd->lex, table))
{
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
/*
@@ -5504,71 +5679,102 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
if (thd->lex->requires_prelocking())
{
mark_real_tables_as_free_for_reuse(first_not_own);
- DBUG_PRINT("info", ("thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES"));
- thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES;
+ DBUG_PRINT("info",
+ ("thd->locked_tables_mode= LTM_PRELOCKED_UNDER_LOCK_TABLES"));
+ thd->locked_tables_mode= LTM_PRELOCKED_UNDER_LOCK_TABLES;
}
}
- DBUG_RETURN(decide_logging_format(thd, tables));
+ DBUG_RETURN(thd->decide_logging_format(tables));
}
-/*
+/**
Prepare statement for reopening of tables and recalculation of set of
prelocked tables.
- SYNOPSIS
- close_tables_for_reopen()
- thd in Thread context
- tables in/out List of tables which we were trying to open and lock
-
+ @param[in] thd Thread context.
+ @param[in,out] tables List of tables which we were trying to open
+ and lock.
+ @param[in] start_of_statement_svp MDL savepoint which represents the set
+ of metadata locks which the current transaction
+ managed to acquire before execution of the current
+ statement and to which we should revert before
+ trying to reopen tables. NULL if no metadata locks
+ were held and thus all metadata locks should be
+ released.
*/
-void close_tables_for_reopen(THD *thd, TABLE_LIST **tables)
+void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
+ const MDL_savepoint &start_of_statement_svp)
{
+ TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
+ TABLE_LIST *tmp;
+
/*
If table list consists only from tables from prelocking set, table list
for new attempt should be empty, so we have to update list's root pointer.
*/
- if (thd->lex->first_not_own_table() == *tables)
+ if (first_not_own_table == *tables)
*tables= 0;
thd->lex->chop_off_not_own_tables();
+ /* Reset MDL tickets for procedures/functions */
+ for (Sroutine_hash_entry *rt=
+ (Sroutine_hash_entry*)thd->lex->sroutines_list.first;
+ rt; rt= rt->next)
+ rt->mdl_request.ticket= NULL;
sp_remove_not_own_routines(thd->lex);
- for (TABLE_LIST *tmp= *tables; tmp; tmp= tmp->next_global)
+ for (tmp= *tables; tmp; tmp= tmp->next_global)
+ {
tmp->table= 0;
+ tmp->mdl_request.ticket= NULL;
+ /* We have to cleanup translation tables of views. */
+ tmp->cleanup_items();
+ }
+ /*
+ No need to commit/rollback the statement transaction: it's
+ either not started or we're filling in an INFORMATION_SCHEMA
+ table on the fly, and thus mustn't manipulate with the
+ transaction of the enclosing statement.
+ */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
+ (thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
close_thread_tables(thd);
+ thd->mdl_context.rollback_to_savepoint(start_of_statement_svp);
}
-/*
- Open a single table without table caching and don't set it in open_list
-
- SYNPOSIS
- open_temporary_table()
- thd Thread object
- path Path (without .frm)
- db database
- table_name Table name
- link_in_list 1 if table should be linked into thd->temporary_tables
-
- NOTES:
- Used by alter_table to open a temporary table and when creating
- a temporary table with CREATE TEMPORARY ...
-
- RETURN
- 0 Error
- # TABLE object
+/**
+ Open a single table without table caching and don't add it to
+ THD::open_tables. Depending on the 'add_to_temporary_tables_list' value,
+ the opened TABLE instance will be addded to THD::temporary_tables list.
+
+ @param thd Thread context.
+ @param path Path (without .frm)
+ @param db Database name.
+ @param table_name Table name.
+ @param add_to_temporary_tables_list Specifies if the opened TABLE
+ instance should be linked into
+ THD::temporary_tables list.
+
+ @note This function is used:
+ - by alter_table() to open a temporary table;
+ - when creating a temporary table with CREATE TEMPORARY TABLE.
+
+ @return TABLE instance for opened table.
+ @retval NULL on error.
*/
-TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
- const char *table_name, bool link_in_list)
+TABLE *open_table_uncached(THD *thd, const char *path, const char *db,
+ const char *table_name,
+ bool add_to_temporary_tables_list)
{
TABLE *tmp_table;
TABLE_SHARE *share;
char cache_key[MAX_DBKEY_LENGTH], *saved_cache_key, *tmp_path;
uint key_length;
TABLE_LIST table_list;
- DBUG_ENTER("open_temporary_table");
+ DBUG_ENTER("open_table_uncached");
DBUG_PRINT("enter",
("table: '%s'.'%s' path: '%s' server_id: %u "
"pseudo_thread_id: %lu",
@@ -5603,7 +5809,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
{
/* No need to lock share->mutex as this is not needed for tmp tables */
free_table_share(share);
- my_free((char*) tmp_table,MYF(0));
+ my_free(tmp_table);
DBUG_RETURN(0);
}
@@ -5611,7 +5817,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
share->tmp_table= (tmp_table->file->has_transactions() ?
TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE);
- if (link_in_list)
+ if (add_to_temporary_tables_list)
{
/* growing temp list at the head */
tmp_table->next= thd->temporary_tables;
@@ -5637,7 +5843,7 @@ bool rm_temporary_table(handlerton *base, char *path)
DBUG_ENTER("rm_temporary_table");
strmov(ext= strend(path), reg_ext);
- if (my_delete(path,MYF(0)))
+ if (mysql_file_delete(key_file_frm, path, MYF(0)))
error=1; /* purecov: inspected */
*ext= 0; // remove extension
file= get_new_handler((TABLE_SHARE*) 0, current_thd->mem_root, base);
@@ -5967,8 +6173,8 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
field_ptr= table->field + cached_field_index;
else if (table->s->name_hash.records)
{
- field_ptr= (Field**) hash_search(&table->s->name_hash, (uchar*) name,
- length);
+ field_ptr= (Field**) my_hash_search(&table->s->name_hash, (uchar*) name,
+ length);
if (field_ptr)
{
/*
@@ -6095,7 +6301,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
table_name && table_name[0] &&
(my_strcasecmp(table_alias_charset, table_list->alias, table_name) ||
(db_name && db_name[0] && table_list->db && table_list->db[0] &&
- strcmp(db_name, table_list->db))))
+ (table_list->schema_table ?
+ my_strcasecmp(system_charset_info, db_name, table_list->db) :
+ strcmp(db_name, table_list->db)))))
DBUG_RETURN(0);
*actual_table= NULL;
@@ -6214,8 +6422,8 @@ Field *find_field_in_table_sef(TABLE *table, const char *name)
Field **field_ptr;
if (table->s->name_hash.records)
{
- field_ptr= (Field**)hash_search(&table->s->name_hash,(uchar*) name,
- strlen(name));
+ field_ptr= (Field**)my_hash_search(&table->s->name_hash,(uchar*) name,
+ strlen(name));
if (field_ptr)
{
/*
@@ -8051,7 +8259,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
COND **conds)
{
SELECT_LEX *select_lex= thd->lex->current_select;
- Query_arena *arena= thd->stmt_arena, backup;
TABLE_LIST *table= NULL; // For HP compilers
/*
it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX
@@ -8067,10 +8274,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
select_lex->is_item_list_lookup= 0;
DBUG_ENTER("setup_conds");
- if (select_lex->conds_processed_with_permanent_arena ||
- arena->is_conventional())
- arena= 0; // For easier test
-
thd->mark_used_columns= MARK_COLUMNS_READ;
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
select_lex->cond_count= 0;
@@ -8139,7 +8342,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
We do this ON -> WHERE transformation only once per PS/SP statement.
*/
select_lex->where= *conds;
- select_lex->conds_processed_with_permanent_arena= 1;
}
thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
DBUG_RETURN(test(thd->is_error()));
@@ -8424,7 +8626,7 @@ my_bool mysql_rm_tmp_tables(void)
So we hide error messages which happnes during deleting of these
files(MYF(0)).
*/
- VOID(my_delete(filePath, MYF(0)));
+ (void) mysql_file_delete(key_file_misc, filePath, MYF(0));
}
}
my_dirend(dirp);
@@ -8441,36 +8643,6 @@ my_bool mysql_rm_tmp_tables(void)
*****************************************************************************/
/*
- Invalidate any cache entries that are for some DB
-
- SYNOPSIS
- remove_db_from_cache()
- db Database name. This will be in lower case if
- lower_case_table_name is set
-
- NOTE:
- We can't use hash_delete when looping hash_elements. We mark them first
- and afterwards delete those marked unused.
-*/
-
-void remove_db_from_cache(const char *db)
-{
- for (uint idx=0 ; idx < open_cache.records ; idx++)
- {
- TABLE *table=(TABLE*) hash_element(&open_cache,idx);
- if (!strcmp(table->s->db.str, db))
- {
- table->s->version= 0L; /* Free when thread is ready */
- if (!table->in_use)
- relink_unused(table);
- }
- }
- while (unused_tables && !unused_tables->s->version)
- VOID(hash_delete(&open_cache,(uchar*) unused_tables));
-}
-
-
-/*
free all unused tables
NOTE
@@ -8478,171 +8650,176 @@ void remove_db_from_cache(const char *db)
all not used tables.
*/
-void flush_tables()
+void tdc_flush_unused_tables()
{
- (void) pthread_mutex_lock(&LOCK_open);
+ mysql_mutex_lock(&LOCK_open);
while (unused_tables)
- hash_delete(&open_cache,(uchar*) unused_tables);
- (void) pthread_mutex_unlock(&LOCK_open);
+ free_cache_entry(unused_tables);
+ mysql_mutex_unlock(&LOCK_open);
}
-/*
- Mark all entries with the table as deleted to force an reopen of the table
+/**
+ A callback to the server internals that is used to address
+ special cases of the locking protocol.
+ Invoked when acquiring an exclusive lock, for each thread that
+ has a conflicting shared metadata lock.
+
+ This function:
+ - aborts waiting of the thread on a data lock, to make it notice
+ the pending exclusive lock and back off.
+ - if the thread is an INSERT DELAYED thread, sends it a KILL
+ signal to terminate it.
+
+ @note This function does not wait for the thread to give away its
+ locks. Waiting is done outside for all threads at once.
+
+ @param thd Current thread context
+ @param in_use The thread to wake up
+ @param needs_thr_lock_abort Indicates that to wake up thread
+ this call needs to abort its waiting
+ on table-level lock.
+
+ @retval TRUE if the thread was woken up
+ @retval FALSE otherwise.
+
+ @note It is one of two places where border between MDL and the
+ rest of the server is broken.
+*/
+
+bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
+ bool needs_thr_lock_abort)
+{
+ bool signalled= FALSE;
+ if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
+ !in_use->killed)
+ {
+ in_use->killed= THD::KILL_CONNECTION;
+ mysql_mutex_lock(&in_use->mysys_var->mutex);
+ if (in_use->mysys_var->current_cond)
+ mysql_cond_broadcast(in_use->mysys_var->current_cond);
+ mysql_mutex_unlock(&in_use->mysys_var->mutex);
+ signalled= TRUE;
+ }
- The table will be closed (not stored in cache) by the current thread when
- close_thread_tables() is called.
+ if (needs_thr_lock_abort)
+ {
+ mysql_mutex_lock(&in_use->LOCK_thd_data);
+ for (TABLE *thd_table= in_use->open_tables;
+ thd_table ;
+ thd_table= thd_table->next)
+ {
+ /*
+ Check for TABLE::needs_reopen() is needed since in some places we call
+ handler::close() for table instance (and set TABLE::db_stat to 0)
+ and do not remove such instances from the THD::open_tables
+ for some time, during which other thread can see those instances
+ (e.g. see partitioning code).
+ */
+ if (!thd_table->needs_reopen())
+ signalled|= mysql_lock_abort_for_thread(thd, thd_table);
+ }
+ mysql_mutex_unlock(&in_use->LOCK_thd_data);
+ }
+ return signalled;
+}
- PREREQUISITES
- Lock on LOCK_open()
- RETURN
- 0 This thread now have exclusive access to this table and no other thread
- can access the table until close_thread_tables() is called.
- 1 Table is in use by another thread
+/**
+ Remove all or some (depending on parameter) instances of TABLE and
+ TABLE_SHARE from the table definition cache.
+
+ @param thd Thread context
+ @param remove_type Type of removal:
+ TDC_RT_REMOVE_ALL - remove all TABLE instances and
+ TABLE_SHARE instance. There
+ should be no used TABLE objects
+ and caller should have exclusive
+ metadata lock on the table.
+ TDC_RT_REMOVE_NOT_OWN - remove all TABLE instances
+ except those that belong to
+ this thread. There should be
+ no TABLE objects used by other
+ threads and caller should have
+ exclusive metadata lock on the
+ table.
+ TDC_RT_REMOVE_UNUSED - remove all unused TABLE
+ instances (if there are no
+ used instances will also
+ remove TABLE_SHARE).
+ @param db Name of database
+ @param table_name Name of table
+ @param has_lock If TRUE, LOCK_open is already acquired
+
+ @note It assumes that table instances are already not used by any
+ (other) thread (this should be achieved by using meta-data locks).
*/
-bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
- uint flags)
+void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
+ const char *db, const char *table_name,
+ bool has_lock)
{
char key[MAX_DBKEY_LENGTH];
uint key_length;
TABLE *table;
TABLE_SHARE *share;
- bool result= 0, signalled= 0;
- DBUG_ENTER("remove_table_from_cache");
- DBUG_PRINT("enter", ("table: '%s'.'%s' flags: %u", db, table_name, flags));
- key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
- for (;;)
+ if (! has_lock)
+ mysql_mutex_lock(&LOCK_open);
+ else
{
- HASH_SEARCH_STATE state;
- result= signalled= 0;
+ mysql_mutex_assert_owner(&LOCK_open);
+ }
- for (table= (TABLE*) hash_first(&open_cache, (uchar*) key, key_length,
- &state);
- table;
- table= (TABLE*) hash_next(&open_cache, (uchar*) key, key_length,
- &state))
- {
- THD *in_use;
- DBUG_PRINT("tcache", ("found table: '%s'.'%s' 0x%lx", table->s->db.str,
- table->s->table_name.str, (long) table));
+ DBUG_ASSERT(remove_type == TDC_RT_REMOVE_UNUSED ||
+ thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
+ MDL_EXCLUSIVE));
- table->s->version=0L; /* Free when thread is ready */
- if (!(in_use=table->in_use))
- {
- DBUG_PRINT("info",("Table was not in use"));
- relink_unused(table);
- }
- else if (in_use != thd)
- {
- DBUG_PRINT("info", ("Table was in use by other thread"));
- /*
- Mark that table is going to be deleted from cache. This will
- force threads that are in mysql_lock_tables() (but not yet
- in thr_multi_lock()) to abort it's locks, close all tables and retry
- */
- in_use->some_tables_deleted= 1;
- if (table->is_name_opened())
- {
- DBUG_PRINT("info", ("Found another active instance of the table"));
- result=1;
- }
- /* Kill delayed insert threads */
- if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
- ! in_use->killed)
- {
- in_use->killed= THD::KILL_CONNECTION;
- pthread_mutex_lock(&in_use->mysys_var->mutex);
- if (in_use->mysys_var->current_cond)
- {
- pthread_mutex_lock(in_use->mysys_var->current_mutex);
- signalled= 1;
- pthread_cond_broadcast(in_use->mysys_var->current_cond);
- pthread_mutex_unlock(in_use->mysys_var->current_mutex);
- }
- pthread_mutex_unlock(&in_use->mysys_var->mutex);
- }
- /*
- Now we must abort all tables locks used by this thread
- as the thread may be waiting to get a lock for another table.
- Note that we need to hold LOCK_open while going through the
- list. So that the other thread cannot change it. The other
- thread must also hold LOCK_open whenever changing the
- open_tables list. Aborting the MERGE lock after a child was
- closed and before the parent is closed would be fatal.
- */
- for (TABLE *thd_table= in_use->open_tables;
- thd_table ;
- thd_table= thd_table->next)
- {
- /* Do not handle locks of MERGE children. */
- if (thd_table->db_stat && !thd_table->parent) // If table is open
- signalled|= mysql_lock_abort_for_thread(thd, thd_table);
- }
- }
- else
- {
- DBUG_PRINT("info", ("Table was in use by current thread. db_stat: %u",
- table->db_stat));
- result= result || (flags & RTFC_OWNED_BY_THD_FLAG);
- }
- }
- while (unused_tables && !unused_tables->s->version)
- VOID(hash_delete(&open_cache,(uchar*) unused_tables));
+ key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
- DBUG_PRINT("info", ("Removing table from table_def_cache"));
- /* Remove table from table definition cache if it's not in use */
- if ((share= (TABLE_SHARE*) hash_search(&table_def_cache,(uchar*) key,
- key_length)))
+ if ((share= (TABLE_SHARE*) my_hash_search(&table_def_cache,(uchar*) key,
+ key_length)))
+ {
+ if (share->ref_count)
{
- DBUG_PRINT("info", ("share version: %lu ref_count: %u",
- share->version, share->ref_count));
- share->version= 0; // Mark for delete
- if (share->ref_count == 0)
+ I_P_List_iterator<TABLE, TABLE_share> it(share->free_tables);
+#ifndef DBUG_OFF
+ if (remove_type == TDC_RT_REMOVE_ALL)
{
- pthread_mutex_lock(&share->mutex);
- VOID(hash_delete(&table_def_cache, (uchar*) share));
+ DBUG_ASSERT(share->used_tables.is_empty());
}
- }
-
- if (result && (flags & RTFC_WAIT_OTHER_THREAD_FLAG))
- {
- /*
- Signal any thread waiting for tables to be freed to
- reopen their tables
- */
- broadcast_refresh();
- DBUG_PRINT("info", ("Waiting for refresh signal"));
- if (!(flags & RTFC_CHECK_KILLED_FLAG) || !thd->killed)
+ else if (remove_type == TDC_RT_REMOVE_NOT_OWN)
{
- dropping_tables++;
- if (likely(signalled))
- (void) pthread_cond_wait(&COND_refresh, &LOCK_open);
- else
- {
- struct timespec abstime;
- /*
- It can happen that another thread has opened the
- table but has not yet locked any table at all. Since
- it can be locked waiting for a table that our thread
- has done LOCK TABLE x WRITE on previously, we need to
- ensure that the thread actually hears our signal
- before we go to sleep. Thus we wait for a short time
- and then we retry another loop in the
- remove_table_from_cache routine.
- */
- set_timespec(abstime, 10);
- pthread_cond_timedwait(&COND_refresh, &LOCK_open, &abstime);
- }
- dropping_tables--;
- continue;
+ I_P_List_iterator<TABLE, TABLE_share> it2(share->used_tables);
+ while ((table= it2++))
+ if (table->in_use != thd)
+ {
+ DBUG_ASSERT(0);
+ }
}
+#endif
+ /*
+ Set share's version to zero in order to ensure that it gets
+ automatically deleted once it is no longer referenced.
+
+ Note that code in TABLE_SHARE::wait_for_old_version() assumes
+ that marking share as old and removal of its unused tables
+ and of the share itself from TDC happens atomically under
+ protection of LOCK_open, or, putting it another way, that
+ TDC does not contain old shares which don't have any tables
+ used.
+ */
+ share->version= 0;
+
+ while ((table= it++))
+ free_cache_entry(table);
}
- break;
+ else
+ (void) my_hash_delete(&table_def_cache, (uchar*) share);
}
- DBUG_RETURN(result);
+
+ if (! has_lock)
+ mysql_mutex_unlock(&LOCK_open);
}
@@ -8703,7 +8880,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
mem_root temporary MEM_ROOT for parsing
*/
-static bool
+bool
open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
@@ -8743,7 +8920,6 @@ open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
}
err:
- bzero(outparam, sizeof(TABLE)); // do not run repair
DBUG_RETURN(1);
}
@@ -8755,179 +8931,12 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b)
/*
- SYNOPSIS
- abort_and_upgrade_lock_and_close_table()
- lpt Parameter passing struct
- All parameters passed through the ALTER_PARTITION_PARAM_TYPE object
- RETURN VALUE
- 0
- DESCRIPTION
- Remember old lock level (for possible downgrade later on), abort all
- waiting threads and ensure that all keeping locks currently are
- completed such that we own the lock exclusively and no other interaction
- is ongoing. Close the table and hold the name lock.
-
- thd Thread object
- table Table object
- db Database name
- table_name Table name
- old_lock_level Old lock level
-*/
-
-int abort_and_upgrade_lock_and_close_table(ALTER_PARTITION_PARAM_TYPE *lpt)
-{
- uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG;
- const char *db= lpt->db;
- const char *table_name= lpt->table_name;
- THD *thd= lpt->thd;
- DBUG_ENTER("abort_and_upgrade_lock_and_close_table");
-
- lpt->old_lock_type= lpt->table->reginfo.lock_type;
- safe_mutex_assert_not_owner(&LOCK_open);
- VOID(pthread_mutex_lock(&LOCK_open));
- /* If MERGE child, forward lock handling to parent. */
- mysql_lock_abort(thd, lpt->table->parent ? lpt->table->parent : lpt->table,
- TRUE);
- if (remove_table_from_cache(thd, db, table_name, flags))
- {
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(1);
- }
- close_data_files_and_morph_locks(thd, db, table_name);
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(0);
-}
-
-
-/*
- SYNOPSIS
- close_open_tables_and_downgrade()
- RESULT VALUES
- NONE
- DESCRIPTION
- We need to ensure that any thread that has managed to open the table
- but not yet encountered our lock on the table is also thrown out to
- ensure that no threads see our frm changes premature to the final
- version. The intermediate versions are only meant for use after a
- crash and later REPAIR TABLE.
- We also downgrade locks after the upgrade to WRITE_ONLY
-*/
+ Tells if two (or more) tables have auto_increment columns and we want to
+ lock those tables with a write lock.
-/* purecov: begin deadcode */
-void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt)
-{
- VOID(pthread_mutex_lock(&LOCK_open));
- remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name,
- RTFC_WAIT_OTHER_THREAD_FLAG);
- VOID(pthread_mutex_unlock(&LOCK_open));
- /* If MERGE child, forward lock handling to parent. */
- mysql_lock_downgrade_write(lpt->thd, lpt->table->parent ? lpt->table->parent :
- lpt->table, lpt->old_lock_type);
-}
-/* purecov: end */
-
-
-/*
SYNOPSIS
- mysql_wait_completed_table()
- lpt Parameter passing struct
- my_table My table object
- All parameters passed through the ALTER_PARTITION_PARAM object
- RETURN VALUES
- TRUE Failure
- FALSE Success
- DESCRIPTION
- We have changed the frm file and now we want to wait for all users of
- the old frm to complete before proceeding to ensure that no one
- remains that uses the old frm definition.
- Start by ensuring that all users of the table will be removed from cache
- once they are done. Then abort all that have stumbled on locks and
- haven't been started yet.
-
- thd Thread object
- table Table object
- db Database name
- table_name Table name
-*/
-
-void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table)
-{
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
- TABLE *table;
- DBUG_ENTER("mysql_wait_completed_table");
-
- key_length=(uint) (strmov(strmov(key,lpt->db)+1,lpt->table_name)-key)+1;
- VOID(pthread_mutex_lock(&LOCK_open));
- HASH_SEARCH_STATE state;
- for (table= (TABLE*) hash_first(&open_cache,(uchar*) key,key_length,
- &state) ;
- table;
- table= (TABLE*) hash_next(&open_cache,(uchar*) key,key_length,
- &state))
- {
- THD *in_use= table->in_use;
- table->s->version= 0L;
- if (!in_use)
- {
- relink_unused(table);
- }
- else
- {
- /* Kill delayed insert threads */
- if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
- ! in_use->killed)
- {
- in_use->killed= THD::KILL_CONNECTION;
- pthread_mutex_lock(&in_use->mysys_var->mutex);
- if (in_use->mysys_var->current_cond)
- {
- pthread_mutex_lock(in_use->mysys_var->current_mutex);
- pthread_cond_broadcast(in_use->mysys_var->current_cond);
- pthread_mutex_unlock(in_use->mysys_var->current_mutex);
- }
- pthread_mutex_unlock(&in_use->mysys_var->mutex);
- }
- /*
- Now we must abort all tables locks used by this thread
- as the thread may be waiting to get a lock for another table.
- Note that we need to hold LOCK_open while going through the
- list. So that the other thread cannot change it. The other
- thread must also hold LOCK_open whenever changing the
- open_tables list. Aborting the MERGE lock after a child was
- closed and before the parent is closed would be fatal.
- */
- for (TABLE *thd_table= in_use->open_tables;
- thd_table ;
- thd_table= thd_table->next)
- {
- /* Do not handle locks of MERGE children. */
- if (thd_table->db_stat && !thd_table->parent) // If table is open
- mysql_lock_abort_for_thread(lpt->thd, thd_table);
- }
- }
- }
- /*
- We start by removing all unused objects from the cache and marking
- those in use for removal after completion. Now we also need to abort
- all that are locked and are not progressing due to being locked
- by our lock. We don't upgrade our lock here.
- If MERGE child, forward lock handling to parent.
- */
- mysql_lock_abort(lpt->thd, my_table->parent ? my_table->parent : my_table,
- FALSE);
- VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Check if one (or more) write tables have auto_increment columns.
-
- @param[in] tables Table list
-
- @retval 0 if at least one write tables has an auto_increment column
- @retval 1 otherwise
+ has_two_write_locked_tables_with_auto_increment
+ tables Table list
NOTES:
Call this function only when you have established the list of all tables
@@ -8977,45 +8986,40 @@ has_write_table_with_auto_increment(TABLE_LIST *tables)
bool
open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
- Open_tables_state *backup)
+ Open_tables_backup *backup)
{
+ Query_tables_list query_tables_list_backup;
+ LEX *lex= thd->lex;
+
DBUG_ENTER("open_system_tables_for_read");
+ /*
+ Besides using new Open_tables_state for opening system tables,
+ we also have to backup and reset/and then restore part of LEX
+ which is accessed by open_tables() in order to determine if
+ prelocking is needed and what tables should be added for it.
+ close_system_tables() doesn't require such treatment.
+ */
+ lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
thd->reset_n_backup_open_tables_state(backup);
- uint count= 0;
- bool not_used;
- for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
+ if (open_and_lock_tables(thd, table_list, FALSE,
+ MYSQL_OPEN_IGNORE_FLUSH |
+ MYSQL_LOCK_IGNORE_TIMEOUT))
{
- TABLE *table= open_table(thd, tables, thd->mem_root, &not_used,
- MYSQL_LOCK_IGNORE_FLUSH);
- if (!table)
- goto error;
-
- DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM);
-
- table->use_all_columns();
- table->reginfo.lock_type= tables->lock_type;
- tables->table= table;
- count++;
+ lex->restore_backup_query_tables_list(&query_tables_list_backup);
+ thd->restore_backup_open_tables_state(backup);
+ DBUG_RETURN(TRUE);
}
+ for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
{
- TABLE **list= (TABLE**) thd->alloc(sizeof(TABLE*) * count);
- TABLE **ptr= list;
- for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
- *(ptr++)= tables->table;
-
- thd->lock= mysql_lock_tables(thd, list, count,
- MYSQL_LOCK_IGNORE_FLUSH, &not_used);
+ DBUG_ASSERT(tables->table->s->table_category == TABLE_CATEGORY_SYSTEM);
+ tables->table->use_all_columns();
}
- if (thd->lock)
- DBUG_RETURN(FALSE);
-
-error:
- close_system_tables(thd, backup);
+ lex->restore_backup_query_tables_list(&query_tables_list_backup);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(FALSE);
}
@@ -9025,19 +9029,51 @@ error:
SYNOPSIS
close_system_tables()
thd Thread context
- backup Pointer to Open_tables_state instance which holds
+ backup Pointer to Open_tables_backup instance which holds
information about tables which were open before we
decided to access system tables.
*/
void
-close_system_tables(THD *thd, Open_tables_state *backup)
+close_system_tables(THD *thd, Open_tables_backup *backup)
{
close_thread_tables(thd);
thd->restore_backup_open_tables_state(backup);
}
+/**
+ A helper function to close a mysql.* table opened
+ in an auxiliary THD during bootstrap or in the main
+ connection, when we know that there are no locks
+ held by the connection due to a preceding implicit
+ commit.
+
+ This function assumes that there is no
+ statement transaction started for the operation
+ itself, since mysql.* tables are not transactional
+ and when they are used the binlog is off (DDL
+ binlogging is always statement-based.
+
+ We need this function since we'd like to not
+ just close the system table, but also release
+ the metadata lock on it.
+
+ Note, that in LOCK TABLES mode this function
+ does not release the metadata lock. But in this
+ mode the table can be opened only if it is locked
+ explicitly with LOCK TABLES.
+*/
+
+void
+close_mysql_tables(THD *thd)
+{
+ /* No need to commit/rollback statement transaction, it's not started. */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
+}
+
/*
Open and lock one system table for update.
@@ -9059,7 +9095,8 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
{
DBUG_ENTER("open_system_table_for_update");
- TABLE *table= open_ltable(thd, one_table, one_table->lock_type, 0);
+ TABLE *table= open_ltable(thd, one_table, one_table->lock_type,
+ MYSQL_LOCK_IGNORE_TIMEOUT);
if (table)
{
DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM);
@@ -9070,34 +9107,34 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
}
/**
- Open a performance schema table.
+ Open a log table.
Opening such tables is performed internally in the server
implementation, and is a 'nested' open, since some tables
might be already opened by the current thread.
The thread context before this call is saved, and is restored
- when calling close_performance_schema_table().
+ when calling close_log_table().
@param thd The current thread
- @param one_table Performance schema table to open
+ @param one_table Log table to open
@param backup [out] Temporary storage used to save the thread context
*/
TABLE *
-open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
- Open_tables_state *backup)
+open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup)
{
- uint flags= ( MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
+ uint flags= ( MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |
- MYSQL_LOCK_IGNORE_FLUSH |
- MYSQL_LOCK_PERF_SCHEMA);
+ MYSQL_OPEN_IGNORE_FLUSH |
+ MYSQL_LOCK_IGNORE_TIMEOUT |
+ MYSQL_LOCK_LOG_TABLE);
TABLE *table;
/* Save value that is changed in mysql_lock_tables() */
ulonglong save_utime_after_lock= thd->utime_after_lock;
- DBUG_ENTER("open_performance_schema_table");
+ DBUG_ENTER("open_log_table");
thd->reset_n_backup_open_tables_state(backup);
if ((table= open_ltable(thd, one_table, one_table->lock_type, flags)))
{
- DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_PERFORMANCE);
+ DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_LOG);
/* Make sure all columns get assigned to a default value */
table->use_all_columns();
table->no_replicate= 1;
@@ -9108,72 +9145,22 @@ open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
}
else
- {
- /*
- If error in mysql_lock_tables(), open_ltable doesn't close the
- table. Thread kill during mysql_lock_tables() is such error. But
- open tables cannot be accepted when restoring the open tables
- state.
- */
- if (thd->killed)
- close_thread_tables(thd);
thd->restore_backup_open_tables_state(backup);
- }
thd->utime_after_lock= save_utime_after_lock;
DBUG_RETURN(table);
}
/**
- Close a performance schema table.
- The last table opened by open_performance_schema_table()
+ Close a log table.
+ The last table opened by open_log_table()
is closed, then the thread context is restored.
@param thd The current thread
@param backup [in] the context to restore.
*/
-void close_performance_schema_table(THD *thd, Open_tables_state *backup)
+void close_log_table(THD *thd, Open_tables_backup *backup)
{
- bool found_old_table;
-
- /*
- If open_performance_schema_table() fails,
- this function should not be called.
- */
- DBUG_ASSERT(thd->lock != NULL);
-
- /*
- Note:
- We do not create explicitly a separate transaction for the
- performance table I/O, but borrow the current transaction.
- lock + unlock will autocommit the change done in the
- performance schema table: this is the expected result.
- The current transaction should not be affected by this code.
- TODO: Note that if a transactional engine is used for log tables,
- this code will need to be revised, as a separate transaction
- might be needed.
- */
- mysql_unlock_tables(thd, thd->lock);
- thd->lock= 0;
-
- pthread_mutex_lock(&LOCK_open);
-
- found_old_table= false;
- /*
- Note that we need to hold LOCK_open while changing the
- open_tables list. Another thread may work on it.
- (See: remove_table_from_cache(), mysql_wait_completed_table())
- Closing a MERGE child before the parent would be fatal if the
- other thread tries to abort the MERGE lock in between.
- */
- while (thd->open_tables)
- found_old_table|= close_thread_table(thd, &thd->open_tables);
-
- if (found_old_table)
- broadcast_refresh();
-
- pthread_mutex_unlock(&LOCK_open);
-
- thd->restore_backup_open_tables_state(backup);
+ close_system_tables(thd, backup);
}
/**
diff --git a/sql/sql_base.h b/sql/sql_base.h
new file mode 100644
index 00000000000..35fa04b3674
--- /dev/null
+++ b/sql/sql_base.h
@@ -0,0 +1,597 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_BASE_INCLUDED
+#define SQL_BASE_INCLUDED
+
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_trigger.h" /* trg_event_type */
+#include "sql_class.h" /* enum_mark_columns */
+#include "mysqld.h" /* key_map */
+
+class Item_ident;
+struct Name_resolution_context;
+class Open_table_context;
+class Open_tables_state;
+class Prelocking_strategy;
+struct TABLE_LIST;
+class THD;
+struct handlerton;
+struct TABLE;
+
+typedef class st_select_lex SELECT_LEX;
+
+typedef struct st_lock_param_type ALTER_PARTITION_PARAM_TYPE;
+
+/*
+ This enumeration type is used only by the function find_item_in_list
+ to return the info on how an item has been resolved against a list
+ of possibly aliased items.
+ The item can be resolved:
+ - against an alias name of the list's element (RESOLVED_AGAINST_ALIAS)
+ - against non-aliased field name of the list (RESOLVED_WITH_NO_ALIAS)
+ - against an aliased field name of the list (RESOLVED_BEHIND_ALIAS)
+ - ignoring the alias name in cases when SQL requires to ignore aliases
+ (e.g. when the resolved field reference contains a table name or
+ when the resolved item is an expression) (RESOLVED_IGNORING_ALIAS)
+*/
+enum enum_resolution_type {
+ NOT_RESOLVED=0,
+ RESOLVED_IGNORING_ALIAS,
+ RESOLVED_BEHIND_ALIAS,
+ RESOLVED_WITH_NO_ALIAS,
+ RESOLVED_AGAINST_ALIAS
+};
+
+enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
+ IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE,
+ IGNORE_EXCEPT_NON_UNIQUE};
+
+enum enum_tdc_remove_table_type {TDC_RT_REMOVE_ALL, TDC_RT_REMOVE_NOT_OWN,
+ TDC_RT_REMOVE_UNUSED};
+
+/* bits for last argument to remove_table_from_cache() */
+#define RTFC_NO_FLAG 0x0000
+#define RTFC_OWNED_BY_THD_FLAG 0x0001
+#define RTFC_WAIT_OTHER_THREAD_FLAG 0x0002
+#define RTFC_CHECK_KILLED_FLAG 0x0004
+
+bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
+extern mysql_mutex_t LOCK_open;
+bool table_cache_init(void);
+void table_cache_free(void);
+bool table_def_init(void);
+void table_def_free(void);
+void table_def_start_shutdown(void);
+void assign_new_table_id(TABLE_SHARE *share);
+uint cached_open_tables(void);
+uint cached_table_definitions(void);
+uint create_table_def_key(THD *thd, char *key,
+ const TABLE_LIST *table_list,
+ bool tmp_table);
+TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
+ uint key_length, uint db_flags, int *error,
+ my_hash_value_type hash_value);
+void release_table_share(TABLE_SHARE *share);
+TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name);
+
+TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
+ uint lock_flags);
+
+/* mysql_lock_tables() and open_table() flags bits */
+#define MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK 0x0001
+#define MYSQL_OPEN_IGNORE_FLUSH 0x0002
+#define MYSQL_OPEN_TEMPORARY_ONLY 0x0004
+#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008
+#define MYSQL_LOCK_LOG_TABLE 0x0010
+/**
+ Do not try to acquire a metadata lock on the table: we
+ already have one.
+*/
+#define MYSQL_OPEN_HAS_MDL_LOCK 0x0020
+/**
+ If in locked tables mode, ignore the locked tables and get
+ a new instance of the table.
+*/
+#define MYSQL_OPEN_GET_NEW_TABLE 0x0040
+/** Don't look up the table in the list of temporary tables. */
+#define MYSQL_OPEN_SKIP_TEMPORARY 0x0080
+/** Fail instead of waiting when conficting metadata lock is discovered. */
+#define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0100
+/** Open tables using MDL_SHARED lock instead of one specified in parser. */
+#define MYSQL_OPEN_FORCE_SHARED_MDL 0x0200
+/**
+ Open tables using MDL_SHARED_HIGH_PRIO lock instead of one specified
+ in parser.
+*/
+#define MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL 0x0400
+/**
+ When opening or locking the table, use the maximum timeout
+ (LONG_TIMEOUT = 1 year) rather than the user-supplied timeout value.
+*/
+#define MYSQL_LOCK_IGNORE_TIMEOUT 0x0800
+/**
+ When acquiring "strong" (SNW, SNRW, X) metadata locks on tables to
+ be open do not acquire global and schema-scope IX locks.
+*/
+#define MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK 0x1000
+
+/** Please refer to the internals manual. */
+#define MYSQL_OPEN_REOPEN (MYSQL_OPEN_IGNORE_FLUSH |\
+ MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |\
+ MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\
+ MYSQL_LOCK_IGNORE_TIMEOUT |\
+ MYSQL_OPEN_GET_NEW_TABLE |\
+ MYSQL_OPEN_SKIP_TEMPORARY |\
+ MYSQL_OPEN_HAS_MDL_LOCK)
+
+bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
+ Open_table_context *ot_ctx);
+bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
+ uint db_stat, uint prgflag,
+ uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
+ MEM_ROOT *mem_root);
+
+bool get_key_map_from_key_list(key_map *map, TABLE *table,
+ List<String> *index_list);
+TABLE *open_table_uncached(THD *thd, const char *path, const char *db,
+ const char *table_name,
+ bool add_to_temporary_tables_list);
+TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name);
+TABLE *find_write_locked_table(TABLE *list, const char *db,
+ const char *table_name);
+thr_lock_type read_lock_type_for_table(THD *thd,
+ Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list);
+
+my_bool mysql_rm_tmp_tables(void);
+bool rm_temporary_table(handlerton *base, char *path);
+void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
+ const MDL_savepoint &start_of_statement_svp);
+TABLE_LIST *find_table_in_list(TABLE_LIST *table,
+ TABLE_LIST *TABLE_LIST::*link,
+ const char *db_name,
+ const char *table_name);
+TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name);
+TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
+TABLE *find_temporary_table(THD *thd, const char *table_key,
+ uint table_key_length);
+void close_thread_tables(THD *thd);
+bool fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
+ List<Item> &values,
+ bool ignore_errors,
+ Table_triggers_list *triggers,
+ enum trg_event_type event);
+bool fill_record_n_invoke_before_triggers(THD *thd, Field **field,
+ List<Item> &values,
+ bool ignore_errors,
+ Table_triggers_list *triggers,
+ enum trg_event_type event);
+bool insert_fields(THD *thd, Name_resolution_context *context,
+ const char *db_name, const char *table_name,
+ List_iterator<Item> *it, bool any_privileges);
+int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
+ List<Item> *sum_func_list, uint wild_num);
+bool setup_fields(THD *thd, Item** ref_pointer_array,
+ List<Item> &item, enum_mark_columns mark_used_columns,
+ List<Item> *sum_func_list, bool allow_sum_func);
+bool fill_record(THD *thd, Field **field, List<Item> &values,
+ bool ignore_errors);
+
+Field *
+find_field_in_tables(THD *thd, Item_ident *item,
+ TABLE_LIST *first_table, TABLE_LIST *last_table,
+ Item **ref, find_item_error_report_type report_error,
+ bool check_privileges, bool register_tree_change);
+Field *
+find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
+ const char *name, uint length,
+ const char *item_name, const char *db_name,
+ const char *table_name, Item **ref,
+ bool check_privileges, bool allow_rowid,
+ uint *cached_field_index_ptr,
+ bool register_tree_change, TABLE_LIST **actual_table);
+Field *
+find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
+ bool allow_rowid, uint *cached_field_index_ptr);
+Field *
+find_field_in_table_sef(TABLE *table, const char *name);
+Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
+ find_item_error_report_type report_error,
+ enum_resolution_type *resolution);
+bool setup_tables(THD *thd, Name_resolution_context *context,
+ List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
+ TABLE_LIST **leaves, bool select_insert);
+bool setup_tables_and_check_access(THD *thd,
+ Name_resolution_context *context,
+ List<TABLE_LIST> *from_clause,
+ TABLE_LIST *tables,
+ TABLE_LIST **leaves,
+ bool select_insert,
+ ulong want_access_first,
+ ulong want_access);
+bool wait_while_table_is_used(THD *thd, TABLE *table,
+ enum ha_extra_function function);
+
+void drop_open_table(THD *thd, TABLE *table, const char *db_name,
+ const char *table_name);
+void update_non_unique_table_error(TABLE_LIST *update,
+ const char *operation,
+ TABLE_LIST *duplicate);
+int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
+ COND **conds);
+int setup_ftfuncs(SELECT_LEX* select);
+int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
+bool lock_table_names(THD *thd, TABLE_LIST *table_list,
+ TABLE_LIST *table_list_end, ulong lock_wait_timeout,
+ uint flags);
+bool open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags,
+ Prelocking_strategy *prelocking_strategy);
+/* open_and_lock_tables with optional derived handling */
+bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
+ bool derived, uint flags,
+ Prelocking_strategy *prelocking_strategy);
+/* simple open_and_lock_tables without derived handling for single table */
+TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
+ thr_lock_type lock_type, uint flags,
+ Prelocking_strategy *prelocking_strategy);
+bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags);
+bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags);
+int decide_logging_format(THD *thd, TABLE_LIST *tables);
+void free_io_cache(TABLE *entry);
+void intern_close_table(TABLE *entry);
+bool close_thread_table(THD *thd, TABLE **table_ptr);
+bool close_temporary_tables(THD *thd);
+TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
+ bool check_alias);
+int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans);
+void close_temporary_table(THD *thd, TABLE *table, bool free_share,
+ bool delete_table);
+void close_temporary(TABLE *table, bool free_share, bool delete_table);
+bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
+ const char *table_name);
+bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
+
+/* Functions to work with system tables. */
+bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
+ Open_tables_backup *backup);
+void close_system_tables(THD *thd, Open_tables_backup *backup);
+void close_mysql_tables(THD *thd);
+TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table);
+TABLE *open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup);
+void close_log_table(THD *thd, Open_tables_backup *backup);
+
+TABLE *open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
+ Open_tables_state *backup);
+void close_performance_schema_table(THD *thd, Open_tables_state *backup);
+
+bool close_cached_tables(THD *thd, TABLE_LIST *tables,
+ bool wait_for_refresh, ulong timeout);
+bool close_cached_connection_tables(THD *thd, LEX_STRING *connect_string);
+void close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
+ bool remove_from_locked_tables);
+OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild);
+void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
+ const char *db, const char *table_name,
+ bool has_lock);
+bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
+ char *cache_key, uint cache_key_length,
+ MEM_ROOT *mem_root, uint flags);
+void tdc_flush_unused_tables();
+TABLE *find_table_for_mdl_upgrade(TABLE *list, const char *db,
+ const char *table_name,
+ bool no_error);
+void mark_tmp_table_for_reuse(TABLE *table);
+bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists);
+
+extern TABLE *unused_tables;
+extern Item **not_found_item;
+extern Field *not_found_field;
+extern Field *view_ref_found;
+extern HASH table_def_cache;
+
+/**
+ clean/setup table fields and map.
+
+ @param table TABLE structure pointer (which should be setup)
+ @param table_list TABLE_LIST structure pointer (owner of TABLE)
+ @param tablenr table number
+*/
+
+
+inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
+{
+ table->used_fields= 0;
+ table->const_table= 0;
+ table->null_row= 0;
+ table->status= STATUS_NO_RECORD;
+ table->maybe_null= table_list->outer_join;
+ TABLE_LIST *embedding= table_list->embedding;
+ while (!table->maybe_null && embedding)
+ {
+ table->maybe_null= embedding->outer_join;
+ embedding= embedding->embedding;
+ }
+ table->tablenr= tablenr;
+ table->map= (table_map) 1 << tablenr;
+ table->force_index= table_list->force_index;
+ table->force_index_order= table->force_index_group= 0;
+ table->covering_keys= table->s->keys_for_keyread;
+ table->merge_keys.clear_all();
+}
+
+inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table,
+ const char *db_name,
+ const char *table_name)
+{
+ return find_table_in_list(table, &TABLE_LIST::next_global,
+ db_name, table_name);
+}
+
+inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table,
+ const char *db_name,
+ const char *table_name)
+{
+ return find_table_in_list(table, &TABLE_LIST::next_local,
+ db_name, table_name);
+}
+
+
+inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array,
+ List<Item> &item,
+ enum_mark_columns mark_used_columns,
+ List<Item> *sum_func_list,
+ bool allow_sum_func)
+{
+ bool res;
+ thd->lex->select_lex.no_wrap_view_item= TRUE;
+ res= setup_fields(thd, ref_pointer_array, item, mark_used_columns,
+ sum_func_list, allow_sum_func);
+ thd->lex->select_lex.no_wrap_view_item= FALSE;
+ return res;
+}
+
+/**
+ An abstract class for a strategy specifying how the prelocking
+ algorithm should extend the prelocking set while processing
+ already existing elements in the set.
+*/
+
+class Prelocking_strategy
+{
+public:
+ virtual ~Prelocking_strategy() { }
+
+ virtual bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
+ Sroutine_hash_entry *rt, sp_head *sp,
+ bool *need_prelocking) = 0;
+ virtual bool handle_table(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking) = 0;
+ virtual bool handle_view(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking)= 0;
+};
+
+
+/**
+ A Strategy for prelocking algorithm suitable for DML statements.
+
+ Ensures that all tables used by all statement's SF/SP/triggers and
+ required for foreign key checks are prelocked and SF/SPs used are
+ cached.
+*/
+
+class DML_prelocking_strategy : public Prelocking_strategy
+{
+public:
+ virtual bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
+ Sroutine_hash_entry *rt, sp_head *sp,
+ bool *need_prelocking);
+ virtual bool handle_table(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking);
+ virtual bool handle_view(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking);
+};
+
+
+/**
+ A strategy for prelocking algorithm to be used for LOCK TABLES
+ statement.
+*/
+
+class Lock_tables_prelocking_strategy : public DML_prelocking_strategy
+{
+ virtual bool handle_table(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking);
+};
+
+
+/**
+ Strategy for prelocking algorithm to be used for ALTER TABLE statements.
+
+ Unlike DML or LOCK TABLES strategy, it doesn't
+ prelock triggers, views or stored routines, since they are not
+ used during ALTER.
+*/
+
+class Alter_table_prelocking_strategy : public Prelocking_strategy
+{
+public:
+
+ Alter_table_prelocking_strategy(Alter_info *alter_info)
+ : m_alter_info(alter_info)
+ {}
+
+ virtual bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
+ Sroutine_hash_entry *rt, sp_head *sp,
+ bool *need_prelocking);
+ virtual bool handle_table(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking);
+ virtual bool handle_view(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking);
+
+private:
+ Alter_info *m_alter_info;
+};
+
+
+inline bool
+open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags)
+{
+ DML_prelocking_strategy prelocking_strategy;
+
+ return open_tables(thd, tables, counter, flags, &prelocking_strategy);
+}
+
+
+inline TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
+ thr_lock_type lock_type, uint flags)
+{
+ DML_prelocking_strategy prelocking_strategy;
+
+ return open_n_lock_single_table(thd, table_l, lock_type, flags,
+ &prelocking_strategy);
+}
+
+
+/* open_and_lock_tables with derived handling */
+inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
+ bool derived, uint flags)
+{
+ DML_prelocking_strategy prelocking_strategy;
+
+ return open_and_lock_tables(thd, tables, derived, flags,
+ &prelocking_strategy);
+}
+
+
+/**
+ A context of open_tables() function, used to recover
+ from a failed open_table() or open_routine() attempt.
+*/
+
+class Open_table_context
+{
+public:
+ enum enum_open_table_action
+ {
+ OT_NO_ACTION= 0,
+ OT_BACKOFF_AND_RETRY,
+ OT_REOPEN_TABLES,
+ OT_DISCOVER,
+ OT_REPAIR
+ };
+ Open_table_context(THD *thd, uint flags);
+
+ bool recover_from_failed_open(THD *thd);
+ bool request_backoff_action(enum_open_table_action action_arg,
+ TABLE_LIST *table);
+
+ bool can_recover_from_failed_open() const
+ { return m_action != OT_NO_ACTION; }
+
+ /**
+ When doing a back-off, we close all tables acquired by this
+ statement. Return an MDL savepoint taken at the beginning of
+ the statement, so that we can rollback to it before waiting on
+ locks.
+ */
+ const MDL_savepoint &start_of_statement_svp() const
+ {
+ return m_start_of_statement_svp;
+ }
+
+ inline ulong get_timeout() const
+ {
+ return m_timeout;
+ }
+
+ uint get_flags() const { return m_flags; }
+
+ /**
+ Set flag indicating that we have already acquired metadata lock
+ protecting this statement against GRL while opening tables.
+ */
+ void set_has_protection_against_grl()
+ {
+ m_has_protection_against_grl= TRUE;
+ }
+
+ bool has_protection_against_grl() const
+ {
+ return m_has_protection_against_grl;
+ }
+
+private:
+ /**
+ For OT_DISCOVER and OT_REPAIR actions, the table list element for
+ the table which definition should be re-discovered or which
+ should be repaired.
+ */
+ TABLE_LIST *m_failed_table;
+ MDL_savepoint m_start_of_statement_svp;
+ /**
+ Lock timeout in seconds. Initialized to LONG_TIMEOUT when opening system
+ tables or to the "lock_wait_timeout" system variable for regular tables.
+ */
+ ulong m_timeout;
+ /* open_table() flags. */
+ uint m_flags;
+ /** Back off action. */
+ enum enum_open_table_action m_action;
+ /**
+ Whether we had any locks when this context was created.
+ If we did, they are from the previous statement of a transaction,
+ and we can't safely do back-off (and release them).
+ */
+ bool m_has_locks;
+ /**
+ Indicates that in the process of opening tables we have acquired
+ protection against global read lock.
+ */
+ bool m_has_protection_against_grl;
+};
+
+
+/**
+ This internal handler is used to trap ER_NO_SUCH_TABLE.
+*/
+
+class No_such_table_error_handler : public Internal_error_handler
+{
+public:
+ No_such_table_error_handler()
+ : m_handled_errors(0), m_unhandled_errors(0)
+ {}
+
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl);
+
+ /**
+ Returns TRUE if one or more ER_NO_SUCH_TABLE errors have been
+ trapped and no other errors have been seen. FALSE otherwise.
+ */
+ bool safely_trapped_errors();
+
+private:
+ int m_handled_errors;
+ int m_unhandled_errors;
+};
+
+
+#endif /* SQL_BASE_INCLUDED */
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index 31fd2de3722..503d830a10e 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -13,10 +13,20 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_binlog.h"
+#include "sql_parse.h" // check_global_access
+#include "sql_acl.h" // *_ACL
#include "rpl_rli.h"
#include "base64.h"
-
+#include "slave.h" // apply_event_and_update_pos
+#include "log_event.h" // Format_description_log_event,
+ // EVENT_LEN_OFFSET,
+ // EVENT_TYPE_OFFSET,
+ // FORMAT_DESCRIPTION_LOG_EVENT,
+ // START_EVENT_V3,
+ // Log_event_type,
+ // Log_event
/**
Execute a BINLOG statement.
@@ -51,11 +61,11 @@ void mysql_client_binlog_statement(THD* thd)
size_t decoded_len= base64_needed_decoded_length(coded_len);
/*
- thd->options will be changed when applying the event. But we don't expect
+ option_bits will be changed when applying the event. But we don't expect
it be changed permanently after BINLOG statement, so backup it first.
It will be restored at the end of this function.
*/
- ulonglong thd_options= thd->options;
+ ulonglong thd_options= thd->variables.option_bits;
/*
Allocation
@@ -72,7 +82,7 @@ void mysql_client_binlog_statement(THD* thd)
rli= thd->rli_fake;
if (!rli)
{
- rli= thd->rli_fake= new Relay_log_info;
+ rli= thd->rli_fake= new Relay_log_info(FALSE);
#ifdef HAVE_purify
rli->is_fake= TRUE;
#endif
@@ -243,8 +253,8 @@ void mysql_client_binlog_statement(THD* thd)
my_ok(thd);
end:
- thd->options= thd_options;
- rli->clear_tables_to_lock();
- my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+ thd->variables.option_bits= thd_options;
+ rli->slave_close_thread_tables(thd);
+ my_free(buf);
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_binlog.h b/sql/sql_binlog.h
new file mode 100644
index 00000000000..50251eaac50
--- /dev/null
+++ b/sql/sql_binlog.h
@@ -0,0 +1,23 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_BINLOG_INCLUDED
+#define SQL_BINLOG_INCLUDED
+
+class THD;
+
+void mysql_client_binlog_statement(THD *thd);
+
+#endif /* SQL_BINLOG_INCLUDED */
diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h
index 97accefe8aa..54a207c8adf 100644
--- a/sql/sql_bitmap.h
+++ b/sql/sql_bitmap.h
@@ -19,6 +19,10 @@
also be able to use 32 or 64 bits bitmaps very efficiently
*/
+#ifndef SQL_BITMAP_INCLUDED
+#define SQL_BITMAP_INCLUDED
+
+#include <my_sys.h>
#include <my_bitmap.h>
template <uint default_width> class Bitmap
@@ -98,16 +102,7 @@ template <> class Bitmap<64>
ulonglong map;
public:
Bitmap<64>() { }
-#if defined(__NETWARE__) || defined(__MWERKS__)
- /*
- Metwork compiler gives error on Bitmap<64>
- Changed to Bitmap, since in this case also it will proper construct
- this class
- */
- explicit Bitmap(uint prefix_to_set) { set_prefix(prefix_to_set); }
-#else
explicit Bitmap<64>(uint prefix_to_set) { set_prefix(prefix_to_set); }
-#endif
void init() { }
void init(uint prefix_to_set) { set_prefix(prefix_to_set); }
uint length() const { return 64; }
@@ -138,3 +133,5 @@ public:
ulonglong to_ulonglong() const { return map; }
};
+
+#endif /* SQL_BITMAP_INCLUDED */
diff --git a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in
index 3becdbaccfe..8265c781e79 100644
--- a/sql/sql_builtin.cc.in
+++ b/sql/sql_builtin.cc.in
@@ -17,11 +17,20 @@
typedef struct st_mysql_plugin builtin_plugin[];
-extern builtin_plugin
- builtin_binlog_plugin@mysql_plugin_defs@;
-
-struct st_mysql_plugin *mysqld_builtins[]=
+#ifdef _MSC_VER
+extern "C"
+#else
+extern
+#endif
+builtin_plugin
+ @mysql_mandatory_plugins@ @mysql_optional_plugins@ builtin_binlog_plugin, builtin_mysql_password_plugin;
+
+struct st_mysql_plugin *mysql_optional_plugins[]=
{
- builtin_binlog_plugin@mysql_plugin_defs@,(struct st_mysql_plugin *)0
+ @mysql_optional_plugins@ 0
};
+struct st_mysql_plugin *mysql_mandatory_plugins[]=
+{
+ builtin_binlog_plugin, builtin_mysql_password_plugin, @mysql_mandatory_plugins@ 0
+};
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index befeecb1902..0dadc0f0cd4 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -286,6 +286,7 @@ functions:
if (and only if) this query has a registered result set writer
(thd->net.query_cache_query).
4. Query_cache::invalidate
+ Query_cache::invalidate_locked_for_write
- Called from various places to invalidate query cache based on data-
base, table and myisam file name. During an on going invalidation
the query cache is temporarily disabled.
@@ -326,31 +327,36 @@ TODO list:
(This could be done with almost no speed penalty)
*/
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "sql_cache.h"
+#include "sql_parse.h" // check_table_access
+#include "tztime.h" // struct Time_zone
+#include "sql_acl.h" // SELECT_ACL
+#include "sql_base.h" // TMP_TABLE_KEY_EXTRA
+#include "debug_sync.h" // DEBUG_SYNC
#ifdef HAVE_QUERY_CACHE
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
#include "../storage/myisammrg/ha_myisammrg.h"
#include "../storage/myisammrg/myrg_def.h"
+#include "probes_mysql.h"
+#include "transaction.h"
#ifdef EMBEDDED_LIBRARY
#include "emb_qcache.h"
#endif
#if !defined(EXTRA_DBUG) && !defined(DBUG_OFF)
-#define MUTEX_LOCK(M) { DBUG_PRINT("lock", ("mutex lock 0x%lx", (ulong)(M))); \
- pthread_mutex_lock(M);}
-#define MUTEX_UNLOCK(M) {DBUG_PRINT("lock", ("mutex unlock 0x%lx",\
- (ulong)(M))); pthread_mutex_unlock(M);}
#define RW_WLOCK(M) {DBUG_PRINT("lock", ("rwlock wlock 0x%lx",(ulong)(M))); \
- if (!rw_wrlock(M)) DBUG_PRINT("lock", ("rwlock wlock ok")); \
+ if (!mysql_rwlock_wrlock(M)) DBUG_PRINT("lock", ("rwlock wlock ok")); \
else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); }
#define RW_RLOCK(M) {DBUG_PRINT("lock", ("rwlock rlock 0x%lx", (ulong)(M))); \
- if (!rw_rdlock(M)) DBUG_PRINT("lock", ("rwlock rlock ok")); \
+ if (!mysql_rwlock_rdlock(M)) DBUG_PRINT("lock", ("rwlock rlock ok")); \
else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); }
#define RW_UNLOCK(M) {DBUG_PRINT("lock", ("rwlock unlock 0x%lx",(ulong)(M))); \
- if (!rw_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")); \
+ if (!mysql_rwlock_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")); \
else DBUG_PRINT("lock", ("rwlock unlock FAILED %d", errno)); }
#define BLOCK_LOCK_WR(B) {DBUG_PRINT("lock", ("%d LOCK_WR 0x%lx",\
__LINE__,(ulong)(B))); \
@@ -366,38 +372,10 @@ TODO list:
__LINE__,(ulong)(B)));B->query()->unlock_reading();}
#define DUMP(C) DBUG_EXECUTE("qcache", {\
(C)->cache_dump(); (C)->queries_dump();(C)->tables_dump();})
-
-
-/**
- Causes the thread to wait in a spin lock for a query kill signal.
- This function is used by the test frame work to identify race conditions.
-
- The signal is caught and ignored and the thread is not killed.
-*/
-
-static void debug_wait_for_kill(const char *info)
-{
- DBUG_ENTER("debug_wait_for_kill");
- const char *prev_info;
- THD *thd;
- thd= current_thd;
- prev_info= thd->proc_info;
- thd->proc_info= info;
- sql_print_information("%s", info);
- while(!thd->killed)
- my_sleep(1000);
- thd->killed= THD::NOT_KILLED;
- sql_print_information("Exit debug_wait_for_kill");
- thd->proc_info= prev_info;
- DBUG_VOID_RETURN;
-}
-
#else
-#define MUTEX_LOCK(M) pthread_mutex_lock(M)
-#define MUTEX_UNLOCK(M) pthread_mutex_unlock(M)
-#define RW_WLOCK(M) rw_wrlock(M)
-#define RW_RLOCK(M) rw_rdlock(M)
-#define RW_UNLOCK(M) rw_unlock(M)
+#define RW_WLOCK(M) mysql_rwlock_wrlock(M)
+#define RW_RLOCK(M) mysql_rwlock_rdlock(M)
+#define RW_UNLOCK(M) mysql_rwlock_unlock(M)
#define BLOCK_LOCK_WR(B) B->query()->lock_writing()
#define BLOCK_LOCK_RD(B) B->query()->lock_reading()
#define BLOCK_UNLOCK_WR(B) B->query()->unlock_writing()
@@ -405,10 +383,49 @@ static void debug_wait_for_kill(const char *info)
#define DUMP(C)
#endif
-const char *query_cache_type_names[]= { "OFF", "ON", "DEMAND",NullS };
-TYPELIB query_cache_type_typelib=
+
+/**
+ Macro that executes the requested action at a synchronization point
+ only if the thread has a associated THD session.
+*/
+#if defined(ENABLED_DEBUG_SYNC)
+#define QC_DEBUG_SYNC(name) \
+ do { \
+ THD *thd= current_thd; \
+ if (thd) \
+ DEBUG_SYNC(thd, name); \
+ } while (0)
+#else
+#define QC_DEBUG_SYNC(name)
+#endif
+
+
+/**
+ Thread state to be used when the query cache lock needs to be acquired.
+ Sets the thread state name in the constructor, resets on destructor.
+*/
+
+struct Query_cache_wait_state
{
- array_elements(query_cache_type_names)-1,"", query_cache_type_names, NULL
+ THD *m_thd;
+ const char *m_proc_info;
+
+ Query_cache_wait_state(THD *thd, const char *func,
+ const char *file, unsigned int line)
+ : m_thd(thd),
+ m_proc_info(NULL)
+ {
+ if (m_thd)
+ m_proc_info= set_thd_proc_info(m_thd,
+ "Waiting for query cache lock",
+ func, file, line);
+ }
+
+ ~Query_cache_wait_state()
+ {
+ if (m_thd)
+ set_thd_proc_info(m_thd, m_proc_info, NULL, NULL, 0);
+ }
};
@@ -433,16 +450,17 @@ TYPELIB query_cache_type_typelib=
bool Query_cache::try_lock(bool use_timeout)
{
bool interrupt= FALSE;
+ THD *thd= current_thd;
+ Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__);
DBUG_ENTER("Query_cache::try_lock");
- pthread_mutex_lock(&structure_guard_mutex);
+ mysql_mutex_lock(&structure_guard_mutex);
while (1)
{
if (m_cache_lock_status == Query_cache::UNLOCKED)
{
m_cache_lock_status= Query_cache::LOCKED;
#ifndef DBUG_OFF
- THD *thd= current_thd;
if (thd)
m_cache_lock_thread_id= thd->thread_id;
#endif
@@ -468,8 +486,8 @@ bool Query_cache::try_lock(bool use_timeout)
{
struct timespec waittime;
set_timespec_nsec(waittime,(ulong)(50000000L)); /* Wait for 50 msec */
- int res= pthread_cond_timedwait(&COND_cache_status_changed,
- &structure_guard_mutex,&waittime);
+ int res= mysql_cond_timedwait(&COND_cache_status_changed,
+ &structure_guard_mutex, &waittime);
if (res == ETIMEDOUT)
{
interrupt= TRUE;
@@ -478,11 +496,11 @@ bool Query_cache::try_lock(bool use_timeout)
}
else
{
- pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
+ mysql_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
}
}
}
- pthread_mutex_unlock(&structure_guard_mutex);
+ mysql_mutex_unlock(&structure_guard_mutex);
DBUG_RETURN(interrupt);
}
@@ -501,20 +519,21 @@ bool Query_cache::try_lock(bool use_timeout)
void Query_cache::lock_and_suspend(void)
{
+ THD *thd= current_thd;
+ Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__);
DBUG_ENTER("Query_cache::lock_and_suspend");
- pthread_mutex_lock(&structure_guard_mutex);
+ mysql_mutex_lock(&structure_guard_mutex);
while (m_cache_lock_status != Query_cache::UNLOCKED)
- pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
+ mysql_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
m_cache_lock_status= Query_cache::LOCKED_NO_WAIT;
#ifndef DBUG_OFF
- THD *thd= current_thd;
if (thd)
m_cache_lock_thread_id= thd->thread_id;
#endif
/* Wake up everybody, a whole cache flush is starting! */
- pthread_cond_broadcast(&COND_cache_status_changed);
- pthread_mutex_unlock(&structure_guard_mutex);
+ mysql_cond_broadcast(&COND_cache_status_changed);
+ mysql_mutex_unlock(&structure_guard_mutex);
DBUG_VOID_RETURN;
}
@@ -529,18 +548,19 @@ void Query_cache::lock_and_suspend(void)
void Query_cache::lock(void)
{
+ THD *thd= current_thd;
+ Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__);
DBUG_ENTER("Query_cache::lock");
- pthread_mutex_lock(&structure_guard_mutex);
+ mysql_mutex_lock(&structure_guard_mutex);
while (m_cache_lock_status != Query_cache::UNLOCKED)
- pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
+ mysql_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
m_cache_lock_status= Query_cache::LOCKED;
#ifndef DBUG_OFF
- THD *thd= current_thd;
if (thd)
m_cache_lock_thread_id= thd->thread_id;
#endif
- pthread_mutex_unlock(&structure_guard_mutex);
+ mysql_mutex_unlock(&structure_guard_mutex);
DBUG_VOID_RETURN;
}
@@ -553,7 +573,7 @@ void Query_cache::lock(void)
void Query_cache::unlock(void)
{
DBUG_ENTER("Query_cache::unlock");
- pthread_mutex_lock(&structure_guard_mutex);
+ mysql_mutex_lock(&structure_guard_mutex);
#ifndef DBUG_OFF
THD *thd= current_thd;
if (thd)
@@ -563,8 +583,8 @@ void Query_cache::unlock(void)
m_cache_lock_status == Query_cache::LOCKED_NO_WAIT);
m_cache_lock_status= Query_cache::UNLOCKED;
DBUG_PRINT("Query_cache",("Sending signal"));
- pthread_cond_signal(&COND_cache_status_changed);
- pthread_mutex_unlock(&structure_guard_mutex);
+ mysql_cond_signal(&COND_cache_status_changed);
+ mysql_mutex_unlock(&structure_guard_mutex);
DBUG_VOID_RETURN;
}
@@ -733,7 +753,7 @@ inline void Query_cache_query::lock_writing()
my_bool Query_cache_query::try_lock_writing()
{
DBUG_ENTER("Query_cache_block::try_lock_writing");
- if (rw_trywrlock(&lock)!=0)
+ if (mysql_rwlock_trywrlock(&lock) != 0)
{
DBUG_PRINT("info", ("can't lock rwlock"));
DBUG_RETURN(0);
@@ -765,7 +785,7 @@ void Query_cache_query::init_n_lock()
{
DBUG_ENTER("Query_cache_query::init_n_lock");
res=0; wri = 0; len = 0;
- my_rwlock_init(&lock, NULL);
+ mysql_rwlock_init(key_rwlock_query_cache_query_lock, &lock);
lock_writing();
DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx",
(long) (((uchar*) this) -
@@ -785,7 +805,7 @@ void Query_cache_query::unlock_n_destroy()
active semaphore
*/
this->unlock_writing();
- rwlock_destroy(&lock);
+ mysql_rwlock_destroy(&lock);
DBUG_VOID_RETURN;
}
@@ -811,19 +831,20 @@ uchar *query_cache_query_get_key(const uchar *record, size_t *length,
Note on double-check locking (DCL) usage.
Below, in query_cache_insert(), query_cache_abort() and
- query_cache_end_of_result() we use what is called double-check
- locking (DCL) for NET::query_cache_query. I.e. we test it first
- without a lock, and, if positive, test again under the lock.
+ Query_cache::end_of_result() we use what is called double-check
+ locking (DCL) for Query_cache_tls::first_query_block.
+ I.e. we test it first without a lock, and, if positive, test again
+ under the lock.
- This means that if we see 'NET::query_cache_query == 0' without a
+ This means that if we see 'first_query_block == 0' without a
lock we will skip the operation. But this is safe here: when we
started to cache a query, we called Query_cache::store_query(), and
- NET::query_cache_query was set to non-zero in this thread (and the
+ 'first_query_block' was set to non-zero in this thread (and the
thread always sees results of its memory operations, mutex or not).
- If later we see 'NET::query_cache_query == 0' without locking a
+ If later we see 'first_query_block == 0' without locking a
mutex, that may only mean that some other thread have reset it by
invalidating the query. Skipping the operation in this case is the
- right thing to do, as NET::query_cache_query won't get non-zero for
+ right thing to do, as first_query_block won't get non-zero for
this query again.
See also comments in Query_cache::store_query() and
@@ -832,56 +853,69 @@ uchar *query_cache_query_get_key(const uchar *record, size_t *length,
NOTE, however, that double-check locking is not applicable in
'invalidate' functions, as we may erroneously skip invalidation,
because the thread doing invalidation may never see non-zero
- NET::query_cache_query.
+ 'first_query_block'.
*/
-void query_cache_init_query(NET *net)
+/**
+ libmysql convenience wrapper to insert data into query cache.
+*/
+void query_cache_insert(const char *packet, ulong length,
+ unsigned pkt_nr)
{
+ THD *thd= current_thd;
+
/*
- It is safe to initialize 'NET::query_cache_query' without a lock
- here, because before it will be accessed from different threads it
- will be set in this thread under a lock, and access from the same
- thread is always safe.
+ Current_thd can be NULL when a new connection is immediately ended
+ due to "Too many connections". thd->store_globals() has not been
+ called at this time and hence my_pthread_setspecific_ptr(THR_THD,
+ this) has not been called for this thread.
*/
- net->query_cache_query= 0;
+
+ if (!thd)
+ return;
+
+ query_cache.insert(&thd->query_cache_tls,
+ packet, length,
+ pkt_nr);
}
-/*
+/**
Insert the packet into the query cache.
*/
-void query_cache_insert(NET *net, const char *packet, ulong length)
+void
+Query_cache::insert(Query_cache_tls *query_cache_tls,
+ const char *packet, ulong length,
+ unsigned pkt_nr)
{
- DBUG_ENTER("query_cache_insert");
+ DBUG_ENTER("Query_cache::insert");
/* See the comment on double-check locking usage above. */
- if (net->query_cache_query == 0)
+ if (is_disabled() || query_cache_tls->first_query_block == NULL)
DBUG_VOID_RETURN;
- DBUG_EXECUTE_IF("wait_in_query_cache_insert",
- debug_wait_for_kill("wait_in_query_cache_insert"); );
+ QC_DEBUG_SYNC("wait_in_query_cache_insert");
- if (query_cache.try_lock())
+ if (try_lock())
DBUG_VOID_RETURN;
- Query_cache_block *query_block= (Query_cache_block*)net->query_cache_query;
- if (!query_block)
+ Query_cache_block *query_block = query_cache_tls->first_query_block;
+ if (query_block == NULL)
{
/*
We lost the writer and the currently processed query has been
invalidated; there is nothing left to do.
*/
- query_cache.unlock();
+ unlock();
DBUG_VOID_RETURN;
}
-
BLOCK_LOCK_WR(query_block);
Query_cache_query *header= query_block->query();
Query_cache_block *result= header->result();
- DUMP(&query_cache);
+ DUMP(this);
DBUG_PRINT("qcache", ("insert packet %lu bytes long",length));
/*
@@ -889,8 +923,8 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
still need structure_guard_mutex to free the query, and therefore unlock
it later in this function.
*/
- if (!query_cache.append_result_data(&result, length, (uchar*) packet,
- query_block))
+ if (!append_result_data(&result, length, (uchar*) packet,
+ query_block))
{
DBUG_PRINT("warning", ("Can't append data"));
header->result(result);
@@ -899,80 +933,83 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
query_cache.free_query(query_block);
query_cache.refused++;
// append_result_data no success => we need unlock
- query_cache.unlock();
+ unlock();
DBUG_VOID_RETURN;
}
header->result(result);
- header->last_pkt_nr= net->pkt_nr;
+ header->last_pkt_nr= pkt_nr;
BLOCK_UNLOCK_WR(query_block);
- DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
+ DBUG_EXECUTE("check_querycache",check_integrity(0););
DBUG_VOID_RETURN;
}
-void query_cache_abort(NET *net)
+void
+Query_cache::abort(Query_cache_tls *query_cache_tls)
{
DBUG_ENTER("query_cache_abort");
THD *thd= current_thd;
/* See the comment on double-check locking usage above. */
- if (net->query_cache_query == 0)
+ if (is_disabled() || query_cache_tls->first_query_block == NULL)
DBUG_VOID_RETURN;
- if (query_cache.try_lock())
+ if (try_lock())
DBUG_VOID_RETURN;
/*
While we were waiting another thread might have changed the status
of the writer. Make sure the writer still exists before continue.
*/
- Query_cache_block *query_block= ((Query_cache_block*)
- net->query_cache_query);
+ Query_cache_block *query_block= query_cache_tls->first_query_block;
if (query_block)
{
thd_proc_info(thd, "storing result in query cache");
- DUMP(&query_cache);
+ DUMP(this);
BLOCK_LOCK_WR(query_block);
// The following call will remove the lock on query_block
- query_cache.free_query(query_block);
- net->query_cache_query= 0;
- DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
+ free_query(query_block);
+ query_cache_tls->first_query_block= NULL;
+ DBUG_EXECUTE("check_querycache", check_integrity(1););
}
- query_cache.unlock();
+ unlock();
+
DBUG_VOID_RETURN;
}
-void query_cache_end_of_result(THD *thd)
+void Query_cache::end_of_result(THD *thd)
{
Query_cache_block *query_block;
- DBUG_ENTER("query_cache_end_of_result");
+ Query_cache_tls *query_cache_tls= &thd->query_cache_tls;
+ ulonglong limit_found_rows= thd->limit_found_rows;
+ DBUG_ENTER("Query_cache::end_of_result");
/* See the comment on double-check locking usage above. */
- if (thd->net.query_cache_query == 0)
+ if (query_cache_tls->first_query_block == NULL)
DBUG_VOID_RETURN;
/* Ensure that only complete results are cached. */
- DBUG_ASSERT(thd->main_da.is_eof());
+ DBUG_ASSERT(thd->stmt_da->is_eof());
if (thd->killed)
{
- query_cache_abort(&thd->net);
+ query_cache_abort(&thd->query_cache_tls);
DBUG_VOID_RETURN;
}
#ifdef EMBEDDED_LIBRARY
- query_cache_insert(&thd->net, (char*)thd,
- emb_count_querycache_size(thd));
+ insert(query_cache_tls, (char*)thd,
+ emb_count_querycache_size(thd), 0);
#endif
- if (query_cache.try_lock())
+ if (try_lock())
DBUG_VOID_RETURN;
- query_block= ((Query_cache_block*) thd->net.query_cache_query);
+ query_block= query_cache_tls->first_query_block;
if (query_block)
{
/*
@@ -981,7 +1018,7 @@ void query_cache_end_of_result(THD *thd)
block, the writer should be dropped.
*/
thd_proc_info(thd, "storing result in query cache");
- DUMP(&query_cache);
+ DUMP(this);
BLOCK_LOCK_WR(query_block);
Query_cache_query *header= query_block->query();
Query_cache_block *last_result_block;
@@ -998,8 +1035,8 @@ void query_cache_end_of_result(THD *thd)
and removed from QC.
*/
DBUG_ASSERT(0);
- query_cache.free_query(query_block);
- query_cache.unlock();
+ free_query(query_block);
+ unlock();
DBUG_VOID_RETURN;
}
last_result_block= header->result()->prev;
@@ -1008,17 +1045,17 @@ void query_cache_end_of_result(THD *thd)
if (last_result_block->length >= query_cache.min_allocation_unit + len)
query_cache.split_block(last_result_block,len);
- header->found_rows(current_thd->limit_found_rows);
+ header->found_rows(limit_found_rows);
header->result()->type= Query_cache_block::RESULT;
/* Drop the writer. */
header->writer(0);
- thd->net.query_cache_query= 0;
+ query_cache_tls->first_query_block= NULL;
BLOCK_UNLOCK_WR(query_block);
- DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
-
+ DBUG_EXECUTE("check_querycache", check_integrity(1););
}
- query_cache.unlock();
+
+ unlock();
DBUG_VOID_RETURN;
}
@@ -1053,7 +1090,7 @@ Query_cache::Query_cache(ulong query_cache_limit_arg,
:query_cache_size(0),
query_cache_limit(query_cache_limit_arg),
queries_in_cache(0), hits(0), inserts(0), refused(0),
- total_blocks(0), lowmem_prunes(0),
+ total_blocks(0), lowmem_prunes(0), m_query_cache_is_disabled(FALSE),
min_allocation_unit(ALIGN_SIZE(min_allocation_unit_arg)),
min_result_data_size(ALIGN_SIZE(min_result_data_size_arg)),
def_query_hash_size(ALIGN_SIZE(def_query_hash_size_arg)),
@@ -1096,7 +1133,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
Drop the writer; this will cancel any attempts to store
the processed statement associated with this writer.
*/
- query->writer()->query_cache_query= 0;
+ query->writer()->first_query_block= NULL;
query->writer(0);
refused++;
}
@@ -1138,7 +1175,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
See also a note on double-check locking usage above.
*/
- if (thd->locked_tables || query_cache_size == 0)
+ if (thd->locked_tables_mode || query_cache_size == 0)
DBUG_VOID_RETURN;
uint8 tables_type= 0;
@@ -1158,10 +1195,12 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
protocol (COM_EXECUTE) cannot be served to statements asking for results
in the text protocol (COM_QUERY) and vice-versa.
*/
- flags.result_in_binary_protocol= (unsigned int) thd->protocol->type();
+ flags.protocol_type= (unsigned int) thd->protocol->type();
+ /* PROTOCOL_LOCAL results are not cached. */
+ DBUG_ASSERT(flags.protocol_type != (unsigned int) Protocol::PROTOCOL_LOCAL);
flags.more_results_exists= test(thd->server_status &
SERVER_MORE_RESULTS_EXISTS);
- flags.in_trans= test(thd->server_status & SERVER_STATUS_IN_TRANS);
+ flags.in_trans= thd->in_active_multi_stmt_transaction();
flags.autocommit= test(thd->server_status & SERVER_STATUS_AUTOCOMMIT);
flags.pkt_nr= net->pkt_nr;
flags.character_set_client_num=
@@ -1187,7 +1226,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu, div_precision: %lu, \
def_week_frmt: %lu, in_trans: %d, autocommit: %d",
(int)flags.client_long_flag,
(int)flags.client_protocol_41,
- (int)flags.result_in_binary_protocol,
+ (int)flags.protocol_type,
(int)flags.more_results_exists,
flags.pkt_nr,
flags.character_set_client_num,
@@ -1259,7 +1298,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
/* Check if another thread is processing the same query? */
Query_cache_block *competitor = (Query_cache_block *)
- hash_search(&queries, (uchar*) thd->query(), tot_length);
+ my_hash_search(&queries, (uchar*) thd->query(), tot_length);
DBUG_PRINT("qcache", ("competitor 0x%lx", (ulong) competitor));
if (competitor == 0)
{
@@ -1288,7 +1327,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
{
refused++;
DBUG_PRINT("warning", ("tables list including failed"));
- hash_delete(&queries, (uchar *) query_block);
+ my_hash_delete(&queries, (uchar *) query_block);
header->unlock_n_destroy();
free_memory_block(query_block);
unlock();
@@ -1297,8 +1336,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
double_linked_list_simple_include(query_block, &queries_blocks);
inserts++;
queries_in_cache++;
- net->query_cache_query= (uchar*) query_block;
- header->writer(net);
+ thd->query_cache_tls.first_query_block= query_block;
+ header->writer(&thd->query_cache_tls);
header->tables_type(tables_type);
unlock();
@@ -1385,14 +1424,18 @@ send_data_in_chunks(NET *net, const uchar *packet, ulong len)
Check if the query is in the cache. If it was cached, send it
to the user.
- RESULTS
- 1 Query was not cached.
- 0 The query was cached and user was sent the result.
- -1 The query was cached but we didn't have rights to use it.
- No error is sent to the client yet.
+ @param thd Pointer to the thread handler
+ @param sql A pointer to the sql statement *
+ @param query_length Length of the statement in characters
- NOTE
- This method requires that sql points to allocated memory of size:
+ @return status code
+ @retval 0 Query was not cached.
+ @retval 1 The query was cached and user was sent the result.
+ @retval -1 The query was cached but we didn't have rights to use it.
+
+ In case of -1, no error is sent to the client.
+
+ *) The buffer must be allocated memory of size:
tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE;
*/
@@ -1401,7 +1444,10 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
{
ulonglong engine_data;
Query_cache_query *query;
- Query_cache_block *first_result_block, *result_block;
+#ifndef EMBEDDED_LIBRARY
+ Query_cache_block *first_result_block;
+#endif
+ Query_cache_block *result_block;
Query_cache_block_table *block_table, *block_table_end;
ulong tot_length;
Query_cache_query_flags flags;
@@ -1414,8 +1460,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
See also a note on double-check locking usage above.
*/
- if (thd->locked_tables || thd->variables.query_cache_type == 0 ||
- query_cache_size == 0)
+ if (is_disabled() || thd->locked_tables_mode ||
+ thd->variables.query_cache_type == 0 || query_cache_size == 0)
goto err;
if (!thd->lex->safe_to_cache_query)
@@ -1474,12 +1520,6 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
if (query_cache_size == 0)
goto err_unlock;
- /*
- Check that we haven't forgot to reset the query cache variables;
- make sure there are no attached query cache writer to this thread.
- */
- DBUG_ASSERT(thd->net.query_cache_query == 0);
-
Query_cache_block *query_block;
tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE;
@@ -1501,10 +1541,10 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG);
flags.client_protocol_41= test(thd->client_capabilities &
CLIENT_PROTOCOL_41);
- flags.result_in_binary_protocol= (unsigned int)thd->protocol->type();
+ flags.protocol_type= (unsigned int) thd->protocol->type();
flags.more_results_exists= test(thd->server_status &
SERVER_MORE_RESULTS_EXISTS);
- flags.in_trans= test(thd->server_status & SERVER_STATUS_IN_TRANS);
+ flags.in_trans= thd->in_active_multi_stmt_transaction();
flags.autocommit= test(thd->server_status & SERVER_STATUS_AUTOCOMMIT);
flags.pkt_nr= thd->net.pkt_nr;
flags.character_set_client_num= thd->variables.character_set_client->number;
@@ -1528,7 +1568,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu, div_precision: %lu, \
def_week_frmt: %lu, in_trans: %d, autocommit: %d",
(int)flags.client_long_flag,
(int)flags.client_protocol_41,
- (int)flags.result_in_binary_protocol,
+ (int)flags.protocol_type,
(int)flags.more_results_exists,
flags.pkt_nr,
flags.character_set_client_num,
@@ -1545,8 +1585,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
(int)flags.autocommit));
memcpy((uchar *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
(uchar*) &flags, QUERY_CACHE_FLAGS_SIZE);
- query_block = (Query_cache_block *) hash_search(&queries, (uchar*) sql,
- tot_length);
+ query_block = (Query_cache_block *) my_hash_search(&queries, (uchar*) sql,
+ tot_length);
/* Quick abort on unlocked data */
if (query_block == 0 ||
query_block->query()->result() == 0 ||
@@ -1561,7 +1601,10 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
BLOCK_LOCK_RD(query_block);
query = query_block->query();
- result_block= first_result_block= query->result();
+ result_block= query->result();
+#ifndef EMBEDDED_LIBRARY
+ first_result_block= result_block;
+#endif
if (result_block == 0 || result_block->type != Query_cache_block::RESULT)
{
@@ -1572,7 +1615,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
}
DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query));
- if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
+ if (thd->in_multi_stmt_transaction_mode() &&
(query->tables_type() & HA_CACHE_TBL_TRANSACT))
{
DBUG_PRINT("qcache",
@@ -1623,7 +1666,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
table_list.db = table->db();
table_list.alias= table_list.table_name= table->table();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_table_access(thd,SELECT_ACL,&table_list, 1, TRUE))
+ if (check_table_access(thd,SELECT_ACL,&table_list, FALSE, 1,TRUE))
{
DBUG_PRINT("qcache",
("probably no SELECT access to %s.%s => return to normal processing",
@@ -1663,6 +1706,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
}
else
thd->lex->safe_to_cache_query= 0; // Don't try to cache this
+ /* End the statement transaction potentially started by engine. */
+ trans_rollback_stmt(thd);
goto err_unlock; // Parse query
}
else
@@ -1704,15 +1749,24 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
thd->limit_found_rows = query->found_rows();
thd->status_var.last_query_cost= 0.0;
- if (!thd->main_da.is_set())
- thd->main_da.disable_status();
+ /*
+ End the statement transaction potentially started by an
+ engine callback. We ignore the return value for now,
+ since as long as EOF packet is part of the query cache
+ response, we can't handle it anyway.
+ */
+ (void) trans_commit_stmt(thd);
+ if (!thd->stmt_da->is_set())
+ thd->stmt_da->disable_status();
BLOCK_UNLOCK_RD(query_block);
+ MYSQL_QUERY_CACHE_HIT(thd->query(), (ulong) thd->limit_found_rows);
DBUG_RETURN(1); // Result sent to client
err_unlock:
unlock();
err:
+ MYSQL_QUERY_CACHE_MISS(thd->query());
DBUG_RETURN(0); // Query was not cached
}
@@ -1725,9 +1779,10 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
my_bool using_transactions)
{
DBUG_ENTER("Query_cache::invalidate (table list)");
+ if (is_disabled())
+ DBUG_VOID_RETURN;
- using_transactions= using_transactions &&
- (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
+ using_transactions= using_transactions && thd->in_multi_stmt_transaction_mode();
for (; tables_used; tables_used= tables_used->next_local)
{
DBUG_ASSERT(!using_transactions || tables_used->table!=0);
@@ -1746,8 +1801,7 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
invalidate_table(thd, tables_used);
}
- DBUG_EXECUTE_IF("wait_after_query_cache_invalidate",
- debug_wait_for_kill("wait_after_query_cache_invalidate"););
+ DEBUG_SYNC(thd, "wait_after_query_cache_invalidate");
DBUG_VOID_RETURN;
}
@@ -1755,6 +1809,9 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
{
DBUG_ENTER("Query_cache::invalidate (changed table list)");
+ if (is_disabled())
+ DBUG_VOID_RETURN;
+
THD *thd= current_thd;
for (; tables_used; tables_used= tables_used->next)
{
@@ -1780,8 +1837,11 @@ void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
*/
void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used)
{
- THD *thd= current_thd;
DBUG_ENTER("Query_cache::invalidate_locked_for_write");
+ if (is_disabled())
+ DBUG_VOID_RETURN;
+
+ THD *thd= current_thd;
for (; tables_used; tables_used= tables_used->next_local)
{
thd_proc_info(thd, "invalidating query cache entries (table)");
@@ -1802,9 +1862,10 @@ void Query_cache::invalidate(THD *thd, TABLE *table,
my_bool using_transactions)
{
DBUG_ENTER("Query_cache::invalidate (table)");
-
- using_transactions= using_transactions &&
- (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
+ if (is_disabled())
+ DBUG_VOID_RETURN;
+
+ using_transactions= using_transactions && thd->in_multi_stmt_transaction_mode();
if (using_transactions &&
(table->file->table_cache_type() == HA_CACHE_TBL_TRANSACT))
thd->add_changed_table(table);
@@ -1819,9 +1880,10 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
my_bool using_transactions)
{
DBUG_ENTER("Query_cache::invalidate (key)");
+ if (is_disabled())
+ DBUG_VOID_RETURN;
- using_transactions= using_transactions &&
- (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
+ using_transactions= using_transactions && thd->in_multi_stmt_transaction_mode();
if (using_transactions) // used for innodb => has_transactions() is TRUE
thd->add_changed_table(key, key_length);
else
@@ -1837,9 +1899,12 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
void Query_cache::invalidate(char *db)
{
- bool restart= FALSE;
+
DBUG_ENTER("Query_cache::invalidate (db)");
+ if (is_disabled())
+ DBUG_VOID_RETURN;
+ bool restart= FALSE;
/*
Lock the query cache and queue all invalidation attempts to avoid
the risk of a race between invalidation, cache inserts and flushes.
@@ -1924,8 +1989,10 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
void Query_cache::flush()
{
DBUG_ENTER("Query_cache::flush");
- DBUG_EXECUTE_IF("wait_in_query_cache_flush1",
- debug_wait_for_kill("wait_in_query_cache_flush1"););
+ if (is_disabled())
+ DBUG_VOID_RETURN;
+
+ QC_DEBUG_SYNC("wait_in_query_cache_flush1");
lock_and_suspend();
if (query_cache_size > 0)
@@ -1955,6 +2022,9 @@ void Query_cache::pack(ulong join_limit, uint iteration_limit)
{
DBUG_ENTER("Query_cache::pack");
+ if (is_disabled())
+ DBUG_VOID_RETURN;
+
/*
If the entire qc is being invalidated we can bail out early
instead of waiting for the lock.
@@ -1993,8 +2063,8 @@ void Query_cache::destroy()
free_cache();
unlock();
- pthread_cond_destroy(&COND_cache_status_changed);
- pthread_mutex_destroy(&structure_guard_mutex);
+ mysql_cond_destroy(&COND_cache_status_changed);
+ mysql_mutex_destroy(&structure_guard_mutex);
initialized = 0;
}
DBUG_VOID_RETURN;
@@ -2008,10 +2078,21 @@ void Query_cache::destroy()
void Query_cache::init()
{
DBUG_ENTER("Query_cache::init");
- pthread_mutex_init(&structure_guard_mutex,MY_MUTEX_INIT_FAST);
- pthread_cond_init(&COND_cache_status_changed, NULL);
+ mysql_mutex_init(key_structure_guard_mutex,
+ &structure_guard_mutex, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_cache_status_changed,
+ &COND_cache_status_changed, NULL);
m_cache_lock_status= Query_cache::UNLOCKED;
initialized = 1;
+ /*
+ If we explicitly turn off query cache from the command line query cache will
+ be disabled for the reminder of the server life time. This is because we
+ want to avoid locking the QC specific mutex if query cache isn't going to
+ be used.
+ */
+ if (global_system_variables.query_cache_type == 0)
+ query_cache.disable_query_cache();
+
DBUG_VOID_RETURN;
}
@@ -2150,9 +2231,9 @@ ulong Query_cache::init_cache()
DUMP(this);
- VOID(hash_init(&queries, &my_charset_bin, def_query_hash_size, 0, 0,
- query_cache_query_get_key, 0, 0));
-#ifndef FN_NO_CASE_SENCE
+ (void) my_hash_init(&queries, &my_charset_bin, def_query_hash_size, 0, 0,
+ query_cache_query_get_key, 0, 0);
+#ifndef FN_NO_CASE_SENSE
/*
If lower_case_table_names!=0 then db and table names are already
converted to lower case and we can use binary collation for their
@@ -2161,8 +2242,8 @@ ulong Query_cache::init_cache()
lower_case_table_names == 0 then we should distinguish my_table
and MY_TABLE cases and so again can use binary collation.
*/
- VOID(hash_init(&tables, &my_charset_bin, def_table_hash_size, 0, 0,
- query_cache_table_get_key, 0, 0));
+ (void) my_hash_init(&tables, &my_charset_bin, def_table_hash_size, 0, 0,
+ query_cache_table_get_key, 0, 0);
#else
/*
On windows, OS/2, MacOS X with HFS+ or any other case insensitive
@@ -2172,10 +2253,11 @@ ulong Query_cache::init_cache()
file system) and so should use case insensitive collation for
comparison.
*/
- VOID(hash_init(&tables,
- lower_case_table_names ? &my_charset_bin :
- files_charset_info,
- def_table_hash_size, 0, 0,query_cache_table_get_key, 0, 0));
+ (void) my_hash_init(&tables,
+ lower_case_table_names ? &my_charset_bin :
+ files_charset_info,
+ def_table_hash_size, 0, 0,query_cache_table_get_key,
+ 0, 0);
#endif
queries_in_cache = 0;
@@ -2223,10 +2305,10 @@ void Query_cache::free_cache()
{
DBUG_ENTER("Query_cache::free_cache");
- my_free((uchar*) cache, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(cache);
make_disabled();
- hash_free(&queries);
- hash_free(&tables);
+ my_hash_free(&queries);
+ my_hash_free(&tables);
DBUG_VOID_RETURN;
}
@@ -2250,9 +2332,7 @@ void Query_cache::free_cache()
void Query_cache::flush_cache()
{
-
- DBUG_EXECUTE_IF("wait_in_query_cache_flush2",
- debug_wait_for_kill("wait_in_query_cache_flush2"););
+ QC_DEBUG_SYNC("wait_in_query_cache_flush2");
my_hash_reset(&queries);
while (queries_blocks != 0)
@@ -2338,7 +2418,7 @@ void Query_cache::free_query_internal(Query_cache_block *query_block)
if (query->writer() != 0)
{
/* Tell MySQL that this query should not be cached anymore */
- query->writer()->query_cache_query= 0;
+ query->writer()->first_query_block= NULL;
query->writer(0);
}
double_linked_list_exclude(query_block, &queries_blocks);
@@ -2401,7 +2481,7 @@ void Query_cache::free_query(Query_cache_block *query_block)
(ulong) query_block,
query_block->query()->length() ));
- hash_delete(&queries,(uchar *) query_block);
+ my_hash_delete(&queries,(uchar *) query_block);
free_query_internal(query_block);
DBUG_VOID_RETURN;
@@ -2698,8 +2778,7 @@ void Query_cache::invalidate_table(THD *thd, TABLE *table)
void Query_cache::invalidate_table(THD *thd, uchar * key, uint32 key_length)
{
- DBUG_EXECUTE_IF("wait_in_query_cache_invalidate1",
- debug_wait_for_kill("wait_in_query_cache_invalidate1"); );
+ DEBUG_SYNC(thd, "wait_in_query_cache_invalidate1");
/*
Lock the query cache and queue all invalidation attempts to avoid
@@ -2707,9 +2786,7 @@ void Query_cache::invalidate_table(THD *thd, uchar * key, uint32 key_length)
*/
lock();
- DBUG_EXECUTE_IF("wait_in_query_cache_invalidate2",
- debug_wait_for_kill("wait_in_query_cache_invalidate2"); );
-
+ DEBUG_SYNC(thd, "wait_in_query_cache_invalidate2");
if (query_cache_size > 0)
invalidate_table_internal(thd, key, key_length);
@@ -2730,7 +2807,7 @@ void
Query_cache::invalidate_table_internal(THD *thd, uchar *key, uint32 key_length)
{
Query_cache_block *table_block=
- (Query_cache_block*)hash_search(&tables, key, key_length);
+ (Query_cache_block*)my_hash_search(&tables, key, key_length);
if (table_block)
{
Query_cache_block_table *list_root= table_block->table(0);
@@ -2759,7 +2836,6 @@ Query_cache::invalidate_query_block_list(THD *thd,
Query_cache_block *query_block= list_root->next->block();
BLOCK_LOCK_WR(query_block);
free_query(query_block);
- DBUG_EXECUTE_IF("debug_cache_locks", sleep(10););
}
}
@@ -2928,7 +3004,7 @@ Query_cache::insert_table(uint key_len, char *key,
THD *thd= current_thd;
Query_cache_block *table_block=
- (Query_cache_block *)hash_search(&tables, (uchar*) key, key_len);
+ (Query_cache_block *) my_hash_search(&tables, (uchar*) key, key_len);
if (table_block &&
table_block->table()->engine_data() != engine_data)
@@ -3044,7 +3120,7 @@ void Query_cache::unlink_table(Query_cache_block_table *node)
Query_cache_block *table_block= neighbour->block();
double_linked_list_exclude(table_block,
&tables_blocks);
- hash_delete(&tables,(uchar *) table_block);
+ my_hash_delete(&tables,(uchar *) table_block);
free_memory_block(table_block);
}
DBUG_VOID_RETURN;
@@ -3551,7 +3627,8 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used,
*/
TABLE_COUNTER_TYPE
-Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex,
+Query_cache::is_cacheable(THD *thd, size_t query_len, const char *query,
+ LEX *lex,
TABLE_LIST *tables_used, uint8 *tables_type)
{
TABLE_COUNTER_TYPE table_count;
@@ -3571,7 +3648,7 @@ Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex,
tables_type)))
DBUG_RETURN(0);
- if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
+ if (thd->in_multi_stmt_transaction_mode() &&
((*tables_type)&HA_CACHE_TBL_TRANSACT))
{
DBUG_PRINT("qcache", ("not in autocommin mode"));
@@ -3728,7 +3805,7 @@ my_bool Query_cache::move_by_type(uchar **border,
uchar *key;
size_t key_length;
key=query_cache_table_get_key((uchar*) block, &key_length, 0);
- hash_first(&tables, (uchar*) key, key_length, &record_idx);
+ my_hash_first(&tables, (uchar*) key, key_length, &record_idx);
block->destroy();
new_block->init(len);
@@ -3762,7 +3839,7 @@ my_bool Query_cache::move_by_type(uchar **border,
/* Fix pointer to table name */
new_block->table()->table(new_block->table()->db() + tablename_offset);
/* Fix hash to point at moved block */
- hash_replace(&tables, &record_idx, (uchar*) new_block);
+ my_hash_replace(&tables, &record_idx, (uchar*) new_block);
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
len, (ulong) new_block, (ulong) *border));
@@ -3788,7 +3865,7 @@ my_bool Query_cache::move_by_type(uchar **border,
uchar *key;
size_t key_length;
key=query_cache_query_get_key((uchar*) block, &key_length, 0);
- hash_first(&queries, (uchar*) key, key_length, &record_idx);
+ my_hash_first(&queries, (uchar*) key, key_length, &record_idx);
// Move table of used tables
memmove((char*) new_block->table(0), (char*) block->table(0),
ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table)));
@@ -3844,19 +3921,19 @@ my_bool Query_cache::move_by_type(uchar **border,
} while ( result_block != first_result_block );
}
Query_cache_query *new_query= ((Query_cache_query *) new_block->data());
- my_rwlock_init(&new_query->lock, NULL);
+ mysql_rwlock_init(key_rwlock_query_cache_query_lock, &new_query->lock);
/*
If someone is writing to this block, inform the writer that the block
has been moved.
*/
- NET *net = new_block->query()->writer();
- if (net != 0)
+ Query_cache_tls *query_cache_tls= new_block->query()->writer();
+ if (query_cache_tls != NULL)
{
- net->query_cache_query= (uchar*) new_block;
+ query_cache_tls->first_query_block= new_block;
}
/* Fix hash to point at moved block */
- hash_replace(&queries, &record_idx, (uchar*) new_block);
+ my_hash_replace(&queries, &record_idx, (uchar*) new_block);
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
len, (ulong) new_block, (ulong) *border));
break;
@@ -4267,13 +4344,13 @@ my_bool Query_cache::check_integrity(bool locked)
if (!locked)
lock_and_suspend();
- if (hash_check(&queries))
+ if (my_hash_check(&queries))
{
DBUG_PRINT("error", ("queries hash is damaged"));
result = 1;
}
- if (hash_check(&tables))
+ if (my_hash_check(&tables))
{
DBUG_PRINT("error", ("tables hash is damaged"));
result = 1;
@@ -4440,7 +4517,7 @@ my_bool Query_cache::check_integrity(bool locked)
(ulong) block, (uint) block->type));
size_t length;
uchar *key = query_cache_query_get_key((uchar*) block, &length, 0);
- uchar* val = hash_search(&queries, key, length);
+ uchar* val = my_hash_search(&queries, key, length);
if (((uchar*)block) != val)
{
DBUG_PRINT("error", ("block 0x%lx found in queries hash like 0x%lx",
@@ -4475,7 +4552,7 @@ my_bool Query_cache::check_integrity(bool locked)
(ulong) block, (uint) block->type));
size_t length;
uchar *key = query_cache_table_get_key((uchar*) block, &length, 0);
- uchar* val = hash_search(&tables, key, length);
+ uchar* val = my_hash_search(&tables, key, length);
if (((uchar*)block) != val)
{
DBUG_PRINT("error", ("block 0x%lx found in tables hash like 0x%lx",
@@ -4715,3 +4792,4 @@ err2:
#endif /* DBUG_OFF */
#endif /*HAVE_QUERY_CACHE*/
+
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index 44fc3123b98..792ae6ba960 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2006 MySQL AB
+/* Copyright (C) 2001-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -16,6 +16,16 @@
#ifndef _SQL_CACHE_H
#define _SQL_CACHE_H
+#include "hash.h"
+#include "my_base.h" /* ha_rows */
+
+class MY_LOCALE;
+struct TABLE_LIST;
+class Time_zone;
+struct LEX;
+struct TABLE;
+typedef struct st_changed_table_list CHANGED_TABLE_LIST;
+
/* Query cache */
/*
@@ -64,6 +74,13 @@ struct Query_cache_table;
struct Query_cache_query;
struct Query_cache_result;
class Query_cache;
+struct Query_cache_tls;
+struct LEX;
+class THD;
+
+typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
+ uint key_length,
+ ulonglong *engine_data);
/**
This class represents a node in the linked chain of queries
@@ -135,9 +152,9 @@ struct Query_cache_block
struct Query_cache_query
{
ulonglong limit_found_rows;
- rw_lock_t lock;
+ mysql_rwlock_t lock;
Query_cache_block *res;
- NET *wri;
+ Query_cache_tls *wri;
ulong len;
uint8 tbls_type;
unsigned int last_pkt_nr;
@@ -149,8 +166,8 @@ struct Query_cache_query
inline void found_rows(ulonglong rows) { limit_found_rows= rows; }
inline Query_cache_block *result() { return res; }
inline void result(Query_cache_block *p) { res= p; }
- inline NET *writer() { return wri; }
- inline void writer(NET *p) { wri= p; }
+ inline Query_cache_tls *writer() { return wri; }
+ inline void writer(Query_cache_tls *p) { wri= p; }
inline uint8 tables_type() { return tbls_type; }
inline void tables_type(uint8 type) { tbls_type= type; }
inline ulong length() { return len; }
@@ -275,12 +292,15 @@ private:
#ifndef DBUG_OFF
my_thread_id m_cache_lock_thread_id;
#endif
- pthread_cond_t COND_cache_status_changed;
+ mysql_cond_t COND_cache_status_changed;
enum Cache_lock_status { UNLOCKED, LOCKED_NO_WAIT, LOCKED };
Cache_lock_status m_cache_lock_status;
+ bool m_query_cache_is_disabled;
+
void free_query_internal(Query_cache_block *point);
void invalidate_table_internal(THD *thd, uchar *key, uint32 key_length);
+ void disable_query_cache(void) { m_query_cache_is_disabled= TRUE; }
protected:
/*
@@ -297,7 +317,7 @@ protected:
is other threads that were going to do cache flush---they'll wait
till the end of a flush operation.
*/
- pthread_mutex_t structure_guard_mutex;
+ mysql_mutex_t structure_guard_mutex;
uchar *cache; // cache memory
Query_cache_block *first_block; // physical location block list
Query_cache_block *queries_blocks; // query list (LIFO)
@@ -407,7 +427,8 @@ protected:
If query is cacheable return number tables in query
(query without tables not cached)
*/
- TABLE_COUNTER_TYPE is_cacheable(THD *thd, uint32 query_len, char *query,
+ TABLE_COUNTER_TYPE is_cacheable(THD *thd, size_t query_len,
+ const char *query,
LEX *lex, TABLE_LIST *tables_used,
uint8 *tables_type);
TABLE_COUNTER_TYPE process_and_count_tables(THD *thd,
@@ -423,6 +444,8 @@ protected:
uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE,
uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE);
+ bool is_disabled(void) { return m_query_cache_is_disabled; }
+
/* initialize cache (mutex) */
void init();
/* resize query cache (return real query size, 0 if disabled) */
@@ -462,10 +485,13 @@ protected:
void destroy();
- friend void query_cache_init_query(NET *net);
- friend void query_cache_insert(NET *net, const char *packet, ulong length);
- friend void query_cache_end_of_result(THD *thd);
- friend void query_cache_abort(NET *net);
+ void insert(Query_cache_tls *query_cache_tls,
+ const char *packet,
+ ulong length,
+ unsigned pkt_nr);
+
+ void end_of_result(THD *thd);
+ void abort(Query_cache_tls *query_cache_tls);
/*
The following functions are only used when debugging
@@ -491,11 +517,68 @@ protected:
void unlock(void);
};
-extern Query_cache query_cache;
-extern TYPELIB query_cache_type_typelib;
-void query_cache_init_query(NET *net);
-void query_cache_insert(NET *net, const char *packet, ulong length);
-void query_cache_end_of_result(THD *thd);
-void query_cache_abort(NET *net);
+#ifdef HAVE_QUERY_CACHE
+struct Query_cache_query_flags
+{
+ unsigned int client_long_flag:1;
+ unsigned int client_protocol_41:1;
+ unsigned int protocol_type:2;
+ unsigned int more_results_exists:1;
+ unsigned int in_trans:1;
+ unsigned int autocommit:1;
+ unsigned int pkt_nr;
+ uint character_set_client_num;
+ uint character_set_results_num;
+ uint collation_connection_num;
+ ha_rows limit;
+ Time_zone *time_zone;
+ ulong sql_mode;
+ ulong max_sort_length;
+ ulong group_concat_max_len;
+ ulong default_week_format;
+ ulong div_precision_increment;
+ MY_LOCALE *lc_time_names;
+};
+#define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags)
+#include "sql_cache.h"
+#define query_cache_abort(A) query_cache.abort(A)
+#define query_cache_end_of_result(A) query_cache.end_of_result(A)
+#define query_cache_store_query(A, B) query_cache.store_query(A, B)
+#define query_cache_destroy() query_cache.destroy()
+#define query_cache_result_size_limit(A) query_cache.result_size_limit(A)
+#define query_cache_init() query_cache.init()
+#define query_cache_resize(A) query_cache.resize(A)
+#define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A)
+#define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C)
+#define query_cache_invalidate1(A) query_cache.invalidate(A)
+#define query_cache_send_result_to_client(A, B, C) \
+ query_cache.send_result_to_client(A, B, C)
+#define query_cache_invalidate_by_MyISAM_filename_ref \
+ &query_cache_invalidate_by_MyISAM_filename
+/* note the "maybe": it's a read without mutex */
+#define query_cache_maybe_disabled(T) \
+ (T->variables.query_cache_type == 0 || query_cache.query_cache_size == 0)
+#define query_cache_is_cacheable_query(L) \
+ (((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query)
+#else
+#define QUERY_CACHE_FLAGS_SIZE 0
+#define query_cache_store_query(A, B)
+#define query_cache_destroy()
+#define query_cache_result_size_limit(A)
+#define query_cache_init()
+#define query_cache_resize(A)
+#define query_cache_set_min_res_unit(A)
+#define query_cache_invalidate3(A, B, C)
+#define query_cache_invalidate1(A)
+#define query_cache_send_result_to_client(A, B, C) 0
+#define query_cache_invalidate_by_MyISAM_filename_ref NULL
+
+#define query_cache_abort(A)
+#define query_cache_end_of_result(A)
+#define query_cache_invalidate_by_MyISAM_filename_ref NULL
+#define query_cache_maybe_disabled(T) 1
+#define query_cache_is_cacheable_query(L) 0
+#endif /*HAVE_QUERY_CACHE*/
+extern Query_cache query_cache;
#endif
diff --git a/sql/sql_callback.h b/sql/sql_callback.h
new file mode 100644
index 00000000000..430514d3d7e
--- /dev/null
+++ b/sql/sql_callback.h
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef SQL_CALLBACK_INCLUDED
+#define SQL_CALLBACK_INCLUDED
+
+/**
+ Macro used for an internal callback.
+
+ The macro will check that the object exists and that the function
+ is defined. If that is the case, it will call the function with the
+ given parameters.
+
+ If the object or the function is not defined, the callback will be
+ considered successful (nothing needed to be done) and will
+ therefore return no error.
+ */
+
+#define MYSQL_CALLBACK(OBJ, FUNC, PARAMS) \
+ do { \
+ if ((OBJ) && ((OBJ)->FUNC)) \
+ (OBJ)->FUNC PARAMS; \
+ } while (0)
+
+#define MYSQL_CALLBACK_ELSE(OBJ, FUNC, PARAMS, ELSE) \
+ (((OBJ) && ((OBJ)->FUNC)) ? (OBJ)->FUNC PARAMS : (ELSE))
+
+
+#endif /* SQL_CALLBACK_INCLUDED */
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index a61ce7bfd14..2df7a2c8572 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -25,13 +25,24 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_class.h"
+#include "sql_cache.h" // query_cache_abort
+#include "sql_base.h" // close_thread_tables
+#include "sql_time.h" // date_time_format_copy
+#include "sql_acl.h" // NO_ACCESS,
+ // acl_getroot_no_password
+#include "sql_base.h" // close_temporary_tables
+#include "sql_handler.h" // mysql_ha_cleanup
#include "rpl_rli.h"
#include "rpl_filter.h"
#include "rpl_record.h"
#include "slave.h"
#include <my_bitmap.h>
#include "log_event.h"
+#include "sql_audit.h"
#include <m_ctype.h>
#include <sys/stat.h>
#include <thr_alarm.h>
@@ -39,10 +50,14 @@
#include <io.h>
#endif
#include <mysys_err.h>
+#include <limits.h>
#include "sp_rcontext.h"
#include "sp_cache.h"
+#include "transaction.h"
#include "debug_sync.h"
+#include "sql_parse.h" // is_update_query
+#include "sql_callback.h"
/*
The following is used to initialise Table_ident with a internal
@@ -85,15 +100,15 @@ extern "C" void free_user_var(user_var_entry *entry)
{
char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
if (entry->value && entry->value != pos)
- my_free(entry->value, MYF(0));
- my_free((char*) entry,MYF(0));
+ my_free(entry->value);
+ my_free(entry);
}
bool Key_part_spec::operator==(const Key_part_spec& other) const
{
return length == other.length &&
- !my_strcasecmp(system_charset_info, field_name,
- other.field_name);
+ !my_strcasecmp(system_charset_info, field_name.str,
+ other.field_name.str);
}
/**
@@ -202,25 +217,6 @@ bool foreign_key_prefix(Key *a, Key *b)
** Thread specific functions
****************************************************************************/
-/** Push an error to the error stack and return TRUE for now. */
-
-bool
-Reprepare_observer::report_error(THD *thd)
-{
- my_error(ER_NEED_REPREPARE, MYF(ME_NO_WARNING_FOR_ERROR|ME_NO_SP_HANDLER));
-
- m_invalidated= TRUE;
-
- return TRUE;
-}
-
-
-Open_tables_state::Open_tables_state(ulong version_arg)
- :version(version_arg), state_flags(0U)
-{
- reset_open_tables_state();
-}
-
/*
The following functions form part of the C plugin API
*/
@@ -265,15 +261,20 @@ int thd_tablespace_op(const THD *thd)
extern "C"
-const char *set_thd_proc_info(THD *thd, const char *info,
- const char *calling_function,
- const char *calling_file,
+const char *set_thd_proc_info(void *thd_arg, const char *info,
+ const char *calling_function,
+ const char *calling_file,
const unsigned int calling_line)
{
+ THD *thd= (THD *) thd_arg;
+
+ if (!thd)
+ thd= current_thd;
+
const char *old_info= thd->proc_info;
- DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line,
+ DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line,
(info != NULL) ? info : "(null)"));
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
thd->profiling.status_change(info, calling_function, calling_file, calling_line);
#endif
thd->proc_info= info;
@@ -281,11 +282,36 @@ const char *set_thd_proc_info(THD *thd, const char *info,
}
extern "C"
+const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond,
+ mysql_mutex_t *mutex, const char *msg)
+{
+ if (!thd)
+ thd= current_thd;
+
+ return thd->enter_cond(cond, mutex, msg);
+}
+
+extern "C"
+void thd_exit_cond(MYSQL_THD thd, const char *old_msg)
+{
+ if (!thd)
+ thd= current_thd;
+
+ thd->exit_cond(old_msg);
+ return;
+}
+
+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;
+}
/**
Provide a handler data getter to simplify coding
@@ -320,7 +346,7 @@ void thd_set_ha_data(THD *thd, const struct handlerton *hton,
extern "C"
long long thd_test_options(const THD *thd, long long test_options)
{
- return thd->options & test_options;
+ return thd->variables.option_bits & test_options;
}
extern "C"
@@ -332,13 +358,13 @@ int thd_sql_command(const THD *thd)
extern "C"
int thd_tx_isolation(const THD *thd)
{
- return (int) thd->variables.tx_isolation;
+ return (int) thd->tx_isolation;
}
extern "C"
void thd_inc_row_count(THD *thd)
{
- thd->row_count++;
+ thd->warning_info->inc_current_row_for_warning();
}
@@ -409,7 +435,7 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
str.append(proc_info);
}
- pthread_mutex_lock(&thd->LOCK_thd_data);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
if (thd->query())
{
@@ -421,7 +447,7 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
str.append(thd->query(), len);
}
- pthread_mutex_unlock(&thd->LOCK_thd_data);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
if (str.c_ptr_safe() == buffer)
return buffer;
@@ -440,7 +466,7 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
/**
- Implementation of Drop_table_error_handler::handle_error().
+ Implementation of Drop_table_error_handler::handle_condition().
The reason in having this implementation is to silence technical low-level
warnings during DROP TABLE operation. Currently we don't want to expose
the following warnings during DROP TABLE:
@@ -453,158 +479,26 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
@return TRUE if the condition is handled.
*/
-bool Drop_table_error_handler::handle_error(uint sql_errno,
- const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd)
-{
+bool Drop_table_error_handler::handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
+{
+ *cond_hdl= NULL;
return ((sql_errno == EE_DELETE && my_errno == ENOENT) ||
sql_errno == ER_TRG_NO_DEFINER);
}
-/**
- Clear this diagnostics area.
-
- Normally called at the end of a statement.
-*/
-
-void
-Diagnostics_area::reset_diagnostics_area()
-{
-#ifdef DBUG_OFF
- can_overwrite_status= FALSE;
- /** Don't take chances in production */
- m_message[0]= '\0';
- m_sql_errno= 0;
- m_server_status= 0;
- m_affected_rows= 0;
- m_last_insert_id= 0;
- m_total_warn_count= 0;
-#endif
- is_sent= FALSE;
- /** Tiny reset in debug mode to see garbage right away */
- m_status= DA_EMPTY;
-}
-
-
-/**
- Set OK status -- ends commands that do not return a
- result set, e.g. INSERT/UPDATE/DELETE.
-*/
-
-void
-Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
- ulonglong last_insert_id_arg,
- const char *message_arg)
-{
- DBUG_ASSERT(! is_set());
-#ifdef DBUG_OFF
- /*
- In production, refuse to overwrite an error or a custom response
- with an OK packet.
- */
- if (is_error() || is_disabled())
- return;
-#endif
- /** Only allowed to report success if has not yet reported an error */
-
- m_server_status= thd->server_status;
- m_total_warn_count= thd->total_warn_count;
- m_affected_rows= affected_rows_arg;
- m_last_insert_id= last_insert_id_arg;
- if (message_arg)
- strmake(m_message, message_arg, sizeof(m_message) - 1);
- else
- m_message[0]= '\0';
- m_status= DA_OK;
-}
-
-
-/**
- Set EOF status.
-*/
-
-void
-Diagnostics_area::set_eof_status(THD *thd)
-{
- /** Only allowed to report eof if has not yet reported an error */
-
- DBUG_ASSERT(! is_set());
-#ifdef DBUG_OFF
- /*
- In production, refuse to overwrite an error or a custom response
- with an EOF packet.
- */
- if (is_error() || is_disabled())
- return;
-#endif
-
- m_server_status= thd->server_status;
- /*
- If inside a stored procedure, do not return the total
- number of warnings, since they are not available to the client
- anyway.
- */
- m_total_warn_count= thd->spcont ? 0 : thd->total_warn_count;
-
- m_status= DA_EOF;
-}
-
-/**
- Set ERROR status.
-*/
-
-void
-Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
- const char *message_arg)
-{
- /*
- Only allowed to report error if has not yet reported a success
- The only exception is when we flush the message to the client,
- an error can happen during the flush.
- */
- DBUG_ASSERT(! is_set() || can_overwrite_status);
-#ifdef DBUG_OFF
- /*
- In production, refuse to overwrite a custom response with an
- ERROR packet.
- */
- if (is_disabled())
- return;
-#endif
-
- m_sql_errno= sql_errno_arg;
- strmake(m_message, message_arg, sizeof(m_message) - 1);
-
- m_status= DA_ERROR;
-}
-
-
-/**
- Mark the diagnostics area as 'DISABLED'.
-
- This is used in rare cases when the COM_ command at hand sends a response
- in a custom format. One example is the query cache, another is
- COM_STMT_PREPARE.
-*/
-
-void
-Diagnostics_area::disable_status()
-{
- DBUG_ASSERT(! is_set());
- m_status= DA_DISABLED;
-}
-
-
THD::THD()
:Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,
/* statement id */ 0),
- Open_tables_state(refresh_version), rli_fake(0),
- lock_id(&main_lock_id),
+ rli_fake(0),
user_time(0), in_sub_stmt(0),
- sql_log_bin_toplevel(false),
- binlog_table_maps(0), binlog_flags(0UL),
+ binlog_unsafe_warning_flags(0),
+ binlog_table_maps(0),
table_map_for_update(0),
arg_of_last_insert_id_function(FALSE),
first_successful_insert_id_in_prev_stmt(0),
@@ -612,7 +506,8 @@ THD::THD()
first_successful_insert_id_in_cur_stmt(0),
stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
examined_row_count(0),
- global_read_lock(0),
+ warning_info(&main_warning_info),
+ stmt_da(&main_da),
is_fatal_error(0),
transaction_rollback_request(0),
is_fatal_sub_stmt_error(0),
@@ -622,13 +517,15 @@ THD::THD()
bootstrap(0),
derived_tables_processing(FALSE),
spcont(NULL),
- m_parser_state(NULL)
+ m_parser_state(NULL),
#if defined(ENABLED_DEBUG_SYNC)
- , debug_sync_control(0)
+ debug_sync_control(0),
#endif /* defined(ENABLED_DEBUG_SYNC) */
+ main_warning_info(0)
{
ulong tmp;
+ mdl_context.init(this);
/*
Pass nominal parameters to init_alloc_root only to ensure that
the destructor works OK in case of an error. The main_mem_root
@@ -640,22 +537,21 @@ THD::THD()
catalog= (char*)"std"; // the only catalog we have for now
main_security_ctx.init();
security_ctx= &main_security_ctx;
- locked=some_tables_deleted=no_errors=password= 0;
+ no_errors= 0;
+ password= 0;
query_start_used= 0;
count_cuted_fields= CHECK_FIELD_IGNORE;
killed= NOT_KILLED;
col_access=0;
is_slave_error= thread_specific_used= FALSE;
- hash_clear(&handler_tables_hash);
+ my_hash_clear(&handler_tables_hash);
tmp_table=0;
used_tables=0;
- cuted_fields= sent_row_count= row_count= 0L;
+ cuted_fields= 0L;
+ sent_row_count= 0L;
limit_found_rows= 0;
- row_count_func= -1;
+ m_row_count_func= -1;
statement_id_counter= 0UL;
-#ifdef ERROR_INJECT_SUPPORT
- error_inject_value= 0UL;
-#endif
// Must be reset to handle error with THD's created for init of mysqld
lex->current_select= 0;
start_time=(time_t) 0;
@@ -669,7 +565,6 @@ THD::THD()
file_id = 0;
query_id= 0;
query_name_consts= 0;
- warn_id= 0;
db_charset= global_system_variables.collation_database;
bzero(ha_data, sizeof(ha_data));
mysys_var=0;
@@ -679,12 +574,10 @@ THD::THD()
dbug_sentry=THD_SENTRY_MAGIC;
#endif
#ifndef EMBEDDED_LIBRARY
+ mysql_audit_init_thd(this);
net.vio=0;
#endif
client_capabilities= 0; // minimalistic client
-#ifdef HAVE_QUERY_CACHE
- query_cache_init_query(&net); // If error on boot
-#endif
ull=0;
system_thread= NON_SYSTEM_THREAD;
cleanup_done= abort_on_warning= no_warnings_for_error= 0;
@@ -694,7 +587,7 @@ THD::THD()
#ifdef SIGNAL_WITH_VIO_CLOSE
active_vio = 0;
#endif
- pthread_mutex_init(&LOCK_thd_data, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_thd_data, &LOCK_thd_data, MY_MUTEX_INIT_FAST);
/* Variables with default values */
proc_info="login";
@@ -704,16 +597,17 @@ THD::THD()
command=COM_CONNECT;
*scramble= '\0';
+ /* Call to init() below requires fully initialized Open_tables_state. */
+ reset_open_tables_state(this);
+
init();
- /* Initialize sub structures */
- init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
profiling.set_thd(this);
#endif
user_connect=(USER_CONN *)0;
- hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
- (hash_get_key) get_var_key,
- (hash_free_key) free_user_var, 0);
+ my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
+ (my_hash_get_key) get_var_key,
+ (my_hash_free_key) free_user_var, 0);
sp_proc_cache= NULL;
sp_func_cache= NULL;
@@ -735,7 +629,6 @@ THD::THD()
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
substitute_null_with_insert_id = FALSE;
thr_lock_info_init(&lock_info); /* safety: will be reset after start */
- thr_lock_owner_init(&main_lock_id, &lock_info);
m_internal_handler= NULL;
m_binlog_invoker= FALSE;
@@ -757,16 +650,27 @@ void THD::push_internal_handler(Internal_error_handler *handler)
}
}
-
-bool THD::handle_error(uint sql_errno, const char *message,
- MYSQL_ERROR::enum_warning_level level)
+bool THD::handle_condition(uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
{
+ if (!m_internal_handler)
+ {
+ *cond_hdl= NULL;
+ return FALSE;
+ }
+
for (Internal_error_handler *error_handler= m_internal_handler;
error_handler;
error_handler= error_handler->m_prev_internal_handler)
{
- if (error_handler->handle_error(sql_errno, message, level, this))
+ if (error_handler->handle_condition(this, sql_errno, sqlstate, level, msg,
+ cond_hdl))
+ {
return TRUE;
+ }
}
return FALSE;
@@ -781,6 +685,185 @@ Internal_error_handler *THD::pop_internal_handler()
return popped_handler;
}
+
+void THD::raise_error(uint sql_errno)
+{
+ const char* msg= ER(sql_errno);
+ (void) raise_condition(sql_errno,
+ NULL,
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ msg);
+}
+
+void THD::raise_error_printf(uint sql_errno, ...)
+{
+ va_list args;
+ char ebuff[MYSQL_ERRMSG_SIZE];
+ DBUG_ENTER("THD::raise_error_printf");
+ DBUG_PRINT("my", ("nr: %d errno: %d", sql_errno, errno));
+ const char* format= ER(sql_errno);
+ va_start(args, sql_errno);
+ my_vsnprintf(ebuff, sizeof(ebuff), format, args);
+ va_end(args);
+ (void) raise_condition(sql_errno,
+ NULL,
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ebuff);
+ DBUG_VOID_RETURN;
+}
+
+void THD::raise_warning(uint sql_errno)
+{
+ const char* msg= ER(sql_errno);
+ (void) raise_condition(sql_errno,
+ NULL,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ msg);
+}
+
+void THD::raise_warning_printf(uint sql_errno, ...)
+{
+ va_list args;
+ char ebuff[MYSQL_ERRMSG_SIZE];
+ DBUG_ENTER("THD::raise_warning_printf");
+ DBUG_PRINT("enter", ("warning: %u", sql_errno));
+ const char* format= ER(sql_errno);
+ va_start(args, sql_errno);
+ my_vsnprintf(ebuff, sizeof(ebuff), format, args);
+ va_end(args);
+ (void) raise_condition(sql_errno,
+ NULL,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ebuff);
+ DBUG_VOID_RETURN;
+}
+
+void THD::raise_note(uint sql_errno)
+{
+ DBUG_ENTER("THD::raise_note");
+ DBUG_PRINT("enter", ("code: %d", sql_errno));
+ if (!(variables.option_bits & OPTION_SQL_NOTES))
+ DBUG_VOID_RETURN;
+ const char* msg= ER(sql_errno);
+ (void) raise_condition(sql_errno,
+ NULL,
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ msg);
+ DBUG_VOID_RETURN;
+}
+
+void THD::raise_note_printf(uint sql_errno, ...)
+{
+ va_list args;
+ char ebuff[MYSQL_ERRMSG_SIZE];
+ DBUG_ENTER("THD::raise_note_printf");
+ DBUG_PRINT("enter",("code: %u", sql_errno));
+ if (!(variables.option_bits & OPTION_SQL_NOTES))
+ DBUG_VOID_RETURN;
+ const char* format= ER(sql_errno);
+ va_start(args, sql_errno);
+ my_vsnprintf(ebuff, sizeof(ebuff), format, args);
+ va_end(args);
+ (void) raise_condition(sql_errno,
+ NULL,
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ebuff);
+ DBUG_VOID_RETURN;
+}
+
+MYSQL_ERROR* THD::raise_condition(uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg)
+{
+ MYSQL_ERROR *cond= NULL;
+ DBUG_ENTER("THD::raise_condition");
+
+ if (!(variables.option_bits & OPTION_SQL_NOTES) &&
+ (level == MYSQL_ERROR::WARN_LEVEL_NOTE))
+ DBUG_RETURN(NULL);
+
+ warning_info->opt_clear_warning_info(query_id);
+
+ /*
+ TODO: replace by DBUG_ASSERT(sql_errno != 0) once all bugs similar to
+ Bug#36768 are fixed: a SQL condition must have a real (!=0) error number
+ so that it can be caught by handlers.
+ */
+ if (sql_errno == 0)
+ sql_errno= ER_UNKNOWN_ERROR;
+ if (msg == NULL)
+ msg= ER(sql_errno);
+ if (sqlstate == NULL)
+ sqlstate= mysql_errno_to_sqlstate(sql_errno);
+
+ if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
+ really_abort_on_warning())
+ {
+ /*
+ FIXME:
+ push_warning and strict SQL_MODE case.
+ */
+ level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+ killed= THD::KILL_BAD_DATA;
+ }
+
+ switch (level)
+ {
+ case MYSQL_ERROR::WARN_LEVEL_NOTE:
+ case MYSQL_ERROR::WARN_LEVEL_WARN:
+ got_warning= 1;
+ break;
+ case MYSQL_ERROR::WARN_LEVEL_ERROR:
+ break;
+ default:
+ DBUG_ASSERT(FALSE);
+ }
+
+ if (handle_condition(sql_errno, sqlstate, level, msg, &cond))
+ DBUG_RETURN(cond);
+
+ if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
+ {
+ is_slave_error= 1; // needed to catch query errors during replication
+
+ /*
+ thd->lex->current_select == 0 if lex structure is not inited
+ (not query command (COM_QUERY))
+ */
+ if (lex->current_select &&
+ lex->current_select->no_error && !is_fatal_error)
+ {
+ DBUG_PRINT("error",
+ ("Error converted to warning: current_select: no_error %d "
+ "fatal_error: %d",
+ (lex->current_select ?
+ lex->current_select->no_error : 0),
+ (int) is_fatal_error));
+ }
+ else
+ {
+ if (! stmt_da->is_error())
+ {
+ set_row_count_func(-1);
+ stmt_da->set_error_status(this, sql_errno, msg, sqlstate);
+ }
+ }
+ }
+
+ query_cache_abort(&query_cache_tls);
+
+ /* FIXME: broken special case */
+ if (no_warnings_for_error && (level == MYSQL_ERROR::WARN_LEVEL_ERROR))
+ DBUG_RETURN(NULL);
+
+ /* When simulating OOM, skip writing to error log to avoid mtr errors */
+ DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(NULL););
+
+ cond= warning_info->push_warning(this, sql_errno, sqlstate, level, msg);
+ DBUG_RETURN(cond);
+}
+
extern "C"
void *thd_alloc(MYSQL_THD thd, unsigned int size)
{
@@ -838,44 +921,34 @@ extern "C" THD *_current_thd_noinline(void)
void THD::init(void)
{
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
plugin_thdvar_init(this);
- variables.time_format= date_time_format_copy((THD*) 0,
- variables.time_format);
- variables.date_format= date_time_format_copy((THD*) 0,
- variables.date_format);
- variables.datetime_format= date_time_format_copy((THD*) 0,
- variables.datetime_format);
/*
variables= global_system_variables above has reset
variables.pseudo_thread_id to 0. We need to correct it here to
avoid temporary tables replication failure.
*/
variables.pseudo_thread_id= thread_id;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
server_status= SERVER_STATUS_AUTOCOMMIT;
if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
- options= thd_startup_options;
-
- if (variables.max_join_size == HA_POS_ERROR)
- options |= OPTION_BIG_SELECTS;
- else
- options &= ~OPTION_BIG_SELECTS;
- transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= FALSE;
+ transaction.all.modified_non_trans_table=
+ transaction.stmt.modified_non_trans_table= FALSE;
open_options=ha_open_options;
update_lock_default= (variables.low_priority_updates ?
TL_WRITE_LOW_PRIORITY :
TL_WRITE);
- session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
- warn_list.empty();
- bzero((char*) warn_count, sizeof(warn_count));
- total_warn_count= 0;
+ tx_isolation= (enum_tx_isolation) variables.tx_isolation;
update_charset();
- reset_current_stmt_binlog_row_based();
+ reset_current_stmt_binlog_format_row();
bzero((char *) &status_var, sizeof(status_var));
- sql_log_bin_toplevel= options & OPTION_BIN_LOG;
+
+ if (variables.sql_log_bin)
+ variables.option_bits|= OPTION_BIN_LOG;
+ else
+ variables.option_bits&= ~OPTION_BIN_LOG;
#if defined(ENABLED_DEBUG_SYNC)
/* Initialize the Debug Sync Facility. See debug_sync.cc. */
@@ -897,11 +970,9 @@ void THD::init_for_queries()
reset_root_defaults(mem_root, variables.query_alloc_block_size,
variables.query_prealloc_size);
-#ifdef USING_TRANSACTIONS
reset_root_defaults(&transaction.mem_root,
variables.trans_alloc_block_size,
variables.trans_prealloc_size);
-#endif
transaction.xid_state.xid.null();
transaction.xid_state.in_thd=1;
}
@@ -920,18 +991,18 @@ void THD::init_for_queries()
void THD::change_user(void)
{
- pthread_mutex_lock(&LOCK_status);
+ mysql_mutex_lock(&LOCK_status);
add_to_status(&global_status_var, &status_var);
- pthread_mutex_unlock(&LOCK_status);
+ mysql_mutex_unlock(&LOCK_status);
cleanup();
killed= NOT_KILLED;
cleanup_done= 0;
init();
stmt_map.reset();
- hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
- (hash_get_key) get_var_key,
- (hash_free_key) free_user_var, 0);
+ my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
+ (my_hash_get_key) get_var_key,
+ (my_hash_free_key) free_user_var, 0);
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
}
@@ -952,38 +1023,46 @@ void THD::cleanup(void)
}
#endif
{
- ha_rollback(this);
+ transaction.xid_state.xa_state= XA_NOTR;
+ trans_rollback(this);
xid_cache_delete(&transaction.xid_state);
}
- if (locked_tables)
- {
- lock=locked_tables; locked_tables=0;
- close_thread_tables(this);
- }
+
+ locked_tables_list.unlock_locked_tables(this);
+ mysql_ha_cleanup(this);
+
+ DBUG_ASSERT(open_tables == NULL);
+ /*
+ If the thread was in the middle of an ongoing transaction (rolled
+ back a few lines above) or under LOCK TABLES (unlocked the tables
+ and left the mode a few lines above), there will be outstanding
+ metadata locks. Release them.
+ */
+ mdl_context.release_transactional_locks();
+
+ /* Release the global read lock, if acquired. */
+ if (global_read_lock.is_acquired())
+ global_read_lock.unlock_global_read_lock(this);
+
+ /* All metadata locks must have been released by now. */
+ DBUG_ASSERT(!mdl_context.has_locks());
#if defined(ENABLED_DEBUG_SYNC)
/* End the Debug Sync Facility. See debug_sync.cc. */
debug_sync_end_thread(this);
#endif /* defined(ENABLED_DEBUG_SYNC) */
- mysql_ha_cleanup(this);
delete_dynamic(&user_var_events);
- hash_free(&user_vars);
+ my_hash_free(&user_vars);
close_temporary_tables(this);
- my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR));
-
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
- if (global_read_lock)
- unlock_global_read_lock(this);
if (ull)
{
- pthread_mutex_lock(&LOCK_user_locks);
+ mysql_mutex_lock(&LOCK_user_locks);
item_user_lock_release(ull);
- pthread_mutex_unlock(&LOCK_user_locks);
+ mysql_mutex_unlock(&LOCK_user_locks);
ull= NULL;
}
@@ -997,8 +1076,9 @@ THD::~THD()
THD_CHECK_SENTRY(this);
DBUG_ENTER("~THD()");
/* Ensure that no one is using THD */
- pthread_mutex_lock(&LOCK_thd_data);
- pthread_mutex_unlock(&LOCK_thd_data);
+ mysql_mutex_lock(&LOCK_thd_data);
+ mysys_var=0; // Safety (shouldn't be needed)
+ mysql_mutex_unlock(&LOCK_thd_data);
add_to_status(&global_status_var, &status_var);
/* Close connection */
@@ -1010,22 +1090,20 @@ THD::~THD()
}
#endif
stmt_map.reset(); /* close all prepared statements */
- DBUG_ASSERT(lock_info.n_cursors == 0);
if (!cleanup_done)
cleanup();
+ mdl_context.destroy();
ha_close_connection(this);
+ mysql_audit_release(this);
plugin_thdvar_cleanup(this);
DBUG_PRINT("info", ("freeing security context"));
main_security_ctx.destroy();
- safeFree(db);
- free_root(&warn_root,MYF(0));
-#ifdef USING_TRANSACTIONS
+ my_free(db);
+ db= NULL;
free_root(&transaction.mem_root,MYF(0));
-#endif
- mysys_var=0; // Safety (shouldn't be needed)
- pthread_mutex_destroy(&LOCK_thd_data);
+ mysql_mutex_destroy(&LOCK_thd_data);
#ifndef DBUG_OFF
dbug_sentry= THD_SENTRY_GONE;
#endif
@@ -1035,6 +1113,8 @@ THD::~THD()
delete rli_fake;
rli_fake= NULL;
}
+
+ mysql_audit_free_thd(this);
#endif
free_root(&main_mem_root, MYF(0));
@@ -1099,39 +1179,73 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
}
+/**
+ Awake a thread.
+
+ @param[in] state_to_set value for THD::killed
+
+ This is normally called from another thread's THD object.
+
+ @note Do always call this while holding LOCK_thd_data.
+*/
+
void THD::awake(THD::killed_state state_to_set)
{
DBUG_ENTER("THD::awake");
- DBUG_PRINT("enter", ("this: 0x%lx", (long) this));
+ DBUG_PRINT("enter", ("this: %p current_thd: %p", this, current_thd));
THD_CHECK_SENTRY(this);
- safe_mutex_assert_owner(&LOCK_thd_data);
+ mysql_mutex_assert_owner(&LOCK_thd_data);
+ /* Set the 'killed' flag of 'this', which is the target THD object. */
killed= state_to_set;
+
if (state_to_set != THD::KILL_QUERY)
{
- thr_alarm_kill(thread_id);
- if (!slave_thread)
- thread_scheduler.post_kill_notification(this);
#ifdef SIGNAL_WITH_VIO_CLOSE
if (this != current_thd)
{
/*
- In addition to a signal, let's close the socket of the thread that
- is being killed. This is to make sure it does not block if the
- signal is lost. This needs to be done only on platforms where
- signals are not a reliable interruption mechanism.
-
- If we're killing ourselves, we know that we're not blocked, so this
- hack is not used.
+ Before sending a signal, let's close the socket of the thread
+ that is being killed ("this", which is not the current thread).
+ This is to make sure it does not block if the signal is lost.
+ This needs to be done only on platforms where signals are not
+ a reliable interruption mechanism.
+
+ Note that the downside of this mechanism is that we could close
+ the connection while "this" target thread is in the middle of
+ sending a result to the application, thus violating the client-
+ server protocol.
+
+ On the other hand, without closing the socket we have a race
+ condition. If "this" target thread passes the check of
+ thd->killed, and then the current thread runs through
+ THD::awake(), sets the 'killed' flag and completes the
+ signaling, and then the target thread runs into read(), it will
+ block on the socket. As a result of the discussions around
+ Bug#37780, it has been decided that we accept the race
+ condition. A second KILL awakes the target from read().
+
+ If we are killing ourselves, we know that we are not blocked.
+ We also know that we will check thd->killed before we go for
+ reading the next statement.
*/
close_active_vio();
}
-#endif
+#endif
+
+ /* Mark the target thread's alarm request expired, and signal alarm. */
+ thr_alarm_kill(thread_id);
+
+ /* Send an event to the scheduler that a thread should be killed. */
+ if (!slave_thread)
+ MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (this));
}
+
+ /* Broadcast a condition to kick the target if it is waiting on it. */
if (mysys_var)
{
- pthread_mutex_lock(&mysys_var->mutex);
+ mysql_mutex_lock(&mysys_var->mutex);
if (!system_thread) // Don't abort locks
mysys_var->abort=1;
/*
@@ -1152,14 +1266,19 @@ void THD::awake(THD::killed_state state_to_set)
we issue a second KILL or the status it's waiting for happens).
It's true that we have set its thd->killed but it may not
see it immediately and so may have time to reach the cond_wait().
+
+ However, where possible, we test for killed once again after
+ enter_cond(). This should make the signaling as safe as possible.
+ However, there is still a small chance of failure on platforms with
+ instruction or memory write reordering.
*/
if (mysys_var->current_cond && mysys_var->current_mutex)
{
- pthread_mutex_lock(mysys_var->current_mutex);
- pthread_cond_broadcast(mysys_var->current_cond);
- pthread_mutex_unlock(mysys_var->current_mutex);
+ mysql_mutex_lock(mysys_var->current_mutex);
+ mysql_cond_broadcast(mysys_var->current_cond);
+ mysql_mutex_unlock(mysys_var->current_mutex);
}
- pthread_mutex_unlock(&mysys_var->mutex);
+ mysql_mutex_unlock(&mysys_var->mutex);
}
DBUG_VOID_RETURN;
}
@@ -1180,6 +1299,15 @@ bool THD::store_globals()
if (my_pthread_setspecific_ptr(THR_THD, this) ||
my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
return 1;
+ /*
+ mysys_var is concurrently readable by a killer thread.
+ It is protected by LOCK_thd_data, it is not needed to lock while the
+ pointer is changing from NULL not non-NULL. If the kill thread reads
+ NULL it doesn't refer to anything, but if it is non-NULL we need to
+ ensure that the thread doesn't proceed to assign another thread to
+ have the mysys_var reference (which in fact refers to the worker
+ threads local storage with key THR_KEY_mysys.
+ */
mysys_var=my_thread_var;
/*
Let mysqld define the thread id (not mysys)
@@ -1251,6 +1379,20 @@ void THD::cleanup_after_query()
}
+LEX_STRING *
+make_lex_string_root(MEM_ROOT *mem_root,
+ LEX_STRING *lex_str, const char* str, uint length,
+ bool allocate_lex_string)
+{
+ if (allocate_lex_string)
+ if (!(lex_str= (LEX_STRING *)alloc_root(mem_root, sizeof(LEX_STRING))))
+ return 0;
+ if (!(lex_str->str= strmake_root(mem_root, str, length)))
+ return 0;
+ lex_str->length= length;
+ return lex_str;
+}
+
/**
Create a LEX_STRING in this connection.
@@ -1265,13 +1407,8 @@ LEX_STRING *THD::make_lex_string(LEX_STRING *lex_str,
const char* str, uint length,
bool allocate_lex_string)
{
- if (allocate_lex_string)
- if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
- return 0;
- if (!(lex_str->str= strmake_root(mem_root, str, length)))
- return 0;
- lex_str->length= length;
- return lex_str;
+ return make_lex_string_root (mem_root, lex_str, str,
+ length, allocate_lex_string);
}
@@ -1352,15 +1489,21 @@ bool THD::convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs)
void THD::update_charset()
{
uint32 not_used;
- charset_is_system_charset= !String::needs_conversion(0,charset(),
- system_charset_info,
- &not_used);
+ charset_is_system_charset=
+ !String::needs_conversion(0,
+ variables.character_set_client,
+ system_charset_info,
+ &not_used);
charset_is_collation_connection=
- !String::needs_conversion(0,charset(),variables.collation_connection,
+ !String::needs_conversion(0,
+ variables.character_set_client,
+ variables.collation_connection,
&not_used);
charset_is_character_set_filesystem=
- !String::needs_conversion(0, charset(),
- variables.character_set_filesystem, &not_used);
+ !String::needs_conversion(0,
+ variables.character_set_client,
+ variables.character_set_filesystem,
+ &not_used);
}
@@ -1383,8 +1526,7 @@ void THD::add_changed_table(TABLE *table)
{
DBUG_ENTER("THD::add_changed_table(table)");
- DBUG_ASSERT((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
- table->file->has_transactions());
+ DBUG_ASSERT(in_multi_stmt_transaction_mode() && table->file->has_transactions());
add_changed_table(table->s->table_cache_key.str,
(long) table->s->table_cache_key.length);
DBUG_VOID_RETURN;
@@ -1494,15 +1636,15 @@ int THD::send_explain_fields(select_result *result)
}
item->maybe_null= 1;
field_list.push_back(new Item_empty_string("Extra", 255, cs));
- return (result->send_fields(field_list,
- Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
+ return (result->send_result_set_metadata(field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
}
#ifdef SIGNAL_WITH_VIO_CLOSE
void THD::close_active_vio()
{
DBUG_ENTER("close_active_vio");
- safe_mutex_assert_owner(&LOCK_thd_data);
+ mysql_mutex_assert_owner(&LOCK_thd_data);
#ifndef EMBEDDED_LIBRARY
if (active_vio)
{
@@ -1578,7 +1720,6 @@ void THD::rollback_item_tree_changes()
select_result::select_result()
{
thd=current_thd;
- nest_level= -1;
}
void select_result::send_error(uint errcode,const char *err)
@@ -1602,13 +1743,17 @@ bool select_result::check_simple_select() const
static String default_line_term("\n",default_charset_info);
static String default_escaped("\\",default_charset_info);
static String default_field_term("\t",default_charset_info);
+static String default_xml_row_term("<row>", default_charset_info);
-sql_exchange::sql_exchange(char *name,bool flag)
+sql_exchange::sql_exchange(char *name, bool flag,
+ enum enum_filetype filetype_arg)
:file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0)
{
+ filetype= filetype_arg;
field_term= &default_field_term;
enclosed= line_start= &my_empty_string;
- line_term= &default_line_term;
+ line_term= filetype == FILETYPE_CSV ?
+ &default_line_term : &default_xml_row_term;
escaped= &default_escaped;
cs= NULL;
}
@@ -1619,32 +1764,30 @@ bool sql_exchange::escaped_given(void)
}
-bool select_send::send_fields(List<Item> &list, uint flags)
+bool select_send::send_result_set_metadata(List<Item> &list, uint flags)
{
bool res;
- if (!(res= thd->protocol->send_fields(&list, flags)))
+ if (!(res= thd->protocol->send_result_set_metadata(&list, flags)))
is_result_set_started= 1;
return res;
}
-void select_send::abort()
+void select_send::abort_result_set()
{
- DBUG_ENTER("select_send::abort");
- if (is_result_set_started && thd->spcont &&
- thd->spcont->find_handler(thd, thd->main_da.sql_errno(),
- MYSQL_ERROR::WARN_LEVEL_ERROR))
+ DBUG_ENTER("select_send::abort_result_set");
+
+ if (is_result_set_started && thd->spcont)
{
/*
We're executing a stored procedure, have an open result
- set, an SQL exception condition and a handler for it.
- In this situation we must abort the current statement,
- silence the error and start executing the continue/exit
- handler.
+ set and an SQL exception condition. In this situation we
+ must abort the current statement, silence the error and
+ start executing the continue/exit handler if one is found.
Before aborting the statement, let's end the open result set, as
otherwise the client will hang due to the violation of the
client/server protocol.
*/
- thd->protocol->end_partial_result_set(thd);
+ thd->spcont->end_partial_result_set= TRUE;
}
DBUG_VOID_RETURN;
}
@@ -1665,10 +1808,13 @@ void select_send::cleanup()
bool select_send::send_data(List<Item> &items)
{
+ Protocol *protocol= thd->protocol;
+ DBUG_ENTER("select_send::send_data");
+
if (unit->offset_limit_cnt)
{ // using limit offset,count
unit->offset_limit_cnt--;
- return 0;
+ DBUG_RETURN(FALSE);
}
/*
@@ -1678,36 +1824,18 @@ bool select_send::send_data(List<Item> &items)
*/
ha_release_temporary_latches(thd);
- List_iterator_fast<Item> li(items);
- Protocol *protocol= thd->protocol;
- char buff[MAX_FIELD_WIDTH];
- String buffer(buff, sizeof(buff), &my_charset_bin);
- DBUG_ENTER("select_send::send_data");
-
protocol->prepare_for_resend();
- Item *item;
- while ((item=li++))
- {
- if (item->send(protocol, &buffer))
- {
- protocol->free(); // Free used buffer
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
- break;
- }
- /*
- Reset buffer to its original state, as it may have been altered in
- Item::send().
- */
- buffer.set(buff, sizeof(buff), &my_charset_bin);
- }
- thd->sent_row_count++;
- if (thd->is_error())
+ if (protocol->send_result_set_row(&items))
{
protocol->remove_last_row();
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
+
+ thd->sent_row_count++;
+
if (thd->vio_ok())
DBUG_RETURN(protocol->write());
+
DBUG_RETURN(0);
}
@@ -1720,12 +1848,6 @@ bool select_send::send_eof()
*/
ha_release_temporary_latches(thd);
- /* Unlock tables before sending packet to gain some speed */
- if (thd->lock)
- {
- mysql_unlock_tables(thd, thd->lock);
- thd->lock=0;
- }
/*
Don't send EOF if we're in error condition (which implies we've already
sent or are sending an error)
@@ -1748,8 +1870,9 @@ void select_to_file::send_error(uint errcode,const char *err)
if (file > 0)
{
(void) end_io_cache(&cache);
- (void) my_close(file,MYF(0));
- (void) my_delete(path,MYF(0)); // Delete file on error
+ mysql_file_close(file, MYF(0));
+ /* Delete file on error */
+ mysql_file_delete(key_select_to_file, path, MYF(0));
file= -1;
}
}
@@ -1758,15 +1881,11 @@ void select_to_file::send_error(uint errcode,const char *err)
bool select_to_file::send_eof()
{
int error= test(end_io_cache(&cache));
- if (my_close(file,MYF(MY_WME)))
- error= 1;
+ if (mysql_file_close(file, MYF(MY_WME)) || thd->is_error())
+ error= true;
+
if (!error)
{
- /*
- In order to remember the value of affected rows for ROW_COUNT()
- function, SELECT INTO has to have an own SQLCOM.
- TODO: split from SQLCOM_SELECT
- */
::my_ok(thd,row_count);
}
file= -1;
@@ -1780,7 +1899,7 @@ void select_to_file::cleanup()
if (file >= 0)
{
(void) end_io_cache(&cache);
- (void) my_close(file,MYF(0));
+ mysql_file_close(file, MYF(0));
file= -1;
}
path[0]= '\0';
@@ -1793,7 +1912,7 @@ select_to_file::~select_to_file()
if (file >= 0)
{ // This only happens in case of error
(void) end_io_cache(&cache);
- (void) my_close(file,MYF(0));
+ mysql_file_close(file, MYF(0));
file= -1;
}
}
@@ -1856,7 +1975,8 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange,
return -1;
}
/* Create the file world readable */
- if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
+ if ((file= mysql_file_create(key_select_to_file,
+ path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
return file;
#ifdef HAVE_FCHMOD
(void) fchmod(file, 0666); // Because of umask()
@@ -1865,8 +1985,9 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange,
#endif
if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
{
- my_close(file, MYF(0));
- my_delete(path, MYF(0)); // Delete file on error, it was just created
+ mysql_file_close(file, MYF(0));
+ /* Delete file on error, it was just created */
+ mysql_file_delete(key_select_to_file, path, MYF(0));
return -1;
}
return file;
@@ -2501,12 +2622,9 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
id(id_arg),
mark_used_columns(MARK_COLUMNS_READ),
lex(lex_arg),
- cursor(0),
db(NULL),
db_length(0)
{
- query_string.length= 0;
- query_string.str= NULL;
name.str= NULL;
}
@@ -2523,7 +2641,6 @@ void Statement::set_statement(Statement *stmt)
mark_used_columns= stmt->mark_used_columns;
lex= stmt->lex;
query_string= stmt->query_string;
- cursor= stmt->cursor;
}
@@ -2546,15 +2663,6 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
}
-/** Assign a new value to thd->query. */
-
-void Statement::set_query_inner(char *query_arg, uint32 query_length_arg)
-{
- query_string.str= query_arg;
- query_string.length= query_length_arg;
-}
-
-
void THD::end_statement()
{
/* Cleanup SQL processing state to reuse this statement in next query. */
@@ -2633,12 +2741,12 @@ Statement_map::Statement_map() :
START_STMT_HASH_SIZE = 16,
START_NAME_HASH_SIZE = 16
};
- hash_init(&st_hash, &my_charset_bin, START_STMT_HASH_SIZE, 0, 0,
- get_statement_id_as_hash_key,
- delete_statement_as_hash_key, MYF(0));
- hash_init(&names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0,
- (hash_get_key) get_stmt_name_hash_key,
- NULL,MYF(0));
+ my_hash_init(&st_hash, &my_charset_bin, START_STMT_HASH_SIZE, 0, 0,
+ get_statement_id_as_hash_key,
+ delete_statement_as_hash_key, MYF(0));
+ my_hash_init(&names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0,
+ (my_hash_get_key) get_stmt_name_hash_key,
+ NULL,MYF(0));
}
@@ -2680,7 +2788,7 @@ int Statement_map::insert(THD *thd, Statement *statement)
my_error(ER_OUT_OF_RESOURCES, MYF(0));
goto err_names_hash;
}
- pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ mysql_mutex_lock(&LOCK_prepared_stmt_count);
/*
We don't check that prepared_stmt_count is <= max_prepared_stmt_count
because we would like to allow to lower the total limit
@@ -2690,22 +2798,22 @@ int Statement_map::insert(THD *thd, Statement *statement)
*/
if (prepared_stmt_count >= max_prepared_stmt_count)
{
- pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+ mysql_mutex_unlock(&LOCK_prepared_stmt_count);
my_error(ER_MAX_PREPARED_STMT_COUNT_REACHED, MYF(0),
max_prepared_stmt_count);
goto err_max;
}
prepared_stmt_count++;
- pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+ mysql_mutex_unlock(&LOCK_prepared_stmt_count);
last_found_statement= statement;
return 0;
err_max:
if (statement->name.str)
- hash_delete(&names_hash, (uchar*) statement);
+ my_hash_delete(&names_hash, (uchar*) statement);
err_names_hash:
- hash_delete(&st_hash, (uchar*) statement);
+ my_hash_delete(&st_hash, (uchar*) statement);
err_st_hash:
return 1;
}
@@ -2726,23 +2834,23 @@ void Statement_map::erase(Statement *statement)
if (statement == last_found_statement)
last_found_statement= 0;
if (statement->name.str)
- hash_delete(&names_hash, (uchar *) statement);
+ my_hash_delete(&names_hash, (uchar *) statement);
- hash_delete(&st_hash, (uchar *) statement);
- pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ my_hash_delete(&st_hash, (uchar *) statement);
+ mysql_mutex_lock(&LOCK_prepared_stmt_count);
DBUG_ASSERT(prepared_stmt_count > 0);
prepared_stmt_count--;
- pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+ mysql_mutex_unlock(&LOCK_prepared_stmt_count);
}
void Statement_map::reset()
{
/* Must be first, hash_free will reset st_hash.records */
- pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ mysql_mutex_lock(&LOCK_prepared_stmt_count);
DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
prepared_stmt_count-= st_hash.records;
- pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+ mysql_mutex_unlock(&LOCK_prepared_stmt_count);
my_hash_reset(&names_hash);
my_hash_reset(&st_hash);
@@ -2753,13 +2861,13 @@ void Statement_map::reset()
Statement_map::~Statement_map()
{
/* Must go first, hash_free will reset st_hash.records */
- pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ mysql_mutex_lock(&LOCK_prepared_stmt_count);
DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
prepared_stmt_count-= st_hash.records;
- pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+ mysql_mutex_unlock(&LOCK_prepared_stmt_count);
- hash_free(&names_hash);
- hash_free(&st_hash);
+ my_hash_free(&names_hash);
+ my_hash_free(&st_hash);
}
bool select_dumpvar::send_data(List<Item> &items)
@@ -2806,10 +2914,12 @@ bool select_dumpvar::send_eof()
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
/*
- In order to remember the value of affected rows for ROW_COUNT()
- function, SELECT INTO has to have an own SQLCOM.
- TODO: split from SQLCOM_SELECT
+ Don't send EOF if we're in error condition (which implies we've already
+ sent or are sending an error)
*/
+ if (thd->is_error())
+ return true;
+
::my_ok(thd,row_count);
return 0;
}
@@ -2861,9 +2971,9 @@ void THD::set_status_var_init()
void Security_context::init()
{
- host= user= priv_user= ip= 0;
+ host= user= ip= external_user= 0;
host_or_ip= "connecting host";
- priv_host[0]= '\0';
+ priv_user[0]= priv_host[0]= '\0';
master_access= 0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
db_access= NO_ACCESS;
@@ -2875,10 +2985,24 @@ void Security_context::destroy()
{
// If not pointer to constant
if (host != my_localhost)
- safeFree(host);
+ {
+ my_free(host);
+ host= NULL;
+ }
if (user != delayed_user)
- safeFree(user);
- safeFree(ip);
+ {
+ my_free(user);
+ user= NULL;
+ }
+
+ if (external_user)
+ {
+ my_free(external_user);
+ user= NULL;
+ }
+
+ my_free(ip);
+ ip= NULL;
}
@@ -2887,14 +3011,13 @@ void Security_context::skip_grants()
/* privileges for the user are unknown everything is allowed */
host_or_ip= (char *)"";
master_access= ~NO_ACCESS;
- priv_user= (char *)"";
- *priv_host= '\0';
+ *priv_user= *priv_host= '\0';
}
bool Security_context::set_user(char *user_arg)
{
- safeFree(user);
+ my_free(user);
user= my_strdup(user_arg, MYF(0));
return user == 0;
}
@@ -2930,7 +3053,7 @@ bool Security_context::set_user(char *user_arg)
of a statement under credentials of a different user, e.g.
definer of a procedure, we authenticate this user in a local
instance of Security_context by means of this method (and
- ultimately by means of acl_getroot_no_password), and make the
+ ultimately by means of acl_getroot), and make the
local instance active in the thread by re-setting
thd->security_ctx pointer.
@@ -2964,19 +3087,12 @@ change_security_context(THD *thd,
DBUG_ASSERT(definer_user->str && definer_host->str);
*backup= NULL;
- /*
- The current security context may have NULL members
- if we have just started the thread and not authenticated
- any user. This use case is currently in events worker thread.
- */
- needs_change= (thd->security_ctx->priv_user == NULL ||
- strcmp(definer_user->str, thd->security_ctx->priv_user) ||
- thd->security_ctx->priv_host == NULL ||
+ needs_change= (strcmp(definer_user->str, thd->security_ctx->priv_user) ||
my_strcasecmp(system_charset_info, definer_host->str,
thd->security_ctx->priv_host));
if (needs_change)
{
- if (acl_getroot_no_password(this, definer_user->str, definer_host->str,
+ if (acl_getroot(this, definer_user->str, definer_host->str,
definer_host->str, db->str))
{
my_error(ER_NO_SUCH_USER, MYF(0), definer_user->str,
@@ -3016,28 +3132,31 @@ bool Security_context::user_matches(Security_context *them)
access to mysql.proc table to find definitions of stored routines.
****************************************************************************/
-void THD::reset_n_backup_open_tables_state(Open_tables_state *backup)
+void THD::reset_n_backup_open_tables_state(Open_tables_backup *backup)
{
DBUG_ENTER("reset_n_backup_open_tables_state");
backup->set_open_tables_state(this);
- reset_open_tables_state();
+ backup->mdl_system_tables_svp= mdl_context.mdl_savepoint();
+ reset_open_tables_state(this);
state_flags|= Open_tables_state::BACKUPS_AVAIL;
DBUG_VOID_RETURN;
}
-void THD::restore_backup_open_tables_state(Open_tables_state *backup)
+void THD::restore_backup_open_tables_state(Open_tables_backup *backup)
{
DBUG_ENTER("restore_backup_open_tables_state");
+ mdl_context.rollback_to_savepoint(backup->mdl_system_tables_svp);
/*
Before we will throw away current open tables state we want
to be sure that it was properly cleaned up.
*/
DBUG_ASSERT(open_tables == 0 && temporary_tables == 0 &&
- handler_tables == 0 && derived_tables == 0 &&
- lock == 0 && locked_tables == 0 &&
- prelocked_mode == NON_PRELOCKED &&
+ derived_tables == 0 &&
+ lock == 0 &&
+ locked_tables_mode == LTM_NONE &&
m_reprepare_observer == NULL);
+
set_open_tables_state(backup);
DBUG_VOID_RETURN;
}
@@ -3076,7 +3195,7 @@ extern "C" struct charset_info_st *thd_charset(MYSQL_THD thd)
*/
extern "C" char **thd_query(MYSQL_THD thd)
{
- return(&thd->query_string.str);
+ return (&thd->query_string.string.str);
}
/**
@@ -3087,7 +3206,7 @@ extern "C" char **thd_query(MYSQL_THD thd)
*/
extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd)
{
- return(&thd->query_string);
+ return(&thd->query_string.string);
}
extern "C" int thd_slave_thread(const MYSQL_THD thd)
@@ -3102,7 +3221,7 @@ extern "C" int thd_non_transactional_update(const MYSQL_THD thd)
extern "C" int thd_binlog_format(const MYSQL_THD thd)
{
- if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG))
+ if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
return (int) thd->variables.binlog_format;
else
return BINLOG_FORMAT_UNSPEC;
@@ -3117,6 +3236,65 @@ extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd)
{
return binlog_filter->db_ok(thd->db);
}
+
+extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd)
+{
+ return sqlcom_can_generate_row_events(thd);
+}
+
+#ifndef EMBEDDED_LIBRARY
+extern "C" void thd_pool_wait_begin(MYSQL_THD thd, int wait_type);
+extern "C" void thd_pool_wait_end(MYSQL_THD thd);
+
+/*
+ Interface for MySQL Server, plugins and storage engines to report
+ when they are going to sleep/stall.
+
+ SYNOPSIS
+ thd_wait_begin()
+ thd Thread object
+ wait_type Type of wait
+ 1 -- short wait (e.g. for mutex)
+ 2 -- medium wait (e.g. for disk io)
+ 3 -- large wait (e.g. for locked row/table)
+ NOTES
+ This is used by the threadpool to have better knowledge of which
+ threads that currently are actively running on CPUs. When a thread
+ reports that it's going to sleep/stall, the threadpool scheduler is
+ free to start another thread in the pool most likely. The expected wait
+ time is simply an indication of how long the wait is expected to
+ become, the real wait time could be very different.
+
+ thd_wait_end MUST be called immediately after waking up again.
+*/
+extern "C" void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type)
+{
+ MYSQL_CALLBACK(thread_scheduler, thd_wait_begin, (thd, wait_type));
+}
+
+/**
+ Interface for MySQL Server, plugins and storage engines to report
+ when they waking up from a sleep/stall.
+
+ @param thd Thread handle
+*/
+extern "C" void thd_wait_end(MYSQL_THD thd)
+{
+ MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (thd));
+}
+#else
+extern "C" void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type)
+{
+ /* do NOTHING for the embedded library */
+ return;
+}
+
+extern "C" void thd_wait_end(MYSQL_THD thd)
+{
+ /* do NOTHING for the embedded library */
+ return;
+}
+#endif
#endif // INNODB_COMPATIBILITY_HOOKS */
/****************************************************************************
@@ -3163,8 +3341,8 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
}
#endif
+ backup->option_bits= variables.option_bits;
backup->count_cuted_fields= count_cuted_fields;
- backup->options= options;
backup->in_sub_stmt= in_sub_stmt;
backup->enable_slow_log= enable_slow_log;
backup->limit_found_rows= limit_found_rows;
@@ -3179,13 +3357,14 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
first_successful_insert_id_in_cur_stmt;
if ((!lex->requires_prelocking() || is_update_query(lex->sql_command)) &&
- !current_stmt_binlog_row_based)
+ !is_current_stmt_binlog_format_row())
{
- options&= ~OPTION_BIN_LOG;
+ variables.option_bits&= ~OPTION_BIN_LOG;
}
- if ((backup->options & OPTION_BIN_LOG) && is_update_query(lex->sql_command)&&
- !current_stmt_binlog_row_based)
+ if ((backup->option_bits & OPTION_BIN_LOG) &&
+ is_update_query(lex->sql_command) &&
+ !is_current_stmt_binlog_format_row())
mysql_bin_log.start_union_events(this, this->query_id);
/* Disable result sets */
@@ -3230,7 +3409,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
}
count_cuted_fields= backup->count_cuted_fields;
transaction.savepoints= backup->savepoints;
- options= backup->options;
+ variables.option_bits= backup->option_bits;
in_sub_stmt= backup->in_sub_stmt;
enable_slow_log= backup->enable_slow_log;
first_successful_insert_id_in_prev_stmt=
@@ -3248,8 +3427,8 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
if (!in_sub_stmt)
is_fatal_sub_stmt_error= FALSE;
- if ((options & OPTION_BIN_LOG) && is_update_query(lex->sql_command) &&
- !current_stmt_binlog_row_based)
+ if ((variables.option_bits & OPTION_BIN_LOG) && is_update_query(lex->sql_command) &&
+ !is_current_stmt_binlog_format_row())
mysql_bin_log.stop_union_events(this);
/*
@@ -3264,19 +3443,67 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
void THD::set_statement(Statement *stmt)
{
- pthread_mutex_lock(&LOCK_thd_data);
+ mysql_mutex_lock(&LOCK_thd_data);
Statement::set_statement(stmt);
- pthread_mutex_unlock(&LOCK_thd_data);
+ mysql_mutex_unlock(&LOCK_thd_data);
}
/** Assign a new value to thd->query. */
-void THD::set_query(char *query_arg, uint32 query_length_arg)
+void THD::set_query(const CSET_STRING &string_arg)
+{
+ mysql_mutex_lock(&LOCK_thd_data);
+ set_query_inner(string_arg);
+ mysql_mutex_unlock(&LOCK_thd_data);
+}
+
+/** Assign a new value to thd->query and thd->query_id. */
+
+void THD::set_query_and_id(char *query_arg, uint32 query_length_arg,
+ CHARSET_INFO *cs,
+ query_id_t new_query_id)
{
- pthread_mutex_lock(&LOCK_thd_data);
- set_query_inner(query_arg, query_length_arg);
- pthread_mutex_unlock(&LOCK_thd_data);
+ mysql_mutex_lock(&LOCK_thd_data);
+ set_query_inner(query_arg, query_length_arg, cs);
+ query_id= new_query_id;
+ mysql_mutex_unlock(&LOCK_thd_data);
+}
+
+/** Assign a new value to thd->query_id. */
+
+void THD::set_query_id(query_id_t new_query_id)
+{
+ mysql_mutex_lock(&LOCK_thd_data);
+ query_id= new_query_id;
+ mysql_mutex_unlock(&LOCK_thd_data);
+}
+
+/** Assign a new value to thd->mysys_var. */
+void THD::set_mysys_var(struct st_my_thread_var *new_mysys_var)
+{
+ mysql_mutex_lock(&LOCK_thd_data);
+ mysys_var= new_mysys_var;
+ mysql_mutex_unlock(&LOCK_thd_data);
+}
+
+/**
+ Leave explicit LOCK TABLES or prelocked mode and restore value of
+ transaction sentinel in MDL subsystem.
+*/
+
+void THD::leave_locked_tables_mode()
+{
+ locked_tables_mode= LTM_NONE;
+ mdl_context.set_transaction_duration_for_all_locks();
+ /*
+ Make sure we don't release the global read lock and commit blocker
+ when leaving LTM.
+ */
+ global_read_lock.set_explicit_lock_duration(this);
+ /* Also ensure that we don't release metadata locks for open HANDLERs. */
+ if (handler_tables_hash.records)
+ mysql_ha_set_explicit_lock_duration(this);
}
void THD::get_definer(LEX_USER *definer)
@@ -3289,6 +3516,10 @@ void THD::get_definer(LEX_USER *definer)
definer->host= invoker_host;
definer->password.str= NULL;
definer->password.length= 0;
+ definer->plugin.str= (char *) "";
+ definer->plugin.length= 0;
+ definer->auth.str= (char *) "";
+ definer->auth.length= 0;
}
else
#endif
@@ -3325,7 +3556,7 @@ void mark_transaction_to_rollback(THD *thd, bool all)
Handling of XA id cacheing
***************************************************************************/
-pthread_mutex_t LOCK_xid_cache;
+mysql_mutex_t LOCK_xid_cache;
HASH xid_cache;
extern "C" uchar *xid_get_hash_key(const uchar *, size_t *, my_bool);
@@ -3341,30 +3572,56 @@ uchar *xid_get_hash_key(const uchar *ptr, size_t *length,
void xid_free_hash(void *ptr)
{
if (!((XID_STATE*)ptr)->in_thd)
- my_free((uchar*)ptr, MYF(0));
+ my_free(ptr);
+}
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_LOCK_xid_cache;
+
+static PSI_mutex_info all_xid_mutexes[]=
+{
+ { &key_LOCK_xid_cache, "LOCK_xid_cache", PSI_FLAG_GLOBAL}
+};
+
+static void init_xid_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_xid_mutexes);
+ PSI_server->register_mutex(category, all_xid_mutexes, count);
}
+#endif /* HAVE_PSI_INTERFACE */
bool xid_cache_init()
{
- pthread_mutex_init(&LOCK_xid_cache, MY_MUTEX_INIT_FAST);
- return hash_init(&xid_cache, &my_charset_bin, 100, 0, 0,
- xid_get_hash_key, xid_free_hash, 0) != 0;
+#ifdef HAVE_PSI_INTERFACE
+ init_xid_psi_keys();
+#endif
+
+ mysql_mutex_init(key_LOCK_xid_cache, &LOCK_xid_cache, MY_MUTEX_INIT_FAST);
+ return my_hash_init(&xid_cache, &my_charset_bin, 100, 0, 0,
+ xid_get_hash_key, xid_free_hash, 0) != 0;
}
void xid_cache_free()
{
- if (hash_inited(&xid_cache))
+ if (my_hash_inited(&xid_cache))
{
- hash_free(&xid_cache);
- pthread_mutex_destroy(&LOCK_xid_cache);
+ my_hash_free(&xid_cache);
+ mysql_mutex_destroy(&LOCK_xid_cache);
}
}
XID_STATE *xid_cache_search(XID *xid)
{
- pthread_mutex_lock(&LOCK_xid_cache);
- XID_STATE *res=(XID_STATE *)hash_search(&xid_cache, xid->key(), xid->key_length());
- pthread_mutex_unlock(&LOCK_xid_cache);
+ mysql_mutex_lock(&LOCK_xid_cache);
+ XID_STATE *res=(XID_STATE *)my_hash_search(&xid_cache, xid->key(),
+ xid->key_length());
+ mysql_mutex_unlock(&LOCK_xid_cache);
return res;
}
@@ -3373,8 +3630,8 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state)
{
XID_STATE *xs;
my_bool res;
- pthread_mutex_lock(&LOCK_xid_cache);
- if (hash_search(&xid_cache, xid->key(), xid->key_length()))
+ mysql_mutex_lock(&LOCK_xid_cache);
+ if (my_hash_search(&xid_cache, xid->key(), xid->key_length()))
res=0;
else if (!(xs=(XID_STATE *)my_malloc(sizeof(*xs), MYF(MY_WME))))
res=1;
@@ -3385,33 +3642,409 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state)
xs->in_thd=0;
res=my_hash_insert(&xid_cache, (uchar*)xs);
}
- pthread_mutex_unlock(&LOCK_xid_cache);
+ mysql_mutex_unlock(&LOCK_xid_cache);
return res;
}
bool xid_cache_insert(XID_STATE *xid_state)
{
- pthread_mutex_lock(&LOCK_xid_cache);
- if (hash_search(&xid_cache, xid_state->xid.key(), xid_state->xid.key_length()))
- {
- pthread_mutex_unlock(&LOCK_xid_cache);
- my_error(ER_XAER_DUPID, MYF(0));
- return TRUE;
- }
- my_bool res= my_hash_insert(&xid_cache, (uchar*)xid_state);
- pthread_mutex_unlock(&LOCK_xid_cache);
+ mysql_mutex_lock(&LOCK_xid_cache);
+ DBUG_ASSERT(my_hash_search(&xid_cache, xid_state->xid.key(),
+ xid_state->xid.key_length())==0);
+ my_bool res=my_hash_insert(&xid_cache, (uchar*)xid_state);
+ mysql_mutex_unlock(&LOCK_xid_cache);
return res;
}
void xid_cache_delete(XID_STATE *xid_state)
{
- pthread_mutex_lock(&LOCK_xid_cache);
- hash_delete(&xid_cache, (uchar *)xid_state);
- pthread_mutex_unlock(&LOCK_xid_cache);
+ mysql_mutex_lock(&LOCK_xid_cache);
+ my_hash_delete(&xid_cache, (uchar *)xid_state);
+ mysql_mutex_unlock(&LOCK_xid_cache);
}
+
+/**
+ Decide on logging format to use for the statement and issue errors
+ or warnings as needed. The decision depends on the following
+ parameters:
+
+ - The logging mode, i.e., the value of binlog_format. Can be
+ statement, mixed, or row.
+
+ - The type of statement. There are three types of statements:
+ "normal" safe statements; unsafe statements; and row injections.
+ An unsafe statement is one that, if logged in statement format,
+ might produce different results when replayed on the slave (e.g.,
+ INSERT DELAYED). A row injection is either a BINLOG statement, or
+ a row event executed by the slave's SQL thread.
+
+ - The capabilities of tables modified by the statement. The
+ *capabilities vector* for a table is a set of flags associated
+ with the table. Currently, it only includes two flags: *row
+ capability flag* and *statement capability flag*.
+
+ The row capability flag is set if and only if the engine can
+ handle row-based logging. The statement capability flag is set if
+ and only if the table can handle statement-based logging.
+
+ Decision table for logging format
+ ---------------------------------
+
+ The following table summarizes how the format and generated
+ warning/error depends on the tables' capabilities, the statement
+ type, and the current binlog_format.
+
+ Row capable N NNNNNNNNN YYYYYYYYY YYYYYYYYY
+ Statement capable N YYYYYYYYY NNNNNNNNN YYYYYYYYY
+
+ Statement type * SSSUUUIII SSSUUUIII SSSUUUIII
+
+ binlog_format * SMRSMRSMR SMRSMRSMR SMRSMRSMR
+
+ Logged format - SS-S----- -RR-RR-RR SRRSRR-RR
+ Warning/Error 1 --2732444 5--5--6-- ---7--6--
+
+ Legend
+ ------
+
+ Row capable: N - Some table not row-capable, Y - All tables row-capable
+ Stmt capable: N - Some table not stmt-capable, Y - All tables stmt-capable
+ Statement type: (S)afe, (U)nsafe, or Row (I)njection
+ binlog_format: (S)TATEMENT, (M)IXED, or (R)OW
+ Logged format: (S)tatement or (R)ow
+ Warning/Error: Warnings and error messages are as follows:
+
+ 1. Error: Cannot execute statement: binlogging impossible since both
+ row-incapable engines and statement-incapable engines are
+ involved.
+
+ 2. Error: Cannot execute statement: binlogging impossible since
+ BINLOG_FORMAT = ROW and at least one table uses a storage engine
+ limited to statement-logging.
+
+ 3. Error: Cannot execute statement: binlogging of unsafe statement
+ is impossible when storage engine is limited to statement-logging
+ and BINLOG_FORMAT = MIXED.
+
+ 4. Error: Cannot execute row injection: binlogging impossible since
+ at least one table uses a storage engine limited to
+ statement-logging.
+
+ 5. Error: Cannot execute statement: binlogging impossible since
+ BINLOG_FORMAT = STATEMENT and at least one table uses a storage
+ engine limited to row-logging.
+
+ 6. Error: Cannot execute row injection: binlogging impossible since
+ BINLOG_FORMAT = STATEMENT.
+
+ 7. Warning: Unsafe statement binlogged in statement format since
+ BINLOG_FORMAT = STATEMENT.
+
+ In addition, we can produce the following error (not depending on
+ the variables of the decision diagram):
+
+ 8. Error: Cannot execute statement: binlogging impossible since more
+ than one engine is involved and at least one engine is
+ self-logging.
+
+ For each error case above, the statement is prevented from being
+ logged, we report an error, and roll back the statement. For
+ warnings, we set the thd->binlog_flags variable: the warning will be
+ printed only if the statement is successfully logged.
+
+ @see THD::binlog_query
+
+ @param[in] thd Client thread
+ @param[in] tables Tables involved in the query
+
+ @retval 0 No error; statement can be logged.
+ @retval -1 One of the error conditions above applies (1, 2, 4, 5, or 6).
+*/
+
+int THD::decide_logging_format(TABLE_LIST *tables)
+{
+ DBUG_ENTER("THD::decide_logging_format");
+ DBUG_PRINT("info", ("query: %s", query()));
+ DBUG_PRINT("info", ("variables.binlog_format: %lu",
+ variables.binlog_format));
+ DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
+ lex->get_stmt_unsafe_flags()));
+
+ /*
+ We should not decide logging format if the binlog is closed or
+ binlogging is off, or if the statement is filtered out from the
+ binlog by filtering rules.
+ */
+ if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) &&
+ !(variables.binlog_format == BINLOG_FORMAT_STMT &&
+ !binlog_filter->db_ok(db)))
+ {
+ /*
+ Compute one bit field with the union of all the engine
+ capabilities, and one with the intersection of all the engine
+ capabilities.
+ */
+ handler::Table_flags flags_write_some_set= 0;
+ handler::Table_flags flags_access_some_set= 0;
+ handler::Table_flags flags_write_all_set=
+ HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
+
+ /*
+ If different types of engines are about to be updated.
+ For example: Innodb and Falcon; Innodb and MyIsam.
+ */
+ my_bool multi_write_engine= FALSE;
+ /*
+ If different types of engines are about to be accessed
+ and any of them is about to be updated. For example:
+ Innodb and Falcon; Innodb and MyIsam.
+ */
+ my_bool multi_access_engine= FALSE;
+ /*
+ Identifies if a table is changed.
+ */
+ my_bool is_write= FALSE;
+ /*
+ A pointer to a previous table that was changed.
+ */
+ TABLE* prev_write_table= NULL;
+ /*
+ A pointer to a previous table that was accessed.
+ */
+ TABLE* prev_access_table= NULL;
+
+#ifndef DBUG_OFF
+ {
+ static const char *prelocked_mode_name[] = {
+ "NON_PRELOCKED",
+ "PRELOCKED",
+ "PRELOCKED_UNDER_LOCK_TABLES",
+ };
+ DBUG_PRINT("debug", ("prelocked_mode: %s",
+ prelocked_mode_name[locked_tables_mode]));
+ }
+#endif
+
+ /*
+ Get the capabilities vector for all involved storage engines and
+ mask out the flags for the binary log.
+ */
+ for (TABLE_LIST *table= tables; table; table= table->next_global)
+ {
+ if (table->placeholder())
+ continue;
+
+ if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE ||
+ table->table->s->table_category == TABLE_CATEGORY_LOG)
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
+
+ handler::Table_flags const flags= table->table->file->ha_table_flags();
+
+ DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
+ table->table_name, flags));
+ if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ if (prev_write_table && prev_write_table->file->ht !=
+ table->table->file->ht)
+ multi_write_engine= TRUE;
+
+ my_bool trans= table->table->file->has_transactions();
+
+ if (table->table->s->tmp_table)
+ lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TEMP_TRANS_TABLE :
+ LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE);
+ else
+ lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TRANS_TABLE :
+ LEX::STMT_WRITES_NON_TRANS_TABLE);
+
+ flags_write_all_set &= flags;
+ flags_write_some_set |= flags;
+ is_write= TRUE;
+
+ prev_write_table= table->table;
+
+ }
+ flags_access_some_set |= flags;
+
+ if (lex->sql_command != SQLCOM_CREATE_TABLE ||
+ (lex->sql_command == SQLCOM_CREATE_TABLE &&
+ (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)))
+ {
+ my_bool trans= table->table->file->has_transactions();
+
+ if (table->table->s->tmp_table)
+ lex->set_stmt_accessed_table(trans ? LEX::STMT_READS_TEMP_TRANS_TABLE :
+ LEX::STMT_READS_TEMP_NON_TRANS_TABLE);
+ else
+ lex->set_stmt_accessed_table(trans ? LEX::STMT_READS_TRANS_TABLE :
+ LEX::STMT_READS_NON_TRANS_TABLE);
+ }
+
+ if (prev_access_table && prev_access_table->file->ht !=
+ table->table->file->ht)
+ multi_access_engine= TRUE;
+
+ prev_access_table= table->table;
+ }
+
+ DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
+ DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set));
+ DBUG_PRINT("info", ("flags_access_some_set: 0x%llx", flags_access_some_set));
+ DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
+ DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
+
+ int error= 0;
+ int unsafe_flags;
+
+ bool multi_stmt_trans= in_multi_stmt_transaction_mode();
+ bool trans_table= trans_has_updated_trans_table(this);
+ bool binlog_direct= variables.binlog_direct_non_trans_update;
+
+ if (lex->is_mixed_stmt_unsafe(multi_stmt_trans, binlog_direct,
+ trans_table, tx_isolation))
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
+ else if (multi_stmt_trans && trans_table && !binlog_direct &&
+ lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE))
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS);
+
+ /*
+ If more than one engine is involved in the statement and at
+ least one is doing it's own logging (is *self-logging*), the
+ statement cannot be logged atomically, so we generate an error
+ rather than allowing the binlog to become corrupt.
+ */
+ if (multi_write_engine &&
+ (flags_write_some_set & HA_HAS_OWN_BINLOGGING))
+ my_error((error= ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE),
+ MYF(0));
+ else if (multi_access_engine && flags_access_some_set & HA_HAS_OWN_BINLOGGING)
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE);
+
+ /* both statement-only and row-only engines involved */
+ if ((flags_write_all_set & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE)) == 0)
+ {
+ /*
+ 1. Error: Binary logging impossible since both row-incapable
+ engines and statement-incapable engines are involved
+ */
+ my_error((error= ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE), MYF(0));
+ }
+ /* statement-only engines involved */
+ else if ((flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
+ {
+ if (lex->is_stmt_row_injection())
+ {
+ /*
+ 4. Error: Cannot execute row injection since table uses
+ storage engine limited to statement-logging
+ */
+ my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
+ }
+ else if (variables.binlog_format == BINLOG_FORMAT_ROW &&
+ sqlcom_can_generate_row_events(this))
+ {
+ /*
+ 2. Error: Cannot modify table that uses a storage engine
+ limited to statement-logging when BINLOG_FORMAT = ROW
+ */
+ my_error((error= ER_BINLOG_ROW_MODE_AND_STMT_ENGINE), MYF(0));
+ }
+ else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
+ {
+ /*
+ 3. Error: Cannot execute statement: binlogging of unsafe
+ statement is impossible when storage engine is limited to
+ statement-logging and BINLOG_FORMAT = MIXED.
+ */
+ for (int unsafe_type= 0;
+ unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
+ unsafe_type++)
+ if (unsafe_flags & (1 << unsafe_type))
+ my_error((error= ER_BINLOG_UNSAFE_AND_STMT_ENGINE), MYF(0),
+ ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
+ }
+ /* log in statement format! */
+ }
+ /* no statement-only engines */
+ else
+ {
+ /* binlog_format = STATEMENT */
+ if (variables.binlog_format == BINLOG_FORMAT_STMT)
+ {
+ if (lex->is_stmt_row_injection())
+ {
+ /*
+ 6. Error: Cannot execute row injection since
+ BINLOG_FORMAT = STATEMENT
+ */
+ my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
+ }
+ else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0 &&
+ sqlcom_can_generate_row_events(this))
+ {
+ /*
+ 5. Error: Cannot modify table that uses a storage engine
+ limited to row-logging when binlog_format = STATEMENT
+ */
+ my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
+ }
+ else if (is_write && (unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
+ {
+ /*
+ 7. Warning: Unsafe statement logged as statement due to
+ binlog_format = STATEMENT
+ */
+ binlog_unsafe_warning_flags|= unsafe_flags;
+
+ DBUG_PRINT("info", ("Scheduling warning to be issued by "
+ "binlog_query: '%s'",
+ ER(ER_BINLOG_UNSAFE_STATEMENT)));
+ DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
+ binlog_unsafe_warning_flags));
+ }
+ /* log in statement format! */
+ }
+ /* No statement-only engines and binlog_format != STATEMENT.
+ I.e., nothing prevents us from row logging if needed. */
+ else
+ {
+ if (lex->is_stmt_unsafe() || lex->is_stmt_row_injection()
+ || (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
+ {
+ /* log in row format! */
+ set_current_stmt_binlog_format_row_if_mixed();
+ }
+ }
+ }
+
+ if (error) {
+ DBUG_PRINT("info", ("decision: no logging since an error was generated"));
+ DBUG_RETURN(-1);
+ }
+ DBUG_PRINT("info", ("decision: logging in %s format",
+ is_current_stmt_binlog_format_row() ?
+ "ROW" : "STATEMENT"));
+ }
+#ifndef DBUG_OFF
+ else
+ DBUG_PRINT("info", ("decision: no logging since "
+ "mysql_bin_log.is_open() = %d "
+ "and (options & OPTION_BIN_LOG) = 0x%llx "
+ "and binlog_format = %lu "
+ "and binlog_filter->db_ok(db) = %d",
+ mysql_bin_log.is_open(),
+ (variables.option_bits & OPTION_BIN_LOG),
+ variables.binlog_format,
+ binlog_filter->db_ok(db)));
+#endif
+
+ DBUG_RETURN(0);
+}
+
+
/*
Implementation of interface to write rows to the binary log through the
thread. The thread is responsible for writing the rows it has
@@ -3463,7 +4096,7 @@ THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
if (binlog_setup_trx_data())
DBUG_RETURN(NULL);
- Rows_log_event* pending= binlog_get_pending_rows_event();
+ Rows_log_event* pending= binlog_get_pending_rows_event(is_transactional);
if (unlikely(pending && !pending->is_valid()))
DBUG_RETURN(NULL);
@@ -3497,7 +4130,9 @@ THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
flush the pending event and replace it with the newly created
event...
*/
- if (unlikely(mysql_bin_log.flush_and_set_pending_rows_event(this, ev)))
+ if (unlikely(
+ mysql_bin_log.flush_and_set_pending_rows_event(this, ev,
+ is_transactional)))
{
delete ev;
DBUG_RETURN(NULL);
@@ -3529,72 +4164,9 @@ THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
Update_rows_log_event *);
#endif
-#ifdef NOT_USED
-static char const*
-field_type_name(enum_field_types type)
-{
- switch (type) {
- case MYSQL_TYPE_DECIMAL:
- return "MYSQL_TYPE_DECIMAL";
- case MYSQL_TYPE_TINY:
- return "MYSQL_TYPE_TINY";
- case MYSQL_TYPE_SHORT:
- return "MYSQL_TYPE_SHORT";
- case MYSQL_TYPE_LONG:
- return "MYSQL_TYPE_LONG";
- case MYSQL_TYPE_FLOAT:
- return "MYSQL_TYPE_FLOAT";
- case MYSQL_TYPE_DOUBLE:
- return "MYSQL_TYPE_DOUBLE";
- case MYSQL_TYPE_NULL:
- return "MYSQL_TYPE_NULL";
- case MYSQL_TYPE_TIMESTAMP:
- return "MYSQL_TYPE_TIMESTAMP";
- case MYSQL_TYPE_LONGLONG:
- return "MYSQL_TYPE_LONGLONG";
- case MYSQL_TYPE_INT24:
- return "MYSQL_TYPE_INT24";
- case MYSQL_TYPE_DATE:
- return "MYSQL_TYPE_DATE";
- case MYSQL_TYPE_TIME:
- return "MYSQL_TYPE_TIME";
- case MYSQL_TYPE_DATETIME:
- return "MYSQL_TYPE_DATETIME";
- case MYSQL_TYPE_YEAR:
- return "MYSQL_TYPE_YEAR";
- case MYSQL_TYPE_NEWDATE:
- return "MYSQL_TYPE_NEWDATE";
- case MYSQL_TYPE_VARCHAR:
- return "MYSQL_TYPE_VARCHAR";
- case MYSQL_TYPE_BIT:
- return "MYSQL_TYPE_BIT";
- case MYSQL_TYPE_NEWDECIMAL:
- return "MYSQL_TYPE_NEWDECIMAL";
- case MYSQL_TYPE_ENUM:
- return "MYSQL_TYPE_ENUM";
- case MYSQL_TYPE_SET:
- return "MYSQL_TYPE_SET";
- case MYSQL_TYPE_TINY_BLOB:
- return "MYSQL_TYPE_TINY_BLOB";
- case MYSQL_TYPE_MEDIUM_BLOB:
- return "MYSQL_TYPE_MEDIUM_BLOB";
- case MYSQL_TYPE_LONG_BLOB:
- return "MYSQL_TYPE_LONG_BLOB";
- case MYSQL_TYPE_BLOB:
- return "MYSQL_TYPE_BLOB";
- case MYSQL_TYPE_VAR_STRING:
- return "MYSQL_TYPE_VAR_STRING";
- case MYSQL_TYPE_STRING:
- return "MYSQL_TYPE_STRING";
- case MYSQL_TYPE_GEOMETRY:
- return "MYSQL_TYPE_GEOMETRY";
- }
- return "Unknown";
-}
-#endif
-
+/* Declare in unnamed namespace. */
+CPP_UNNAMED_NS_START
-namespace {
/**
Class to handle temporary allocation of memory for row data.
@@ -3647,7 +4219,7 @@ namespace {
~Row_data_memory()
{
if (m_memory != 0 && m_release_memory_on_destruction)
- my_free((uchar*) m_memory, MYF(MY_WME));
+ my_free(m_memory);
}
/**
@@ -3713,14 +4285,14 @@ namespace {
uchar *m_memory;
uchar *m_ptr[2];
};
-}
+CPP_UNNAMED_NS_END
int THD::binlog_write_row(TABLE* table, bool is_trans,
MY_BITMAP const* cols, size_t colcnt,
uchar const *record)
{
- DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
+ DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
/*
Pack records into format for transfer. We are allocating more
@@ -3750,7 +4322,7 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
const uchar *before_record,
const uchar *after_record)
{
- DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
+ DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
size_t const before_maxlen = max_row_length(table, before_record);
size_t const after_maxlen = max_row_length(table, after_record);
@@ -3795,7 +4367,7 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
MY_BITMAP const* cols, size_t colcnt,
uchar const *record)
{
- DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
+ DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
/*
Pack records into format for transfer. We are allocating more
@@ -3821,14 +4393,15 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
}
-int THD::binlog_remove_pending_rows_event(bool clear_maps)
+int THD::binlog_remove_pending_rows_event(bool clear_maps,
+ bool is_transactional)
{
DBUG_ENTER("THD::binlog_remove_pending_rows_event");
if (!mysql_bin_log.is_open())
DBUG_RETURN(0);
- mysql_bin_log.remove_pending_rows_event(this);
+ mysql_bin_log.remove_pending_rows_event(this, is_transactional);
if (clear_maps)
binlog_table_maps= 0;
@@ -3836,7 +4409,7 @@ int THD::binlog_remove_pending_rows_event(bool clear_maps)
DBUG_RETURN(0);
}
-int THD::binlog_flush_pending_rows_event(bool stmt_end)
+int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional)
{
DBUG_ENTER("THD::binlog_flush_pending_rows_event");
/*
@@ -3852,7 +4425,7 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end)
flag is set.
*/
int error= 0;
- if (Rows_log_event *pending= binlog_get_pending_rows_event())
+ if (Rows_log_event *pending= binlog_get_pending_rows_event(is_transactional))
{
if (stmt_end)
{
@@ -3860,7 +4433,8 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end)
binlog_table_maps= 0;
}
- error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0);
+ error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0,
+ is_transactional);
}
DBUG_RETURN(error);
@@ -3876,8 +4450,6 @@ show_query_type(THD::enum_binlog_query_type qtype)
return "ROW";
case THD::STMT_QUERY_TYPE:
return "STMT";
- case THD::MYSQL_QUERY_TYPE:
- return "MYSQL";
case THD::QUERY_TYPE_COUNT:
default:
DBUG_ASSERT(0 <= qtype && qtype < THD::QUERY_TYPE_COUNT);
@@ -3889,32 +4461,78 @@ show_query_type(THD::enum_binlog_query_type qtype)
#endif
-/*
- Member function that will log query, either row-based or
- statement-based depending on the value of the 'current_stmt_binlog_row_based'
- the value of the 'qtype' flag.
+/**
+ Auxiliary method used by @c binlog_query() to raise warnings.
- This function should be called after the all calls to ha_*_row()
- functions have been issued, but before tables are unlocked and
- closed.
+ The type of warning and the type of unsafeness is stored in
+ THD::binlog_unsafe_warning_flags.
+*/
+void THD::issue_unsafe_warnings()
+{
+ DBUG_ENTER("issue_unsafe_warnings");
+ /*
+ Ensure that binlog_unsafe_warning_flags is big enough to hold all
+ bits. This is actually a constant expression.
+ */
+ DBUG_ASSERT(LEX::BINLOG_STMT_UNSAFE_COUNT <=
+ sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
- OBSERVE
- There shall be no writes to any system table after calling
- binlog_query(), so these writes has to be moved to before the call
- of binlog_query() for correct functioning.
+ uint32 unsafe_type_flags= binlog_unsafe_warning_flags;
+ /*
+ For each unsafe_type, check if the statement is unsafe in this way
+ and issue a warning.
+ */
+ for (int unsafe_type=0;
+ unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
+ unsafe_type++)
+ {
+ if ((unsafe_type_flags & (1 << unsafe_type)) != 0)
+ {
+ push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_BINLOG_UNSAFE_STATEMENT,
+ ER(ER_BINLOG_UNSAFE_STATEMENT),
+ ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
+ if (global_system_variables.log_warnings)
+ {
+ char buf[MYSQL_ERRMSG_SIZE * 2];
+ sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT),
+ ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
+ sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query());
+ }
+ }
+ }
+ DBUG_VOID_RETURN;
+}
- This is necessesary not only for RBR, but the master might crash
- after binlogging the query but before changing the system tables.
- This means that the slave and the master are not in the same state
- (after the master has restarted), so therefore we have to
- eliminate this problem.
- RETURN VALUE
- Error code, or 0 if no error.
+/**
+ Log the current query.
+
+ The query will be logged in either row format or statement format
+ depending on the value of @c current_stmt_binlog_format_row field and
+ the value of the @c qtype parameter.
+
+ This function must be called:
+
+ - After the all calls to ha_*_row() functions have been issued.
+
+ - After any writes to system tables. Rationale: if system tables
+ were written after a call to this function, and the master crashes
+ after the call to this function and before writing the system
+ tables, then the master and slave get out of sync.
+
+ - Before tables are unlocked and closed.
+
+ @see decide_logging_format
+
+ @retval 0 Success
+
+ @retval nonzero If there is a failure when writing the query (e.g.,
+ write failure), then the error code is returned.
*/
int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
- ulong query_len, bool is_trans, bool suppress_use,
- int errcode)
+ ulong query_len, bool is_trans, bool direct,
+ bool suppress_use, int errcode)
{
DBUG_ENTER("THD::binlog_query");
DBUG_PRINT("enter", ("qtype: %s query: '%s'",
@@ -3930,60 +4548,72 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
If we are in prelocked mode, the flushing will be done inside the
top-most close_thread_tables().
*/
- if (this->prelocked_mode == NON_PRELOCKED)
- if (int error= binlog_flush_pending_rows_event(TRUE))
+ if (this->locked_tables_mode <= LTM_LOCK_TABLES)
+ if (int error= binlog_flush_pending_rows_event(TRUE, is_trans))
DBUG_RETURN(error);
/*
- If we are in statement mode and trying to log an unsafe statement,
- we should print a warning.
+ Warnings for unsafe statements logged in statement format are
+ printed in three places instead of in decide_logging_format().
+ This is because the warnings should be printed only if the statement
+ is actually logged. When executing decide_logging_format(), we cannot
+ know for sure if the statement will be logged:
+
+ 1 - sp_head::execute_procedure which prints out warnings for calls to
+ stored procedures.
+
+ 2 - sp_head::execute_function which prints out warnings for calls
+ involving functions.
+
+ 3 - THD::binlog_query (here) which prints warning for top level
+ statements not covered by the two cases above: i.e., if not insided a
+ procedure and a function.
+
+ Besides, we should not try to print these warnings if it is not
+ possible to write statements to the binary log as it happens when
+ the execution is inside a function, or generaly speaking, when
+ the variables.option_bits & OPTION_BIN_LOG is false.
+
*/
- if (sql_log_bin_toplevel && lex->is_stmt_unsafe() &&
- variables.binlog_format == BINLOG_FORMAT_STMT &&
- binlog_filter->db_ok(this->db))
- {
- /*
- A warning can be elevated a error when STRICT sql mode.
- But we don't want to elevate binlog warning to error here.
- */
- push_warning(this, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_BINLOG_UNSAFE_STATEMENT,
- ER(ER_BINLOG_UNSAFE_STATEMENT));
- if (global_system_variables.log_warnings &&
- !(binlog_flags & BINLOG_FLAG_UNSAFE_STMT_PRINTED))
- {
- sql_print_warning("%s Statement: %.*s",
- ER(ER_BINLOG_UNSAFE_STATEMENT),
- MYSQL_ERRMSG_SIZE, query_arg);
- binlog_flags|= BINLOG_FLAG_UNSAFE_STMT_PRINTED;
- }
- }
+ if ((variables.option_bits & OPTION_BIN_LOG) &&
+ spcont == NULL && !binlog_evt_union.do_union)
+ issue_unsafe_warnings();
+
switch (qtype) {
+ /*
+ ROW_QUERY_TYPE means that the statement may be logged either in
+ row format or in statement format. If
+ current_stmt_binlog_format is row, it means that the
+ statement has already been logged in row format and hence shall
+ not be logged again.
+ */
case THD::ROW_QUERY_TYPE:
DBUG_PRINT("debug",
- ("current_stmt_binlog_row_based: %d",
- current_stmt_binlog_row_based));
- if (current_stmt_binlog_row_based)
+ ("is_current_stmt_binlog_format_row: %d",
+ is_current_stmt_binlog_format_row()));
+ if (is_current_stmt_binlog_format_row())
DBUG_RETURN(0);
- /* Otherwise, we fall through */
- case THD::MYSQL_QUERY_TYPE:
- /*
- Using this query type is a conveniece hack, since we have been
- moving back and forth between using RBR for replication of
- system tables and not using it.
+ /* Fall through */
- Make sure to change in check_table_binlog_row_based() according
- to how you treat this.
+ /*
+ STMT_QUERY_TYPE means that the query must be logged in statement
+ format; it cannot be logged in row format. This is typically
+ used by DDL statements. It is an error to use this query type
+ if current_stmt_binlog_format_row is row.
+
+ @todo Currently there are places that call this method with
+ STMT_QUERY_TYPE and current_stmt_binlog_format is row. Fix those
+ places and add assert to ensure correct behavior. /Sven
*/
case THD::STMT_QUERY_TYPE:
/*
The MYSQL_LOG::write() function will set the STMT_END_F flag and
flush the pending rows event if necessary.
- */
+ */
{
- Query_log_event qinfo(this, query_arg, query_len, is_trans, suppress_use,
- errcode);
+ Query_log_event qinfo(this, query_arg, query_len, is_trans, direct,
+ suppress_use, errcode);
/*
Binlog table maps will be irrelevant after a Query_log_event
(they are just removed on the slave side) so after the query
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 774ae4abac4..02f28b54e10 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -14,60 +14,34 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#ifndef SQL_CLASS_INCLUDED
+#define SQL_CLASS_INCLUDED
+
/* Classes in mysql */
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#ifdef MYSQL_SERVER
+#include "unireg.h" // REQUIRED: for other includes
+#endif
+#include "sql_const.h"
+#include <mysql/plugin_audit.h>
#include "log.h"
#include "rpl_tblmap.h"
-
-/**
- An interface that is used to take an action when
- the locking module notices that a table version has changed
- since the last execution. "Table" here may refer to any kind of
- table -- a base table, a temporary table, a view or an
- information schema table.
-
- When we open and lock tables for execution of a prepared
- statement, we must verify that they did not change
- since statement prepare. If some table did change, the statement
- parse tree *may* be no longer valid, e.g. in case it contains
- optimizations that depend on table metadata.
-
- This class provides an interface (a method) that is
- invoked when such a situation takes place.
- The implementation of the method simply reports an error, but
- the exact details depend on the nature of the SQL statement.
-
- At most 1 instance of this class is active at a time, in which
- case THD::m_reprepare_observer is not NULL.
-
- @sa check_and_update_table_version() for details of the
- version tracking algorithm
-
- @sa Open_tables_state::m_reprepare_observer for the life cycle
- of metadata observers.
-*/
-
-class Reprepare_observer
-{
-public:
- /**
- Check if a change of metadata is OK. In future
- the signature of this method may be extended to accept the old
- and the new versions, but since currently the check is very
- simple, we only need the THD to report an error.
- */
- bool report_error(THD *thd);
- bool is_invalidated() const { return m_invalidated; }
- void reset_reprepare_observer() { m_invalidated= FALSE; }
-private:
- bool m_invalidated;
-};
+#include "mdl.h"
+#include "sql_locale.h" /* my_locale_st */
+#include "sql_profile.h" /* PROFILING */
+#include "scheduler.h" /* thd_scheduler */
+#include "protocol.h" /* Protocol_text, Protocol_binary */
+#include "violite.h" /* vio_is_connected */
+#include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA,
+ THR_LOCK_INFO */
+class Reprepare_observer;
class Relay_log_info;
class Query_log_event;
@@ -77,18 +51,57 @@ class sp_rcontext;
class sp_cache;
class Parser_state;
class Rows_log_event;
+class Sroutine_hash_entry;
+class User_level_lock;
+class user_var_entry;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE };
enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
DELAY_KEY_WRITE_ALL };
-
-#define SLAVE_EXEC_MODE_STRICT (1U << 0)
-#define SLAVE_EXEC_MODE_IDEMPOTENT (1U << 1)
-
+enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT,
+ SLAVE_EXEC_MODE_IDEMPOTENT,
+ SLAVE_EXEC_MODE_LAST_BIT};
+enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY,
+ SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY};
enum enum_mark_columns
{ MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE};
+enum enum_filetype { FILETYPE_CSV, FILETYPE_XML };
+
+/* Bits for different SQL modes modes (including ANSI mode) */
+#define MODE_REAL_AS_FLOAT 1
+#define MODE_PIPES_AS_CONCAT 2
+#define MODE_ANSI_QUOTES 4
+#define MODE_IGNORE_SPACE 8
+#define MODE_NOT_USED 16
+#define MODE_ONLY_FULL_GROUP_BY 32
+#define MODE_NO_UNSIGNED_SUBTRACTION 64
+#define MODE_NO_DIR_IN_CREATE 128
+#define MODE_POSTGRESQL 256
+#define MODE_ORACLE 512
+#define MODE_MSSQL 1024
+#define MODE_DB2 2048
+#define MODE_MAXDB 4096
+#define MODE_NO_KEY_OPTIONS 8192
+#define MODE_NO_TABLE_OPTIONS 16384
+#define MODE_NO_FIELD_OPTIONS 32768
+#define MODE_MYSQL323 65536L
+#define MODE_MYSQL40 (MODE_MYSQL323*2)
+#define MODE_ANSI (MODE_MYSQL40*2)
+#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
+#define MODE_NO_BACKSLASH_ESCAPES (MODE_NO_AUTO_VALUE_ON_ZERO*2)
+#define MODE_STRICT_TRANS_TABLES (MODE_NO_BACKSLASH_ESCAPES*2)
+#define MODE_STRICT_ALL_TABLES (MODE_STRICT_TRANS_TABLES*2)
+#define MODE_NO_ZERO_IN_DATE (MODE_STRICT_ALL_TABLES*2)
+#define MODE_NO_ZERO_DATE (MODE_NO_ZERO_IN_DATE*2)
+#define MODE_INVALID_DATES (MODE_NO_ZERO_DATE*2)
+#define MODE_ERROR_FOR_DIVISION_BY_ZERO (MODE_INVALID_DATES*2)
+#define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2)
+#define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2)
+#define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2)
+#define MODE_NO_ENGINE_SUBSTITUTION (MODE_HIGH_NOT_PRECEDENCE*2)
+#define MODE_PAD_CHAR_TO_FULL_LENGTH (ULL(1) << 31)
extern char internal_table_name[2];
extern char empty_c_string[1];
@@ -96,12 +109,47 @@ extern MYSQL_PLUGIN_IMPORT const char **errmesg;
extern bool volatile shutdown_in_progress;
+extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd);
+extern "C" char **thd_query(MYSQL_THD thd);
+
+/**
+ @class CSET_STRING
+ @brief Character set armed LEX_STRING
+*/
+class CSET_STRING
+{
+private:
+ LEX_STRING string;
+ CHARSET_INFO *cs;
+public:
+ CSET_STRING() : cs(&my_charset_bin)
+ {
+ string.str= NULL;
+ string.length= 0;
+ }
+ CSET_STRING(char *str_arg, size_t length_arg, CHARSET_INFO *cs_arg) :
+ cs(cs_arg)
+ {
+ DBUG_ASSERT(cs_arg != NULL);
+ string.str= str_arg;
+ string.length= length_arg;
+ }
+
+ inline char *str() const { return string.str; }
+ inline uint32 length() const { return string.length; }
+ CHARSET_INFO *charset() const { return cs; }
+
+ friend LEX_STRING * thd_query_string (MYSQL_THD thd);
+ friend char **thd_query(MYSQL_THD thd);
+};
+
+
#define TC_LOG_PAGE_SIZE 8192
#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE)
#define TC_HEURISTIC_RECOVER_COMMIT 1
#define TC_HEURISTIC_RECOVER_ROLLBACK 2
-extern uint tc_heuristic_recover;
+extern ulong tc_heuristic_recover;
typedef struct st_user_var_events
{
@@ -110,6 +158,7 @@ typedef struct st_user_var_events
ulong length;
Item_result type;
uint charset_number;
+ bool unsigned_flag;
} BINLOG_USER_VAR_EVENT;
#define RP_LOCK_LOG_IS_ALREADY_LOCKED 1
@@ -147,9 +196,14 @@ typedef struct st_copy_info {
class Key_part_spec :public Sql_alloc {
public:
- const char *field_name;
+ LEX_STRING field_name;
uint length;
- Key_part_spec(const char *name,uint len=0) :field_name(name), length(len) {}
+ Key_part_spec(const LEX_STRING &name, uint len)
+ : field_name(name), length(len)
+ {}
+ Key_part_spec(const char *name, const size_t name_len, uint len)
+ : length(len)
+ { field_name.str= (char *)name; field_name.length= name_len; }
bool operator==(const Key_part_spec& other) const;
/**
Construct a copy of this Key_part_spec. field_name is copied
@@ -202,15 +256,24 @@ public:
enum Keytype type;
KEY_CREATE_INFO key_create_info;
List<Key_part_spec> columns;
- const char *name;
+ LEX_STRING name;
bool generated;
- Key(enum Keytype type_par, const char *name_arg,
+ Key(enum Keytype type_par, const LEX_STRING &name_arg,
KEY_CREATE_INFO *key_info_arg,
bool generated_arg, List<Key_part_spec> &cols)
:type(type_par), key_create_info(*key_info_arg), columns(cols),
name(name_arg), generated(generated_arg)
{}
+ Key(enum Keytype type_par, const char *name_arg, size_t name_len_arg,
+ KEY_CREATE_INFO *key_info_arg, bool generated_arg,
+ List<Key_part_spec> &cols)
+ :type(type_par), key_create_info(*key_info_arg), columns(cols),
+ generated(generated_arg)
+ {
+ name.str= (char *)name_arg;
+ name.length= name_len_arg;
+ }
Key(const Key &rhs, MEM_ROOT *mem_root);
virtual ~Key() {}
/* Equality comparison of keys (ignoring name) */
@@ -235,7 +298,7 @@ public:
Table_ident *ref_table;
List<Key_part_spec> ref_columns;
uint delete_opt, update_opt, match_opt;
- Foreign_key(const char *name_arg, List<Key_part_spec> &cols,
+ Foreign_key(const LEX_STRING &name_arg, List<Key_part_spec> &cols,
Table_ident *table, List<Key_part_spec> &ref_cols,
uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg)
:Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols),
@@ -268,6 +331,64 @@ public:
LEX_COLUMN (const String& x,const uint& y ): column (x),rights (y) {}
};
+class MY_LOCALE;
+
+/**
+ Query_cache_tls -- query cache thread local data.
+*/
+
+struct Query_cache_block;
+
+struct Query_cache_tls
+{
+ /*
+ 'first_query_block' should be accessed only via query cache
+ functions and methods to maintain proper locking.
+ */
+ Query_cache_block *first_query_block;
+ void set_first_query_block(Query_cache_block *first_query_block_arg)
+ {
+ first_query_block= first_query_block_arg;
+ }
+
+ Query_cache_tls() :first_query_block(NULL) {}
+};
+
+/* SIGNAL / RESIGNAL / GET DIAGNOSTICS */
+
+/**
+ This enumeration list all the condition item names of a condition in the
+ SQL condition area.
+*/
+typedef enum enum_diag_condition_item_name
+{
+ /*
+ Conditions that can be set by the user (SIGNAL/RESIGNAL),
+ and by the server implementation.
+ */
+
+ DIAG_CLASS_ORIGIN= 0,
+ FIRST_DIAG_SET_PROPERTY= DIAG_CLASS_ORIGIN,
+ DIAG_SUBCLASS_ORIGIN= 1,
+ DIAG_CONSTRAINT_CATALOG= 2,
+ DIAG_CONSTRAINT_SCHEMA= 3,
+ DIAG_CONSTRAINT_NAME= 4,
+ DIAG_CATALOG_NAME= 5,
+ DIAG_SCHEMA_NAME= 6,
+ DIAG_TABLE_NAME= 7,
+ DIAG_COLUMN_NAME= 8,
+ DIAG_CURSOR_NAME= 9,
+ DIAG_MESSAGE_TEXT= 10,
+ DIAG_MYSQL_ERRNO= 11,
+ LAST_DIAG_SET_PROPERTY= DIAG_MYSQL_ERRNO
+} Diag_condition_item_name;
+
+/**
+ Name of each diagnostic condition item.
+ This array is indexed by Diag_condition_item_name.
+*/
+extern const LEX_STRING Diag_condition_item_names[];
+
#include "sql_lex.h" /* Must be here */
class Delayed_insert;
@@ -279,7 +400,7 @@ class Time_zone;
#define THD_CHECK_SENTRY(thd) DBUG_ASSERT(thd->dbug_sentry == THD_SENTRY_MAGIC)
-struct system_variables
+typedef struct system_variables
{
/*
How dynamically allocated system variables are handled:
@@ -295,16 +416,18 @@ struct system_variables
uint dynamic_variables_head; /* largest valid variable offset */
uint dynamic_variables_size; /* how many bytes are in use */
- ulonglong myisam_max_extra_sort_file_size;
- ulonglong myisam_max_sort_file_size;
ulonglong max_heap_table_size;
ulonglong tmp_table_size;
ulonglong long_query_time;
+ ulonglong optimizer_switch;
+ ulonglong sql_mode; ///< which non-standard SQL behaviour should be enabled
+ ulonglong option_bits; ///< OPTION_xxx constants, e.g. OPTION_PROFILING
ha_rows select_limit;
ha_rows max_join_size;
ulong auto_increment_increment, auto_increment_offset;
ulong bulk_insert_buff_size;
ulong join_buff_size;
+ ulong lock_wait_timeout;
ulong max_allowed_packet;
ulong max_error_count;
ulong max_length_for_sort_data;
@@ -313,9 +436,6 @@ struct system_variables
ulong max_insert_delayed_threads;
ulong min_examined_row_limit;
ulong multi_range_count;
- ulong myisam_repair_threads;
- ulong myisam_sort_buff_size;
- ulong myisam_stats_method;
ulong net_buffer_length;
ulong net_interactive_timeout;
ulong net_read_timeout;
@@ -324,23 +444,13 @@ struct system_variables
ulong net_write_timeout;
ulong optimizer_prune_level;
ulong optimizer_search_depth;
- /* A bitmap for switching optimizations on/off */
- ulong optimizer_switch;
ulong preload_buff_size;
ulong profiling_history_size;
- ulong query_cache_type;
ulong read_buff_size;
ulong read_rnd_buff_size;
ulong div_precincrement;
ulong sortbuff_size;
- ulong thread_handling;
- ulong tx_isolation;
- ulong completion_type;
- /* Determines which non-standard SQL behaviour should be enabled */
- ulong sql_mode;
ulong max_sp_recursion_depth;
- /* check of key presence in updatable view */
- ulong updatable_views_with_limit;
ulong default_week_format;
ulong max_seeks_for_key;
ulong range_alloc_block_size;
@@ -350,12 +460,16 @@ struct system_variables
ulong trans_prealloc_size;
ulong log_warnings;
ulong group_concat_max_len;
- ulong ndb_autoincrement_prefetch_sz;
- ulong ndb_index_stat_cache_entries;
- ulong ndb_index_stat_update_freq;
- ulong binlog_format; // binlog format for this thd (see enum_binlog_format)
+
+ ulong binlog_format; ///< binlog format for this thd (see enum_binlog_format)
my_bool binlog_direct_non_trans_update;
- /*
+ my_bool sql_log_bin;
+ ulong completion_type;
+ ulong query_cache_type;
+ ulong tx_isolation;
+ ulong updatable_views_with_limit;
+ uint max_user_connections;
+ /**
In slave thread we need to know in behalf of which
thread the query is being run to replicate temp tables properly
*/
@@ -363,22 +477,13 @@ struct system_variables
my_bool low_priority_updates;
my_bool new_mode;
- /*
- compatibility option:
- - index usage hints (USE INDEX without a FOR clause) behave as in 5.0
- */
- my_bool old_mode;
my_bool query_cache_wlock_invalidate;
my_bool engine_condition_pushdown;
my_bool keep_files_on_create;
- my_bool ndb_force_send;
- my_bool ndb_use_copying_alter_table;
- my_bool ndb_use_exact_count;
- my_bool ndb_use_transactions;
- my_bool ndb_index_stat_enable;
my_bool old_alter_table;
my_bool old_passwords;
+ my_bool big_tables;
plugin_ref table_plugin;
@@ -392,17 +497,18 @@ struct system_variables
CHARSET_INFO *collation_database;
CHARSET_INFO *collation_connection;
+ /* Error messages */
+ MY_LOCALE *lc_messages;
/* Locale Support */
MY_LOCALE *lc_time_names;
Time_zone *time_zone;
- /* DATE, DATETIME and MYSQL_TIME formats */
- DATE_TIME_FORMAT *date_format;
- DATE_TIME_FORMAT *datetime_format;
- DATE_TIME_FORMAT *time_format;
my_bool sysdate_is_now;
-};
+
+ double long_query_time_double;
+
+} SV;
/**
@@ -651,13 +757,24 @@ public:
This printing is needed at least in SHOW PROCESSLIST and SHOW
ENGINE INNODB STATUS.
*/
- LEX_STRING query_string;
- Server_side_cursor *cursor;
-
- inline char *query() { return query_string.str; }
- inline uint32 query_length() { return query_string.length; }
- void set_query_inner(char *query_arg, uint32 query_length_arg);
+ CSET_STRING query_string;
+ inline char *query() const { return query_string.str(); }
+ inline uint32 query_length() const { return query_string.length(); }
+ CHARSET_INFO *query_charset() const { return query_string.charset(); }
+ void set_query_inner(const CSET_STRING &string_arg)
+ {
+ query_string= string_arg;
+ }
+ void set_query_inner(char *query_arg, uint32 query_length_arg,
+ CHARSET_INFO *cs_arg)
+ {
+ set_query_inner(CSET_STRING(query_arg, query_length_arg, cs_arg));
+ }
+ void reset_query_inner()
+ {
+ set_query_inner(CSET_STRING());
+ }
/**
Name of the current (default) database.
@@ -713,8 +830,8 @@ public:
Statement *find_by_name(LEX_STRING *name)
{
Statement *stmt;
- stmt= (Statement*)hash_search(&names_hash, (uchar*)name->str,
- name->length);
+ stmt= (Statement*)my_hash_search(&names_hash, (uchar*)name->str,
+ name->length);
return stmt;
}
@@ -723,7 +840,7 @@ public:
if (last_found_statement == 0 || id != last_found_statement->id)
{
Statement *stmt;
- stmt= (Statement *) hash_search(&st_hash, (uchar *) &id, sizeof(id));
+ stmt= (Statement *) my_hash_search(&st_hash, (uchar *) &id, sizeof(id));
if (stmt && stmt->name.str)
return NULL;
last_found_statement= stmt;
@@ -752,6 +869,8 @@ struct st_savepoint {
char *name;
uint length;
Ha_trx_info *ha_list;
+ /** State of metadata locks before this savepoint was set. */
+ MDL_savepoint mdl_savepoint;
};
enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY};
@@ -766,7 +885,7 @@ typedef struct st_xid_state {
uint rm_error;
} XID_STATE;
-extern pthread_mutex_t LOCK_xid_cache;
+extern mysql_mutex_t LOCK_xid_cache;
extern HASH xid_cache;
bool xid_cache_init(void);
void xid_cache_free(void);
@@ -790,9 +909,13 @@ public:
priv_user - The user privilege we are using. May be "" for anonymous user.
ip - client IP
*/
- char *host, *user, *priv_user, *ip;
+ char *host, *user, *ip;
+ char priv_user[USERNAME_LENGTH];
+ char proxy_user[USERNAME_LENGTH + MAX_HOSTNAME + 5];
/* The host privilege we are using */
char priv_host[MAX_HOSTNAME];
+ /* The external user (if available) */
+ char *external_user;
/* points to host if host is available, otherwise points to ip */
const char *host_or_ip;
ulong master_access; /* Global privileges from mysql.user */
@@ -835,12 +958,17 @@ typedef I_List<Item_change_record> Item_change_list;
/**
- Type of prelocked mode.
- See comment for THD::prelocked_mode for complete description.
+ Type of locked tables mode.
+ See comment for THD::locked_tables_mode for complete description.
*/
-enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
- PRELOCKED_UNDER_LOCK_TABLES= 2};
+enum enum_locked_tables_mode
+{
+ LTM_NONE= 0,
+ LTM_LOCK_TABLES,
+ LTM_PRELOCKED,
+ LTM_PRELOCKED_UNDER_LOCK_TABLES
+};
/**
@@ -879,11 +1007,6 @@ public:
XXX Why are internal temporary tables added to this list?
*/
TABLE *temporary_tables;
- /**
- List of tables that were opened with HANDLER OPEN and are
- still in use by this thread.
- */
- TABLE *handler_tables;
TABLE *derived_tables;
/*
During a MySQL session, one can lock tables in two modes: automatic
@@ -893,19 +1016,13 @@ public:
statement ends.
Manual mode comes into play when a user issues a 'LOCK TABLES'
statement. In this mode the user can only use the locked tables.
- Trying to use any other tables will give an error. The locked tables are
- stored in 'locked_tables' member. Manual locking is described in
+ Trying to use any other tables will give an error.
+ The locked tables are also stored in this member, however,
+ thd->locked_tables_mode is turned on. Manual locking is described in
the 'LOCK_TABLES' chapter of the MySQL manual.
See also lock_tables() for details.
*/
MYSQL_LOCK *lock;
- /*
- Tables that were locked with explicit or implicit LOCK TABLES.
- (Implicit LOCK TABLES happens when we are prelocking tables for
- execution of statement which uses stored routines. See description
- THD::prelocked_mode for more info.)
- */
- MYSQL_LOCK *locked_tables;
/*
CREATE-SELECT keeps an extra lock for the table being
@@ -915,30 +1032,34 @@ public:
MYSQL_LOCK *extra_lock;
/*
- prelocked_mode_type enum and prelocked_mode member are used for
- indicating whenever "prelocked mode" is on, and what type of
- "prelocked mode" is it.
-
- Prelocked mode is used for execution of queries which explicitly
- or implicitly (via views or triggers) use functions, thus may need
- some additional tables (mentioned in query table list) for their
- execution.
-
- First open_tables() call for such query will analyse all functions
- used by it and add all additional tables to table its list. It will
- also mark this query as requiring prelocking. After that lock_tables()
- will issue implicit LOCK TABLES for the whole table list and change
- thd::prelocked_mode to non-0. All queries called in functions invoked
- by the main query will use prelocked tables. Non-0 prelocked_mode
- will also surpress mentioned analysys in those queries thus saving
- cycles. Prelocked mode will be turned off once close_thread_tables()
- for the main query will be called.
-
- Note: Since not all "tables" present in table list are really locked
- thd::prelocked_mode does not imply thd::locked_tables.
- */
- prelocked_mode_type prelocked_mode;
- ulong version;
+ Enum enum_locked_tables_mode and locked_tables_mode member are
+ used to indicate whether the so-called "locked tables mode" is on,
+ and what kind of mode is active.
+
+ Locked tables mode is used when it's necessary to open and
+ lock many tables at once, for usage across multiple
+ (sub-)statements.
+ This may be necessary either for queries that use stored functions
+ and triggers, in which case the statements inside functions and
+ triggers may be executed many times, or for implementation of
+ LOCK TABLES, in which case the opened tables are reused by all
+ subsequent statements until a call to UNLOCK TABLES.
+
+ The kind of locked tables mode employed for stored functions and
+ triggers is also called "prelocked mode".
+ In this mode, first open_tables() call to open the tables used
+ in a statement analyses all functions used by the statement
+ and adds all indirectly used tables to the list of tables to
+ open and lock.
+ It also marks the parse tree of the statement as requiring
+ prelocking. After that, lock_tables() locks the entire list
+ of tables and changes THD::locked_tables_modeto LTM_PRELOCKED.
+ All statements executed inside functions or triggers
+ use the prelocked tables, instead of opening their own ones.
+ Prelocked mode is turned off automatically once close_thread_tables()
+ of the main statement is called.
+ */
+ enum enum_locked_tables_mode locked_tables_mode;
uint current_tablenr;
enum enum_flags {
@@ -949,30 +1070,49 @@ public:
Flags with information about the open tables state.
*/
uint state_flags;
-
- /*
- This constructor serves for creation of Open_tables_state instances
- which are used as backup storage.
+ /**
+ This constructor initializes Open_tables_state instance which can only
+ be used as backup storage. To prepare Open_tables_state instance for
+ operations which open/lock/close tables (e.g. open_table()) one has to
+ call init_open_tables_state().
*/
Open_tables_state() : state_flags(0U) { }
- Open_tables_state(ulong version_arg);
-
void set_open_tables_state(Open_tables_state *state)
{
*this= *state;
}
- void reset_open_tables_state()
+ void reset_open_tables_state(THD *thd)
{
- open_tables= temporary_tables= handler_tables= derived_tables= 0;
- extra_lock= lock= locked_tables= 0;
- prelocked_mode= NON_PRELOCKED;
+ open_tables= temporary_tables= derived_tables= 0;
+ extra_lock= lock= 0;
+ locked_tables_mode= LTM_NONE;
state_flags= 0U;
m_reprepare_observer= NULL;
}
};
+
+/**
+ Storage for backup of Open_tables_state. Must
+ be used only to open system tables (TABLE_CATEGORY_SYSTEM
+ and TABLE_CATEGORY_LOG).
+*/
+
+class Open_tables_backup: public Open_tables_state
+{
+public:
+ /**
+ When we backup the open tables state to open a system
+ table or tables, we want to save state of metadata
+ locks which were acquired before the backup. It is used
+ to release metadata locks on system tables after they are
+ no longer used.
+ */
+ MDL_savepoint mdl_system_tables_svp;
+};
+
/**
@class Sub_statement_state
@brief Used to save context when executing a function or trigger
@@ -987,7 +1127,7 @@ public:
class Sub_statement_state
{
public:
- ulonglong options;
+ ulonglong option_bits;
ulonglong first_successful_insert_id_in_prev_stmt;
ulonglong first_successful_insert_id_in_cur_stmt, insert_id_for_cur_row;
Discrete_interval auto_inc_interval_for_cur_row;
@@ -1051,12 +1191,12 @@ protected:
public:
/**
- Handle an error condition.
+ Handle a sql condition.
This method can be implemented by a subclass to achieve any of the
following:
- - mask an error internally, prevent exposing it to the user,
- - mask an error and throw another one instead.
- When this method returns true, the error condition is considered
+ - mask a warning/error internally, prevent exposing it to the user,
+ - mask a warning/error and throw another one instead.
+ When this method returns true, the sql condition is considered
'handled', and will not be propagated to upper layers.
It is the responsability of the code installing an internal handler
to then check for trapped conditions, and implement logic to recover
@@ -1070,15 +1210,17 @@ public:
before removing it from the exception stack with
<code>THD::pop_internal_handler()</code>.
- @param sql_errno the error number
- @param level the error level
@param thd the calling thread
- @return true if the error is handled
+ @param cond the condition raised.
+ @return true if the condition is handled
*/
- virtual bool handle_error(uint sql_errno,
- const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd) = 0;
+ virtual bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl) = 0;
+
private:
Internal_error_handler *m_prev_internal_handler;
friend class THD;
@@ -1093,10 +1235,12 @@ private:
class Dummy_error_handler : public Internal_error_handler
{
public:
- bool handle_error(uint sql_errno,
- const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd)
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
{
/* Ignore error */
return TRUE;
@@ -1105,7 +1249,7 @@ public:
/**
- This class is an internal error handler implementation for
+ This class is an internal error handler implementation for
DROP TABLE statements. The thing is that there may be warnings during
execution of these statements, which should not be exposed to the user.
This class is intended to silence such warnings.
@@ -1114,135 +1258,82 @@ public:
class Drop_table_error_handler : public Internal_error_handler
{
public:
- Drop_table_error_handler(Internal_error_handler *err_handler)
- :m_err_handler(err_handler)
- { }
+ Drop_table_error_handler() {}
public:
- bool handle_error(uint sql_errno,
- const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd);
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl);
private:
- Internal_error_handler *m_err_handler;
};
/**
- Stores status of the currently executed statement.
- Cleared at the beginning of the statement, and then
- can hold either OK, ERROR, or EOF status.
- Can not be assigned twice per statement.
+ Tables that were locked with LOCK TABLES statement.
+
+ Encapsulates a list of TABLE_LIST instances for tables
+ locked by LOCK TABLES statement, memory root for metadata locks,
+ and, generally, the context of LOCK TABLES statement.
+
+ In LOCK TABLES mode, the locked tables are kept open between
+ statements.
+ Therefore, we can't allocate metadata locks on execution memory
+ root -- as well as tables, the locks need to stay around till
+ UNLOCK TABLES is called.
+ The locks are allocated in the memory root encapsulated in this
+ class.
+
+ Some SQL commands, like FLUSH TABLE or ALTER TABLE, demand that
+ the tables they operate on are closed, at least temporarily.
+ This class encapsulates a list of TABLE_LIST instances, one
+ for each base table from LOCK TABLES list,
+ which helps conveniently close the TABLEs when it's necessary
+ and later reopen them.
+
+ Implemented in sql_base.cc
*/
-class Diagnostics_area
+class Locked_tables_list
{
+private:
+ MEM_ROOT m_locked_tables_root;
+ TABLE_LIST *m_locked_tables;
+ TABLE_LIST **m_locked_tables_last;
+ /** An auxiliary array used only in reopen_tables(). */
+ TABLE **m_reopen_array;
+ /**
+ Count the number of tables in m_locked_tables list. We can't
+ rely on thd->lock->table_count because it excludes
+ non-transactional temporary tables. We need to know
+ an exact number of TABLE objects.
+ */
+ size_t m_locked_tables_count;
public:
- enum enum_diagnostics_status
- {
- /** The area is cleared at start of a statement. */
- DA_EMPTY= 0,
- /** Set whenever one calls my_ok(). */
- DA_OK,
- /** Set whenever one calls my_eof(). */
- DA_EOF,
- /** Set whenever one calls my_error() or my_message(). */
- DA_ERROR,
- /** Set in case of a custom response, such as one from COM_STMT_PREPARE. */
- DA_DISABLED
- };
- /** True if status information is sent to the client. */
- bool is_sent;
- /** Set to make set_error_status after set_{ok,eof}_status possible. */
- bool can_overwrite_status;
-
- void set_ok_status(THD *thd, ha_rows affected_rows_arg,
- ulonglong last_insert_id_arg,
- const char *message);
- void set_eof_status(THD *thd);
- void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg);
-
- void disable_status();
-
- void reset_diagnostics_area();
-
- bool is_set() const { return m_status != DA_EMPTY; }
- bool is_error() const { return m_status == DA_ERROR; }
- bool is_eof() const { return m_status == DA_EOF; }
- bool is_ok() const { return m_status == DA_OK; }
- bool is_disabled() const { return m_status == DA_DISABLED; }
- enum_diagnostics_status status() const { return m_status; }
-
- const char *message() const
- { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK); return m_message; }
-
- uint sql_errno() const
- { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; }
-
- uint server_status() const
+ Locked_tables_list()
+ :m_locked_tables(NULL),
+ m_locked_tables_last(&m_locked_tables),
+ m_reopen_array(NULL),
+ m_locked_tables_count(0)
{
- DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
- return m_server_status;
+ init_sql_alloc(&m_locked_tables_root, MEM_ROOT_BLOCK_SIZE, 0);
}
-
- ha_rows affected_rows() const
- { DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; }
-
- ulonglong last_insert_id() const
- { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; }
-
- uint total_warn_count() const
+ void unlock_locked_tables(THD *thd);
+ ~Locked_tables_list()
{
- DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
- return m_total_warn_count;
+ unlock_locked_tables(0);
}
-
- Diagnostics_area() { reset_diagnostics_area(); }
-
-private:
- /** Message buffer. Can be used by OK or ERROR status. */
- char m_message[MYSQL_ERRMSG_SIZE];
- /**
- SQL error number. One of ER_ codes from share/errmsg.txt.
- Set by set_error_status.
- */
- uint m_sql_errno;
-
- /**
- Copied from thd->server_status when the diagnostics area is assigned.
- We need this member as some places in the code use the following pattern:
- thd->server_status|= ...
- my_eof(thd);
- thd->server_status&= ~...
- Assigned by OK, EOF or ERROR.
- */
- uint m_server_status;
- /**
- The number of rows affected by the last statement. This is
- semantically close to thd->row_count_func, but has a different
- life cycle. thd->row_count_func stores the value returned by
- function ROW_COUNT() and is cleared only by statements that
- update its value, such as INSERT, UPDATE, DELETE and few others.
- This member is cleared at the beginning of the next statement.
-
- We could possibly merge the two, but life cycle of thd->row_count_func
- can not be changed.
- */
- ha_rows m_affected_rows;
- /**
- Similarly to the previous member, this is a replacement of
- thd->first_successful_insert_id_in_prev_stmt, which is used
- to implement LAST_INSERT_ID().
- */
- ulonglong m_last_insert_id;
- /** The total number of warnings. */
- uint m_total_warn_count;
- enum_diagnostics_status m_status;
- /**
- @todo: the following THD members belong here:
- - warn_list, warn_count,
- */
+ bool init_locked_tables(THD *thd);
+ TABLE_LIST *locked_tables() { return m_locked_tables; }
+ void unlink_from_list(THD *thd, TABLE_LIST *table_list,
+ bool remove_from_locked_tables);
+ void unlink_all_closed_tables(THD *thd,
+ MYSQL_LOCK *lock,
+ size_t reopen_count);
+ bool reopen_tables(THD *thd);
};
@@ -1276,6 +1367,63 @@ struct Ha_data
Ha_data() :ha_ptr(NULL) {}
};
+/**
+ An instance of the global read lock in a connection.
+ Implemented in lock.cc.
+*/
+
+class Global_read_lock
+{
+public:
+ enum enum_grl_state
+ {
+ GRL_NONE,
+ GRL_ACQUIRED,
+ GRL_ACQUIRED_AND_BLOCKS_COMMIT
+ };
+
+ Global_read_lock()
+ : m_state(GRL_NONE),
+ m_mdl_global_shared_lock(NULL),
+ m_mdl_blocks_commits_lock(NULL)
+ {}
+
+ bool lock_global_read_lock(THD *thd);
+ void unlock_global_read_lock(THD *thd);
+ /**
+ Check if this connection can acquire protection against GRL and
+ emit error if otherwise.
+ */
+ bool can_acquire_protection() const
+ {
+ if (m_state)
+ {
+ my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0));
+ return TRUE;
+ }
+ return FALSE;
+ }
+ bool make_global_read_lock_block_commit(THD *thd);
+ bool is_acquired() const { return m_state != GRL_NONE; }
+ void set_explicit_lock_duration(THD *thd);
+private:
+ enum_grl_state m_state;
+ /**
+ In order to acquire the global read lock, the connection must
+ acquire shared metadata lock in GLOBAL namespace, to prohibit
+ all DDL.
+ */
+ MDL_ticket *m_mdl_global_shared_lock;
+ /**
+ Also in order to acquire the global read lock, the connection
+ must acquire a shared metadata lock in COMMIT namespace, to
+ prohibit commits.
+ */
+ MDL_ticket *m_mdl_blocks_commits_lock;
+};
+
+
+extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
/**
@class THD
@@ -1287,9 +1435,12 @@ class THD :public Statement,
public Open_tables_state
{
public:
+ MDL_context mdl_context;
+
/* Used to execute base64 coded binlog events in MySQL server */
Relay_log_info* rli_fake;
+ void reset_for_next_command();
/*
Constant for THD::where initialization in the beginning of every query.
@@ -1317,23 +1468,21 @@ public:
*/
struct st_mysql_stmt *current_stmt;
#endif
+#ifdef HAVE_QUERY_CACHE
+ Query_cache_tls query_cache_tls;
+#endif
NET net; // client connection descriptor
- MEM_ROOT warn_root; // For warnings and errors
Protocol *protocol; // Current protocol
Protocol_text protocol_text; // Normal protocol
Protocol_binary protocol_binary; // Binary protocol
HASH user_vars; // hash for user variables
String packet; // dynamic buffer for network I/O
String convert_buffer; // buffer for charset conversions
- struct sockaddr_in remote; // client socket address
struct rand_struct rand; // used for authentication
struct system_variables variables; // Changeable local variables
struct system_status_var status_var; // Per thread statistic vars
struct system_status_var *initial_status_var; /* used by show status */
THR_LOCK_INFO lock_info; // Locking info of this thread
- THR_LOCK_OWNER main_lock_id; // To use for conventional queries
- THR_LOCK_OWNER *lock_id; // If not main_lock_id, points to
- // the lock_id of a cursor.
/**
Protects THD data accessed from other threads:
- thd->query and thd->query_length (used by SHOW ENGINE
@@ -1341,7 +1490,7 @@ public:
- thd->mysys_var (used by KILL statement and shutdown).
Is locked when THD is deleted.
*/
- pthread_mutex_t LOCK_thd_data;
+ mysql_mutex_t LOCK_thd_data;
/* all prepared statements and cursors of this connection */
Statement_map stmt_map;
@@ -1393,7 +1542,6 @@ public:
*/
const char *where;
- double tmp_double_value; /* Used in set_var.cc */
ulong client_capabilities; /* What the client supports */
ulong max_client_packet_length;
@@ -1421,14 +1569,12 @@ public:
// track down slow pthread_create
ulonglong prior_thr_create_utime, thr_create_utime;
ulonglong start_utime, utime_after_lock;
-
+
thr_lock_type update_lock_default;
Delayed_insert *di;
/* <> 0 if we are inside of trigger or stored function. */
uint in_sub_stmt;
- /* TRUE when the current top has SQL_LOG_BIN ON */
- bool sql_log_bin_toplevel;
/* container for handler's private per-connection data */
Ha_data ha_data[MAX_HA];
@@ -1464,32 +1610,65 @@ public:
size_t needed,
bool is_transactional,
RowsEventT* hint);
- Rows_log_event* binlog_get_pending_rows_event() const;
- void binlog_set_pending_rows_event(Rows_log_event* ev);
- int binlog_flush_pending_rows_event(bool stmt_end);
- int binlog_remove_pending_rows_event(bool clear_maps);
+ Rows_log_event* binlog_get_pending_rows_event(bool is_transactional) const;
+ void binlog_set_pending_rows_event(Rows_log_event* ev, bool is_transactional);
+ inline int binlog_flush_pending_rows_event(bool stmt_end)
+ {
+ return (binlog_flush_pending_rows_event(stmt_end, FALSE) ||
+ binlog_flush_pending_rows_event(stmt_end, TRUE));
+ }
+ int binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional);
+ int binlog_remove_pending_rows_event(bool clear_maps, bool is_transactional);
+
+ /**
+ Determine the binlog format of the current statement.
+
+ @retval 0 if the current statement will be logged in statement
+ format.
+ @retval nonzero if the current statement will be logged in row
+ format.
+ */
+ int is_current_stmt_binlog_format_row() const {
+ DBUG_ASSERT(current_stmt_binlog_format == BINLOG_FORMAT_STMT ||
+ current_stmt_binlog_format == BINLOG_FORMAT_ROW);
+ return current_stmt_binlog_format == BINLOG_FORMAT_ROW;
+ }
private:
+ /**
+ Indicates the format in which the current statement will be
+ logged. This can only be set from @c decide_logging_format().
+ */
+ enum_binlog_format current_stmt_binlog_format;
+
+ /**
+ Bit field for the state of binlog warnings.
+
+ The first Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types of
+ unsafeness that the current statement has.
+
+ This must be a member of THD and not of LEX, because warnings are
+ detected and issued in different places (@c
+ decide_logging_format() and @c binlog_query(), respectively).
+ Between these calls, the THD->lex object may change; e.g., if a
+ stored routine is invoked. Only THD persists between the calls.
+ */
+ uint32 binlog_unsafe_warning_flags;
+
/*
Number of outstanding table maps, i.e., table maps in the
transaction cache.
*/
uint binlog_table_maps;
-
- enum enum_binlog_flag {
- BINLOG_FLAG_UNSAFE_STMT_PRINTED,
- BINLOG_FLAG_COUNT
- };
-
- /**
- Flags with per-thread information regarding the status of the
- binary log.
- */
- uint32 binlog_flags;
public:
+ void issue_unsafe_warnings();
+
uint get_binlog_table_maps() const {
return binlog_table_maps;
}
+ void clear_binlog_table_maps() {
+ binlog_table_maps= 0;
+ }
#endif /* MYSQL_CLIENT */
public:
@@ -1521,21 +1700,20 @@ public:
*/
if (!xid_state.rm_error)
xid_state.xid.null();
-#ifdef USING_TRANSACTIONS
free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
-#endif
+ }
+ my_bool is_active()
+ {
+ return (all.ha_list != NULL);
}
st_transactions()
{
-#ifdef USING_TRANSACTIONS
bzero((char*)this, sizeof(*this));
xid_state.xid.null();
init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
-#else
- xid_state.xa_state= XA_NOTR;
-#endif
}
} transaction;
+ Global_read_lock global_read_lock;
Field *dup_field;
#ifndef __WIN__
sigset_t signals;
@@ -1710,8 +1888,50 @@ public:
}
ulonglong limit_found_rows;
- ulonglong options; /* Bitmap of states */
- longlong row_count_func; /* For the ROW_COUNT() function */
+
+private:
+ /**
+ Stores the result of ROW_COUNT() function.
+
+ ROW_COUNT() function is a MySQL extention, but we try to keep it
+ similar to ROW_COUNT member of the GET DIAGNOSTICS stack of the SQL
+ standard (see SQL99, part 2, search for ROW_COUNT). It's value is
+ implementation defined for anything except INSERT, DELETE, UPDATE.
+
+ ROW_COUNT is assigned according to the following rules:
+
+ - In my_ok():
+ - for DML statements: to the number of affected rows;
+ - for DDL statements: to 0.
+
+ - In my_eof(): to -1 to indicate that there was a result set.
+
+ We derive this semantics from the JDBC specification, where int
+ java.sql.Statement.getUpdateCount() is defined to (sic) "return the
+ current result as an update count; if the result is a ResultSet
+ object or there are no more results, -1 is returned".
+
+ - In my_error(): to -1 to be compatible with the MySQL C API and
+ MySQL ODBC driver.
+
+ - For SIGNAL statements: to 0 per WL#2110 specification (see also
+ sql_signal.cc comment). Zero is used since that's the "default"
+ value of ROW_COUNT in the diagnostics area.
+ */
+
+ longlong m_row_count_func; /* For the ROW_COUNT() function */
+
+public:
+ inline longlong get_row_count_func() const
+ {
+ return m_row_count_func;
+ }
+
+ inline void set_row_count_func(longlong row_count_func)
+ {
+ m_row_count_func= row_count_func;
+ }
+
ha_rows cuted_fields;
/*
@@ -1741,17 +1961,9 @@ public:
table_map used_tables;
USER_CONN *user_connect;
CHARSET_INFO *db_charset;
- /*
- FIXME: this, and some other variables like 'count_cuted_fields'
- maybe should be statement/cursor local, that is, moved to Statement
- class. With current implementation warnings produced in each prepared
- statement/cursor settle here.
- */
- List <MYSQL_ERROR> warn_list;
- uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
- uint total_warn_count;
- Diagnostics_area main_da;
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+ Warning_info *warning_info;
+ Diagnostics_area *stmt_da;
+#if defined(ENABLED_PROFILING)
PROFILING profiling;
#endif
@@ -1763,33 +1975,54 @@ public:
from table are necessary for this select, to check if it's necessary to
update auto-updatable fields (like auto_increment and timestamp).
*/
- query_id_t query_id, warn_id;
+ query_id_t query_id;
ulong col_access;
-#ifdef ERROR_INJECT_SUPPORT
- ulong error_inject_value;
-#endif
/* Statement id is thread-wide. This counter is used to generate ids */
ulong statement_id_counter;
ulong rand_saved_seed1, rand_saved_seed2;
- /*
- Row counter, mainly for errors and warnings. Not increased in
- create_sort_index(); may differ from examined_row_count.
- */
- ulong row_count;
pthread_t real_id; /* For debugging */
my_thread_id thread_id;
- uint tmp_table, global_read_lock;
+ uint tmp_table;
uint server_status,open_options;
enum enum_thread_type system_thread;
uint select_number; //number of select (used for EXPLAIN)
- /* variables.transaction_isolation is reset to this after each commit */
- enum_tx_isolation session_tx_isolation;
+ /*
+ Current or next transaction isolation level.
+ When a connection is established, the value is taken from
+ @@session.tx_isolation (default transaction isolation for
+ the session), which is in turn taken from @@global.tx_isolation
+ (the global value).
+ If there is no transaction started, this variable
+ holds the value of the next transaction's isolation level.
+ When a transaction starts, the value stored in this variable
+ becomes "actual".
+ At transaction commit or rollback, we assign this variable
+ again from @@session.tx_isolation.
+ The only statement that can otherwise change the value
+ of this variable is SET TRANSACTION ISOLATION LEVEL.
+ Its purpose is to effect the isolation level of the next
+ transaction in this session. When this statement is executed,
+ the value in this variable is changed. However, since
+ this statement is only allowed when there is no active
+ transaction, this assignment (naturally) only affects the
+ upcoming transaction.
+ At the end of the current active transaction the value is
+ be reset again from @@session.tx_isolation, as described
+ above.
+ */
+ enum_tx_isolation tx_isolation;
enum_check_fields count_cuted_fields;
DYNAMIC_ARRAY user_var_events; /* For user variables replication */
MEM_ROOT *user_var_events_alloc; /* Allocate above array elements here */
+ /*
+ If checking this in conjunction with a wait condition, please
+ include a check after enter_cond() if you want to avoid a race
+ condition. For details see the implementation of awake(),
+ especially the "broadcast" part.
+ */
enum killed_state
{
NOT_KILLED=0,
@@ -1804,11 +2037,8 @@ public:
char scramble[SCRAMBLE_LENGTH+1];
bool slave_thread, one_shot_set;
- /* tells if current statement should binlog row-based(1) or stmt-based(0) */
- bool current_stmt_binlog_row_based;
- bool locked, some_tables_deleted;
- bool last_cuted_field;
- bool no_errors, password;
+ bool no_errors;
+ uchar password;
/**
Set to TRUE if execution of the current compound statement
can not continue. In particular, disables activation of
@@ -1850,6 +2080,10 @@ public:
/** is set if some thread specific value(s) used in a statement. */
bool thread_specific_used;
+ /**
+ is set if a statement accesses a temporary table created through
+ CREATE TEMPORARY TABLE.
+ */
bool charset_is_system_charset, charset_is_collation_connection;
bool charset_is_character_set_filesystem;
bool enable_slow_log; /* enable slow log for current statement */
@@ -1916,15 +2150,30 @@ public:
*/
Parser_state *m_parser_state;
+ Locked_tables_list locked_tables_list;
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
partition_info *work_part_info;
#endif
+#ifndef EMBEDDED_LIBRARY
+ /**
+ Array of active audit plugins which have been used by this THD.
+ This list is later iterated to invoke release_thd() on those
+ plugins.
+ */
+ DYNAMIC_ARRAY audit_class_plugins;
+ /**
+ Array of bits indicating which audit classes have already been
+ added to the list of audit plugins which are currently in use.
+ */
+ unsigned long audit_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
+#endif
+
#if defined(ENABLED_DEBUG_SYNC)
/* Debug Sync facility. See debug_sync.cc. */
struct st_debug_sync_control *debug_sync_control;
#endif /* defined(ENABLED_DEBUG_SYNC) */
-
THD();
~THD();
@@ -1946,15 +2195,15 @@ public:
#ifdef SIGNAL_WITH_VIO_CLOSE
inline void set_active_vio(Vio* vio)
{
- pthread_mutex_lock(&LOCK_thd_data);
+ mysql_mutex_lock(&LOCK_thd_data);
active_vio = vio;
- pthread_mutex_unlock(&LOCK_thd_data);
+ mysql_mutex_unlock(&LOCK_thd_data);
}
inline void clear_active_vio()
{
- pthread_mutex_lock(&LOCK_thd_data);
+ mysql_mutex_lock(&LOCK_thd_data);
active_vio = 0;
- pthread_mutex_unlock(&LOCK_thd_data);
+ mysql_mutex_unlock(&LOCK_thd_data);
}
void close_active_vio();
#endif
@@ -1962,27 +2211,18 @@ public:
#ifndef MYSQL_CLIENT
enum enum_binlog_query_type {
- /*
- The query can be logged row-based or statement-based
- */
+ /* The query can be logged in row format or in statement format. */
ROW_QUERY_TYPE,
- /*
- The query has to be logged statement-based
- */
+ /* The query has to be logged in statement format. */
STMT_QUERY_TYPE,
- /*
- The query represents a change to a table in the "mysql"
- database and is currently mapped to ROW_QUERY_TYPE.
- */
- MYSQL_QUERY_TYPE,
QUERY_TYPE_COUNT
};
int binlog_query(enum_binlog_query_type qtype,
- char const *query, ulong query_len,
- bool is_trans, bool suppress_use,
+ char const *query, ulong query_len, bool is_trans,
+ bool direct, bool suppress_use,
int errcode);
#endif
@@ -1991,11 +2231,11 @@ public:
enter_cond(); this mutex is then released by exit_cond().
Usage must be: lock mutex; enter_cond(); your code; exit_cond().
*/
- inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex,
- const char* msg)
+ inline const char* enter_cond(mysql_cond_t *cond, mysql_mutex_t* mutex,
+ const char* msg)
{
const char* old_msg = proc_info;
- safe_mutex_assert_owner(mutex);
+ mysql_mutex_assert_owner(mutex);
mysys_var->current_mutex = mutex;
mysys_var->current_cond = cond;
proc_info = msg;
@@ -2004,17 +2244,18 @@ public:
inline void exit_cond(const char* old_msg)
{
/*
- Putting the mutex unlock in exit_cond() ensures that
+ Putting the mutex unlock in thd->exit_cond() ensures that
mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
locked (if that would not be the case, you'll get a deadlock if someone
does a THD::awake() on you).
*/
- pthread_mutex_unlock(mysys_var->current_mutex);
- pthread_mutex_lock(&mysys_var->mutex);
+ mysql_mutex_unlock(mysys_var->current_mutex);
+ mysql_mutex_lock(&mysys_var->mutex);
mysys_var->current_mutex = 0;
mysys_var->current_cond = 0;
proc_info = old_msg;
- pthread_mutex_unlock(&mysys_var->mutex);
+ mysql_mutex_unlock(&mysys_var->mutex);
+ return;
}
inline time_t query_start() { query_start_used=1; return start_time; }
inline void set_time()
@@ -2040,17 +2281,87 @@ public:
}
void set_time_after_lock() { utime_after_lock= my_micro_time(); }
ulonglong current_utime() { return my_micro_time(); }
+ /**
+ Update server status after execution of a top level statement.
+
+ Currently only checks if a query was slow, and assigns
+ the status accordingly.
+ Evaluate the current time, and if it exceeds the long-query-time
+ setting, mark the query as slow.
+ */
+ void update_server_status()
+ {
+ ulonglong end_utime_of_query= current_utime();
+ if (end_utime_of_query > utime_after_lock + variables.long_query_time)
+ server_status|= SERVER_QUERY_WAS_SLOW;
+ }
inline ulonglong found_rows(void)
{
return limit_found_rows;
}
- inline bool active_transaction()
+ /**
+ Returns TRUE if session is in a multi-statement transaction mode.
+
+ OPTION_NOT_AUTOCOMMIT: When autocommit is off, a multi-statement
+ transaction is implicitly started on the first statement after a
+ previous transaction has been ended.
+
+ OPTION_BEGIN: Regardless of the autocommit status, a multi-statement
+ transaction can be explicitly started with the statements "START
+ TRANSACTION", "BEGIN [WORK]", "[COMMIT | ROLLBACK] AND CHAIN", etc.
+
+ Note: this doesn't tell you whether a transaction is active.
+ A session can be in multi-statement transaction mode, and yet
+ have no active transaction, e.g., in case of:
+ set @@autocommit=0;
+ set @a= 3; <-- these statements don't
+ set transaction isolation level serializable; <-- start an active
+ flush tables; <-- transaction
+
+ I.e. for the above scenario this function returns TRUE, even
+ though no active transaction has begun.
+ @sa in_active_multi_stmt_transaction()
+ */
+ inline bool in_multi_stmt_transaction_mode()
+ {
+ return variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN);
+ }
+ /**
+ TRUE if the session is in a multi-statement transaction mode
+ (@sa in_multi_stmt_transaction_mode()) *and* there is an
+ active transaction, i.e. there is an explicit start of a
+ transaction with BEGIN statement, or implicit with a
+ statement that uses a transactional engine.
+
+ For example, these scenarios don't start an active transaction
+ (even though the server is in multi-statement transaction mode):
+
+ set @@autocommit=0;
+ select * from nontrans_table;
+ set @var=TRUE;
+ flush tables;
+
+ Note, that even for a statement that starts a multi-statement
+ transaction (i.e. select * from trans_table), this
+ flag won't be set until we open the statement's tables
+ and the engines register themselves for the transaction
+ (see trans_register_ha()),
+ hence this method is reliable to use only after
+ open_tables() has completed.
+
+ Why do we need a flag?
+ ----------------------
+ We need to maintain a (at first glance redundant)
+ session flag, rather than looking at thd->transaction.all.ha_list
+ because of explicit start of a transaction with BEGIN.
+
+ I.e. in case of
+ BEGIN;
+ select * from nontrans_t1; <-- in_active_multi_stmt_transaction() is true
+ */
+ inline bool in_active_multi_stmt_transaction()
{
-#ifdef USING_TRANSACTIONS
return server_status & SERVER_STATUS_IN_TRANS;
-#else
- return 0;
-#endif
}
inline bool fill_derived_tables()
{
@@ -2079,7 +2390,7 @@ public:
void add_changed_table(const char *key, long key_length);
CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length);
int send_explain_fields(select_result *result);
-#ifndef EMBEDDED_LIBRARY
+
/**
Clear the current error, if any.
We do not clear is_fatal_error or is_fatal_sub_stmt_error since we
@@ -2090,15 +2401,26 @@ public:
inline void clear_error()
{
DBUG_ENTER("clear_error");
- if (main_da.is_error())
- main_da.reset_diagnostics_area();
+ if (stmt_da->is_error())
+ stmt_da->reset_diagnostics_area();
is_slave_error= 0;
DBUG_VOID_RETURN;
}
+#ifndef EMBEDDED_LIBRARY
inline bool vio_ok() const { return net.vio != 0; }
+ /** Return FALSE if connection to client is broken. */
+ bool is_connected()
+ {
+ /*
+ All system threads (e.g., the slave IO thread) are connected but
+ not using vio. So this function always returns true for all
+ system threads.
+ */
+ return system_thread || (vio_ok() ? vio_is_connected(net.vio) : FALSE);
+ }
#else
- void clear_error();
- inline bool vio_ok() const { return true; }
+ inline bool vio_ok() const { return TRUE; }
+ inline bool is_connected() { return TRUE; }
#endif
/**
Mark the current error as fatal. Warning: this does not
@@ -2107,6 +2429,7 @@ public:
*/
inline void fatal_error()
{
+ DBUG_ASSERT(stmt_da->is_error() || killed);
is_fatal_error= 1;
DBUG_PRINT("error",("Fatal error set"));
}
@@ -2123,7 +2446,7 @@ public:
To raise this flag, use my_error().
*/
- inline bool is_error() const { return main_da.is_error(); }
+ inline bool is_error() const { return stmt_da->is_error(); }
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
@@ -2182,38 +2505,58 @@ public:
void set_status_var_init();
bool is_context_analysis_only()
{ return stmt_arena->is_stmt_prepare() || lex->view_prepare_mode; }
- void reset_n_backup_open_tables_state(Open_tables_state *backup);
- void restore_backup_open_tables_state(Open_tables_state *backup);
+ void reset_n_backup_open_tables_state(Open_tables_backup *backup);
+ void restore_backup_open_tables_state(Open_tables_backup *backup);
void reset_sub_statement_state(Sub_statement_state *backup, uint new_state);
void restore_sub_statement_state(Sub_statement_state *backup);
void set_n_backup_active_arena(Query_arena *set, Query_arena *backup);
void restore_active_arena(Query_arena *set, Query_arena *backup);
- inline void set_current_stmt_binlog_row_based_if_mixed()
+ /*
+ @todo Make these methods private or remove them completely. Only
+ decide_logging_format should call them. /Sven
+ */
+ inline void set_current_stmt_binlog_format_row_if_mixed()
{
+ DBUG_ENTER("set_current_stmt_binlog_format_row_if_mixed");
+ /*
+ This should only be called from decide_logging_format.
+
+ @todo Once we have ensured this, uncomment the following
+ statement, remove the big comment below that, and remove the
+ in_sub_stmt==0 condition from the following 'if'.
+ */
+ /* DBUG_ASSERT(in_sub_stmt == 0); */
/*
If in a stored/function trigger, the caller should already have done the
change. We test in_sub_stmt to prevent introducing bugs where people
wouldn't ensure that, and would switch to row-based mode in the middle
of executing a stored function/trigger (which is too late, see also
- reset_current_stmt_binlog_row_based()); this condition will make their
+ reset_current_stmt_binlog_format_row()); this condition will make their
tests fail and so force them to propagate the
lex->binlog_row_based_if_mixed upwards to the caller.
*/
if ((variables.binlog_format == BINLOG_FORMAT_MIXED) &&
(in_sub_stmt == 0))
- current_stmt_binlog_row_based= TRUE;
+ set_current_stmt_binlog_format_row();
+
+ DBUG_VOID_RETURN;
}
- inline void set_current_stmt_binlog_row_based()
+ inline void set_current_stmt_binlog_format_row()
{
- current_stmt_binlog_row_based= TRUE;
+ DBUG_ENTER("set_current_stmt_binlog_format_row");
+ current_stmt_binlog_format= BINLOG_FORMAT_ROW;
+ DBUG_VOID_RETURN;
}
- inline void clear_current_stmt_binlog_row_based()
+ inline void clear_current_stmt_binlog_format_row()
{
- current_stmt_binlog_row_based= FALSE;
+ DBUG_ENTER("clear_current_stmt_binlog_format_row");
+ current_stmt_binlog_format= BINLOG_FORMAT_STMT;
+ DBUG_VOID_RETURN;
}
- inline void reset_current_stmt_binlog_row_based()
+ inline void reset_current_stmt_binlog_format_row()
{
+ DBUG_ENTER("reset_current_stmt_binlog_format_row");
/*
If there are temporary tables, don't reset back to
statement-based. Indeed it could be that:
@@ -2228,19 +2571,19 @@ public:
or trigger is decided when it starts executing, depending for example on
the caller (for a stored function: if caller is SELECT or
INSERT/UPDATE/DELETE...).
-
- Don't reset binlog format for NDB binlog injector thread.
*/
DBUG_PRINT("debug",
("temporary_tables: %s, in_sub_stmt: %s, system_thread: %s",
YESNO(temporary_tables), YESNO(in_sub_stmt),
show_system_thread(system_thread)));
- if ((temporary_tables == NULL) && (in_sub_stmt == 0) &&
- (system_thread != SYSTEM_THREAD_NDBCLUSTER_BINLOG))
+ if (in_sub_stmt == 0)
{
- current_stmt_binlog_row_based=
- test(variables.binlog_format == BINLOG_FORMAT_ROW);
+ if (variables.binlog_format == BINLOG_FORMAT_ROW)
+ set_current_stmt_binlog_format_row();
+ else if (temporary_tables == NULL)
+ clear_current_stmt_binlog_format_row();
}
+ DBUG_VOID_RETURN;
}
/**
@@ -2271,8 +2614,11 @@ public:
memcpy(db, new_db, new_db_len+1);
else
{
- x_free(db);
- db= new_db ? my_strndup(new_db, new_db_len, MYF(MY_WME)) : NULL;
+ my_free(db);
+ if (new_db)
+ db= my_strndup(new_db, new_db_len, MYF(MY_WME | ME_FATALERROR));
+ else
+ db= NULL;
}
db_length= db ? new_db_len : 0;
return new_db && !db;
@@ -2323,27 +2669,128 @@ public:
void push_internal_handler(Internal_error_handler *handler);
/**
- Handle an error condition.
- @param sql_errno the error number
- @param level the error level
- @return true if the error is handled
- */
- virtual bool handle_error(uint sql_errno, const char *message,
- MYSQL_ERROR::enum_warning_level level);
+ Handle a sql condition.
+ @param sql_errno the condition error number
+ @param sqlstate the condition sqlstate
+ @param level the condition level
+ @param msg the condition message text
+ @param[out] cond_hdl the sql condition raised, if any
+ @return true if the condition is handled
+ */
+ virtual bool handle_condition(uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl);
/**
Remove the error handler last pushed.
*/
Internal_error_handler *pop_internal_handler();
+ /**
+ Raise an exception condition.
+ @param code the MYSQL_ERRNO error code of the error
+ */
+ void raise_error(uint code);
+
+ /**
+ Raise an exception condition, with a formatted message.
+ @param code the MYSQL_ERRNO error code of the error
+ */
+ void raise_error_printf(uint code, ...);
+
+ /**
+ Raise a completion condition (warning).
+ @param code the MYSQL_ERRNO error code of the warning
+ */
+ void raise_warning(uint code);
+
+ /**
+ Raise a completion condition (warning), with a formatted message.
+ @param code the MYSQL_ERRNO error code of the warning
+ */
+ void raise_warning_printf(uint code, ...);
+
+ /**
+ Raise a completion condition (note), with a fixed message.
+ @param code the MYSQL_ERRNO error code of the note
+ */
+ void raise_note(uint code);
+
+ /**
+ Raise an completion condition (note), with a formatted message.
+ @param code the MYSQL_ERRNO error code of the note
+ */
+ void raise_note_printf(uint code, ...);
+
+private:
+ /*
+ Only the implementation of the SIGNAL and RESIGNAL statements
+ is permitted to raise SQL conditions in a generic way,
+ or to raise them by bypassing handlers (RESIGNAL).
+ To raise a SQL condition, the code should use the public
+ raise_error() or raise_warning() methods provided by class THD.
+ */
+ friend class Signal_common;
+ friend class Signal_statement;
+ friend class Resignal_statement;
+ friend void push_warning(THD*, MYSQL_ERROR::enum_warning_level, uint, const char*);
+ friend void my_message_sql(uint, const char *, myf);
+
+ /**
+ Raise a generic SQL condition.
+ @param sql_errno the condition error number
+ @param sqlstate the condition SQLSTATE
+ @param level the condition level
+ @param msg the condition message text
+ @return The condition raised, or NULL
+ */
+ MYSQL_ERROR*
+ raise_condition(uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg);
+
+public:
/** Overloaded to guard query/query_length fields */
virtual void set_statement(Statement *stmt);
/**
- Assign a new value to thd->query.
+ Assign a new value to thd->query and thd->query_id and mysys_var.
Protected with LOCK_thd_data mutex.
*/
- void set_query(char *query_arg, uint32 query_length_arg);
+ void set_query(char *query_arg, uint32 query_length_arg,
+ CHARSET_INFO *cs_arg)
+ {
+ set_query(CSET_STRING(query_arg, query_length_arg, cs_arg));
+ }
+ void set_query(char *query_arg, uint32 query_length_arg) /*Mutex protected*/
+ {
+ set_query(CSET_STRING(query_arg, query_length_arg, charset()));
+ }
+ void set_query(const CSET_STRING &str); /* Mutex protected */
+ void reset_query() /* Mutex protected */
+ { set_query(CSET_STRING()); }
+ void set_query_and_id(char *query_arg, uint32 query_length_arg,
+ CHARSET_INFO *cs, query_id_t new_query_id);
+ void set_query_id(query_id_t new_query_id);
+ void set_open_tables(TABLE *open_tables_arg)
+ {
+ mysql_mutex_lock(&LOCK_thd_data);
+ open_tables= open_tables_arg;
+ mysql_mutex_unlock(&LOCK_thd_data);
+ }
+ void set_mysys_var(struct st_my_thread_var *new_mysys_var);
+ void enter_locked_tables_mode(enum_locked_tables_mode mode_arg)
+ {
+ DBUG_ASSERT(locked_tables_mode == LTM_NONE);
+
+ mdl_context.set_explicit_duration_for_all_locks();
+ locked_tables_mode= mode_arg;
+ }
+ void leave_locked_tables_mode();
+ int decide_logging_format(TABLE_LIST *tables);
void binlog_invoker() { m_binlog_invoker= TRUE; }
bool need_binlog_invoker() { return m_binlog_invoker; }
void get_definer(LEX_USER *definer);
@@ -2356,6 +2803,7 @@ public:
LEX_STRING get_invoker_host() { return invoker_host; }
bool has_invoker() { return invoker_user.length > 0; }
private:
+
/** The current internal error handler for this thread, or NULL. */
Internal_error_handler *m_internal_handler;
/**
@@ -2374,6 +2822,8 @@ private:
tree itself is reused between executions and thus is stored elsewhere.
*/
MEM_ROOT main_mem_root;
+ Warning_info main_warning_info;
+ Diagnostics_area main_da;
/**
It will be set TURE if CURRENT_USER() is called in account management
@@ -2396,30 +2846,37 @@ private:
};
-/** A short cut for thd->main_da.set_ok_status(). */
+/** A short cut for thd->stmt_da->set_ok_status(). */
inline void
-my_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0,
+my_ok(THD *thd, ulonglong affected_rows= 0, ulonglong id= 0,
const char *message= NULL)
{
- thd->main_da.set_ok_status(thd, affected_rows, id, message);
+ thd->set_row_count_func(affected_rows);
+ thd->stmt_da->set_ok_status(thd, affected_rows, id, message);
}
-/** A short cut for thd->main_da.set_eof_status(). */
+/** A short cut for thd->stmt_da->set_eof_status(). */
inline void
my_eof(THD *thd)
{
- thd->main_da.set_eof_status(thd);
+ thd->set_row_count_func(-1);
+ thd->stmt_da->set_eof_status(thd);
}
#define tmp_disable_binlog(A) \
- {ulonglong tmp_disable_binlog__save_options= (A)->options; \
- (A)->options&= ~OPTION_BIN_LOG
+ {ulonglong tmp_disable_binlog__save_options= (A)->variables.option_bits; \
+ (A)->variables.option_bits&= ~OPTION_BIN_LOG
+
+#define reenable_binlog(A) (A)->variables.option_bits= tmp_disable_binlog__save_options;}
-#define reenable_binlog(A) (A)->options= tmp_disable_binlog__save_options;}
+LEX_STRING *
+make_lex_string_root(MEM_ROOT *mem_root,
+ LEX_STRING *lex_str, const char* str, uint length,
+ bool allocate_lex_string);
/*
Used to hold information about file and file structure in exchange
@@ -2430,18 +2887,18 @@ my_eof(THD *thd)
class sql_exchange :public Sql_alloc
{
public:
+ enum enum_filetype filetype; /* load XML, Added by Arnold & Erik */
char *file_name;
String *field_term,*enclosed,*line_term,*line_start,*escaped;
bool opt_enclosed;
bool dumpfile;
ulong skip_lines;
CHARSET_INFO *cs;
- sql_exchange(char *name,bool dumpfile_flag);
+ sql_exchange(char *name, bool dumpfile_flag,
+ enum_filetype filetype_arg= FILETYPE_CSV);
bool escaped_given(void);
};
-#include "log_event.h"
-
/*
This is used to get result from a select
*/
@@ -2452,7 +2909,6 @@ class select_result :public Sql_alloc {
protected:
THD *thd;
SELECT_LEX_UNIT *unit;
- int nest_level;
public:
select_result();
virtual ~select_result() {};
@@ -2469,7 +2925,7 @@ public:
*/
virtual uint field_count(List<Item> &fields) const
{ return fields.elements; }
- virtual bool send_fields(List<Item> &list, uint flags)=0;
+ virtual bool send_result_set_metadata(List<Item> &list, uint flags)=0;
virtual bool send_data(List<Item> &items)=0;
virtual bool initialize_tables (JOIN *join=0) { return 0; }
virtual void send_error(uint errcode,const char *err);
@@ -2482,19 +2938,13 @@ public:
@retval TRUE error, an error message is set
*/
virtual bool check_simple_select() const;
- virtual void abort() {}
+ virtual void abort_result_set() {}
/*
Cleanup instance of this class for next execution of a prepared
statement/stored procedure.
*/
virtual void cleanup();
void set_thd(THD *thd_arg) { thd= thd_arg; }
- /**
- The nest level, if supported.
- @return
- -1 if nest level is undefined, otherwise a positive integer.
- */
- int get_nest_level() { return nest_level; }
#ifdef EMBEDDED_LIBRARY
virtual void begin_dataset() {}
#else
@@ -2514,7 +2964,7 @@ class select_result_interceptor: public select_result
public:
select_result_interceptor() {} /* Remove gcc warning */
uint field_count(List<Item> &fields) const { return 0; }
- bool send_fields(List<Item> &fields, uint flag) { return FALSE; }
+ bool send_result_set_metadata(List<Item> &fields, uint flag) { return FALSE; }
};
@@ -2527,11 +2977,11 @@ class select_send :public select_result {
bool is_result_set_started;
public:
select_send() :is_result_set_started(FALSE) {}
- bool send_fields(List<Item> &list, uint flags);
+ bool send_result_set_metadata(List<Item> &list, uint flags);
bool send_data(List<Item> &items);
bool send_eof();
virtual bool check_simple_select() const { return FALSE; }
- void abort();
+ void abort_result_set();
virtual void cleanup();
};
@@ -2589,14 +3039,6 @@ class select_export :public select_to_file {
CHARSET_INFO *write_cs; // output charset
public:
select_export(sql_exchange *ex) :select_to_file(ex) {}
- /**
- Creates a select_export to represent INTO OUTFILE <filename> with a
- defined level of subquery nesting.
- */
- select_export(sql_exchange *ex, int nest_level_arg) :select_to_file(ex)
- {
- nest_level= nest_level_arg;
- }
~select_export();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
@@ -2606,24 +3048,13 @@ public:
class select_dump :public select_to_file {
public:
select_dump(sql_exchange *ex) :select_to_file(ex) {}
- /**
- Creates a select_export to represent INTO DUMPFILE <filename> with a
- defined level of subquery nesting.
- */
- select_dump(sql_exchange *ex, int nest_level_arg) :
- select_to_file(ex)
- {
- nest_level= nest_level_arg;
- }
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
};
class select_insert :public select_result_interceptor {
-protected:
- virtual int write_to_binlog(bool is_trans, int errcode);
-public:
+ public:
TABLE_LIST *table_list;
TABLE *table;
List<Item> *fields;
@@ -2642,7 +3073,7 @@ public:
virtual bool can_rollback_data() { return 0; }
void send_error(uint errcode,const char *err);
bool send_eof();
- void abort();
+ virtual void abort_result_set();
/* not implemented: select_insert is never re-used in prepared statements */
void cleanup();
};
@@ -2659,8 +3090,6 @@ class select_create: public select_insert {
MYSQL_LOCK *m_lock;
/* m_lock or thd->extra_lock */
MYSQL_LOCK **m_plock;
-
- virtual int write_to_binlog(bool is_trans, int errcode);
public:
select_create (TABLE_LIST *table_arg,
HA_CREATE_INFO *create_info_par,
@@ -2676,11 +3105,11 @@ public:
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- int binlog_show_create_table(TABLE **tables, uint count, int errcode);
+ int binlog_show_create_table(TABLE **tables, uint count);
void store_values(List<Item> &values);
void send_error(uint errcode,const char *err);
bool send_eof();
- void abort();
+ virtual void abort_result_set();
virtual bool can_rollback_data() { return 1; }
// Needed for access from local class MY_HOOKS in prepare(), since thd is proteted.
@@ -3010,7 +3439,11 @@ public:
int do_deletes();
int do_table_deletes(TABLE *table, bool ignore);
bool send_eof();
- virtual void abort();
+ inline ha_rows num_deleted()
+ {
+ return deleted;
+ }
+ virtual void abort_result_set();
};
@@ -3053,7 +3486,15 @@ public:
void send_error(uint errcode,const char *err);
int do_updates();
bool send_eof();
- virtual void abort();
+ inline ha_rows num_found()
+ {
+ return found;
+ }
+ inline ha_rows num_updated()
+ {
+ return updated;
+ }
+ virtual void abort_result_set();
};
class my_var : public Sql_alloc {
@@ -3080,16 +3521,6 @@ class select_dumpvar :public select_result_interceptor {
public:
List<my_var> var_list;
select_dumpvar() { var_list.empty(); row_count= 0;}
- /**
- Creates a select_dumpvar to represent INTO <variable> with a defined
- level of subquery nesting.
- */
- select_dumpvar(int nest_level_arg)
- {
- var_list.empty();
- row_count= 0;
- nest_level= nest_level_arg;
- }
~select_dumpvar() {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
@@ -3100,11 +3531,11 @@ public:
/* Bits in sql_command_flags */
-#define CF_CHANGES_DATA 1
-#define CF_HAS_ROW_COUNT 2
-#define CF_STATUS_COMMAND 4
-#define CF_SHOW_TABLE_COMMAND 8
-#define CF_WRITE_LOGS_COMMAND 16
+#define CF_CHANGES_DATA (1U << 0)
+/* The 2nd bit is unused -- it used to be CF_HAS_ROW_COUNT. */
+#define CF_STATUS_COMMAND (1U << 2)
+#define CF_SHOW_TABLE_COMMAND (1U << 3)
+#define CF_WRITE_LOGS_COMMAND (1U << 4)
/**
Must be set for SQL statements that may contain
Item expressions and/or use joins and tables.
@@ -3118,9 +3549,70 @@ public:
reprepare. Consequently, complex item expressions and
joins are currently prohibited in these statements.
*/
-#define CF_REEXECUTION_FRAGILE 32
+#define CF_REEXECUTION_FRAGILE (1U << 5)
+/**
+ Implicitly commit before the SQL statement is executed.
+
+ Statements marked with this flag will cause any active
+ transaction to end (commit) before proceeding with the
+ command execution.
+
+ This flag should be set for statements that probably can't
+ be rolled back or that do not expect any previously metadata
+ locked tables.
+*/
+#define CF_IMPLICT_COMMIT_BEGIN (1U << 6)
+/**
+ Implicitly commit after the SQL statement.
+
+ Statements marked with this flag are automatically committed
+ at the end of the statement.
+
+ This flag should be set for statements that will implicitly
+ open and take metadata locks on system tables that should not
+ be carried for the whole duration of a active transaction.
+*/
+#define CF_IMPLICIT_COMMIT_END (1U << 7)
+/**
+ CF_IMPLICT_COMMIT_BEGIN and CF_IMPLICIT_COMMIT_END are used
+ to ensure that the active transaction is implicitly committed
+ before and after every DDL statement and any statement that
+ modifies our currently non-transactional system tables.
+*/
+#define CF_AUTO_COMMIT_TRANS (CF_IMPLICT_COMMIT_BEGIN | CF_IMPLICIT_COMMIT_END)
+
+/**
+ Diagnostic statement.
+ Diagnostic statements:
+ - SHOW WARNING
+ - SHOW ERROR
+ - GET DIAGNOSTICS (WL#2111)
+ do not modify the diagnostics area during execution.
+*/
+#define CF_DIAGNOSTIC_STMT (1U << 8)
+
+/**
+ Identifies statements that may generate row events
+ and that may end up in the binary log.
+*/
+#define CF_CAN_GENERATE_ROW_EVENTS (1U << 9)
+
+/* Bits in server_command_flags */
+
+/**
+ Skip the increase of the global query id counter. Commonly set for
+ commands that are stateless (won't cause any change on the server
+ internal states).
+*/
+#define CF_SKIP_QUERY_ID (1U << 0)
-/* Functions in sql_class.cc */
+/**
+ Skip the increase of the number of statements that clients have
+ sent to the server. Commonly used for commands that will cause
+ a statement to be executed but the statement might have not been
+ sent by the user (ie: stored procedure).
+*/
+#define CF_SKIP_QUESTIONS (1U << 1)
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
@@ -3128,4 +3620,49 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
STATUS_VAR *dec_var);
void mark_transaction_to_rollback(THD *thd, bool all);
+/*
+ This prototype is placed here instead of in item_func.h because it
+ depends on the definition of enum_sql_command, which is in this
+ file.
+ */
+int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
+ LEX_STRING &name, user_var_entry **out_entry);
+
+/* Inline functions */
+
+inline bool add_item_to_list(THD *thd, Item *item)
+{
+ return thd->lex->current_select->add_item_to_list(thd, item);
+}
+
+inline bool add_value_to_list(THD *thd, Item *value)
+{
+ return thd->lex->value_list.push_back(value);
+}
+
+inline bool add_order_to_list(THD *thd, Item *item, bool asc)
+{
+ return thd->lex->current_select->add_order_to_list(thd, item, asc);
+}
+
+inline bool add_group_to_list(THD *thd, Item *item, bool asc)
+{
+ return thd->lex->current_select->add_group_to_list(thd, item, asc);
+}
+
#endif /* MYSQL_SERVER */
+
+/**
+ The meat of thd_proc_info(THD*, char*), a macro that packs the last
+ three calling-info parameters.
+*/
+extern "C"
+const char *set_thd_proc_info(void *thd_arg, const char *info,
+ const char *calling_func,
+ const char *calling_file,
+ const unsigned int calling_line);
+
+#define thd_proc_info(thd, msg) \
+ set_thd_proc_info(thd, msg, __func__, __FILE__, __LINE__)
+
+#endif /* SQL_CLASS_INCLUDED */
diff --git a/sql/sql_client.cc b/sql/sql_client.cc
index 032a2e26e3a..0c16449276a 100644
--- a/sql/sql_client.cc
+++ b/sql/sql_client.cc
@@ -17,7 +17,8 @@
This files defines some MySQL C API functions that are server specific
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_class.h" // system_variables
/*
Function called by my_net_init() to set some check variables
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 9fa6966baa2..d03d77c1f66 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007 MySQL AB
+/* Copyright (C) 2007 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -18,9 +18,26 @@
Functions to autenticate and handle reqests for a connection
*/
-#include "mysql_priv.h"
-
-#ifdef HAVE_OPENSSL
+#include "my_global.h"
+#include "sql_priv.h"
+#ifndef __WIN__
+#include <netdb.h> // getservbyname, servent
+#endif
+#include "sql_audit.h"
+#include "sql_connect.h"
+#include "my_global.h"
+#include "probes_mysql.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_parse.h" // sql_command_flags,
+ // execute_init_command,
+ // do_command
+#include "sql_db.h" // mysql_change_db
+#include "hostname.h" // inc_host_errors, ip_to_hostname,
+ // reset_host_errors
+#include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL
+#include "sql_callback.h"
+
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
/*
Without SSL the handshake consists of one packet. This packet
has both client capabilites and scrambled password.
@@ -36,11 +53,7 @@
#define MIN_HANDSHAKE_SIZE 2
#else
#define MIN_HANDSHAKE_SIZE 6
-#endif /* HAVE_OPENSSL */
-
-#ifdef __WIN__
-extern void win_install_sigabrt_handler();
-#endif
+#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
/*
Get structure for logging connection data for the current user
@@ -49,9 +62,9 @@ extern void win_install_sigabrt_handler();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
static HASH hash_user_connections;
-static int get_or_create_user_conn(THD *thd, const char *user,
- const char *host,
- USER_RESOURCES *mqh)
+int get_or_create_user_conn(THD *thd, const char *user,
+ const char *host,
+ const USER_RESOURCES *mqh)
{
int return_val= 0;
size_t temp_len, user_len;
@@ -63,8 +76,8 @@ static int get_or_create_user_conn(THD *thd, const char *user,
user_len= strlen(user);
temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
+ mysql_mutex_lock(&LOCK_user_conn);
+ if (!(uc = (struct user_conn *) my_hash_search(&hash_user_connections,
(uchar*) temp_user, temp_len)))
{
/* First connection for user; Create a user connection object */
@@ -86,7 +99,7 @@ static int get_or_create_user_conn(THD *thd, const char *user,
if (my_hash_insert(&hash_user_connections, (uchar*) uc))
{
/* The only possible error is out of memory, MY_WME sets an error. */
- my_free((char*) uc,0);
+ my_free(uc);
return_val= 1;
goto end;
}
@@ -94,7 +107,7 @@ static int get_or_create_user_conn(THD *thd, const char *user,
thd->user_connect=uc;
uc->connections++;
end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
+ mysql_mutex_unlock(&LOCK_user_conn);
return return_val;
}
@@ -117,15 +130,15 @@ end:
1 error
*/
-static
int check_for_max_user_connections(THD *thd, USER_CONN *uc)
{
int error=0;
DBUG_ENTER("check_for_max_user_connections");
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (max_user_connections && !uc->user_resources.user_conn &&
- max_user_connections < (uint) uc->connections)
+ mysql_mutex_lock(&LOCK_user_conn);
+ if (global_system_variables.max_user_connections &&
+ !uc->user_resources.user_conn &&
+ global_system_variables.max_user_connections < (uint) uc->connections)
{
my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user);
error=1;
@@ -154,8 +167,16 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
end:
if (error)
+ {
uc->connections--; // no need for decrease_user_connections() here
- (void) pthread_mutex_unlock(&LOCK_user_conn);
+ /*
+ The thread may returned back to the pool and assigned to a user
+ that doesn't have a limit. Ensure the user is not using resources
+ of someone else.
+ */
+ thd->user_connect= NULL;
+ }
+ mysql_mutex_unlock(&LOCK_user_conn);
DBUG_RETURN(error);
}
@@ -181,14 +202,14 @@ end:
void decrease_user_connections(USER_CONN *uc)
{
DBUG_ENTER("decrease_user_connections");
- (void) pthread_mutex_lock(&LOCK_user_conn);
+ mysql_mutex_lock(&LOCK_user_conn);
DBUG_ASSERT(uc->connections);
if (!--uc->connections && !mqh_used)
{
/* Last connection for user; Delete it */
- (void) hash_delete(&hash_user_connections,(uchar*) uc);
+ (void) my_hash_delete(&hash_user_connections,(uchar*) uc);
}
- (void) pthread_mutex_unlock(&LOCK_user_conn);
+ mysql_mutex_unlock(&LOCK_user_conn);
DBUG_VOID_RETURN;
}
@@ -236,7 +257,7 @@ bool check_mqh(THD *thd, uint check_command)
DBUG_ENTER("check_mqh");
DBUG_ASSERT(uc != 0);
- (void) pthread_mutex_lock(&LOCK_user_conn);
+ mysql_mutex_lock(&LOCK_user_conn);
time_out_user_resource_limits(thd, uc);
@@ -263,246 +284,12 @@ bool check_mqh(THD *thd, uint check_command)
}
}
end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
+ mysql_mutex_unlock(&LOCK_user_conn);
DBUG_RETURN(error);
}
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-
-/**
- Check if user exist and password supplied is correct.
-
- @param thd thread handle, thd->security_ctx->{host,user,ip} are used
- @param command originator of the check: now check_user is called
- during connect and change user procedures; used for
- logging.
- @param passwd scrambled password received from client
- @param passwd_len length of scrambled password
- @param db database name to connect to, may be NULL
- @param check_count TRUE if establishing a new connection. In this case
- check that we have not exceeded the global
- max_connections limist
-
- @note Host, user and passwd may point to communication buffer.
- Current implementation does not depend on that, but future changes
- should be done with this in mind; 'thd' is INOUT, all other params
- are 'IN'.
-
- @retval 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
- thd->db are updated; OK is sent to the client.
- @retval 1 error, e.g. access denied or handshake error, not sent to
- the client. A message is pushed into the error stack.
-*/
-
-int
-check_user(THD *thd, enum enum_server_command command,
- const char *passwd, uint passwd_len, const char *db,
- bool check_count)
-{
- DBUG_ENTER("check_user");
- LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
-
- /*
- Clear thd->db as it points to something, that will be freed when
- connection is closed. We don't want to accidentally free a wrong
- pointer if connect failed. Also in case of 'CHANGE USER' failure,
- current database will be switched to 'no database selected'.
- */
- thd->reset_db(NULL, 0);
-
-#ifdef NO_EMBEDDED_ACCESS_CHECKS
- thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
- /* Change database if necessary */
- if (db && db[0])
- {
- if (mysql_change_db(thd, &db_str, FALSE))
- DBUG_RETURN(1);
- }
- my_ok(thd);
- DBUG_RETURN(0);
-#else
-
- my_bool opt_secure_auth_local;
- pthread_mutex_lock(&LOCK_global_system_variables);
- opt_secure_auth_local= opt_secure_auth;
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
- /*
- If the server is running in secure auth mode, short scrambles are
- forbidden.
- */
- if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
- {
- my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
- general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- DBUG_RETURN(1);
- }
- if (passwd_len != 0 &&
- passwd_len != SCRAMBLE_LENGTH &&
- passwd_len != SCRAMBLE_LENGTH_323)
- {
- my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
- DBUG_RETURN(1);
- }
-
- USER_RESOURCES ur;
- int res= acl_getroot(thd, &ur, passwd, passwd_len);
-#ifndef EMBEDDED_LIBRARY
- if (res == -1)
- {
- /*
- This happens when client (new) sends password scrambled with
- scramble(), but database holds old value (scrambled with
- scramble_323()). Here we please client to send scrambled_password
- in old format.
- */
- NET *net= &thd->net;
- if (opt_secure_auth_local)
- {
- my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip);
- general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip);
- DBUG_RETURN(1);
- }
- /* We have to read very specific packet size */
- if (send_old_password_request(thd) ||
- my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
- {
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
- DBUG_RETURN(1);
- }
- /* Final attempt to check the user based on reply */
- /* So as passwd is short, errcode is always >= 0 */
- res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
- }
-#endif /*EMBEDDED_LIBRARY*/
- /* here res is always >= 0 */
- if (res == 0)
- {
- if (!(thd->main_security_ctx.master_access &
- NO_ACCESS)) // authentication is OK
- {
- DBUG_PRINT("info",
- ("Capabilities: %lu packet_length: %ld Host: '%s' "
- "Login user: '%s' Priv_user: '%s' Using password: %s "
- "Access: %lu db: '%s'",
- thd->client_capabilities,
- thd->max_client_packet_length,
- thd->main_security_ctx.host_or_ip,
- thd->main_security_ctx.user,
- thd->main_security_ctx.priv_user,
- passwd_len ? "yes": "no",
- thd->main_security_ctx.master_access,
- (thd->db ? thd->db : "*none*")));
-
- if (check_count)
- {
- pthread_mutex_lock(&LOCK_connection_count);
- bool count_ok= connection_count <= max_connections ||
- (thd->main_security_ctx.master_access & SUPER_ACL);
- VOID(pthread_mutex_unlock(&LOCK_connection_count));
-
- if (!count_ok)
- { // too many connections
- my_error(ER_CON_COUNT_ERROR, MYF(0));
- DBUG_RETURN(1);
- }
- }
-
- /*
- Log the command before authentication checks, so that the user can
- check the log for the tried login tried and also to detect
- break-in attempts.
- */
- general_log_print(thd, command,
- (thd->main_security_ctx.priv_user ==
- thd->main_security_ctx.user ?
- (char*) "%s@%s on %s" :
- (char*) "%s@%s as anonymous on %s"),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- db ? db : (char*) "");
-
- /*
- This is the default access rights for the current database. It's
- set to 0 here because we don't have an active database yet (and we
- may not have an active database to set.
- */
- thd->main_security_ctx.db_access=0;
-
- /* Don't allow user to connect if he has done too many queries */
- if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
- max_user_connections) &&
- get_or_create_user_conn(thd,
- (opt_old_style_user_limits ? thd->main_security_ctx.user :
- thd->main_security_ctx.priv_user),
- (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
- thd->main_security_ctx.priv_host),
- &ur))
- {
- /* The error is set by get_or_create_user_conn(). */
- DBUG_RETURN(1);
- }
- if (thd->user_connect &&
- (thd->user_connect->user_resources.conn_per_hour ||
- thd->user_connect->user_resources.user_conn ||
- max_user_connections) &&
- check_for_max_user_connections(thd, thd->user_connect))
- {
- /* The error is set in check_for_max_user_connections(). */
- DBUG_RETURN(1);
- }
-
- /* Change database if necessary */
- if (db && db[0])
- {
- if (mysql_change_db(thd, &db_str, FALSE))
- {
- /* mysql_change_db() has pushed the error message. */
- if (thd->user_connect)
- decrease_user_connections(thd->user_connect);
- DBUG_RETURN(1);
- }
- }
- my_ok(thd);
- thd->password= test(passwd_len); // remember for error messages
-#ifndef EMBEDDED_LIBRARY
- /*
- Allow the network layer to skip big packets. Although a malicious
- authenticated session might use this to trick the server to read
- big packets indefinitely, this is a previously established behavior
- that needs to be preserved as to not break backwards compatibility.
- */
- thd->net.skip_big_packet= TRUE;
-#endif
- /* Ready to handle queries */
- DBUG_RETURN(0);
- }
- }
- else if (res == 2) // client gave short hash, server has long hash
- {
- my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
- general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- DBUG_RETURN(1);
- }
- my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
- general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
- DBUG_RETURN(1);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-
/*
Check for maximum allowable user connections, if the mysqld server is
started with corresponding variable that is greater then 0.
@@ -518,17 +305,17 @@ extern "C" uchar *get_key_conn(user_conn *buff, size_t *length,
extern "C" void free_user(struct user_conn *uc)
{
- my_free((char*) uc,MYF(0));
+ my_free(uc);
}
void init_max_user_conn(void)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
- 0,0,
- (hash_get_key) get_key_conn, (hash_free_key) free_user,
- 0);
+ (void)
+ my_hash_init(&hash_user_connections,system_charset_info,max_connections,
+ 0,0, (my_hash_get_key) get_key_conn,
+ (my_hash_free_key) free_user, 0);
#endif
}
@@ -536,7 +323,7 @@ void init_max_user_conn(void)
void free_max_user_conn(void)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- hash_free(&hash_user_connections);
+ my_hash_free(&hash_user_connections);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
@@ -544,7 +331,7 @@ void free_max_user_conn(void)
void reset_mqh(LEX_USER *lu, bool get_them= 0)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- (void) pthread_mutex_lock(&LOCK_user_conn);
+ mysql_mutex_lock(&LOCK_user_conn);
if (lu) // for GRANT
{
USER_CONN *uc;
@@ -554,8 +341,9 @@ void reset_mqh(LEX_USER *lu, bool get_them= 0)
memcpy(temp_user,lu->user.str,lu->user.length);
memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
- if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
- (uchar*) temp_user, temp_len)))
+ if ((uc = (struct user_conn *) my_hash_search(&hash_user_connections,
+ (uchar*) temp_user,
+ temp_len)))
{
uc->questions=0;
get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
@@ -568,8 +356,8 @@ void reset_mqh(LEX_USER *lu, bool get_them= 0)
/* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
for (uint idx=0;idx < hash_user_connections.records; idx++)
{
- USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
- idx);
+ USER_CONN *uc=(struct user_conn *)
+ my_hash_element(&hash_user_connections, idx);
if (get_them)
get_mqh(uc->user,uc->host,uc);
uc->questions=0;
@@ -577,7 +365,7 @@ void reset_mqh(LEX_USER *lu, bool get_them= 0)
uc->conn_per_hour=0;
}
}
- (void) pthread_mutex_unlock(&LOCK_user_conn);
+ mysql_mutex_unlock(&LOCK_user_conn);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
@@ -620,16 +408,12 @@ void thd_init_client_charset(THD *thd, uint cs_number)
bool init_new_connection_handler_thread()
{
pthread_detach_this_thread();
-#if defined(__WIN__)
- win_install_sigabrt_handler();
-#else
- /* Win32 calls this in pthread_create */
if (my_thread_init())
return 1;
-#endif /* __WIN__ */
return 0;
}
+#ifndef EMBEDDED_LIBRARY
/*
Perform handshake, authorize client and update thd ACL variables.
@@ -638,18 +422,14 @@ bool init_new_connection_handler_thread()
thd thread handle
RETURN
- 0 success, OK is sent to user, thd is updated.
- -1 error, which is sent to user
- > 0 error code (not sent to user)
+ 0 success, thd is updated.
+ 1 error
*/
-#ifndef EMBEDDED_LIBRARY
static int check_connection(THD *thd)
{
uint connect_errors= 0;
NET *net= &thd->net;
- ulong pkt_len= 0;
- char *end;
DBUG_PRINT("info",
("New connection received on %s", vio_description(net->vio)));
@@ -659,9 +439,9 @@ static int check_connection(THD *thd)
if (!thd->main_security_ctx.host) // If TCP/IP connection
{
- char ip[30];
+ char ip[NI_MAXHOST];
- if (vio_peer_addr(net->vio, ip, &thd->peer_port))
+ if (vio_peer_addr(net->vio, ip, &thd->peer_port, NI_MAXHOST))
{
my_error(ER_BAD_HOST_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
@@ -669,12 +449,15 @@ static int check_connection(THD *thd)
if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME))))
return 1; /* The error is set by my_strdup(). */
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
- vio_in_addr(net->vio,&thd->remote.sin_addr);
if (!(specialflag & SPECIAL_NO_RESOLVE))
{
- vio_in_addr(net->vio,&thd->remote.sin_addr);
- thd->main_security_ctx.host=
- ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
+ if (ip_to_hostname(&net->vio->remote, thd->main_security_ctx.ip,
+ &thd->main_security_ctx.host, &connect_errors))
+ {
+ my_error(ER_BAD_HOST_ERROR, MYF(0), ip);
+ return 1;
+ }
+
/* Cut very long hostnames to avoid possible overflows */
if (thd->main_security_ctx.host)
{
@@ -707,216 +490,14 @@ static int check_connection(THD *thd)
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
thd->main_security_ctx.ip= 0;
/* Reset sin_addr */
- bzero((char*) &thd->remote, sizeof(thd->remote));
+ bzero((char*) &net->vio->remote, sizeof(net->vio->remote));
}
vio_keepalive(net->vio, TRUE);
- ulong server_capabilites;
- {
- /* buff[] needs to big enough to hold the server_version variable */
- char buff[SERVER_VERSION_LENGTH + 1 + SCRAMBLE_LENGTH + 1 + 64];
- server_capabilites= CLIENT_BASIC_FLAGS;
-
- if (opt_using_transactions)
- server_capabilites|= CLIENT_TRANSACTIONS;
-#ifdef HAVE_COMPRESS
- server_capabilites|= CLIENT_COMPRESS;
-#endif /* HAVE_COMPRESS */
-#ifdef HAVE_OPENSSL
- if (ssl_acceptor_fd)
- {
- server_capabilites |= CLIENT_SSL; /* Wow, SSL is available! */
- server_capabilites |= CLIENT_SSL_VERIFY_SERVER_CERT;
- }
-#endif /* HAVE_OPENSSL */
-
- end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
- int4store((uchar*) end, thd->thread_id);
- end+= 4;
- /*
- So as check_connection is the only entry point to authorization
- procedure, scramble is set here. This gives us new scramble for
- each handshake.
- */
- create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
- /*
- Old clients does not understand long scrambles, but can ignore packet
- tail: that's why first part of the scramble is placed here, and second
- part at the end of packet.
- */
- end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
-
- int2store(end, server_capabilites);
- /* write server characteristics: up to 16 bytes allowed */
- end[2]=(char) default_charset_info->number;
- int2store(end+3, thd->server_status);
- bzero(end+5, 13);
- end+= 18;
- /* write scramble tail */
- end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
- SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
-
- /* At this point we write connection message and read reply */
- if (net_write_command(net, (uchar) protocol_version, (uchar*) "", 0,
- (uchar*) buff, (size_t) (end-buff)) ||
- (pkt_len= my_net_read(net)) == packet_error ||
- pkt_len < MIN_HANDSHAKE_SIZE)
- {
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0),
- thd->main_security_ctx.host_or_ip);
- return 1;
- }
- }
-#ifdef _CUSTOMCONFIG_
-#include "_cust_sql_parse.h"
-#endif
- if (connect_errors)
- reset_host_errors(&thd->remote.sin_addr);
if (thd->packet.alloc(thd->variables.net_buffer_length))
return 1; /* The error is set by alloc(). */
- thd->client_capabilities= uint2korr(net->read_pos);
- if (thd->client_capabilities & CLIENT_PROTOCOL_41)
- {
- thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
- thd->max_client_packet_length= uint4korr(net->read_pos+4);
- DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
- thd_init_client_charset(thd, (uint) net->read_pos[8]);
- thd->update_charset();
- end= (char*) net->read_pos+32;
- }
- else
- {
- thd->max_client_packet_length= uint3korr(net->read_pos+2);
- end= (char*) net->read_pos+5;
- }
- /*
- Disable those bits which are not supported by the server.
- This is a precautionary measure, if the client lies. See Bug#27944.
- */
- thd->client_capabilities&= server_capabilites;
-
- if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
- thd->variables.sql_mode|= MODE_IGNORE_SPACE;
-#ifdef HAVE_OPENSSL
- DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
- if (thd->client_capabilities & CLIENT_SSL)
- {
- /* Do the SSL layering. */
- if (!ssl_acceptor_fd)
- {
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
- return 1;
- }
- DBUG_PRINT("info", ("IO layer change in progress..."));
- if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
- {
- DBUG_PRINT("error", ("Failed to accept new SSL connection"));
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
- return 1;
- }
- DBUG_PRINT("info", ("Reading user information over SSL layer"));
- if ((pkt_len= my_net_read(net)) == packet_error ||
- pkt_len < NORMAL_HANDSHAKE_SIZE)
- {
- DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
- pkt_len));
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
- return 1;
- }
- }
-#endif /* HAVE_OPENSSL */
-
- if (end >= (char*) net->read_pos+ pkt_len +2)
- {
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
- return 1;
- }
-
- if (thd->client_capabilities & CLIENT_INTERACTIVE)
- thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
- if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
- opt_using_transactions)
- net->return_status= &thd->server_status;
-
- char *user= end;
- char *passwd= strend(user)+1;
- uint user_len= passwd - user - 1;
- char *db= passwd;
- char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
- char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
- uint dummy_errors;
-
- /*
- Old clients send null-terminated string as password; new clients send
- the size (1 byte) + string (not null-terminated). Hence in case of empty
- password both send '\0'.
-
- This strlen() can't be easily deleted without changing protocol.
-
- Cast *passwd to an unsigned char, so that it doesn't extend the sign for
- *passwd > 127 and become 2**32-127+ after casting to uint.
- */
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- (uchar)(*passwd++) : strlen(passwd);
- db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
- db + passwd_len + 1 : 0;
- /* strlen() can't be easily deleted without changing protocol */
- uint db_len= db ? strlen(db) : 0;
-
- if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
- {
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
- return 1;
- }
-
- /* Since 4.1 all database names are stored in utf8 */
- if (db)
- {
- db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
- system_charset_info,
- db, db_len,
- thd->charset(), &dummy_errors)]= 0;
- db= db_buff;
- }
-
- user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
- system_charset_info, user, user_len,
- thd->charset(), &dummy_errors)]= '\0';
- user= user_buff;
-
- /* If username starts and ends in "'", chop them off */
- if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
- {
- user[user_len-1]= 0;
- user++;
- user_len-= 2;
- }
-
- /*
- Clip username to allowed length in characters (not bytes). This is
- mostly for backward compatibility.
- */
- {
- CHARSET_INFO *cs= system_charset_info;
- int err;
-
- user_len= (uint) cs->cset->well_formed_len(cs, user, user + user_len,
- USERNAME_CHAR_LENGTH, &err);
- user[user_len]= '\0';
- }
-
- if (thd->main_security_ctx.user)
- x_free(thd->main_security_ctx.user);
- if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME))))
- return 1; /* The error is set by my_strdup(). */
- return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
+ return acl_authenticate(thd, connect_errors, 0);
}
@@ -939,7 +520,7 @@ bool setup_connection_thread_globals(THD *thd)
{
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
statistic_increment(aborted_connects,&LOCK_status);
- thread_scheduler.end_thread(thd, 0);
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
return 1; // Error
}
return 0;
@@ -962,7 +543,7 @@ bool setup_connection_thread_globals(THD *thd)
*/
-static bool login_connection(THD *thd)
+bool login_connection(THD *thd)
{
NET *net= &thd->net;
int error;
@@ -975,11 +556,11 @@ static bool login_connection(THD *thd)
my_net_set_write_timeout(net, connect_timeout);
error= check_connection(thd);
- net_end_statement(thd);
+ thd->protocol->end_statement();
if (error)
{ // Wrong permissions
-#ifdef __NT__
+#ifdef _WIN32
if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
my_sleep(1000); /* must wait after eof() */
#endif
@@ -1000,12 +581,20 @@ static bool login_connection(THD *thd)
This mainly updates status variables
*/
-static void end_connection(THD *thd)
+void end_connection(THD *thd)
{
NET *net= &thd->net;
plugin_thdvar_cleanup(thd);
if (thd->user_connect)
+ {
decrease_user_connections(thd->user_connect);
+ /*
+ The thread may returned back to the pool and assigned to a user
+ that doesn't have a limit. Ensure the user is not using resources
+ of someone else.
+ */
+ thd->user_connect= NULL;
+ }
if (thd->killed || (net->error && net->vio != 0))
{
@@ -1022,7 +611,7 @@ static void end_connection(THD *thd)
thd->thread_id,(thd->db ? thd->db : "unconnected"),
sctx->user ? sctx->user : "unauthenticated",
sctx->host_or_ip,
- (thd->main_da.is_error() ? thd->main_da.message() :
+ (thd->stmt_da->is_error() ? thd->stmt_da->message() :
ER(ER_UNKNOWN_ERROR)));
}
}
@@ -1033,16 +622,10 @@ static void end_connection(THD *thd)
Initialize THD to handle queries
*/
-static void prepare_new_connection_state(THD* thd)
+void prepare_new_connection_state(THD* thd)
{
Security_context *sctx= thd->security_ctx;
-#ifdef __NETWARE__
- netware_reg_user(sctx->ip, sctx->user, "MySQL");
-#endif
-
- if (thd->variables.max_join_size == HA_POS_ERROR)
- thd->options |= OPTION_BIG_SELECTS;
if (thd->client_capabilities & CLIENT_COMPRESS)
thd->net.compress=1; // Use compression
@@ -1051,15 +634,14 @@ static void prepare_new_connection_state(THD* thd)
embedded server library.
TODO: refactor this to avoid code duplication there
*/
- thd->version= refresh_version;
thd->proc_info= 0;
thd->command= COM_SLEEP;
thd->set_time();
thd->init_for_queries();
- if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
+ if (opt_init_connect.length && !(sctx->master_access & SUPER_ACL))
{
- execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
+ execute_init_command(thd, &opt_init_connect, &LOCK_sys_init_connect);
if (thd->is_error())
{
thd->killed= THD::KILL_CONNECTION;
@@ -1067,7 +649,7 @@ static void prepare_new_connection_state(THD* thd)
thd->thread_id,(thd->db ? thd->db : "unconnected"),
sctx->user ? sctx->user : "unauthenticated",
sctx->host_or_ip, "init_connect command failed");
- sql_print_warning("%s", thd->main_da.message());
+ sql_print_warning("%s", thd->stmt_da->message());
}
thd->proc_info=0;
thd->set_time();
@@ -1097,14 +679,24 @@ pthread_handler_t handle_one_connection(void *arg)
{
THD *thd= (THD*) arg;
+ mysql_thread_set_psi_id(thd->thread_id);
+
+ do_handle_one_connection(thd);
+ return 0;
+}
+
+void do_handle_one_connection(THD *thd_arg)
+{
+ THD *thd= thd_arg;
+
thd->thr_create_utime= my_micro_time();
- if (thread_scheduler.init_new_connection_thread())
+ if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0))
{
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
statistic_increment(aborted_connects,&LOCK_status);
- thread_scheduler.end_thread(thd,0);
- return 0;
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
+ return;
}
/*
@@ -1131,7 +723,7 @@ pthread_handler_t handle_one_connection(void *arg)
*/
thd->thread_stack= (char*) &thd;
if (setup_connection_thread_globals(thd))
- return 0;
+ return;
for (;;)
{
@@ -1141,11 +733,15 @@ pthread_handler_t handle_one_connection(void *arg)
if (login_connection(thd))
goto end_thread;
+ MYSQL_CONNECTION_START(thd->thread_id, thd->security_ctx->priv_user,
+ (char *) thd->security_ctx->host_or_ip);
+
prepare_new_connection_state(thd);
while (!net->error && net->vio != 0 &&
!(thd->killed == THD::KILL_CONNECTION))
{
+ mysql_audit_release(thd);
if (do_command(thd))
break;
}
@@ -1153,8 +749,8 @@ pthread_handler_t handle_one_connection(void *arg)
end_thread:
close_connection(thd, 0, 1);
- if (thread_scheduler.end_thread(thd,1))
- return 0; // Probably no-threads
+ if (MYSQL_CALLBACK_ELSE(thread_scheduler, end_thread, (thd, 1), 0))
+ return; // Probably no-threads
/*
If end_thread() returns, we are either running with
diff --git a/sql/sql_connect.h b/sql/sql_connect.h
new file mode 100644
index 00000000000..666db4c6462
--- /dev/null
+++ b/sql/sql_connect.h
@@ -0,0 +1,50 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_CONNECT_INCLUDED
+#define SQL_CONNECT_INCLUDED
+
+#include "my_sys.h" /* pthread_handler_t */
+#include "mysql_com.h" /* enum_server_command */
+
+class THD;
+typedef struct st_lex_user LEX_USER;
+typedef struct user_conn USER_CONN;
+
+void init_max_user_conn(void);
+void free_max_user_conn(void);
+
+pthread_handler_t handle_one_connection(void *arg);
+void do_handle_one_connection(THD *thd_arg);
+bool init_new_connection_handler_thread();
+void reset_mqh(LEX_USER *lu, bool get_them);
+bool check_mqh(THD *thd, uint check_command);
+void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
+void decrease_user_connections(USER_CONN *uc);
+void thd_init_client_charset(THD *thd, uint cs_number);
+bool setup_connection_thread_globals(THD *thd);
+
+int check_user(THD *thd, enum enum_server_command command,
+ const char *passwd, uint passwd_len, const char *db,
+ bool check_count);
+
+bool login_connection(THD *thd);
+void prepare_new_connection_state(THD* thd);
+void end_connection(THD *thd);
+int get_or_create_user_conn(THD *thd, const char *user,
+ const char *host, const USER_RESOURCES *mqh);
+int check_for_max_user_connections(THD *thd, USER_CONN *uc);
+
+#endif /* SQL_CONNECT_INCLUDED */
diff --git a/sql/sql_const.h b/sql/sql_const.h
new file mode 100644
index 00000000000..dca66628ddb
--- /dev/null
+++ b/sql/sql_const.h
@@ -0,0 +1,248 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 */
+
+/**
+ @file
+ File containing constants that can be used throughout the server.
+
+ @note This file shall not contain any includes of any kinds.
+*/
+
+#ifndef SQL_CONST_INCLUDED
+#define SQL_CONST_INCLUDED
+
+#define LIBLEN FN_REFLEN-FN_LEN /* Max l{ngd p} dev */
+/* extra 4+4 bytes for slave tmp tables */
+#define MAX_DBKEY_LENGTH (NAME_LEN*2+1+1+4+4)
+#define MAX_ALIAS_NAME 256
+#define MAX_FIELD_NAME 34 /* Max colum name length +2 */
+#define MAX_SYS_VAR_LENGTH 32
+#define MAX_KEY MAX_INDEXES /* Max used keys */
+#define MAX_REF_PARTS 16 /* Max parts used as ref */
+#define MAX_KEY_LENGTH 3072 /* max possible key */
+#if SIZEOF_OFF_T > 4
+#define MAX_REFLENGTH 8 /* Max length for record ref */
+#else
+#define MAX_REFLENGTH 4 /* Max length for record ref */
+#endif
+#define MAX_HOSTNAME 61 /* len+1 in mysql.user */
+
+#define MAX_MBWIDTH 3 /* Max multibyte sequence */
+#define MAX_FIELD_CHARLENGTH 255
+#define MAX_FIELD_VARCHARLENGTH 65535
+#define MAX_FIELD_BLOBLENGTH UINT_MAX32 /* cf field_blob::get_length() */
+#define CONVERT_IF_BIGGER_TO_BLOB 512 /* Used for CREATE ... SELECT */
+
+/* Max column width +1 */
+#define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1)
+
+#define MAX_BIT_FIELD_LENGTH 64 /* Max length in bits for bit fields */
+
+#define MAX_DATE_WIDTH 10 /* YYYY-MM-DD */
+#define MAX_TIME_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */
+#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */
+#define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */
+#define MAX_DATETIME_COMPRESSED_WIDTH 14 /* YYYYMMDDHHMMSS */
+
+#define MAX_TABLES (sizeof(table_map)*8-3) /* Max tables in join */
+#define PARAM_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-3))
+#define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2))
+#define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1))
+#define PSEUDO_TABLE_BITS (PARAM_TABLE_BIT | OUTER_REF_TABLE_BIT | \
+ RAND_TABLE_BIT)
+#define MAX_FIELDS 4096 /* Limit in the .frm file */
+#define MAX_PARTITIONS 1024
+
+#define MAX_SELECT_NESTING (sizeof(nesting_map)*8-1)
+
+#define MAX_SORT_MEMORY 2048*1024
+#define MIN_SORT_MEMORY 32*1024
+
+/* Some portable defines */
+
+#define portable_sizeof_char_ptr 8
+#define STRING_BUFFER_USUAL_SIZE 80
+
+/* Memory allocated when parsing a statement / saving a statement */
+#define MEM_ROOT_BLOCK_SIZE 8192
+#define MEM_ROOT_PREALLOC 8192
+#define TRANS_MEM_ROOT_BLOCK_SIZE 4096
+#define TRANS_MEM_ROOT_PREALLOC 4096
+
+#define DEFAULT_ERROR_COUNT 64
+#define EXTRA_RECORDS 10 /* Extra records in sort */
+#define SCROLL_EXTRA 5 /* Extra scroll-rows. */
+#define FIELD_NAME_USED ((uint) 32768) /* Bit set if fieldname used */
+#define FORM_NAME_USED ((uint) 16384) /* Bit set if formname used */
+#define FIELD_NR_MASK 16383 /* To get fieldnumber */
+#define FERR -1 /* Error from my_functions */
+#define CREATE_MODE 0 /* Default mode on new files */
+#define NAMES_SEP_CHAR '\377' /* Char to sep. names */
+
+#define READ_RECORD_BUFFER (uint) (IO_SIZE*8) /* Pointer_buffer_size */
+#define DISK_BUFFER_SIZE (uint) (IO_SIZE*16) /* Size of diskbuffer */
+
+#define FRM_VER_TRUE_VARCHAR (FRM_VER+4) /* 10 */
+
+/***************************************************************************
+ Configuration parameters
+****************************************************************************/
+
+#define ACL_CACHE_SIZE 256
+#define MAX_PASSWORD_LENGTH 32
+#define HOST_CACHE_SIZE 128
+#define MAX_ACCEPT_RETRY 10 // Test accept this many times
+#define MAX_FIELDS_BEFORE_HASH 32
+#define USER_VARS_HASH_SIZE 16
+#define TABLE_OPEN_CACHE_MIN 400
+#define TABLE_OPEN_CACHE_DEFAULT 400
+#define TABLE_DEF_CACHE_DEFAULT 400
+/**
+ We must have room for at least 400 table definitions in the table
+ cache, since otherwise there is no chance prepared
+ statements that use these many tables can work.
+ Prepared statements use table definition cache ids (table_map_id)
+ as table version identifiers. If the table definition
+ cache size is less than the number of tables used in a statement,
+ the contents of the table definition cache is guaranteed to rotate
+ between a prepare and execute. This leads to stable validation
+ errors. In future we shall use more stable version identifiers,
+ for now the only solution is to ensure that the table definition
+ cache can contain at least all tables of a given statement.
+*/
+#define TABLE_DEF_CACHE_MIN 400
+
+/*
+ Stack reservation.
+ Feel free to raise this by the smallest amount you can to get the
+ "execution_constants" test to pass.
+*/
+#define STACK_MIN_SIZE 16000 // Abort if less stack during eval.
+
+#define STACK_MIN_SIZE_FOR_OPEN 1024*80
+#define STACK_BUFF_ALLOC 352 ///< For stack overrun checks
+#ifndef MYSQLD_NET_RETRY_COUNT
+#define MYSQLD_NET_RETRY_COUNT 10 ///< Abort read after this many int.
+#endif
+
+#define QUERY_ALLOC_BLOCK_SIZE 8192
+#define QUERY_ALLOC_PREALLOC_SIZE 8192
+#define TRANS_ALLOC_BLOCK_SIZE 4096
+#define TRANS_ALLOC_PREALLOC_SIZE 4096
+#define RANGE_ALLOC_BLOCK_SIZE 4096
+#define ACL_ALLOC_BLOCK_SIZE 1024
+#define UDF_ALLOC_BLOCK_SIZE 1024
+#define TABLE_ALLOC_BLOCK_SIZE 1024
+#define WARN_ALLOC_BLOCK_SIZE 2048
+#define WARN_ALLOC_PREALLOC_SIZE 1024
+
+/*
+ The following parameters is to decide when to use an extra cache to
+ optimise seeks when reading a big table in sorted order
+*/
+#define MIN_FILE_LENGTH_TO_USE_ROW_CACHE (10L*1024*1024)
+#define MIN_ROWS_TO_USE_TABLE_CACHE 100
+#define MIN_ROWS_TO_USE_BULK_INSERT 100
+
+/**
+ The following is used to decide if MySQL should use table scanning
+ instead of reading with keys. The number says how many evaluation of the
+ WHERE clause is comparable to reading one extra row from a table.
+*/
+#define TIME_FOR_COMPARE 5 // 5 compares == one read
+
+/**
+ Number of comparisons of table rowids equivalent to reading one row from a
+ table.
+*/
+#define TIME_FOR_COMPARE_ROWID (TIME_FOR_COMPARE*2)
+
+/*
+ For sequential disk seeks the cost formula is:
+ DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST * #blocks_to_skip
+
+ The cost of average seek
+ DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST*BLOCKS_IN_AVG_SEEK =1.0.
+*/
+#define DISK_SEEK_BASE_COST ((double)0.5)
+
+#define BLOCKS_IN_AVG_SEEK 128
+
+#define DISK_SEEK_PROP_COST ((double)0.5/BLOCKS_IN_AVG_SEEK)
+
+
+/**
+ Number of rows in a reference table when refereed through a not unique key.
+ This value is only used when we don't know anything about the key
+ distribution.
+*/
+#define MATCHING_ROWS_IN_OTHER_TABLE 10
+
+#define MY_CHARSET_BIN_MB_MAXLEN 1
+
+/** Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used). */
+#define KEY_DEFAULT_PACK_LENGTH 8
+
+/** Characters shown for the command in 'show processlist'. */
+#define PROCESS_LIST_WIDTH 100
+/* Characters shown for the command in 'information_schema.processlist' */
+#define PROCESS_LIST_INFO_WIDTH 65535
+
+#define PRECISION_FOR_DOUBLE 53
+#define PRECISION_FOR_FLOAT 24
+
+/* -[digits].E+## */
+#define MAX_FLOAT_STR_LENGTH (FLT_DIG + 6)
+/* -[digits].E+### */
+#define MAX_DOUBLE_STR_LENGTH (DBL_DIG + 7)
+
+/*
+ Default time to wait before aborting a new client connection
+ that does not respond to "initial server greeting" timely
+*/
+#define CONNECT_TIMEOUT 10
+
+/* The following can also be changed from the command line */
+#define DEFAULT_CONCURRENCY 10
+#define DELAYED_LIMIT 100 /**< pause after xxx inserts */
+#define DELAYED_QUEUE_SIZE 1000
+#define DELAYED_WAIT_TIMEOUT 5*60 /**< Wait for delayed insert */
+#define FLUSH_TIME 0 /**< Don't flush tables */
+#define MAX_CONNECT_ERRORS 10 ///< errors before disabling host
+
+#define LONG_TIMEOUT ((ulong) 3600L*24L*365L)
+
+/**
+ Maximum length of time zone name that we support (Time zone name is
+ char(64) in db). mysqlbinlog needs it.
+*/
+#define MAX_TIME_ZONE_NAME_LENGTH (NAME_LEN + 1)
+
+#if defined(__WIN__)
+#undef FLUSH_TIME
+#define FLUSH_TIME 1800 /**< Flush every half hour */
+
+#define INTERRUPT_PRIOR -2
+#define CONNECT_PRIOR -1
+#define WAIT_PRIOR 0
+#define QUERY_PRIOR 2
+#else
+#define INTERRUPT_PRIOR 10
+#define CONNECT_PRIOR 9
+#define WAIT_PRIOR 8
+#define QUERY_PRIOR 6
+#endif /* __WIN92__ */
+
+#endif /* SQL_CONST_INCLUDED */
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
index 3d7d248782b..455e7dc1e7b 100644
--- a/sql/sql_crypt.cc
+++ b/sql/sql_crypt.cc
@@ -26,7 +26,9 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_crypt.h"
+#include "password.h"
void SQL_CRYPT::init(ulong *rand_nr)
{
diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h
index 2b56c387bd1..15cc495858b 100644
--- a/sql/sql_crypt.h
+++ b/sql/sql_crypt.h
@@ -1,3 +1,6 @@
+#ifndef SQL_CRYPT_INCLUDED
+#define SQL_CRYPT_INCLUDED
+
/* Copyright (C) 2000-2001, 2005 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -18,6 +21,9 @@
#pragma interface /* gcc class implementation */
#endif
+#include "sql_list.h" /* Sql_alloc */
+#include "mysql_com.h" /* rand_struct */
+
class SQL_CRYPT :public Sql_alloc
{
struct rand_struct rand,org_rand;
@@ -35,3 +41,5 @@ class SQL_CRYPT :public Sql_alloc
void encode(char *str, uint length);
void decode(char *str, uint length);
};
+
+#endif /* SQL_CRYPT_INCLUDED */
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index d7d029d28d4..acc591f1ea2 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -16,60 +16,17 @@
#pragma implementation /* gcc class implementation */
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
#include "sql_cursor.h"
-#include "sql_select.h"
+#include "probes_mysql.h"
+#include "sql_parse.h" // mysql_execute_command
/****************************************************************************
Declarations.
****************************************************************************/
/**
- Sensitive_cursor -- a sensitive non-materialized server side
- cursor. An instance of this class cursor has its own runtime
- state -- list of used items and memory root for runtime memory,
- open and locked tables, change list for the changes of the
- parsed tree. This state is freed when the cursor is closed.
-*/
-
-class Sensitive_cursor: public Server_side_cursor
-{
- MEM_ROOT main_mem_root;
- Query_arena *stmt_arena;
- JOIN *join;
- TABLE *open_tables;
- MYSQL_LOCK *lock;
- TABLE *derived_tables;
- /* List of items created during execution */
- query_id_t query_id;
- struct Engine_info
- {
- handlerton *ht;
- void *read_view;
- };
- Engine_info ht_info[MAX_HA];
- Item_change_list change_list;
- my_bool close_at_commit;
- THR_LOCK_OWNER lock_id;
-private:
- /* bzero cursor state in THD */
- void reset_thd(THD *thd);
-public:
- Sensitive_cursor(THD *thd, select_result *result_arg);
-
- THR_LOCK_OWNER *get_lock_id() { return &lock_id; }
- /* Save THD state into cursor */
- void post_open(THD *thd);
-
- virtual bool is_open() const { return join != 0; }
- virtual int open(JOIN *join);
- virtual void fetch(ulong num_rows);
- virtual void close();
- virtual ~Sensitive_cursor();
-};
-
-
-/**
Materialized_cursor -- an insensitive materialized server-side
cursor. The result set of this cursor is saved in a temporary
table at open. The cursor itself is simply an interface for the
@@ -89,7 +46,7 @@ class Materialized_cursor: public Server_side_cursor
public:
Materialized_cursor(select_result *result, TABLE *table);
- int fill_item_list(THD *thd, List<Item> &send_fields);
+ int fill_item_list(THD *thd, List<Item> &send_result_set_metadata);
virtual bool is_open() const { return table != 0; }
virtual int open(JOIN *join __attribute__((unused)));
virtual void fetch(ulong num_rows);
@@ -114,17 +71,16 @@ public:
Materialized_cursor *materialized_cursor;
Select_materialize(select_result *result_arg)
:result(result_arg), materialized_cursor(0) {}
- virtual bool send_fields(List<Item> &list, uint flags);
+ virtual bool send_result_set_metadata(List<Item> &list, uint flags);
};
/**************************************************************************/
/**
- Attempt to open a materialized or non-materialized cursor.
+ Attempt to open a materialized cursor.
@param thd thread handle
- @param[in] flags create a materialized cursor or not
@param[in] result result class of the caller used as a destination
for the rows fetched from the cursor
@param[out] pcursor a pointer to store a pointer to cursor in
@@ -137,55 +93,39 @@ public:
non-zero an error, 'pcursor' has been left intact.
*/
-int mysql_open_cursor(THD *thd, uint flags, select_result *result,
+int mysql_open_cursor(THD *thd, select_result *result,
Server_side_cursor **pcursor)
{
- Sensitive_cursor *sensitive_cursor;
select_result *save_result;
Select_materialize *result_materialize;
LEX *lex= thd->lex;
int rc;
- /*
- The lifetime of the sensitive cursor is the same or less as the
- lifetime of the runtime memory of the statement it's opened for.
- */
if (! (result_materialize= new (thd->mem_root) Select_materialize(result)))
return 1;
- if (! (sensitive_cursor= new (thd->mem_root) Sensitive_cursor(thd, result)))
- {
- delete result_materialize;
- result_materialize= NULL;
- return 1;
- }
-
save_result= lex->result;
lex->result= result_materialize;
- if (! (flags & (uint) ALWAYS_MATERIALIZED_CURSOR))
- {
- thd->lock_id= sensitive_cursor->get_lock_id();
- thd->cursor= sensitive_cursor;
- }
+ MYSQL_QUERY_EXEC_START(thd->query(),
+ thd->thread_id,
+ (char *) (thd->db ? thd->db : ""),
+ thd->security_ctx->priv_user,
+ (char *) thd->security_ctx->host_or_ip,
+ 2);
rc= mysql_execute_command(thd);
+ MYSQL_QUERY_EXEC_DONE(rc);
lex->result= save_result;
- thd->lock_id= &thd->main_lock_id;
- thd->cursor= 0;
-
/*
Possible options here:
- - a sensitive cursor is open. In this case rc is 0 and
- result_materialize->materialized_cursor is NULL, or
- a materialized cursor is open. In this case rc is 0 and
result_materialize->materialized is not NULL
- an error occurred during materialization.
result_materialize->materialized_cursor is not NULL, but rc != 0
- successful completion of mysql_execute_command without
- a cursor: rc is 0, result_materialize->materialized_cursor is NULL,
- sensitive_cursor is not open.
+ a cursor: rc is 0, result_materialize->materialized_cursor is NULL.
This is possible if some command writes directly to the
network, bypassing select_result mechanism. An example of
such command is SHOW VARIABLES or SHOW STATUS.
@@ -194,23 +134,10 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
{
if (result_materialize->materialized_cursor)
delete result_materialize->materialized_cursor;
- goto err_open;
- }
-
- if (sensitive_cursor->is_open())
- {
- DBUG_ASSERT(!result_materialize->materialized_cursor);
- /*
- It's safer if we grab THD state after mysql_execute_command
- is finished and not in Sensitive_cursor::open(), because
- currently the call to Sensitive_cursor::open is buried deep
- in JOIN::exec of the top level join.
- */
- sensitive_cursor->post_open(thd);
- *pcursor= sensitive_cursor;
goto end;
}
- else if (result_materialize->materialized_cursor)
+
+ if (result_materialize->materialized_cursor)
{
Materialized_cursor *materialized_cursor=
result_materialize->materialized_cursor;
@@ -218,18 +145,13 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
if ((rc= materialized_cursor->open(0)))
{
delete materialized_cursor;
- materialized_cursor= NULL;
- goto err_open;
+ goto end;
}
*pcursor= materialized_cursor;
thd->stmt_arena->cleanup_stmt();
- goto end;
}
-err_open:
- DBUG_ASSERT(! (sensitive_cursor && sensitive_cursor->is_open()));
- delete sensitive_cursor;
end:
delete result_materialize;
return rc;
@@ -261,282 +183,6 @@ void Server_side_cursor::operator delete(void *ptr, size_t size)
DBUG_VOID_RETURN;
}
-/****************************************************************************
- Sensitive_cursor
-****************************************************************************/
-
-Sensitive_cursor::Sensitive_cursor(THD *thd, select_result *result_arg)
- :Server_side_cursor(&main_mem_root, result_arg),
- stmt_arena(0),
- join(0),
- close_at_commit(FALSE)
-{
- /* We will overwrite it at open anyway. */
- init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
- thr_lock_owner_init(&lock_id, &thd->lock_info);
- bzero((void*) ht_info, sizeof(ht_info));
-}
-
-
-/**
- Save THD state into cursor.
-
- @todo
- - XXX: thd->locked_tables is not changed.
- - What problems can we have with it if cursor is open?
- - TODO: must be fixed because of the prelocked mode.
-*/
-void
-Sensitive_cursor::post_open(THD *thd)
-{
- Engine_info *info;
- /*
- We need to save and reset thd->mem_root, otherwise it'll be
- freed later in mysql_parse.
-
- We can't just change thd->mem_root here as we want to keep the
- things that are already allocated in thd->mem_root for
- Sensitive_cursor::fetch()
- */
- *mem_root= *thd->mem_root;
- stmt_arena= thd->stmt_arena;
- state= stmt_arena->state;
- /* Allocate a new memory root for thd */
- init_sql_alloc(thd->mem_root,
- thd->variables.query_alloc_block_size,
- thd->variables.query_prealloc_size);
-
- /*
- Save tables and zero THD pointers to prevent table close in
- close_thread_tables.
- */
- derived_tables= thd->derived_tables;
- open_tables= thd->open_tables;
- lock= thd->lock;
- query_id= thd->query_id;
- free_list= thd->free_list;
- change_list= thd->change_list;
- reset_thd(thd);
- /* Now we have an active cursor and can cause a deadlock */
- thd->lock_info.n_cursors++;
-
- close_at_commit= FALSE; /* reset in case we're reusing the cursor */
- info= &ht_info[0];
- for (Ha_trx_info *ha_trx_info= thd->transaction.stmt.ha_list;
- ha_trx_info; ha_trx_info= ha_trx_info->next())
- {
- handlerton *ht= ha_trx_info->ht();
- close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
- if (ht->create_cursor_read_view)
- {
- info->ht= ht;
- info->read_view= (ht->create_cursor_read_view)(ht, thd);
- ++info;
- }
- }
- /*
- XXX: thd->locked_tables is not changed.
- What problems can we have with it if cursor is open?
- TODO: must be fixed because of the prelocked mode.
- */
-}
-
-
-/**
- bzero cursor state in THD.
-*/
-
-void
-Sensitive_cursor::reset_thd(THD *thd)
-{
- thd->derived_tables= 0;
- thd->open_tables= 0;
- thd->lock= 0;
- thd->free_list= 0;
- thd->change_list.empty();
-}
-
-
-int
-Sensitive_cursor::open(JOIN *join_arg)
-{
- join= join_arg;
- THD *thd= join->thd;
- /* First non-constant table */
- JOIN_TAB *join_tab= join->join_tab + join->const_tables;
- DBUG_ENTER("Sensitive_cursor::open");
-
- join->change_result(result);
- /*
- Send fields description to the client; server_status is sent
- in 'EOF' packet, which follows send_fields().
- We don't simply use SEND_EOF flag of send_fields because we also
- want to flush the network buffer, which is done only in a standalone
- send_eof().
- */
- result->send_fields(*join->fields, Protocol::SEND_NUM_ROWS);
- thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
- result->send_eof();
- thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
-
- /* Prepare JOIN for reading rows. */
- join->tmp_table= 0;
- join->join_tab[join->tables-1].next_select= setup_end_select_func(join);
- join->send_records= 0;
- join->fetch_limit= join->unit->offset_limit_cnt;
-
- /* Disable JOIN CACHE as it is not working with cursors yet */
- for (JOIN_TAB *tab= join_tab;
- tab != join->join_tab + join->tables - 1;
- tab++)
- {
- if (tab->next_select == sub_select_cache)
- tab->next_select= sub_select;
- }
-
- DBUG_ASSERT(join_tab->table->reginfo.not_exists_optimize == 0);
- DBUG_ASSERT(join_tab->not_used_in_distinct == 0);
- /*
- null_row is set only if row not found and it's outer join: should never
- happen for the first table in join_tab list
- */
- DBUG_ASSERT(join_tab->table->null_row == 0);
- DBUG_RETURN(0);
-}
-
-
-/**
- Fetch next num_rows rows from the cursor and send them to the client.
-
- Precondition:
- - Sensitive_cursor is open
-
- @param num_rows fetch up to this number of rows (maybe less)
-*/
-
-void
-Sensitive_cursor::fetch(ulong num_rows)
-{
- THD *thd= join->thd;
- JOIN_TAB *join_tab= join->join_tab + join->const_tables;
- enum_nested_loop_state error= NESTED_LOOP_OK;
- Query_arena backup_arena;
- Engine_info *info;
- DBUG_ENTER("Sensitive_cursor::fetch");
- DBUG_PRINT("enter",("rows: %lu", num_rows));
-
- DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 &&
- thd->lock == 0);
-
- thd->derived_tables= derived_tables;
- thd->open_tables= open_tables;
- thd->lock= lock;
- thd->query_id= query_id;
- thd->change_list= change_list;
- /* save references to memory allocated during fetch */
- thd->set_n_backup_active_arena(this, &backup_arena);
-
- for (info= ht_info; info->read_view ; info++)
- (info->ht->set_cursor_read_view)(info->ht, thd, info->read_view);
-
- join->fetch_limit+= num_rows;
-
- error= sub_select(join, join_tab, 0);
- if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
- error= sub_select(join,join_tab,1);
- if (error == NESTED_LOOP_QUERY_LIMIT)
- error= NESTED_LOOP_OK; /* select_limit used */
- if (error == NESTED_LOOP_CURSOR_LIMIT)
- join->resume_nested_loop= TRUE;
-
- ha_release_temporary_latches(thd);
-
- /* Grab free_list here to correctly free it in close */
- thd->restore_active_arena(this, &backup_arena);
-
- change_list= thd->change_list;
- reset_thd(thd);
-
- for (info= ht_info; info->read_view; info++)
- (info->ht->set_cursor_read_view)(info->ht, thd, 0);
-
- if (error == NESTED_LOOP_CURSOR_LIMIT)
- {
- /* Fetch limit worked, possibly more rows are there */
- thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
- result->send_eof();
- thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
- }
- else
- {
- close();
- if (error == NESTED_LOOP_OK)
- {
- thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
- result->send_eof();
- thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
- }
- else if (error != NESTED_LOOP_KILLED)
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
- }
- DBUG_VOID_RETURN;
-}
-
-
-/**
- @todo
- Another hack: we need to set THD state as if in a fetch to be
- able to call stmt close.
-*/
-void
-Sensitive_cursor::close()
-{
- THD *thd= join->thd;
- DBUG_ENTER("Sensitive_cursor::close");
-
- for (Engine_info *info= ht_info; info->read_view; info++)
- {
- (info->ht->close_cursor_read_view)(info->ht, thd, info->read_view);
- info->read_view= 0;
- info->ht= 0;
- }
-
- thd->change_list= change_list;
- {
- /*
- XXX: Another hack: we need to set THD state as if in a fetch to be
- able to call stmt close.
- */
- DBUG_ASSERT(lock || open_tables || derived_tables);
-
- TABLE *tmp_derived_tables= thd->derived_tables;
- MYSQL_LOCK *tmp_lock= thd->lock;
-
- thd->open_tables= open_tables;
- thd->derived_tables= derived_tables;
- thd->lock= lock;
-
- /* Is expected to at least close tables and empty thd->change_list */
- stmt_arena->cleanup_stmt();
-
- thd->open_tables= tmp_derived_tables;
- thd->derived_tables= tmp_derived_tables;
- thd->lock= tmp_lock;
- }
- thd->lock_info.n_cursors--; /* Decrease the number of active cursors */
- join= 0;
- stmt_arena= 0;
- free_items();
- change_list.empty();
- DBUG_VOID_RETURN;
-}
-
-
-Sensitive_cursor::~Sensitive_cursor()
-{
- if (is_open())
- close();
-}
/***************************************************************************
Materialized_cursor
@@ -559,14 +205,15 @@ Materialized_cursor::Materialized_cursor(select_result *result_arg,
Preserve the original metadata that would be sent to the client.
@param thd Thread identifier.
- @param send_fields List of fields that would be sent.
+ @param send_result_set_metadata List of fields that would be sent.
*/
-int Materialized_cursor::fill_item_list(THD *thd, List<Item> &send_fields)
+int Materialized_cursor::fill_item_list(THD *thd,
+ List<Item> &send_result_set_metadata)
{
Query_arena backup_arena;
int rc;
- List_iterator_fast<Item> it_org(send_fields);
+ List_iterator_fast<Item> it_org(send_result_set_metadata);
List_iterator_fast<Item> it_dst(item_list);
Item *item_org;
Item *item_dst;
@@ -576,7 +223,7 @@ int Materialized_cursor::fill_item_list(THD *thd, List<Item> &send_fields)
if ((rc= table->fill_item_list(&item_list)))
goto end;
- DBUG_ASSERT(send_fields.elements == item_list.elements);
+ DBUG_ASSERT(send_result_set_metadata.elements == item_list.elements);
/*
Unless we preserve the original metadata, it will be lost,
@@ -600,6 +247,7 @@ end:
return rc || thd->is_error();
}
+
int Materialized_cursor::open(JOIN *join __attribute__((unused)))
{
THD *thd= fake_unit.thd;
@@ -616,20 +264,19 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused)))
{
/*
Now send the result set metadata to the client. We need to
- do it here, as in Select_materialize::send_fields the items
- for column types are not yet created (send_fields requires
+ do it here, as in Select_materialize::send_result_set_metadata the items
+ for column types are not yet created (send_result_set_metadata requires
a list of items). The new types may differ from the original
ones sent at prepare if some of them were altered by MySQL
HEAP tables mechanism -- used when create_tmp_field_from_item
may alter the original column type.
- We can't simply supply SEND_EOF flag to send_fields, because
- send_fields doesn't flush the network buffer.
+ We can't simply supply SEND_EOF flag to send_result_set_metadata, because
+ send_result_set_metadata doesn't flush the network buffer.
*/
- rc= result->send_fields(item_list, Protocol::SEND_NUM_ROWS);
+ rc= result->send_result_set_metadata(item_list, Protocol::SEND_NUM_ROWS);
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
result->send_eof();
- thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
}
return rc;
}
@@ -670,12 +317,10 @@ void Materialized_cursor::fetch(ulong num_rows)
case 0:
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
result->send_eof();
- thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
break;
case HA_ERR_END_OF_FILE:
thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
result->send_eof();
- thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
close();
break;
default:
@@ -715,11 +360,11 @@ Materialized_cursor::~Materialized_cursor()
Select_materialize
****************************************************************************/
-bool Select_materialize::send_fields(List<Item> &list, uint flags)
+bool Select_materialize::send_result_set_metadata(List<Item> &list, uint flags)
{
DBUG_ASSERT(table == 0);
if (create_result_table(unit->thd, unit->get_unit_column_types(),
- FALSE, thd->options | TMP_TABLE_ALL_COLUMNS, ""))
+ FALSE, thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS, ""))
return TRUE;
materialized_cursor= new (&table->mem_root)
diff --git a/sql/sql_cursor.h b/sql/sql_cursor.h
index 1f19cbfdbcf..ed7bfac821a 100644
--- a/sql/sql_cursor.h
+++ b/sql/sql_cursor.h
@@ -20,6 +20,10 @@
#pragma interface /* gcc class interface */
#endif
+#include "sql_class.h" /* Query_arena */
+
+class JOIN;
+
/**
@file
@@ -28,11 +32,11 @@
*/
/**
- Server_side_cursor -- an interface for materialized and
- sensitive (non-materialized) implementation of cursors. All
- cursors are self-contained (created in their own memory root).
- For that reason they must be deleted only using a pointer to
- Server_side_cursor, not to its base class.
+ Server_side_cursor -- an interface for materialized
+ implementation of cursors. All cursors are self-contained
+ (created in their own memory root). For that reason they must
+ be deleted only using a pointer to Server_side_cursor, not to
+ its base class.
*/
class Server_side_cursor: protected Query_arena, public Sql_alloc
@@ -56,11 +60,7 @@ public:
};
-int mysql_open_cursor(THD *thd, uint flags,
- select_result *result,
+int mysql_open_cursor(THD *thd, select_result *result,
Server_side_cursor **res);
-/** Possible values for flags */
-enum { ANY_CURSOR= 1, ALWAYS_MATERIALIZED_CURSOR= 2 };
-
#endif /* _sql_cusor_h_ */
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 2c44c1a8449..292fbba2352 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -16,7 +16,20 @@
/* create and drop of databases */
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_db.h"
+#include "sql_cache.h" // query_cache_*
+#include "lock.h" // lock_schema_name
+#include "sql_table.h" // build_table_filename,
+ // filename_to_tablename
+#include "sql_rename.h" // mysql_rename_tables
+#include "sql_acl.h" // SELECT_ACL, DB_ACLS,
+ // acl_get, check_grant_db
+#include "log_event.h" // Query_log_event
+#include "sql_base.h" // lock_table_names, tdc_remove_table
+#include "sql_handler.h" // mysql_ha_rm_tables
#include <mysys_err.h>
#include "sp.h"
#include "events.h"
@@ -33,10 +46,12 @@ const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS};
static TYPELIB deletable_extentions=
{array_elements(del_exts)-1,"del_exts", del_exts, NULL};
-static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
- const char *db, const char *path, uint level,
- TABLE_LIST **dropped_tables);
-
+static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
+ const char *db,
+ const char *path,
+ TABLE_LIST **tables,
+ bool *found_other_files);
+
long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path);
static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error);
static void mysql_change_db_impl(THD *thd,
@@ -45,110 +60,10 @@ static void mysql_change_db_impl(THD *thd,
CHARSET_INFO *new_db_charset);
-/* Database lock hash */
-HASH lock_db_cache;
-pthread_mutex_t LOCK_lock_db;
-int creating_database= 0; // how many database locks are made
-
-
-/* Structure for database lock */
-typedef struct my_dblock_st
-{
- char *name; /* Database name */
- uint name_length; /* Database length name */
-} my_dblock_t;
-
-
-/*
- lock_db key.
-*/
-
-extern "C" uchar* lock_db_get_key(my_dblock_t *, size_t *, my_bool not_used);
-
-uchar* lock_db_get_key(my_dblock_t *ptr, size_t *length,
- my_bool not_used __attribute__((unused)))
-{
- *length= ptr->name_length;
- return (uchar*) ptr->name;
-}
-
-
-/*
- Free lock_db hash element.
-*/
-
-extern "C" void lock_db_free_element(void *ptr);
-
-void lock_db_free_element(void *ptr)
-{
- my_free(ptr, MYF(0));
-}
-
-
-/*
- Put a database lock entry into the hash.
-
- DESCRIPTION
- Insert a database lock entry into hash.
- LOCK_db_lock must be previously locked.
-
- RETURN VALUES
- 0 on success.
- 1 on error.
-*/
-
-static my_bool lock_db_insert(const char *dbname, uint length)
-{
- my_dblock_t *opt;
- my_bool error= 0;
- DBUG_ENTER("lock_db_insert");
-
- safe_mutex_assert_owner(&LOCK_lock_db);
-
- if (!(opt= (my_dblock_t*) hash_search(&lock_db_cache,
- (uchar*) dbname, length)))
- {
- /* Db is not in the hash, insert it */
- char *tmp_name;
- if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
- NullS))
- {
- error= 1;
- goto end;
- }
-
- opt->name= tmp_name;
- strmov(opt->name, dbname);
- opt->name_length= length;
-
- if ((error= my_hash_insert(&lock_db_cache, (uchar*) opt)))
- my_free(opt, MYF(0));
- }
-
-end:
- DBUG_RETURN(error);
-}
-
-
-/*
- Delete a database lock entry from hash.
-*/
-
-void lock_db_delete(const char *name, uint length)
-{
- my_dblock_t *opt;
- safe_mutex_assert_owner(&LOCK_lock_db);
- if ((opt= (my_dblock_t *)hash_search(&lock_db_cache,
- (const uchar*) name, length)))
- hash_delete(&lock_db_cache, (uchar*) opt);
-}
-
-
/* Database options hash */
static HASH dboptions;
static my_bool dboptions_init= 0;
-static rw_lock_t LOCK_dboptions;
+static mysql_rwlock_t LOCK_dboptions;
/* Structure for database options */
typedef struct my_dbopt_st
@@ -181,7 +96,7 @@ uchar* dboptions_get_key(my_dbopt_t *opt, size_t *length,
static inline int write_to_binlog(THD *thd, char *query, uint q_len,
char *db, uint db_len)
{
- Query_log_event qinfo(thd, query, q_len, 0, 0, 0);
+ Query_log_event qinfo(thd, query, q_len, FALSE, TRUE, FALSE, 0);
qinfo.db= db;
qinfo.db_len= db_len;
return mysql_bin_log.write(&qinfo);
@@ -196,75 +111,88 @@ extern "C" void free_dbopt(void *dbopt);
void free_dbopt(void *dbopt)
{
- my_free((uchar*) dbopt, MYF(0));
+ my_free(dbopt);
}
+#ifdef HAVE_PSI_INTERFACE
+static PSI_rwlock_key key_rwlock_LOCK_dboptions;
-/*
- Initialize database option hash and locked database hash.
+static PSI_rwlock_info all_database_names_rwlocks[]=
+{
+ { &key_rwlock_LOCK_dboptions, "LOCK_dboptions", PSI_FLAG_GLOBAL}
+};
- SYNOPSIS
- my_database_names()
+static void init_database_names_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
- NOTES
- Must be called before any other database function is called.
+ if (PSI_server == NULL)
+ return;
- RETURN
- 0 ok
- 1 Fatal error
+ count= array_elements(all_database_names_rwlocks);
+ PSI_server->register_rwlock(category, all_database_names_rwlocks, count);
+}
+#endif
+
+/**
+ Initialize database option cache.
+
+ @note Must be called before any other database function is called.
+
+ @retval 0 ok
+ @retval 1 Fatal error
*/
-bool my_database_names_init(void)
+bool my_dboptions_cache_init(void)
{
+#ifdef HAVE_PSI_INTERFACE
+ init_database_names_psi_keys();
+#endif
+
bool error= 0;
- (void) my_rwlock_init(&LOCK_dboptions, NULL);
+ mysql_rwlock_init(key_rwlock_LOCK_dboptions, &LOCK_dboptions);
if (!dboptions_init)
{
dboptions_init= 1;
- error= hash_init(&dboptions, lower_case_table_names ?
- &my_charset_bin : system_charset_info,
- 32, 0, 0, (hash_get_key) dboptions_get_key,
- free_dbopt,0) ||
- hash_init(&lock_db_cache, lower_case_table_names ?
- &my_charset_bin : system_charset_info,
- 32, 0, 0, (hash_get_key) lock_db_get_key,
- lock_db_free_element,0);
-
+ error= my_hash_init(&dboptions, lower_case_table_names ?
+ &my_charset_bin : system_charset_info,
+ 32, 0, 0, (my_hash_get_key) dboptions_get_key,
+ free_dbopt,0);
}
return error;
}
-/*
+/**
Free database option hash and locked databases hash.
*/
-void my_database_names_free(void)
+void my_dboptions_cache_free(void)
{
if (dboptions_init)
{
dboptions_init= 0;
- hash_free(&dboptions);
- (void) rwlock_destroy(&LOCK_dboptions);
- hash_free(&lock_db_cache);
+ my_hash_free(&dboptions);
+ mysql_rwlock_destroy(&LOCK_dboptions);
}
}
-/*
- Cleanup cached options
+/**
+ Cleanup cached options.
*/
void my_dbopt_cleanup(void)
{
- rw_wrlock(&LOCK_dboptions);
- hash_free(&dboptions);
- hash_init(&dboptions, lower_case_table_names ?
- &my_charset_bin : system_charset_info,
- 32, 0, 0, (hash_get_key) dboptions_get_key,
- free_dbopt,0);
- rw_unlock(&LOCK_dboptions);
+ mysql_rwlock_wrlock(&LOCK_dboptions);
+ my_hash_free(&dboptions);
+ my_hash_init(&dboptions, lower_case_table_names ?
+ &my_charset_bin : system_charset_info,
+ 32, 0, 0, (my_hash_get_key) dboptions_get_key,
+ free_dbopt,0);
+ mysql_rwlock_unlock(&LOCK_dboptions);
}
@@ -288,13 +216,13 @@ static my_bool get_dbopt(const char *dbname, HA_CREATE_INFO *create)
length= (uint) strlen(dbname);
- rw_rdlock(&LOCK_dboptions);
- if ((opt= (my_dbopt_t*) hash_search(&dboptions, (uchar*) dbname, length)))
+ mysql_rwlock_rdlock(&LOCK_dboptions);
+ if ((opt= (my_dbopt_t*) my_hash_search(&dboptions, (uchar*) dbname, length)))
{
create->default_table_charset= opt->charset;
error= 0;
}
- rw_unlock(&LOCK_dboptions);
+ mysql_rwlock_unlock(&LOCK_dboptions);
return error;
}
@@ -320,8 +248,9 @@ static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
length= (uint) strlen(dbname);
- rw_wrlock(&LOCK_dboptions);
- if (!(opt= (my_dbopt_t*) hash_search(&dboptions, (uchar*) dbname, length)))
+ 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;
@@ -339,7 +268,7 @@ static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
if ((error= my_hash_insert(&dboptions, (uchar*) opt)))
{
- my_free(opt, MYF(0));
+ my_free(opt);
goto end;
}
}
@@ -348,7 +277,7 @@ static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
opt->charset= create->default_table_charset;
end:
- rw_unlock(&LOCK_dboptions);
+ mysql_rwlock_unlock(&LOCK_dboptions);
DBUG_RETURN(error);
}
@@ -357,14 +286,14 @@ end:
Deletes database options from the hash.
*/
-void del_dbopt(const char *path)
+static void del_dbopt(const char *path)
{
my_dbopt_t *opt;
- rw_wrlock(&LOCK_dboptions);
- if ((opt= (my_dbopt_t *)hash_search(&dboptions, (const uchar*) path,
- strlen(path))))
- hash_delete(&dboptions, (uchar*) opt);
- rw_unlock(&LOCK_dboptions);
+ mysql_rwlock_wrlock(&LOCK_dboptions);
+ if ((opt= (my_dbopt_t *)my_hash_search(&dboptions, (const uchar*) path,
+ strlen(path))))
+ my_hash_delete(&dboptions, (uchar*) opt);
+ mysql_rwlock_unlock(&LOCK_dboptions);
}
@@ -391,7 +320,8 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
if (put_dbopt(path, create))
return 1;
- if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
+ if ((file= mysql_file_create(key_file_dbopt, path, CREATE_MODE,
+ O_RDWR | O_TRUNC, MYF(MY_WME))) >= 0)
{
ulong length;
length= (ulong) (strxnmov(buf, sizeof(buf)-1, "default-character-set=",
@@ -400,10 +330,10 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
create->default_table_charset->name,
"\n", NullS) - buf);
- /* Error is written by my_write */
- if (!my_write(file,(uchar*) buf, length, MYF(MY_NABP+MY_WME)))
+ /* Error is written by mysql_file_write */
+ if (!mysql_file_write(file, (uchar*) buf, length, MYF(MY_NABP+MY_WME)))
error=0;
- my_close(file,MYF(0));
+ mysql_file_close(file, MYF(0));
}
return error;
}
@@ -440,7 +370,8 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
DBUG_RETURN(0);
/* Otherwise, load options from the .opt file */
- if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)
+ if ((file= mysql_file_open(key_file_dbopt,
+ path, O_RDONLY | O_SHARE, MYF(0))) < 0)
goto err1;
IO_CACHE cache;
@@ -498,7 +429,7 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
end_io_cache(&cache);
err2:
- my_close(file,MYF(0));
+ mysql_file_close(file, MYF(0));
err1:
DBUG_RETURN(error);
}
@@ -618,49 +549,20 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
DBUG_ENTER("mysql_create_db");
/* do not create 'information_schema' db */
- if (is_schema_db(db))
+ if (is_infoschema_db(db))
{
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
DBUG_RETURN(-1);
}
- /*
- Do not create database if another thread is holding read lock.
- Wait for global read lock before acquiring LOCK_mysql_create_db.
- After wait_if_global_read_lock() we have protection against another
- global read lock. If we would acquire LOCK_mysql_create_db first,
- another thread could step in and get the global read lock before we
- reach wait_if_global_read_lock(). If this thread tries the same as we
- (admin a db), it would then go and wait on LOCK_mysql_create_db...
- Furthermore wait_if_global_read_lock() checks if the current thread
- has the global read lock and refuses the operation with
- ER_CANT_UPDATE_WITH_READLOCK if applicable.
- */
- if (wait_if_global_read_lock(thd, 0, 1))
- {
- error= -1;
- goto exit2;
- }
-
- /*
- Close and mark for re-open all HANDLER tables which are marked for flush
- or which there are pending conflicing locks against. This is needed to
- prevent deadlocks.
- */
- if (thd->handler_tables_hash.records)
- {
- pthread_mutex_lock(&LOCK_open);
- mysql_ha_flush(thd);
- pthread_mutex_unlock(&LOCK_open);
- }
-
- VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+ if (lock_schema_name(thd, db))
+ DBUG_RETURN(-1);
/* Check directory */
path_len= build_table_filename(path, sizeof(path) - 1, db, "", "", 0);
path[path_len-1]= 0; // Remove last '/' from path
- if (my_stat(path,&stat_info,MYF(0)))
+ if (mysql_file_stat(key_file_misc, path, &stat_info, MYF(0)))
{
if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
{
@@ -735,7 +637,7 @@ not_silent:
if (mysql_bin_log.is_open())
{
int errcode= query_error_code(thd, TRUE);
- Query_log_event qinfo(thd, query, query_length, 0,
+ Query_log_event qinfo(thd, query, query_length, FALSE, TRUE,
/* suppress_use */ TRUE, errcode);
/*
@@ -758,7 +660,10 @@ not_silent:
qinfo.db = db;
qinfo.db_len = strlen(db);
- /* These DDL methods and logging protected with LOCK_mysql_create_db */
+ /*
+ These DDL methods and logging are protected with the exclusive
+ metadata lock on the schema
+ */
if (mysql_bin_log.write(&qinfo))
{
error= -1;
@@ -769,9 +674,6 @@ not_silent:
}
exit:
- VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
- start_waiting_global_read_lock(thd);
-exit2:
DBUG_RETURN(error);
}
@@ -785,34 +687,8 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
int error= 0;
DBUG_ENTER("mysql_alter_db");
- /*
- Do not alter database if another thread is holding read lock.
- Wait for global read lock before acquiring LOCK_mysql_create_db.
- After wait_if_global_read_lock() we have protection against another
- global read lock. If we would acquire LOCK_mysql_create_db first,
- another thread could step in and get the global read lock before we
- reach wait_if_global_read_lock(). If this thread tries the same as we
- (admin a db), it would then go and wait on LOCK_mysql_create_db...
- Furthermore wait_if_global_read_lock() checks if the current thread
- has the global read lock and refuses the operation with
- ER_CANT_UPDATE_WITH_READLOCK if applicable.
- */
- if ((error=wait_if_global_read_lock(thd,0,1)))
- goto exit2;
-
- /*
- Close and mark for re-open all HANDLER tables which are marked for flush
- or which there are pending conflicing locks against. This is needed to
- prevent deadlocks.
- */
- if (thd->handler_tables_hash.records)
- {
- pthread_mutex_lock(&LOCK_open);
- mysql_ha_flush(thd);
- pthread_mutex_unlock(&LOCK_open);
- }
-
- VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+ if (lock_schema_name(thd, db))
+ DBUG_RETURN(TRUE);
/*
Recreate db options file: /dbpath/.db.opt
@@ -839,10 +715,9 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
if (mysql_bin_log.is_open())
{
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query(), thd->query_length(), 0,
- /* suppress_use */ TRUE, 0);
-
+ int errcode= query_error_code(thd, TRUE);
+ Query_log_event qinfo(thd, thd->query(), thd->query_length(), FALSE, TRUE,
+ /* suppress_use */ TRUE, errcode);
/*
Write should use the database being created as the "current
database" and not the threads current database, which is the
@@ -851,78 +726,51 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
qinfo.db = db;
qinfo.db_len = strlen(db);
- /* These DDL methods and logging protected with LOCK_mysql_create_db */
+ /*
+ These DDL methods and logging are protected with the exclusive
+ metadata lock on the schema.
+ */
if ((error= mysql_bin_log.write(&qinfo)))
goto exit;
}
my_ok(thd, result);
exit:
- VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
- start_waiting_global_read_lock(thd);
-exit2:
DBUG_RETURN(error);
}
-/*
- Drop all tables in a database and the database itself
-
- SYNOPSIS
- mysql_rm_db()
- thd Thread handle
- db Database name in the case given by user
- It's already validated and set to lower case
- (if needed) when we come here
- if_exists Don't give error if database doesn't exists
- silent Don't generate errors
-
- RETURN
- FALSE ok (Database dropped)
- ERROR Error
+/**
+ Drop all tables, routines and events in a database and the database itself.
+
+ @param thd Thread handle
+ @param db Database name in the case given by user
+ It's already validated and set to lower case
+ (if needed) when we come here
+ @param if_exists Don't give error if database doesn't exists
+ @param silent Don't write the statement to the binary log and don't
+ send ok packet to the client
+
+ @retval false OK (Database dropped)
+ @retval true Error
*/
bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
{
- long deleted=0;
- int error= 0;
+ ulong deleted_tables= 0;
+ bool error= true;
char path[FN_REFLEN+16];
MY_DIR *dirp;
uint length;
- TABLE_LIST* dropped_tables= 0;
+ bool found_other_files= false;
+ TABLE_LIST *tables= NULL;
+ TABLE_LIST *table;
+ Drop_table_error_handler err_handler;
DBUG_ENTER("mysql_rm_db");
- /*
- Do not drop database if another thread is holding read lock.
- Wait for global read lock before acquiring LOCK_mysql_create_db.
- After wait_if_global_read_lock() we have protection against another
- global read lock. If we would acquire LOCK_mysql_create_db first,
- another thread could step in and get the global read lock before we
- reach wait_if_global_read_lock(). If this thread tries the same as we
- (admin a db), it would then go and wait on LOCK_mysql_create_db...
- Furthermore wait_if_global_read_lock() checks if the current thread
- has the global read lock and refuses the operation with
- ER_CANT_UPDATE_WITH_READLOCK if applicable.
- */
- if (wait_if_global_read_lock(thd, 0, 1))
- {
- error= -1;
- goto exit2;
- }
-
- /*
- Close and mark for re-open all HANDLER tables which are marked for flush
- or which there are pending conflicing locks against. This is needed to
- prevent deadlocks.
- */
- if (thd->handler_tables_hash.records)
- {
- pthread_mutex_lock(&LOCK_open);
- mysql_ha_flush(thd);
- pthread_mutex_unlock(&LOCK_open);
- }
- VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+ if (lock_schema_name(thd, db))
+ DBUG_RETURN(true);
length= build_table_filename(path, sizeof(path) - 1, db, "", "", 0);
strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
@@ -934,24 +782,72 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
{
if (!if_exists)
{
- error= -1;
my_error(ER_DB_DROP_EXISTS, MYF(0), db);
- goto exit;
+ DBUG_RETURN(true);
}
else
+ {
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
+ error= false;
+ goto update_binlog;
+ }
}
- else
+
+ thd->push_internal_handler(&err_handler);
+
+ if (find_db_tables_and_rm_known_files(thd, dirp, db, path, &tables,
+ &found_other_files))
+ {
+ thd->pop_internal_handler();
+ goto exit;
+ }
+
+ /*
+ Disable drop of enabled log tables, must be done before name locking.
+ This check is only needed if we are dropping the "mysql" database.
+ */
+ if ((my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0))
+ {
+ for (table= tables; table; table= table->next_local)
+ {
+ if (check_if_log_table(table->db_length, table->db,
+ table->table_name_length, table->table_name, true))
+ {
+ my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
+ thd->pop_internal_handler();
+ goto exit;
+ }
+ }
+ }
+
+ /* Lock all tables and stored routines about to be dropped. */
+ if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
+ MYSQL_OPEN_SKIP_TEMPORARY) ||
+ lock_db_routines(thd, db))
{
- pthread_mutex_lock(&LOCK_open);
- remove_db_from_cache(db);
- pthread_mutex_unlock(&LOCK_open);
+ thd->pop_internal_handler();
+ goto exit;
+ }
- Drop_table_error_handler err_handler(thd->get_internal_handler());
- thd->push_internal_handler(&err_handler);
+ /* mysql_ha_rm_tables() requires a non-null TABLE_LIST. */
+ if (tables)
+ mysql_ha_rm_tables(thd, tables);
- error= -1;
+ for (table= tables; table; table= table->next_local)
+ {
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
+ false);
+ deleted_tables++;
+ }
+
+ if (thd->killed ||
+ (tables && mysql_rm_table_no_locks(thd, tables, true, false, true, true)))
+ {
+ tables= NULL;
+ }
+ else
+ {
/*
We temporarily disable the binary log while dropping the objects
in the database. Since the DROP DATABASE statement is always
@@ -969,23 +865,30 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
ha_drop_database(), since NDB otherwise detects the binary log
as disabled and will not log the drop database statement on any
other connected server.
- */
- if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0,
- &dropped_tables)) >= 0)
- {
- ha_drop_database(path);
- tmp_disable_binlog(thd);
- query_cache_invalidate1(db);
- (void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */
+ */
+
+ ha_drop_database(path);
+ tmp_disable_binlog(thd);
+ query_cache_invalidate1(db);
+ (void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */
#ifdef HAVE_EVENT_SCHEDULER
- Events::drop_schema_events(thd, db);
+ Events::drop_schema_events(thd, db);
#endif
- error = 0;
- reenable_binlog(thd);
- }
- thd->pop_internal_handler();
+ reenable_binlog(thd);
+
+ /*
+ If the directory is a symbolic link, remove the link first, then
+ remove the directory the symbolic link pointed at
+ */
+ if (found_other_files)
+ my_error(ER_DB_DROP_RMDIR, MYF(0), path, EEXIST);
+ else
+ error= rm_dir_w_symlink(path, true);
}
- if (!silent && deleted>=0)
+ thd->pop_internal_handler();
+
+update_binlog:
+ if (!silent && !error)
{
const char *query;
ulong query_length;
@@ -1003,9 +906,9 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
if (mysql_bin_log.is_open())
{
- thd->clear_error();
- Query_log_event qinfo(thd, query, query_length, 0,
- /* suppress_use */ TRUE, 0);
+ int errcode= query_error_code(thd, TRUE);
+ Query_log_event qinfo(thd, query, query_length, FALSE, TRUE,
+ /* suppress_use */ TRUE, errcode);
/*
Write should use the database being created as the "current
database" and not the threads current database, which is the
@@ -1014,17 +917,19 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
qinfo.db = db;
qinfo.db_len = strlen(db);
- /* These DDL methods and logging protected with LOCK_mysql_create_db */
+ /*
+ These DDL methods and logging are protected with the exclusive
+ metadata lock on the schema.
+ */
if (mysql_bin_log.write(&qinfo))
{
- error= -1;
+ error= true;
goto exit;
}
}
thd->clear_error();
thd->server_status|= SERVER_STATUS_DB_DROPPED;
- my_ok(thd, (ulong) deleted);
- thd->server_status&= ~SERVER_STATUS_DB_DROPPED;
+ my_ok(thd, deleted_tables);
}
else if (mysql_bin_log.is_open())
{
@@ -1038,7 +943,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
query_end= query + MAX_DROP_TABLE_Q_LEN;
db_len= strlen(db);
- for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
+ for (tbl= tables; tbl; tbl= tbl->next_local)
{
uint tbl_name_len;
@@ -1046,10 +951,13 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
tbl_name_len= strlen(tbl->table_name) + 3;
if (query_pos + tbl_name_len + 1 >= query_end)
{
- /* These DDL methods and logging protected with LOCK_mysql_create_db */
+ /*
+ These DDL methods and logging are protected with the exclusive
+ metadata lock on the schema.
+ */
if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len))
{
- error= -1;
+ error= true;
goto exit;
}
query_pos= query_data_start;
@@ -1063,10 +971,13 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if (query_pos != query_data_start)
{
- /* These DDL methods and logging protected with LOCK_mysql_create_db */
+ /*
+ These DDL methods and logging are protected with the exclusive
+ metadata lock on the schema.
+ */
if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len))
{
- error= -1;
+ error= true;
goto exit;
}
}
@@ -1079,33 +990,25 @@ exit:
SELECT DATABASE() in the future). For this we free() thd->db and set
it to 0.
*/
- if (thd->db && !strcmp(thd->db, db))
+ if (thd->db && !strcmp(thd->db, db) && !error)
mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
- VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
- start_waiting_global_read_lock(thd);
-exit2:
+ my_dirend(dirp);
DBUG_RETURN(error);
}
-/*
- Removes files with known extensions plus all found subdirectories that
- are 2 hex digits (raid directories).
- thd MUST be set when calling this function!
-*/
-static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
- const char *org_path, uint level,
- TABLE_LIST **dropped_tables)
+static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
+ const char *db,
+ const char *path,
+ TABLE_LIST **tables,
+ bool *found_other_files)
{
- long deleted=0;
- ulong found_other_files=0;
char filePath[FN_REFLEN];
- TABLE_LIST *tot_list=0, **tot_list_next;
- List<String> raid_dirs;
- DBUG_ENTER("mysql_rm_known_files");
- DBUG_PRINT("enter",("path: %s", org_path));
+ TABLE_LIST *tot_list=0, **tot_list_next_local, **tot_list_next_global;
+ DBUG_ENTER("find_db_tables_and_rm_known_files");
+ DBUG_PRINT("enter",("path: %s", path));
- tot_list_next= &tot_list;
+ tot_list_next_local= tot_list_next_global= &tot_list;
for (uint idx=0 ;
idx < (uint) dirp->number_off_files && !thd->killed ;
@@ -1120,36 +1023,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
(file->name[1] == '.' && !file->name[2])))
continue;
- /* Check if file is a raid directory */
- if ((my_isdigit(system_charset_info, file->name[0]) ||
- (file->name[0] >= 'a' && file->name[0] <= 'f')) &&
- (my_isdigit(system_charset_info, file->name[1]) ||
- (file->name[1] >= 'a' && file->name[1] <= 'f')) &&
- !file->name[2] && !level)
- {
- char newpath[FN_REFLEN], *copy_of_path;
- MY_DIR *new_dirp;
- String *dir;
- uint length;
-
- strxmov(newpath,org_path,"/",file->name,NullS);
- length= unpack_filename(newpath,newpath);
- if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT))))
- {
- DBUG_PRINT("my",("New subdir found: %s", newpath));
- if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1,0)) < 0)
- goto err;
- if (!(copy_of_path= (char*) thd->memdup(newpath, length+1)) ||
- !(dir= new (thd->mem_root) String(copy_of_path, length,
- &my_charset_bin)) ||
- raid_dirs.push_back(dir))
- goto err;
- continue;
- }
- found_other_files++;
- continue;
- }
- else if (file->name[0] == 'a' && file->name[1] == 'r' &&
+ if (file->name[0] == 'a' && file->name[1] == 'r' &&
file->name[2] == 'c' && file->name[3] == '\0')
{
/* .frm archive:
@@ -1158,16 +1032,16 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
*/
char newpath[FN_REFLEN];
MY_DIR *new_dirp;
- strxmov(newpath, org_path, "/", "arc", NullS);
+ strxmov(newpath, path, "/", "arc", NullS);
(void) unpack_filename(newpath, newpath);
if ((new_dirp = my_dir(newpath, MYF(MY_DONT_SORT))))
{
DBUG_PRINT("my",("Archive subdir found: %s", newpath));
if ((mysql_rm_arc_files(thd, new_dirp, newpath)) < 0)
- goto err;
+ DBUG_RETURN(true);
continue;
}
- found_other_files++;
+ *found_other_files= true;
continue;
}
if (!(extension= strrchr(file->name, '.')))
@@ -1175,7 +1049,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
if (find_type(extension, &deletable_extentions,1+2) <= 0)
{
if (find_type(extension, ha_known_exts(),1+2) <= 0)
- found_other_files++;
+ *found_other_files= true;
continue;
}
/* just for safety we use files_charset_info */
@@ -1191,12 +1065,15 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
strlen(file->name) + 1);
if (!table_list)
- goto err;
+ DBUG_RETURN(true);
table_list->db= (char*) (table_list+1);
- table_list->table_name= strmov(table_list->db, db) + 1;
- VOID(filename_to_tablename(file->name, table_list->table_name,
- MYSQL50_TABLE_NAME_PREFIX_LENGTH +
- strlen(file->name) + 1));
+ table_list->db_length= strmov(table_list->db, db) - table_list->db;
+ table_list->table_name= table_list->db + table_list->db_length + 1;
+ table_list->table_name_length= filename_to_tablename(file->name,
+ table_list->table_name,
+ MYSQL50_TABLE_NAME_PREFIX_LENGTH +
+ strlen(file->name) + 1);
+ table_list->open_type= OT_BASE_ONLY;
/* To be able to correctly look up the table in the table cache. */
if (lower_case_table_names)
@@ -1205,58 +1082,24 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
table_list->alias= table_list->table_name; // If lower_case_table_names=2
table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix);
+ table_list->mdl_request.init(MDL_key::TABLE, table_list->db,
+ table_list->table_name, MDL_EXCLUSIVE,
+ MDL_TRANSACTION);
/* Link into list */
- (*tot_list_next)= table_list;
- tot_list_next= &table_list->next_local;
- deleted++;
+ (*tot_list_next_local)= table_list;
+ (*tot_list_next_global)= table_list;
+ tot_list_next_local= &table_list->next_local;
+ tot_list_next_global= &table_list->next_global;
}
else
{
- strxmov(filePath, org_path, "/", file->name, NullS);
- if (my_delete_with_symlink(filePath,MYF(MY_WME)))
- {
- goto err;
- }
+ strxmov(filePath, path, "/", file->name, NullS);
+ if (mysql_file_delete_with_symlink(key_file_misc, filePath, MYF(MY_WME)))
+ DBUG_RETURN(true);
}
}
- if (thd->killed ||
- (tot_list && mysql_rm_table_part2(thd, tot_list, 1, 0, 1, 1)))
- goto err;
-
- /* Remove RAID directories */
- {
- List_iterator<String> it(raid_dirs);
- String *dir;
- while ((dir= it++))
- if (rmdir(dir->c_ptr()) < 0)
- found_other_files++;
- }
- my_dirend(dirp);
-
- if (dropped_tables)
- *dropped_tables= tot_list;
-
- /*
- If the directory is a symbolic link, remove the link first, then
- remove the directory the symbolic link pointed at
- */
- if (found_other_files)
- {
- my_error(ER_DB_DROP_RMDIR, MYF(0), org_path, EEXIST);
- DBUG_RETURN(-1);
- }
- else
- {
- /* Don't give errors if we can't delete 'RAID' directory */
- if (rm_dir_w_symlink(org_path, level == 0))
- DBUG_RETURN(-1);
- }
-
- DBUG_RETURN(deleted);
-
-err:
- my_dirend(dirp);
- DBUG_RETURN(-1);
+ *tables= tot_list;
+ DBUG_RETURN(false);
}
@@ -1291,7 +1134,7 @@ static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error)
DBUG_RETURN(1);
if (!error)
{
- if (my_delete(path, MYF(send_error ? MY_WME : 0)))
+ if (mysql_file_delete(key_file_misc, path, MYF(send_error ? MY_WME : 0)))
{
DBUG_RETURN(send_error);
}
@@ -1368,7 +1211,7 @@ long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path)
continue;
}
strxmov(filePath, org_path, "/", file->name, NullS);
- if (my_delete_with_symlink(filePath,MYF(MY_WME)))
+ if (mysql_file_delete_with_symlink(key_file_misc, filePath, MYF(MY_WME)))
{
goto err;
}
@@ -1438,8 +1281,7 @@ static void mysql_change_db_impl(THD *thd,
we just call THD::reset_db(). Since THD::reset_db() does not releases
the previous database name, we should do it explicitly.
*/
-
- x_free(thd->db);
+ my_free(thd->db);
thd->reset_db(new_db_name->str, new_db_name->length);
}
@@ -1616,7 +1458,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
}
}
- if (is_schema_db(new_db_name->str, new_db_name->length))
+ if (is_infoschema_db(new_db_name->str, new_db_name->length))
{
/* Switch the current database to INFORMATION_SCHEMA. */
@@ -1652,7 +1494,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
if (check_db_name(&new_db_file_name))
{
my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
- my_free(new_db_file_name.str, MYF(0));
+ my_free(new_db_file_name.str);
if (force_switch)
mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
@@ -1682,7 +1524,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
new_db_file_name.str);
general_log_print(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
sctx->priv_user, sctx->priv_host, new_db_file_name.str);
- my_free(new_db_file_name.str, MYF(0));
+ my_free(new_db_file_name.str);
DBUG_RETURN(TRUE);
}
#endif
@@ -1697,7 +1539,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
new_db_file_name.str);
- my_free(new_db_file_name.str, MYF(0));
+ my_free(new_db_file_name.str);
/* Change db to NULL. */
@@ -1712,7 +1554,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
/* Report an error and free new_db_file_name. */
my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
- my_free(new_db_file_name.str, MYF(0));
+ my_free(new_db_file_name.str);
/* The operation failed. */
@@ -1770,60 +1612,6 @@ bool mysql_opt_change_db(THD *thd,
}
-static int
-lock_databases(THD *thd, const char *db1, uint length1,
- const char *db2, uint length2)
-{
- pthread_mutex_lock(&LOCK_lock_db);
- while (!thd->killed &&
- (hash_search(&lock_db_cache,(uchar*) db1, length1) ||
- hash_search(&lock_db_cache,(uchar*) db2, length2)))
- {
- wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
- pthread_mutex_lock(&LOCK_lock_db);
- }
-
- if (thd->killed)
- {
- pthread_mutex_unlock(&LOCK_lock_db);
- return 1;
- }
-
- lock_db_insert(db1, length1);
- lock_db_insert(db2, length2);
- creating_database++;
-
- /*
- Wait if a concurent thread is creating a table at the same time.
- The assumption here is that it will not take too long until
- there is a point in time when a table is not created.
- */
-
- while (!thd->killed && creating_table)
- {
- wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
- pthread_mutex_lock(&LOCK_lock_db);
- }
-
- if (thd->killed)
- {
- lock_db_delete(db1, length1);
- lock_db_delete(db2, length2);
- creating_database--;
- pthread_mutex_unlock(&LOCK_lock_db);
- pthread_cond_signal(&COND_refresh);
- return(1);
- }
-
- /*
- We can unlock now as the hash will protect against anyone creating a table
- in the databases we are using
- */
- pthread_mutex_unlock(&LOCK_lock_db);
- return 0;
-}
-
-
/**
Upgrade a 5.0 database.
This function is invoked whenever an ALTER DATABASE UPGRADE query is executed:
@@ -1865,9 +1653,9 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
new_db.str= old_db->str + MYSQL50_TABLE_NAME_PREFIX_LENGTH;
new_db.length= old_db->length - MYSQL50_TABLE_NAME_PREFIX_LENGTH;
- if (lock_databases(thd, old_db->str, old_db->length,
- new_db.str, new_db.length))
- DBUG_RETURN(1);
+ /* Lock the old name, the new name will be locked by mysql_create_db().*/
+ if (lock_schema_name(thd, old_db->str))
+ DBUG_RETURN(-1);
/*
Let's remember if we should do "USE newdb" afterwards.
@@ -1920,9 +1708,11 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
Table_ident *new_ident= new Table_ident(thd, new_db, table_str, 0);
if (!old_ident || !new_ident ||
!sl->add_table_to_list(thd, old_ident, NULL,
- TL_OPTION_UPDATING, TL_IGNORE) ||
+ TL_OPTION_UPDATING, TL_IGNORE,
+ MDL_EXCLUSIVE) ||
!sl->add_table_to_list(thd, new_ident, NULL,
- TL_OPTION_UPDATING, TL_IGNORE))
+ TL_OPTION_UPDATING, TL_IGNORE,
+ MDL_EXCLUSIVE))
{
error= 1;
my_dirend(dirp);
@@ -1948,7 +1738,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
*/
build_table_filename(path, sizeof(path)-1,
new_db.str,"",MY_DB_OPT_FILE, 0);
- my_delete(path, MYF(MY_WME));
+ mysql_file_delete(key_file_dbopt, path, MYF(MY_WME));
length= build_table_filename(path, sizeof(path)-1, new_db.str, "", "", 0);
if (length && path[length-1] == FN_LIBCHAR)
path[length-1]=0; // remove ending '\'
@@ -2004,15 +1794,15 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
old_db->str, "", file->name, 0);
build_table_filename(newname, sizeof(newname)-1,
new_db.str, "", file->name, 0);
- my_rename(oldname, newname, MYF(MY_WME));
+ mysql_file_rename(key_file_misc, oldname, newname, MYF(MY_WME));
}
my_dirend(dirp);
}
/*
Step7: drop the old database.
- remove_db_from_cache(olddb) and query_cache_invalidate(olddb)
- are done inside mysql_rm_db(), no needs to execute them again.
+ query_cache_invalidate(olddb) is done inside mysql_rm_db(), no need
+ to execute them again.
mysql_rm_db() also "unuses" if we drop the current database.
*/
error= mysql_rm_db(thd, old_db->str, 0, 1);
@@ -2022,7 +1812,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
{
int errcode= query_error_code(thd, TRUE);
Query_log_event qinfo(thd, thd->query(), thd->query_length(),
- 0, TRUE, errcode);
+ FALSE, TRUE, TRUE, errcode);
thd->clear_error();
error|= mysql_bin_log.write(&qinfo);
}
@@ -2032,15 +1822,6 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
error|= mysql_change_db(thd, & new_db, FALSE);
exit:
- pthread_mutex_lock(&LOCK_lock_db);
- /* Remove the databases from db lock cache */
- lock_db_delete(old_db->str, old_db->length);
- lock_db_delete(new_db.str, new_db.length);
- creating_database--;
- /* Signal waiting CREATE TABLE's to continue */
- pthread_cond_signal(&COND_refresh);
- pthread_mutex_unlock(&LOCK_lock_db);
-
DBUG_RETURN(error);
}
diff --git a/sql/sql_db.h b/sql/sql_db.h
new file mode 100644
index 00000000000..ecb8deaa397
--- /dev/null
+++ b/sql/sql_db.h
@@ -0,0 +1,50 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_DB_INCLUDED
+#define SQL_DB_INCLUDED
+
+#include "hash.h" /* HASH */
+
+class THD;
+typedef struct charset_info_st CHARSET_INFO;
+typedef struct st_ha_create_information HA_CREATE_INFO;
+typedef struct st_mysql_lex_string LEX_STRING;
+
+int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
+bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
+bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
+bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db);
+bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name,
+ bool force_switch);
+
+bool mysql_opt_change_db(THD *thd,
+ const LEX_STRING *new_db_name,
+ LEX_STRING *saved_db_name,
+ bool force_switch,
+ bool *cur_db_changed);
+bool my_dboptions_cache_init(void);
+void my_dboptions_cache_free(void);
+bool check_db_dir_existence(const char *db_name);
+bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
+bool load_db_opt_by_name(THD *thd, const char *db_name,
+ HA_CREATE_INFO *db_create_info);
+CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name);
+bool my_dbopt_init(void);
+void my_dbopt_cleanup(void);
+
+#define MY_DB_OPT_FILE "db.opt"
+
+#endif /* SQL_DB_INCLUDED */
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 6a87eb4e572..685ce1c7b42 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB
+/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -14,15 +14,29 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
- Delete of records and truncate of tables.
+ Delete of records tables.
Multi-table deletes were introduced by Monty and Sinisa
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_delete.h"
+#include "sql_cache.h" // query_cache_*
+#include "sql_base.h" // open_temprary_table
+#include "sql_table.h" // build_table_filename
+#include "lock.h" // unlock_table_name
+#include "sql_view.h" // check_key_in_view, mysql_frm_type
+#include "sql_parse.h" // mysql_init_select
+#include "sql_acl.h" // *_ACL
+#include "filesort.h" // filesort
+#include "sql_handler.h" // mysql_ha_rm_tables
#include "sql_select.h"
#include "sp_head.h"
#include "sql_trigger.h"
+#include "transaction.h"
+#include "records.h" // init_read_record,
+ // end_read_record
/**
Implement DELETE SQL word.
@@ -33,8 +47,7 @@
*/
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
- SQL_I_List<ORDER> *order, ha_rows limit, ulonglong options,
- bool reset_auto_increment)
+ SQL_I_List<ORDER> *order_list, ha_rows limit, ulonglong options)
{
bool will_batch;
int error, loc_error;
@@ -45,20 +58,17 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
bool transactional_table, safe_update, const_cond;
bool const_cond_result;
ha_rows deleted= 0;
- bool triggers_applicable;
+ bool reverse= FALSE;
+ bool skip_record;
+ ORDER *order= (ORDER *) ((order_list && order_list->elements) ?
+ order_list->first : NULL);
uint usable_index= MAX_KEY;
SELECT_LEX *select_lex= &thd->lex->select_lex;
THD::killed_state killed_status= THD::NOT_KILLED;
+ THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
DBUG_ENTER("mysql_delete");
- bool save_binlog_row_based;
- bool skip_record;
- THD::enum_binlog_query_type query_type=
- thd->lex->sql_command == SQLCOM_TRUNCATE ?
- THD::STMT_QUERY_TYPE :
- THD::ROW_QUERY_TYPE;
-
- if (open_and_lock_tables(thd, table_list))
+ if (open_and_lock_tables(thd, table_list, TRUE, 0))
DBUG_RETURN(TRUE);
if (!(table= table_list->table))
{
@@ -73,7 +83,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DBUG_RETURN(TRUE);
/* check ORDER BY even if it can be ignored */
- if (order && order->elements)
+ if (order)
{
TABLE_LIST tables;
List<Item> fields;
@@ -83,9 +93,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
tables.table = table;
tables.alias = table_list->alias;
- if (select_lex->setup_ref_array(thd, order->elements) ||
+ if (select_lex->setup_ref_array(thd, order_list->elements) ||
setup_order(thd, select_lex->ref_pointer_array, &tables,
- fields, all_fields, order->first))
+ fields, all_fields, order))
{
delete select;
free_underlaid_joins(thd, &thd->lex->select_lex);
@@ -94,7 +104,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
}
const_cond= (!conds || conds->const_item());
- safe_update=test(thd->options & OPTION_SAFE_UPDATES);
+ safe_update=test(thd->variables.option_bits & OPTION_SAFE_UPDATES);
if (safe_update && const_cond)
{
my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
@@ -116,25 +126,20 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
any side-effects (because of triggers), so we can use optimized
handler::delete_all_rows() method.
- We implement fast TRUNCATE for InnoDB even if triggers are
- present. TRUNCATE ignores triggers.
-
We can use delete_all_rows() if and only if:
- We allow new functions (not using option --skip-new), and are
not in safe mode (not using option --safe-mode)
- There is no limit clause
- The condition is constant
- If there is a condition, then it it produces a non-zero value
- - If the current command is DELETE FROM with no where clause
- (i.e., not TRUNCATE) then:
- - We should not be binlogging this statement row-based, and
+ - If the current command is DELETE FROM with no where clause, then:
+ - We should not be binlogging this statement in row-based, and
- there should be no delete triggers associated with the table.
*/
if (!using_limit && const_cond_result &&
!(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
- (thd->lex->sql_command == SQLCOM_TRUNCATE ||
- (!thd->current_stmt_binlog_row_based &&
- !(table->triggers && table->triggers->has_delete_triggers()))))
+ (!thd->is_current_stmt_binlog_format_row() &&
+ !(table->triggers && table->triggers->has_delete_triggers())))
{
/* Update the table->file->stats.records number */
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
@@ -147,16 +152,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
query in row format, so we have to log it in statement format.
*/
query_type= THD::STMT_QUERY_TYPE;
- error= -1; // ok
+ error= -1;
deleted= maybe_deleted;
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
goto cleanup;
}
if (error != HA_ERR_WRONG_COMMAND)
{
table->file->print_error(error,MYF(0));
error=0;
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
goto cleanup;
}
/* Handler didn't support fast delete; Delete rows one by one */
@@ -173,8 +176,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (prune_partitions(thd, table, conds))
{
free_underlaid_joins(thd, select_lex);
- thd->row_count_func= 0;
- my_ok(thd, (ha_rows) thd->row_count_func); // No matching records
+ // No matching record
+ my_ok(thd, 0);
DBUG_RETURN(0);
}
#endif
@@ -183,6 +186,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
table->covering_keys.clear_all();
table->quick_keys.clear_all(); // Can't use 'only index'
+
select=make_select(table, 0, 0, conds, 0, &error);
if (error)
DBUG_RETURN(TRUE);
@@ -190,7 +194,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{
delete select;
free_underlaid_joins(thd, select_lex);
- thd->row_count_func= 0;
/*
Error was already created by quick select evaluation (check_quick()).
TODO: Add error code output parameter to Item::val_xxx() methods.
@@ -199,12 +202,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
*/
if (thd->is_error())
DBUG_RETURN(TRUE);
- my_ok(thd, (ha_rows) thd->row_count_func);
- /*
- We don't need to call reset_auto_increment in this case, because
- mysql_truncate always gives a NULL conds argument, hence we never
- get here.
- */
+ my_ok(thd, 0);
DBUG_RETURN(0); // Nothing to delete
}
@@ -224,22 +222,25 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_QUICK);
- if (order && order->elements)
+ if (order)
{
uint length= 0;
SORT_FIELD *sortorder;
ha_rows examined_rows;
- if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR)
- usable_index= get_index_for_order(table, order->first, limit);
+ table->update_const_key_parts(conds);
+ order= simple_remove_const(order, conds);
- if (usable_index == MAX_KEY)
+ bool need_sort;
+ usable_index= get_index_for_order(order, table, select, limit,
+ &need_sort, &reverse);
+ if (need_sort)
{
+ DBUG_ASSERT(usable_index == MAX_KEY);
table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
- if (!(sortorder= make_unireg_sortorder(order->first,
- &length, NULL)) ||
+ if (!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
(table->sort.found_records = filesort(thd, table, sortorder, length,
select, HA_POS_ERROR, 1,
&examined_rows))
@@ -270,17 +271,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (usable_index==MAX_KEY || (select && select->quick))
init_read_record(&info, thd, table, select, 1, 1, FALSE);
else
- init_read_record_idx(&info, thd, table, 1, usable_index);
+ init_read_record_idx(&info, thd, table, 1, usable_index, reverse);
init_ftfuncs(thd, select_lex, 1);
thd_proc_info(thd, "updating");
- /* NOTE: TRUNCATE must not invoke triggers. */
-
- triggers_applicable= table->triggers &&
- thd->lex->sql_command != SQLCOM_TRUNCATE;
-
- if (triggers_applicable &&
+ if (table->triggers &&
table->triggers->has_triggers(TRG_EVENT_DELETE,
TRG_ACTION_AFTER))
{
@@ -298,11 +294,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
table->mark_columns_needed_for_delete();
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- if (thd->lex->sql_command == SQLCOM_TRUNCATE &&
- thd->current_stmt_binlog_row_based)
- thd->clear_current_stmt_binlog_row_based();
-
while (!(error=info.read_record(&info)) && !thd->killed &&
! thd->is_error())
{
@@ -311,7 +302,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (!select || (!select->skip_record(thd, &skip_record) && !skip_record))
{
- if (triggers_applicable &&
+ if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_BEFORE, FALSE))
{
@@ -322,7 +313,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (!(error= table->file->ha_delete_row(table->record[0])))
{
deleted++;
- if (triggers_applicable &&
+ if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_AFTER, FALSE))
{
@@ -367,21 +358,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL);
- if (reset_auto_increment && (error < 0))
- {
- /*
- We're really doing a truncate and need to reset the table's
- auto-increment counter.
- */
- int error2= table->file->ha_reset_auto_increment(0);
-
- if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
- {
- table->file->print_error(error2, MYF(0));
- error= 1;
- }
- }
-
cleanup:
/*
Invalidate the table in the query cache if something changed. This must
@@ -396,60 +372,43 @@ cleanup:
transactional_table= table->file->has_transactions();
if (!transactional_table && deleted > 0)
- thd->transaction.stmt.modified_non_trans_table= TRUE;
+ thd->transaction.stmt.modified_non_trans_table=
+ thd->transaction.all.modified_non_trans_table= TRUE;
/* See similar binlogging code in sql_update.cc, for comments */
if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
{
- if (mysql_bin_log.is_open() &&
- !(thd->lex->sql_command == SQLCOM_TRUNCATE &&
- thd->current_stmt_binlog_row_based &&
- find_temporary_table(thd, table_list)))
+ if (mysql_bin_log.is_open())
{
- bool const is_trans=
- thd->lex->sql_command == SQLCOM_TRUNCATE ?
- FALSE :
- transactional_table;
-
int errcode= 0;
if (error < 0)
thd->clear_error();
else
errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
-
+
/*
[binlog]: If 'handler::delete_all_rows()' was called and the
storage engine does not inject the rows itself, we replicate
statement-based; otherwise, 'ha_delete_row()' was used to
delete specific rows which we might log row-based.
-
- Note that TRUNCATE TABLE is not transactional and should
- therefore be treated as a DDL.
*/
int log_result= thd->binlog_query(query_type,
thd->query(), thd->query_length(),
- is_trans, FALSE, errcode);
+ transactional_table, FALSE, FALSE,
+ errcode);
if (log_result)
{
error=1;
}
}
- if (thd->transaction.stmt.modified_non_trans_table)
- thd->transaction.all.modified_non_trans_table= TRUE;
}
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table);
free_underlaid_joins(thd, select_lex);
if (error < 0 ||
(thd->lex->ignore && !thd->is_error() && !thd->is_fatal_error))
{
- /*
- If a TRUNCATE TABLE was issued, the number of rows should be reported as
- zero since the exact number is unknown.
- */
- thd->row_count_func= reset_auto_increment ? 0 : deleted;
- my_ok(thd, (ha_rows) thd->row_count_func);
+ my_ok(thd, deleted);
DBUG_PRINT("info",("%ld records deleted",(long) deleted));
}
DBUG_RETURN(error >= 0 || thd->is_error());
@@ -476,19 +435,6 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
DBUG_ENTER("mysql_prepare_delete");
List<Item> all_fields;
- /*
- Statement-based replication of DELETE ... LIMIT is not safe as order of
- rows is not defined, so in mixed mode we go to row-based.
-
- Note that we may consider a statement as safe if ORDER BY primary_key
- is present. However it may confuse users to see very similiar statements
- replicated differently.
- */
- if (thd->lex->current_select->select_limit)
- {
- thd->lex->set_stmt_unsafe();
- thd->set_current_stmt_binlog_row_based_if_mixed();
- }
thd->lex->allow_sum_func= 0;
if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
&thd->lex->select_lex.top_join_list,
@@ -579,9 +525,7 @@ int mysql_multi_delete_prepare(THD *thd)
if (!(target_tbl->table= target_tbl->correspondent_table->table))
{
DBUG_ASSERT(target_tbl->correspondent_table->view &&
- target_tbl->correspondent_table->merge_underlying_list &&
- target_tbl->correspondent_table->merge_underlying_list->
- next_local);
+ target_tbl->correspondent_table->multitable_view);
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
target_tbl->correspondent_table->view_db.str,
target_tbl->correspondent_table->view_name.str);
@@ -646,7 +590,7 @@ multi_delete::initialize_tables(JOIN *join)
Unique **tempfiles_ptr;
DBUG_ENTER("initialize_tables");
- if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
+ if ((thd->variables.option_bits & OPTION_SAFE_UPDATES) && error_if_full_join(join))
DBUG_RETURN(1);
table_map tables_to_delete_from=0;
@@ -824,9 +768,9 @@ void multi_delete::send_error(uint errcode,const char *err)
}
-void multi_delete::abort()
+void multi_delete::abort_result_set()
{
- DBUG_ENTER("multi_delete::abort");
+ DBUG_ENTER("multi_delete::abort_result_set");
/* the error was handled or nothing deleted and no side effects return */
if (error_handled ||
@@ -837,6 +781,9 @@ void multi_delete::abort()
if (deleted)
query_cache_invalidate3(thd, delete_tables, 1);
+ if (thd->transaction.stmt.modified_non_trans_table)
+ thd->transaction.all.modified_non_trans_table= TRUE;
+
/*
If rows from the first table only has been deleted and it is
transactional, just do rollback.
@@ -867,10 +814,9 @@ void multi_delete::abort()
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
/* possible error of writing binary log is ignored deliberately */
(void) thd->binlog_query(THD::ROW_QUERY_TYPE,
- thd->query(), thd->query_length(),
- transactional_tables, FALSE, errcode);
+ thd->query(), thd->query_length(),
+ transactional_tables, FALSE, FALSE, errcode);
}
- thd->transaction.all.modified_non_trans_table= true;
}
DBUG_VOID_RETURN;
}
@@ -1023,6 +969,9 @@ bool multi_delete::send_eof()
/* reset used flags */
thd_proc_info(thd, "end");
+ if (thd->transaction.stmt.modified_non_trans_table)
+ thd->transaction.all.modified_non_trans_table= TRUE;
+
/*
We must invalidate the query cache before binlog writing and
ha_autocommit_...
@@ -1042,162 +991,20 @@ bool multi_delete::send_eof()
errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
- transactional_tables, FALSE, errcode) &&
+ transactional_tables, FALSE, FALSE, errcode) &&
!normal_tables)
{
local_error=1; // Log write failed: roll back the SQL statement
}
}
- if (thd->transaction.stmt.modified_non_trans_table)
- thd->transaction.all.modified_non_trans_table= TRUE;
}
if (local_error != 0)
error_handled= TRUE; // to force early leave from ::send_error()
if (!local_error)
{
- thd->row_count_func= deleted;
- ::my_ok(thd, (ha_rows) thd->row_count_func);
+ ::my_ok(thd, deleted);
}
return 0;
}
-
-/***************************************************************************
- TRUNCATE TABLE
-****************************************************************************/
-
-/*
- Row-by-row truncation if the engine does not support table recreation.
- Probably a InnoDB table.
-*/
-
-static bool mysql_truncate_by_delete(THD *thd, TABLE_LIST *table_list)
-{
- bool error;
- DBUG_ENTER("mysql_truncate_by_delete");
- table_list->lock_type= TL_WRITE;
- mysql_init_select(thd->lex);
- error= mysql_delete(thd, table_list, NULL, NULL, HA_POS_ERROR, LL(0), TRUE);
- ha_autocommit_or_rollback(thd, error);
- end_trans(thd, error ? ROLLBACK : COMMIT);
- DBUG_RETURN(error);
-}
-
-
-/*
- Optimize delete of all rows by doing a full generate of the table
- This will work even if the .ISM and .ISD tables are destroyed
-
- dont_send_ok should be set if:
- - We should always wants to generate the table (even if the table type
- normally can't safely do this.
- - We don't want an ok to be sent to the end user.
- - We don't want to log the truncate command
- - If we want to have a name lock on the table on exit without errors.
-*/
-
-bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
-{
- HA_CREATE_INFO create_info;
- char path[FN_REFLEN + 1];
- TABLE *table;
- bool error;
- uint path_length;
- bool is_temporary_table= false;
- DBUG_ENTER("mysql_truncate");
-
- bzero((char*) &create_info,sizeof(create_info));
-
- /* Remove tables from the HANDLER's hash. */
- mysql_ha_rm_tables(thd, table_list, FALSE);
-
- /* If it is a temporary table, close and regenerate it */
- if (!dont_send_ok && (table= find_temporary_table(thd, table_list)))
- {
- is_temporary_table= true;
- handlerton *table_type= table->s->db_type();
- TABLE_SHARE *share= table->s;
- if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
- goto trunc_by_del;
-
- table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
-
- close_temporary_table(thd, table, 0, 0); // Don't free share
- ha_create_table(thd, share->normalized_path.str,
- share->db.str, share->table_name.str, &create_info, 1);
- // We don't need to call invalidate() because this table is not in cache
- if ((error= (int) !(open_temporary_table(thd, share->path.str,
- share->db.str,
- share->table_name.str, 1))))
- (void) rm_temporary_table(table_type, path);
- else
- thd->thread_specific_used= TRUE;
-
- free_table_share(share);
- my_free((char*) table,MYF(0));
- /*
- If we return here we will not have logged the truncation to the bin log
- and we will not my_ok() to the client.
- */
- goto end;
- }
-
- path_length= build_table_filename(path, sizeof(path) - 1, table_list->db,
- table_list->table_name, reg_ext, 0);
-
- if (!dont_send_ok)
- {
- enum legacy_db_type table_type;
- mysql_frm_type(thd, path, &table_type);
- if (table_type == DB_TYPE_UNKNOWN)
- {
- my_error(ER_NO_SUCH_TABLE, MYF(0),
- table_list->db, table_list->table_name);
- DBUG_RETURN(TRUE);
- }
- if (!ha_check_storage_engine_flag(ha_resolve_by_legacy_type(thd, table_type),
- HTON_CAN_RECREATE))
- goto trunc_by_del;
-
- if (lock_and_wait_for_table_name(thd, table_list))
- DBUG_RETURN(TRUE);
- }
-
- // Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
- // crashes, replacement works. *(path + path_length - reg_ext_length)=
- // '\0';
- path[path_length - reg_ext_length] = 0;
- VOID(pthread_mutex_lock(&LOCK_open));
- error= ha_create_table(thd, path, table_list->db, table_list->table_name,
- &create_info, 1);
- VOID(pthread_mutex_unlock(&LOCK_open));
- query_cache_invalidate3(thd, table_list, 0);
-
-end:
- if (!dont_send_ok)
- {
- if (!error)
- {
- /* In RBR, the statement is not binlogged if the table is temporary. */
- if (!is_temporary_table || !thd->current_stmt_binlog_row_based)
- error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- if (!error)
- my_ok(thd); // This should return record count
- }
- VOID(pthread_mutex_lock(&LOCK_open));
- unlock_table_name(thd, table_list);
- VOID(pthread_mutex_unlock(&LOCK_open));
- }
- else if (error)
- {
- VOID(pthread_mutex_lock(&LOCK_open));
- unlock_table_name(thd, table_list);
- VOID(pthread_mutex_unlock(&LOCK_open));
- }
- DBUG_RETURN(error);
-
-trunc_by_del:
- error= mysql_truncate_by_delete(thd, table_list);
- DBUG_RETURN(error);
-}
diff --git a/sql/sql_delete.h b/sql/sql_delete.h
new file mode 100644
index 00000000000..264991c220b
--- /dev/null
+++ b/sql/sql_delete.h
@@ -0,0 +1,32 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_DELETE_INCLUDED
+#define SQL_DELETE_INCLUDED
+
+#include "my_base.h" /* ha_rows */
+
+class THD;
+struct TABLE_LIST;
+class Item;
+
+typedef class Item COND;
+template <typename T> class SQL_I_List;
+
+int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
+bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
+ SQL_I_List<ORDER> *order, ha_rows rows, ulonglong options);
+
+#endif /* SQL_DELETE_INCLUDED */
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 782589f7d0f..47bc13beb53 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -20,9 +20,13 @@
*/
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_derived.h"
#include "sql_select.h"
-
+#include "sql_view.h" // check_duplicate_names
+#include "sql_acl.h" // SELECT_ACL
/*
@@ -154,7 +158,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
if ((res= check_duplicate_names(unit->types, 0)))
goto exit;
- create_options= (first_select->options | thd->options |
+ create_options= (first_select->options | thd->variables.option_bits |
TMP_TABLE_ALL_COLUMNS);
/*
Temp table is created so that it hounours if UNION without ALL is to be
@@ -178,9 +182,9 @@ exit:
if (orig_table_list->view)
{
if (thd->is_error() &&
- (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR ||
- thd->main_da.sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION ||
- thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST))
+ (thd->stmt_da->sql_errno() == ER_BAD_FIELD_ERROR ||
+ thd->stmt_da->sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION ||
+ thd->stmt_da->sql_errno() == ER_SP_DOES_NOT_EXIST))
{
thd->clear_error();
my_error(ER_VIEW_INVALID, MYF(0), orig_table_list->db,
@@ -289,7 +293,7 @@ bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
first_select->order_list.first,
first_select->group_list.first,
first_select->having, (ORDER*) NULL,
- (first_select->options | thd->options |
+ (first_select->options | thd->variables.option_bits |
SELECT_NO_UNLOCK),
derived_result, unit, first_select);
}
diff --git a/sql/sql_derived.h b/sql/sql_derived.h
new file mode 100644
index 00000000000..0d4eddedf22
--- /dev/null
+++ b/sql/sql_derived.h
@@ -0,0 +1,29 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_DERIVED_INCLUDED
+#define SQL_DERIVED_INCLUDED
+
+struct TABLE_LIST;
+class THD;
+struct LEX;
+
+bool mysql_handle_derived(LEX *lex, bool (*processor)(THD *thd,
+ LEX *lex,
+ TABLE_LIST *table));
+bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
+bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
+
+#endif /* SQL_DERIVED_INCLUDED */
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index 8406a9eaf45..085473c24b8 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -16,7 +16,12 @@
/* Execute DO statement */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "transaction.h"
+#include "unireg.h"
+#include "sql_do.h"
+#include "sql_base.h" // setup_fields
+#include "sql_select.h" // free_underlaid_joins
bool mysql_do(THD *thd, List<Item> &values)
{
@@ -34,9 +39,10 @@ bool mysql_do(THD *thd, List<Item> &values)
/*
Rollback the effect of the statement, since next instruction
will clear the error and the rollback in the end of
- dispatch_command() won't work.
+ mysql_execute_command() won't work.
*/
- ha_autocommit_or_rollback(thd, thd->is_error());
+ if (! thd->in_sub_stmt)
+ trans_rollback_stmt(thd);
thd->clear_error(); // DO always is OK
}
my_ok(thd);
diff --git a/sql/sql_do.h b/sql/sql_do.h
new file mode 100644
index 00000000000..56479f8f88e
--- /dev/null
+++ b/sql/sql_do.h
@@ -0,0 +1,26 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_DO_INCLUDED
+#define SQL_DO_INCLUDED
+
+#include "sql_list.h" /* List */
+
+class THD;
+class Item;
+
+bool mysql_do(THD *thd, List<Item> &values);
+
+#endif /* SQL_DO_INCLUDED */
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index 9ea7facbe41..d0982b879e7 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -1,4 +1,5 @@
-/* Copyright (C) 1995-2002 MySQL AB
+/* Copyright (C) 1995-2002 MySQL AB,
+ Copyright (C) 2008-2009 Sun Microsystems, Inc
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
@@ -41,134 +42,563 @@ This file contains the implementation of error and warnings related
***********************************************************************/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_error.h"
#include "sp_rcontext.h"
/*
- Store a new message in an error object
-
- This is used to in group_concat() to register how many warnings we actually
- got after the query has been executed.
+ Design notes about MYSQL_ERROR::m_message_text.
+
+ The member MYSQL_ERROR::m_message_text contains the text associated with
+ an error, warning or note (which are all SQL 'conditions')
+
+ Producer of MYSQL_ERROR::m_message_text:
+ ----------------------------------------
+
+ (#1) the server implementation itself, when invoking functions like
+ my_error() or push_warning()
+
+ (#2) user code in stored programs, when using the SIGNAL statement.
+
+ (#3) user code in stored programs, when using the RESIGNAL statement.
+
+ When invoking my_error(), the error number and message is typically
+ provided like this:
+ - my_error(ER_WRONG_DB_NAME, MYF(0), ...);
+ - my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
+
+ In both cases, the message is retrieved from ER(ER_XXX), which in turn
+ is read from the resource file errmsg.sys at server startup.
+ The strings stored in the errmsg.sys file are expressed in the character set
+ that corresponds to the server --language start option
+ (see error_message_charset_info).
+
+ When executing:
+ - a SIGNAL statement,
+ - a RESIGNAL statement,
+ the message text is provided by the user logic, and is expressed in UTF8.
+
+ Storage of MYSQL_ERROR::m_message_text:
+ ---------------------------------------
+
+ (#4) The class MYSQL_ERROR is used to hold the message text member.
+ This class represents a single SQL condition.
+
+ (#5) The class Warning_info represents a SQL condition area, and contains
+ a collection of SQL conditions in the Warning_info::m_warn_list
+
+ Consumer of MYSQL_ERROR::m_message_text:
+ ----------------------------------------
+
+ (#6) The statements SHOW WARNINGS and SHOW ERRORS display the content of
+ the warning list.
+
+ (#7) The GET DIAGNOSTICS statement (planned, not implemented yet) will
+ also read the content of:
+ - the top level statement condition area (when executed in a query),
+ - a sub statement (when executed in a stored program)
+ and return the data stored in a MYSQL_ERROR.
+
+ (#8) The RESIGNAL statement reads the MYSQL_ERROR caught by an exception
+ handler, to raise a new or modified condition (in #3).
+
+ The big picture
+ ---------------
+ --------------
+ | ^
+ V |
+ my_error(#1) SIGNAL(#2) RESIGNAL(#3) |
+ |(#A) |(#B) |(#C) |
+ | | | |
+ ----------------------------|---------------------------- |
+ | |
+ V |
+ MYSQL_ERROR(#4) |
+ | |
+ | |
+ V |
+ Warning_info(#5) |
+ | |
+ ----------------------------------------------------- |
+ | | | |
+ | | | |
+ | | | |
+ V V V |
+ SHOW WARNINGS(#6) GET DIAGNOSTICS(#7) RESIGNAL(#8) |
+ | | | | |
+ | -------- | V |
+ | | | --------------
+ V | |
+ Connectors | |
+ | | |
+ -------------------------
+ |
+ V
+ Client application
+
+ Current implementation status
+ -----------------------------
+
+ (#1) (my_error) produces data in the 'error_message_charset_info' CHARSET
+
+ (#2) and (#3) (SIGNAL, RESIGNAL) produces data internally in UTF8
+
+ (#6) (SHOW WARNINGS) produces data in the 'error_message_charset_info' CHARSET
+
+ (#7) (GET DIAGNOSTICS) is not implemented.
+
+ (#8) (RESIGNAL) produces data internally in UTF8 (see #3)
+
+ As a result, the design choice for (#4) and (#5) is to store data in
+ the 'error_message_charset_info' CHARSET, to minimize impact on the code base.
+ This is implemented by using 'String MYSQL_ERROR::m_message_text'.
+
+ The UTF8 -> error_message_charset_info conversion is implemented in
+ Signal_common::eval_signal_informations() (for path #B and #C).
+
+ Future work
+ -----------
+
+ - Change (#1) (my_error) to generate errors in UTF8.
+ See WL#751 (Recoding of error messages)
+
+ - Change (#4 and #5) to store message text in UTF8 natively.
+ In practice, this means changing the type of the message text to
+ '<UTF8 String 128 class> MYSQL_ERROR::m_message_text', and is a direct
+ consequence of WL#751.
+
+ - Implement (#9) (GET DIAGNOSTICS).
+ See WL#2111 (Stored Procedures: Implement GET DIAGNOSTICS)
*/
-void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg)
+MYSQL_ERROR::MYSQL_ERROR()
+ : Sql_alloc(),
+ 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_message_text(),
+ m_sql_errno(0),
+ m_level(MYSQL_ERROR::WARN_LEVEL_ERROR),
+ m_mem_root(NULL)
{
- msg= strdup_root(&thd->warn_root, msg_arg);
+ memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate));
}
+void MYSQL_ERROR::init(MEM_ROOT *mem_root)
+{
+ DBUG_ASSERT(mem_root != NULL);
+ DBUG_ASSERT(m_mem_root == NULL);
+ m_mem_root= mem_root;
+}
-/*
- Reset all warnings for the thread
-
- SYNOPSIS
- mysql_reset_errors()
- thd Thread handle
- force Reset warnings even if it has been done before
+void MYSQL_ERROR::clear()
+{
+ m_class_origin.length(0);
+ m_subclass_origin.length(0);
+ m_constraint_catalog.length(0);
+ m_constraint_schema.length(0);
+ m_constraint_name.length(0);
+ m_catalog_name.length(0);
+ m_schema_name.length(0);
+ m_table_name.length(0);
+ m_column_name.length(0);
+ m_cursor_name.length(0);
+ m_message_text.length(0);
+ m_sql_errno= 0;
+ m_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+}
- IMPLEMENTATION
- Don't reset warnings if this has already been called for this query.
- This may happen if one gets a warning during the parsing stage,
- in which case push_warnings() has already called this function.
-*/
+MYSQL_ERROR::MYSQL_ERROR(MEM_ROOT *mem_root)
+ : Sql_alloc(),
+ 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_message_text(),
+ m_sql_errno(0),
+ m_level(MYSQL_ERROR::WARN_LEVEL_ERROR),
+ m_mem_root(mem_root)
+{
+ DBUG_ASSERT(mem_root != NULL);
+ memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate));
+}
-void mysql_reset_errors(THD *thd, bool force)
+static void copy_string(MEM_ROOT *mem_root, String* dst, const String* src)
{
- DBUG_ENTER("mysql_reset_errors");
- if (thd->query_id != thd->warn_id || force)
+ size_t len= src->length();
+ if (len)
{
- thd->warn_id= thd->query_id;
- free_root(&thd->warn_root,MYF(0));
- bzero((char*) thd->warn_count, sizeof(thd->warn_count));
- if (force)
- thd->total_warn_count= 0;
- thd->warn_list.empty();
- thd->row_count= 1; // by default point to row 1
+ char* copy= (char*) alloc_root(mem_root, len + 1);
+ if (copy)
+ {
+ memcpy(copy, src->ptr(), len);
+ copy[len]= '\0';
+ dst->set(copy, len, src->charset());
+ }
}
+ else
+ dst->length(0);
+}
+
+void
+MYSQL_ERROR::copy_opt_attributes(const MYSQL_ERROR *cond)
+{
+ DBUG_ASSERT(this != cond);
+ copy_string(m_mem_root, & m_class_origin, & cond->m_class_origin);
+ copy_string(m_mem_root, & m_subclass_origin, & cond->m_subclass_origin);
+ copy_string(m_mem_root, & m_constraint_catalog, & cond->m_constraint_catalog);
+ copy_string(m_mem_root, & m_constraint_schema, & cond->m_constraint_schema);
+ copy_string(m_mem_root, & m_constraint_name, & cond->m_constraint_name);
+ copy_string(m_mem_root, & m_catalog_name, & cond->m_catalog_name);
+ copy_string(m_mem_root, & m_schema_name, & cond->m_schema_name);
+ copy_string(m_mem_root, & m_table_name, & cond->m_table_name);
+ copy_string(m_mem_root, & m_column_name, & cond->m_column_name);
+ copy_string(m_mem_root, & m_cursor_name, & cond->m_cursor_name);
+}
+
+void
+MYSQL_ERROR::set(uint sql_errno, const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level, const char* msg)
+{
+ DBUG_ASSERT(sql_errno != 0);
+ DBUG_ASSERT(sqlstate != NULL);
+ DBUG_ASSERT(msg != NULL);
+
+ m_sql_errno= sql_errno;
+ memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH);
+ m_returned_sqlstate[SQLSTATE_LENGTH]= '\0';
+
+ set_builtin_message_text(msg);
+ m_level= level;
+}
+
+void
+MYSQL_ERROR::set_builtin_message_text(const char* str)
+{
+ /*
+ See the comments
+ "Design notes about MYSQL_ERROR::m_message_text."
+ */
+ const char* copy;
+
+ copy= strdup_root(m_mem_root, str);
+ m_message_text.set(copy, strlen(copy), error_message_charset_info);
+ DBUG_ASSERT(! m_message_text.is_alloced());
+}
+
+const char*
+MYSQL_ERROR::get_message_text() const
+{
+ return m_message_text.ptr();
+}
+
+int
+MYSQL_ERROR::get_message_octet_length() const
+{
+ return m_message_text.length();
+}
+
+void
+MYSQL_ERROR::set_sqlstate(const char* sqlstate)
+{
+ memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH);
+ m_returned_sqlstate[SQLSTATE_LENGTH]= '\0';
+}
+
+/**
+ Clear this diagnostics area.
+
+ Normally called at the end of a statement.
+*/
+
+void
+Diagnostics_area::reset_diagnostics_area()
+{
+ DBUG_ENTER("reset_diagnostics_area");
+#ifdef DBUG_OFF
+ can_overwrite_status= FALSE;
+ /** Don't take chances in production */
+ m_message[0]= '\0';
+ m_sql_errno= 0;
+ m_affected_rows= 0;
+ m_last_insert_id= 0;
+ m_statement_warn_count= 0;
+#endif
+ is_sent= FALSE;
+ /** Tiny reset in debug mode to see garbage right away */
+ m_status= DA_EMPTY;
DBUG_VOID_RETURN;
}
-/*
- Push the warning/error to error list if there is still room in the list
+/**
+ Set OK status -- ends commands that do not return a
+ result set, e.g. INSERT/UPDATE/DELETE.
+*/
- SYNOPSIS
- push_warning()
- thd Thread handle
- level Severity of warning (note, warning, error ...)
- code Error number
- msg Clear error message
-
- RETURN
- pointer on MYSQL_ERROR object
+void
+Diagnostics_area::set_ok_status(THD *thd, ulonglong affected_rows_arg,
+ ulonglong last_insert_id_arg,
+ const char *message_arg)
+{
+ DBUG_ENTER("set_ok_status");
+ DBUG_ASSERT(! is_set());
+ /*
+ In production, refuse to overwrite an error or a custom response
+ with an OK packet.
+ */
+ if (is_error() || is_disabled())
+ return;
+
+ m_statement_warn_count= thd->warning_info->statement_warn_count();
+ m_affected_rows= affected_rows_arg;
+ m_last_insert_id= last_insert_id_arg;
+ if (message_arg)
+ strmake(m_message, message_arg, sizeof(m_message) - 1);
+ else
+ m_message[0]= '\0';
+ m_status= DA_OK;
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Set EOF status.
*/
-MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
- uint code, const char *msg)
+void
+Diagnostics_area::set_eof_status(THD *thd)
{
- MYSQL_ERROR *err= 0;
- DBUG_ENTER("push_warning");
- DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg));
+ DBUG_ENTER("set_eof_status");
+ /* Only allowed to report eof if has not yet reported an error */
+ DBUG_ASSERT(! is_set());
+ /*
+ In production, refuse to overwrite an error or a custom response
+ with an EOF packet.
+ */
+ if (is_error() || is_disabled())
+ return;
+
+ /*
+ If inside a stored procedure, do not return the total
+ number of warnings, since they are not available to the client
+ anyway.
+ */
+ m_statement_warn_count= (thd->spcont ?
+ 0 : thd->warning_info->statement_warn_count());
+
+ m_status= DA_EOF;
+ DBUG_VOID_RETURN;
+}
- DBUG_ASSERT(code != 0);
- DBUG_ASSERT(msg != NULL);
+/**
+ Set ERROR status.
+*/
+
+void
+Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
+ const char *message_arg,
+ const char *sqlstate)
+{
+ DBUG_ENTER("set_error_status");
+ /*
+ Only allowed to report error if has not yet reported a success
+ The only exception is when we flush the message to the client,
+ an error can happen during the flush.
+ */
+ DBUG_ASSERT(! is_set() || can_overwrite_status);
+#ifdef DBUG_OFF
+ /*
+ In production, refuse to overwrite a custom response with an
+ ERROR packet.
+ */
+ if (is_disabled())
+ return;
+#endif
+
+ if (sqlstate == NULL)
+ sqlstate= mysql_errno_to_sqlstate(sql_errno_arg);
+
+ m_sql_errno= sql_errno_arg;
+ memcpy(m_sqlstate, sqlstate, SQLSTATE_LENGTH);
+ m_sqlstate[SQLSTATE_LENGTH]= '\0';
+ strmake(m_message, message_arg, sizeof(m_message)-1);
+
+ m_status= DA_ERROR;
+ DBUG_VOID_RETURN;
+}
- if (level == MYSQL_ERROR::WARN_LEVEL_NOTE &&
- !(thd->options & OPTION_SQL_NOTES))
- DBUG_RETURN(0);
- if (thd->query_id != thd->warn_id && !thd->spcont)
- mysql_reset_errors(thd, 0);
- thd->got_warning= 1;
+/**
+ Mark the diagnostics area as 'DISABLED'.
- /* Abort if we are using strict mode and we are not using IGNORE */
- if ((int) level >= (int) MYSQL_ERROR::WARN_LEVEL_WARN &&
- thd->really_abort_on_warning())
- {
- /* Avoid my_message() calling push_warning */
- bool no_warnings_for_error= thd->no_warnings_for_error;
- sp_rcontext *spcont= thd->spcont;
+ This is used in rare cases when the COM_ command at hand sends a response
+ in a custom format. One example is the query cache, another is
+ COM_STMT_PREPARE.
+*/
- thd->no_warnings_for_error= 1;
- thd->spcont= NULL;
+void
+Diagnostics_area::disable_status()
+{
+ DBUG_ASSERT(! is_set());
+ m_status= DA_DISABLED;
+}
- thd->killed= THD::KILL_BAD_DATA;
- my_message(code, msg, MYF(0));
+Warning_info::Warning_info(ulonglong warn_id_arg)
+ :m_statement_warn_count(0),
+ m_current_row_for_warning(1),
+ m_warn_id(warn_id_arg),
+ m_read_only(FALSE)
+{
+ /* Initialize sub structures */
+ init_sql_alloc(&m_warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
+ m_warn_list.empty();
+ bzero((char*) m_warn_count, sizeof(m_warn_count));
+}
- thd->spcont= spcont;
- thd->no_warnings_for_error= no_warnings_for_error;
- /* Store error in error list (as my_message() didn't do it) */
- level= MYSQL_ERROR::WARN_LEVEL_ERROR;
- }
- if (thd->handle_error(code, msg, level))
- DBUG_RETURN(NULL);
+Warning_info::~Warning_info()
+{
+ free_root(&m_warn_root,MYF(0));
+}
+
+
+/**
+ Reset the warning information of this connection.
+*/
- if (thd->spcont &&
- thd->spcont->handle_error(code, level, thd))
+void Warning_info::clear_warning_info(ulonglong warn_id_arg)
+{
+ m_warn_id= warn_id_arg;
+ free_root(&m_warn_root, MYF(0));
+ bzero((char*) m_warn_count, sizeof(m_warn_count));
+ m_warn_list.empty();
+ m_statement_warn_count= 0;
+ m_current_row_for_warning= 1; /* Start counting from the first row */
+}
+
+/**
+ Append warnings only if the original contents of the routine
+ warning info was replaced.
+*/
+void Warning_info::merge_with_routine_info(THD *thd, Warning_info *source)
+{
+ /*
+ If a routine body is empty or if a routine did not
+ generate any warnings (thus m_warn_id didn't change),
+ do not duplicate our own contents by appending the
+ contents of the called routine. We know that the called
+ routine did not change its warning info.
+
+ On the other hand, if the routine body is not empty and
+ some statement in the routine generates a warning or
+ uses tables, m_warn_id is guaranteed to have changed.
+ In this case we know that the routine warning info
+ contains only new warnings, and thus we perform a copy.
+ */
+ if (m_warn_id != source->m_warn_id)
{
- DBUG_RETURN(NULL);
+ /*
+ If the invocation of the routine was a standalone statement,
+ rather than a sub-statement, in other words, if it's a CALL
+ of a procedure, rather than invocation of a function or a
+ trigger, we need to clear the current contents of the caller's
+ warning info.
+
+ This is per MySQL rules: if a statement generates a warning,
+ warnings from the previous statement are flushed. Normally
+ it's done in push_warning(). However, here we don't use
+ push_warning() to avoid invocation of condition handlers or
+ escalation of warnings to errors.
+ */
+ opt_clear_warning_info(thd->query_id);
+ append_warning_info(thd, source);
}
- query_cache_abort(&thd->net);
+}
+/**
+ Add a warning to the list of warnings. Increment the respective
+ counters.
+*/
+MYSQL_ERROR *Warning_info::push_warning(THD *thd,
+ uint sql_errno, const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char *msg)
+{
+ MYSQL_ERROR *cond= NULL;
- if (thd->warn_list.elements < thd->variables.max_error_count)
+ if (! m_read_only)
{
- /* We have to use warn_root, as mem_root is freed after each query */
- if ((err= new (&thd->warn_root) MYSQL_ERROR(thd, code, level, msg)))
- thd->warn_list.push_back(err, &thd->warn_root);
+ if (m_warn_list.elements < thd->variables.max_error_count)
+ {
+ cond= new (& m_warn_root) MYSQL_ERROR(& m_warn_root);
+ if (cond)
+ {
+ cond->set(sql_errno, sqlstate, level, msg);
+ m_warn_list.push_back(cond, &m_warn_root);
+ }
+ }
+ m_warn_count[(uint) level]++;
}
- thd->warn_count[(uint) level]++;
- thd->total_warn_count++;
- DBUG_RETURN(err);
+
+ m_statement_warn_count++;
+ return cond;
+}
+
+/*
+ Push the warning to error list if there is still room in the list
+
+ SYNOPSIS
+ push_warning()
+ thd Thread handle
+ level Severity of warning (note, warning)
+ code Error number
+ msg Clear error message
+*/
+
+void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+ uint code, const char *msg)
+{
+ DBUG_ENTER("push_warning");
+ DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg));
+
+ /*
+ Calling push_warning/push_warning_printf with a level of
+ WARN_LEVEL_ERROR *is* a bug. Either use my_printf_error(),
+ my_error(), or WARN_LEVEL_WARN.
+ */
+ DBUG_ASSERT(level != MYSQL_ERROR::WARN_LEVEL_ERROR);
+
+ if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
+ level= MYSQL_ERROR::WARN_LEVEL_WARN;
+
+ (void) thd->raise_condition(code, NULL, level, msg);
+
+ DBUG_VOID_RETURN;
}
+
/*
- Push the warning/error to error list if there is still room in the list
+ Push the warning to error list if there is still room in the list
SYNOPSIS
push_warning_printf()
thd Thread handle
- level Severity of warning (note, warning, error ...)
+ level Severity of warning (note, warning)
code Error number
msg Clear error message
*/
@@ -185,7 +615,8 @@ void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
DBUG_ASSERT(format != NULL);
va_start(args,format);
- my_vsnprintf(warning, sizeof(warning), format, args);
+ my_vsnprintf_ex(&my_charset_utf8_general_ci, warning,
+ sizeof(warning), format, args);
va_end(args);
push_warning(thd, level, code, warning);
DBUG_VOID_RETURN;
@@ -217,44 +648,196 @@ const LEX_STRING warning_level_names[]=
};
bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
-{
+{
List<Item> field_list;
DBUG_ENTER("mysqld_show_warnings");
+ DBUG_ASSERT(thd->warning_info->is_read_only());
+
field_list.push_back(new Item_empty_string("Level", 7));
field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG));
field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
- if (thd->protocol->send_fields(&field_list,
+ if (thd->protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
MYSQL_ERROR *err;
SELECT_LEX *sel= &thd->lex->select_lex;
SELECT_LEX_UNIT *unit= &thd->lex->unit;
- ha_rows idx= 0;
+ ulonglong idx= 0;
Protocol *protocol=thd->protocol;
unit->set_limit(sel);
- List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+ List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
while ((err= it++))
{
/* Skip levels that the user is not interested in */
- if (!(levels_to_show & ((ulong) 1 << err->level)))
+ if (!(levels_to_show & ((ulong) 1 << err->get_level())))
continue;
if (++idx <= unit->offset_limit_cnt)
continue;
if (idx > unit->select_limit_cnt)
break;
protocol->prepare_for_resend();
- protocol->store(warning_level_names[err->level].str,
- warning_level_names[err->level].length, system_charset_info);
- protocol->store((uint32) err->code);
- protocol->store(err->msg, (uint) strlen(err->msg), system_charset_info);
+ protocol->store(warning_level_names[err->get_level()].str,
+ warning_level_names[err->get_level()].length,
+ system_charset_info);
+ protocol->store((uint32) err->get_sql_errno());
+ protocol->store(err->get_message_text(),
+ err->get_message_octet_length(),
+ system_charset_info);
if (protocol->write())
DBUG_RETURN(TRUE);
}
my_eof(thd);
+
+ thd->warning_info->set_read_only(FALSE);
+
DBUG_RETURN(FALSE);
}
+
+
+/**
+ Convert value for dispatch to error message(see WL#751).
+
+ @param to buffer for converted string
+ @param to_length size of the buffer
+ @param from string which should be converted
+ @param from_length string length
+ @param from_cs charset from convert
+
+ @retval
+ result string
+*/
+
+char *err_conv(char *buff, uint to_length, const char *from,
+ uint from_length, CHARSET_INFO *from_cs)
+{
+ char *to= buff;
+ const char *from_start= from;
+ size_t res;
+
+ DBUG_ASSERT(to_length > 0);
+ to_length--;
+ if (from_cs == &my_charset_bin)
+ {
+ uchar char_code;
+ res= 0;
+ while (1)
+ {
+ if ((uint)(from - from_start) >= from_length ||
+ res >= to_length)
+ {
+ *to= 0;
+ break;
+ }
+
+ char_code= ((uchar) *from);
+ if (char_code >= 0x20 && char_code <= 0x7E)
+ {
+ *to++= char_code;
+ from++;
+ res++;
+ }
+ else
+ {
+ if (res + 4 >= to_length)
+ {
+ *to= 0;
+ break;
+ }
+ res+= my_snprintf(to, 5, "\\x%02X", (uint) char_code);
+ to+=4;
+ from++;
+ }
+ }
+ }
+ else
+ {
+ uint errors;
+ res= copy_and_convert(to, to_length, system_charset_info,
+ from, from_length, from_cs, &errors);
+ to[res]= 0;
+ }
+ return buff;
+}
+
+
+/**
+ Convert string for dispatch to client(see WL#751).
+
+ @param to buffer to convert
+ @param to_length buffer length
+ @param to_cs chraset to convert
+ @param from string from convert
+ @param from_length string length
+ @param from_cs charset from convert
+ @param errors count of errors during convertion
+
+ @retval
+ length of converted string
+*/
+
+uint32 convert_error_message(char *to, uint32 to_length, CHARSET_INFO *to_cs,
+ const char *from, uint32 from_length,
+ CHARSET_INFO *from_cs, uint *errors)
+{
+ int cnvres;
+ my_wc_t wc;
+ const uchar *from_end= (const uchar*) from+from_length;
+ char *to_start= to;
+ uchar *to_end= (uchar*) to+to_length;
+ my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
+ my_charset_conv_wc_mb wc_mb;
+ uint error_count= 0;
+ uint length;
+
+ DBUG_ASSERT(to_length > 0);
+ to_length--;
+
+ if (!to_cs || from_cs == to_cs || to_cs == &my_charset_bin)
+ {
+ length= min(to_length, from_length);
+ memmove(to, from, length);
+ to[length]= 0;
+ return length;
+ }
+
+ wc_mb= to_cs->cset->wc_mb;
+ while (1)
+ {
+ if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from, from_end)) > 0)
+ {
+ if (!wc)
+ break;
+ from+= cnvres;
+ }
+ else if (cnvres == MY_CS_ILSEQ)
+ {
+ wc= (ulong) (uchar) *from;
+ from+=1;
+ }
+ else
+ break;
+
+ if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
+ to+= cnvres;
+ else if (cnvres == MY_CS_ILUNI)
+ {
+ length= (wc <= 0xFFFF) ? 6/* '\1234' format*/ : 9 /* '\+123456' format*/;
+ if ((uchar*)(to + length) >= to_end)
+ break;
+ cnvres= my_snprintf(to, 9,
+ (wc <= 0xFFFF) ? "\\%04X" : "\\+%06X", (uint) wc);
+ to+= cnvres;
+ }
+ else
+ break;
+ }
+
+ *to= 0;
+ *errors= error_count;
+ return (uint32) (to - to_start);
+}
diff --git a/sql/sql_error.h b/sql/sql_error.h
index f98264dce50..14dc5e6d12c 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB,
+ Copyright (C) 2008-2009 Sun Microsystems, Inc
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
@@ -13,31 +14,522 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-class MYSQL_ERROR: public Sql_alloc
+#ifndef SQL_ERROR_H
+#define SQL_ERROR_H
+
+#include "sql_list.h" /* Sql_alloc, MEM_ROOT */
+#include "m_string.h" /* LEX_STRING */
+#include "sql_string.h" /* String */
+#include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */
+
+class THD;
+
+/**
+ Stores status of the currently executed statement.
+ Cleared at the beginning of the statement, and then
+ can hold either OK, ERROR, or EOF status.
+ Can not be assigned twice per statement.
+*/
+
+class Diagnostics_area
+{
+public:
+ enum enum_diagnostics_status
+ {
+ /** The area is cleared at start of a statement. */
+ DA_EMPTY= 0,
+ /** Set whenever one calls my_ok(). */
+ DA_OK,
+ /** Set whenever one calls my_eof(). */
+ DA_EOF,
+ /** Set whenever one calls my_error() or my_message(). */
+ DA_ERROR,
+ /** Set in case of a custom response, such as one from COM_STMT_PREPARE. */
+ DA_DISABLED
+ };
+ /** True if status information is sent to the client. */
+ bool is_sent;
+ /** Set to make set_error_status after set_{ok,eof}_status possible. */
+ bool can_overwrite_status;
+
+ void set_ok_status(THD *thd, ulonglong affected_rows_arg,
+ ulonglong last_insert_id_arg,
+ const char *message);
+ void set_eof_status(THD *thd);
+ void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg,
+ const char *sqlstate);
+
+ void disable_status();
+
+ void reset_diagnostics_area();
+
+ bool is_set() const { return m_status != DA_EMPTY; }
+ bool is_error() const { return m_status == DA_ERROR; }
+ bool is_eof() const { return m_status == DA_EOF; }
+ bool is_ok() const { return m_status == DA_OK; }
+ bool is_disabled() const { return m_status == DA_DISABLED; }
+ enum_diagnostics_status status() const { return m_status; }
+
+ const char *message() const
+ { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK); return m_message; }
+
+ uint sql_errno() const
+ { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; }
+
+ const char* get_sqlstate() const
+ { DBUG_ASSERT(m_status == DA_ERROR); return m_sqlstate; }
+
+ ulonglong affected_rows() const
+ { DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; }
+
+ ulonglong last_insert_id() const
+ { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; }
+
+ uint statement_warn_count() const
+ {
+ DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
+ return m_statement_warn_count;
+ }
+
+ Diagnostics_area() { reset_diagnostics_area(); }
+
+private:
+ /** Message buffer. Can be used by OK or ERROR status. */
+ char m_message[MYSQL_ERRMSG_SIZE];
+ /**
+ SQL error number. One of ER_ codes from share/errmsg.txt.
+ Set by set_error_status.
+ */
+ uint m_sql_errno;
+
+ char m_sqlstate[SQLSTATE_LENGTH+1];
+
+ /**
+ The number of rows affected by the last statement. This is
+ semantically close to thd->row_count_func, but has a different
+ life cycle. thd->row_count_func stores the value returned by
+ function ROW_COUNT() and is cleared only by statements that
+ update its value, such as INSERT, UPDATE, DELETE and few others.
+ This member is cleared at the beginning of the next statement.
+
+ We could possibly merge the two, but life cycle of thd->row_count_func
+ can not be changed.
+ */
+ ulonglong m_affected_rows;
+ /**
+ Similarly to the previous member, this is a replacement of
+ thd->first_successful_insert_id_in_prev_stmt, which is used
+ to implement LAST_INSERT_ID().
+ */
+ ulonglong m_last_insert_id;
+ /**
+ Number of warnings of this last statement. May differ from
+ the number of warnings returned by SHOW WARNINGS e.g. in case
+ the statement doesn't clear the warnings, and doesn't generate
+ them.
+ */
+ uint m_statement_warn_count;
+ enum_diagnostics_status m_status;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Representation of a SQL condition.
+ A SQL condition can be a completion condition (note, warning),
+ or an exception condition (error, not found).
+ @note This class is named MYSQL_ERROR instead of SQL_condition for
+ historical reasons, to facilitate merging code with previous releases.
+*/
+class MYSQL_ERROR : public Sql_alloc
{
public:
+ /*
+ Enumeration value describing the severity of the error.
+
+ Note that these enumeration values must correspond to the indices
+ of the sql_print_message_handlers array.
+ */
enum enum_warning_level
{ WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END};
+ /**
+ Get the MESSAGE_TEXT of this condition.
+ @return the message text.
+ */
+ const char* get_message_text() const;
+
+ /**
+ Get the MESSAGE_OCTET_LENGTH of this condition.
+ @return the length in bytes of the message text.
+ */
+ int get_message_octet_length() const;
+
+ /**
+ Get the SQLSTATE of this condition.
+ @return the sql state.
+ */
+ const char* get_sqlstate() const
+ { return m_returned_sqlstate; }
+
+ /**
+ Get the SQL_ERRNO of this condition.
+ @return the sql error number condition item.
+ */
+ uint get_sql_errno() const
+ { return m_sql_errno; }
+
+ /**
+ Get the error level of this condition.
+ @return the error level condition item.
+ */
+ MYSQL_ERROR::enum_warning_level get_level() const
+ { return m_level; }
+
+private:
+ /*
+ The interface of MYSQL_ERROR is mostly private, by design,
+ so that only the following code:
+ - various raise_error() or raise_warning() methods in class THD,
+ - the implementation of SIGNAL / RESIGNAL
+ - catch / re-throw of SQL conditions in stored procedures (sp_rcontext)
+ is allowed to create / modify a SQL condition.
+ Enforcing this policy prevents confusion, since the only public
+ interface available to the rest of the server implementation
+ is the interface offered by the THD methods (THD::raise_error()),
+ which should be used.
+ */
+ friend class THD;
+ friend class Warning_info;
+ friend class Signal_common;
+ friend class Signal_statement;
+ friend class Resignal_statement;
+ friend class sp_rcontext;
+
+ /**
+ Default constructor.
+ This constructor is usefull when allocating arrays.
+ Note that the init() method should be called to complete the MYSQL_ERROR.
+ */
+ MYSQL_ERROR();
+
+ /**
+ Complete the MYSQL_ERROR initialisation.
+ @param mem_root The memory root to use for the condition items
+ of this condition
+ */
+ void init(MEM_ROOT *mem_root);
+
+ /**
+ Constructor.
+ @param mem_root The memory root to use for the condition items
+ of this condition
+ */
+ MYSQL_ERROR(MEM_ROOT *mem_root);
+
+ /** Destructor. */
+ ~MYSQL_ERROR()
+ {}
+
+ /**
+ Copy optional condition items attributes.
+ @param cond the condition to copy.
+ */
+ void copy_opt_attributes(const MYSQL_ERROR *cond);
+
+ /**
+ Set this condition area with a fixed message text.
+ @param thd the current thread.
+ @param code the error number for this condition.
+ @param str the message text for this condition.
+ @param level the error level for this condition.
+ @param MyFlags additional flags.
+ */
+ void set(uint sql_errno, const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg);
+
+ /**
+ Set the condition message test.
+ @param str Message text, expressed in the character set derived from
+ the server --language option
+ */
+ void set_builtin_message_text(const char* str);
+
+ /** Set the SQLSTATE of this condition. */
+ void set_sqlstate(const char* sqlstate);
+
+ /**
+ Clear this SQL condition.
+ */
+ void clear();
+
+private:
+ /** SQL CLASS_ORIGIN condition item. */
+ String m_class_origin;
+
+ /** SQL SUBCLASS_ORIGIN condition item. */
+ String m_subclass_origin;
+
+ /** SQL CONSTRAINT_CATALOG condition item. */
+ String m_constraint_catalog;
+
+ /** SQL CONSTRAINT_SCHEMA condition item. */
+ String m_constraint_schema;
+
+ /** SQL CONSTRAINT_NAME condition item. */
+ String m_constraint_name;
+
+ /** SQL CATALOG_NAME condition item. */
+ String m_catalog_name;
+
+ /** SQL SCHEMA_NAME condition item. */
+ String m_schema_name;
+
+ /** SQL TABLE_NAME condition item. */
+ String m_table_name;
+
+ /** SQL COLUMN_NAME condition item. */
+ String m_column_name;
+
+ /** SQL CURSOR_NAME condition item. */
+ String m_cursor_name;
+
+ /** Message text, expressed in the character set implied by --language. */
+ String m_message_text;
+
+ /** MySQL extension, MYSQL_ERRNO condition item. */
+ uint m_sql_errno;
- uint code;
- enum_warning_level level;
- char *msg;
-
- MYSQL_ERROR(THD *thd, uint code_arg, enum_warning_level level_arg,
- const char *msg_arg)
- :code(code_arg), level(level_arg)
+ /**
+ SQL RETURNED_SQLSTATE condition item.
+ This member is always NUL terminated.
+ */
+ char m_returned_sqlstate[SQLSTATE_LENGTH+1];
+
+ /** Severity (error, warning, note) of this condition. */
+ MYSQL_ERROR::enum_warning_level m_level;
+
+ /** Memory root to use to hold condition item values. */
+ MEM_ROOT *m_mem_root;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Information about warnings of the current connection.
+*/
+
+class Warning_info
+{
+ /** A memory root to allocate warnings and errors */
+ MEM_ROOT m_warn_root;
+ /** List of warnings of all severities (levels). */
+ List <MYSQL_ERROR> m_warn_list;
+ /** A break down of the number of warnings per severity (level). */
+ uint m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
+ /**
+ The number of warnings of the current statement. Warning_info
+ life cycle differs from statement life cycle -- it may span
+ multiple statements. In that case we get
+ m_statement_warn_count 0, whereas m_warn_list is not empty.
+ */
+ uint m_statement_warn_count;
+ /*
+ Row counter, to print in errors and warnings. Not increased in
+ create_sort_index(); may differ from examined_row_count.
+ */
+ ulong m_current_row_for_warning;
+ /** Used to optionally clear warnings only once per statement. */
+ ulonglong m_warn_id;
+
+private:
+ Warning_info(const Warning_info &rhs); /* Not implemented */
+ Warning_info& operator=(const Warning_info &rhs); /* Not implemented */
+public:
+
+ Warning_info(ulonglong warn_id_arg);
+ ~Warning_info();
+
+ /**
+ Reset the warning information. Clear all warnings,
+ the number of warnings, reset current row counter
+ to point to the first row.
+ */
+ void clear_warning_info(ulonglong warn_id_arg);
+ /**
+ Only clear warning info if haven't yet done that already
+ for the current query. Allows to be issued at any time
+ during the query, without risk of clearing some warnings
+ that have been generated by the current statement.
+
+ @todo: This is a sign of sloppy coding. Instead we need to
+ designate one place in a statement life cycle where we call
+ clear_warning_info().
+ */
+ void opt_clear_warning_info(ulonglong query_id)
+ {
+ if (query_id != m_warn_id)
+ clear_warning_info(query_id);
+ }
+
+ void append_warning_info(THD *thd, Warning_info *source)
+ {
+ append_warnings(thd, & source->warn_list());
+ }
+
+ /**
+ Concatenate the list of warnings.
+ It's considered tolerable to lose a warning.
+ */
+ void append_warnings(THD *thd, List<MYSQL_ERROR> *src)
+ {
+ MYSQL_ERROR *err;
+ MYSQL_ERROR *copy;
+ List_iterator_fast<MYSQL_ERROR> it(*src);
+ /*
+ Don't use ::push_warning() to avoid invocation of condition
+ handlers or escalation of warnings to errors.
+ */
+ while ((err= it++))
+ {
+ copy= Warning_info::push_warning(thd, err->get_sql_errno(), err->get_sqlstate(),
+ err->get_level(), err->get_message_text());
+ if (copy)
+ copy->copy_opt_attributes(err);
+ }
+ }
+
+ /**
+ Conditional merge of related warning information areas.
+ */
+ void merge_with_routine_info(THD *thd, Warning_info *source);
+
+ /**
+ Reset between two COM_ commands. Warnings are preserved
+ between commands, but statement_warn_count indicates
+ the number of warnings of this particular statement only.
+ */
+ void reset_for_next_command() { m_statement_warn_count= 0; }
+
+ /**
+ Used for @@warning_count system variable, which prints
+ the number of rows returned by SHOW WARNINGS.
+ */
+ ulong warn_count() const
+ {
+ /*
+ This may be higher than warn_list.elements if we have
+ had more warnings than thd->variables.max_error_count.
+ */
+ return (m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] +
+ m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] +
+ m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]);
+ }
+
+ /**
+ This is for iteration purposes. We return a non-constant reference
+ since List doesn't have constant iterators.
+ */
+ List<MYSQL_ERROR> &warn_list() { return m_warn_list; }
+
+ /**
+ The number of errors, or number of rows returned by SHOW ERRORS,
+ also the value of session variable @@error_count.
+ */
+ ulong error_count() const
{
- if (msg_arg)
- set_msg(thd, msg_arg);
+ return m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR];
}
- void set_msg(THD *thd, const char *msg_arg);
+
+ /** Id of the warning information area. */
+ ulonglong warn_id() const { return m_warn_id; }
+
+ /** Do we have any errors and warnings that we can *show*? */
+ bool is_empty() const { return m_warn_list.elements == 0; }
+
+ /** Increment the current row counter to point at the next row. */
+ void inc_current_row_for_warning() { m_current_row_for_warning++; }
+ /** Reset the current row counter. Start counting from the first row. */
+ void reset_current_row_for_warning() { m_current_row_for_warning= 1; }
+ /** Return the current counter value. */
+ ulong current_row_for_warning() const { return m_current_row_for_warning; }
+
+ ulong statement_warn_count() const { return m_statement_warn_count; }
+
+ /** Add a new condition to the current list. */
+ MYSQL_ERROR *push_warning(THD *thd,
+ uint sql_errno, const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg);
+
+ /**
+ Set the read only status for this statement area.
+ This is a privileged operation, reserved for the implementation of
+ diagnostics related statements, to enforce that the statement area is
+ left untouched during execution.
+ The diagnostics statements are:
+ - SHOW WARNINGS
+ - SHOW ERRORS
+ - GET DIAGNOSTICS
+ @param read_only the read only property to set
+ */
+ void set_read_only(bool read_only)
+ { m_read_only= read_only; }
+
+ /**
+ Read only status.
+ @return the read only property
+ */
+ bool is_read_only() const
+ { return m_read_only; }
+
+private:
+ /** Read only status. */
+ bool m_read_only;
+
+ friend class Resignal_statement;
+};
+
+extern char *err_conv(char *buff, uint to_length, const char *from,
+ uint from_length, CHARSET_INFO *from_cs);
+
+class ErrConvString
+{
+ char err_buffer[MYSQL_ERRMSG_SIZE];
+public:
+
+ ErrConvString(String *str)
+ {
+ (void) err_conv(err_buffer, sizeof(err_buffer), str->ptr(),
+ str->length(), str->charset());
+ }
+
+ ErrConvString(const char *str, CHARSET_INFO* cs)
+ {
+ (void) err_conv(err_buffer, sizeof(err_buffer),
+ str, strlen(str), cs);
+ }
+
+ ErrConvString(const char *str, uint length, CHARSET_INFO* cs)
+ {
+ (void) err_conv(err_buffer, sizeof(err_buffer),
+ str, length, cs);
+ }
+
+ ~ErrConvString() { };
+ char *ptr() { return err_buffer; }
};
-MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
- uint code, const char *msg);
+
+void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+ uint code, const char *msg);
void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
uint code, const char *format, ...);
-void mysql_reset_errors(THD *thd, bool force);
bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
+uint32 convert_error_message(char *to, uint32 to_length, CHARSET_INFO *to_cs,
+ const char *from, uint32 from_length,
+ CHARSET_INFO *from_cs, uint *errors);
extern const LEX_STRING warning_level_names[];
+
+#endif // SQL_ERROR_H
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index bbc3d0b27a4..b5cd3ac9e9a 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -1,4 +1,5 @@
-/* Copyright (C) 2000-2004 MySQL AB
+/* Copyright (C) 2000-2004 MySQL AB, 2008-2009 Sun Microsystems, Inc
+
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.
@@ -33,32 +34,32 @@
*/
/*
- There are two containers holding information about open handler tables.
- The first is 'thd->handler_tables'. It is a linked list of TABLE objects.
- It is used like 'thd->open_tables' in the table cache. The trick is to
- exchange these two lists during open and lock of tables. Thus the normal
- table cache code can be used.
- The second container is a HASH. It holds objects of the type TABLE_LIST.
- Despite its name, no lists of tables but only single structs are hashed
- (the 'next' pointer is always NULL). The reason for theis second container
- is, that we want handler tables to survive FLUSH TABLE commands. A table
- affected by FLUSH TABLE must be closed so that other threads are not
- blocked by handler tables still in use. Since we use the normal table cache
- functions with 'thd->handler_tables', the closed tables are removed from
- this list. Hence we need the original open information for the handler
- table in the case that it is used again. This information is handed over
- to mysql_ha_open() as a TABLE_LIST. So we store this information in the
- second container, where it is not affected by FLUSH TABLE. The second
- container is implemented as a hash for performance reasons. Consequently,
- we use it not only for re-opening a handler table, but also for the
- HANDLER ... READ commands. For this purpose, we store a pointer to the
- TABLE structure (in the first container) in the TBALE_LIST object in the
- second container. When the table is flushed, the pointer is cleared.
+ The information about open HANDLER objects is stored in a HASH.
+ It holds objects of type TABLE_LIST, which are indexed by table
+ name/alias, and allows us to quickly find a HANDLER table for any
+ operation at hand - be it HANDLER READ or HANDLER CLOSE.
+
+ It also allows us to maintain an "open" HANDLER even in cases
+ when there is no physically open cursor. E.g. a FLUSH TABLE
+ statement in this or some other connection demands that all open
+ HANDLERs against the flushed table are closed. In order to
+ preserve the information about an open HANDLER, we don't perform
+ a complete HANDLER CLOSE, but only close the TABLE object. The
+ corresponding TABLE_LIST is kept in the cache with 'table'
+ pointer set to NULL. The table will be reopened on next access
+ (this, however, leads to loss of cursor position, unless the
+ cursor points at the first record).
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_handler.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_base.h" // close_thread_tables
+#include "lock.h" // mysql_unlock_tables
+#include "key.h" // key_copy
+#include "sql_base.h" // insert_fields
#include "sql_select.h"
-#include <assert.h>
+#include "transaction.h"
#define HANDLER_TABLES_HASH_SIZE 120
@@ -108,7 +109,7 @@ static char *mysql_ha_hash_get_key(TABLE_LIST *tables, size_t *key_len_p,
static void mysql_ha_hash_free(TABLE_LIST *tables)
{
- my_free((char*) tables, MYF(0));
+ my_free(tables);
}
/**
@@ -116,41 +117,22 @@ static void mysql_ha_hash_free(TABLE_LIST *tables)
@param thd Thread identifier.
@param tables A list of tables with the first entry to close.
- @param is_locked If LOCK_open is locked.
@note Though this function takes a list of tables, only the first list entry
will be closed.
@note Broadcasts refresh if it closed a table with old version.
*/
-static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
- bool is_locked)
+static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables)
{
- TABLE **table_ptr;
-
- /*
- Though we could take the table pointer from hash_tables->table,
- we must follow the thd->handler_tables chain anyway, as we need the
- address of the 'next' pointer referencing this table
- for close_thread_table().
- */
- for (table_ptr= &(thd->handler_tables);
- *table_ptr && (*table_ptr != tables->table);
- table_ptr= &(*table_ptr)->next)
- ;
- if (*table_ptr)
+ if (tables->table && !tables->table->s->tmp_table)
{
- (*table_ptr)->file->ha_index_or_rnd_end();
- if (! is_locked)
- VOID(pthread_mutex_lock(&LOCK_open));
- if (close_thread_table(thd, table_ptr))
- {
- /* Tell threads waiting for refresh that something has happened */
- broadcast_refresh();
- }
- if (! is_locked)
- VOID(pthread_mutex_unlock(&LOCK_open));
+ /* Non temporary table. */
+ tables->table->file->ha_index_or_rnd_end();
+ tables->table->open_by_handler= 0;
+ (void) close_thread_table(thd, &tables->table);
+ thd->mdl_context.release_lock(tables->mdl_request.ticket);
}
else if (tables->table)
{
@@ -159,10 +141,13 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
table->file->ha_index_or_rnd_end();
table->query_id= thd->query_id;
table->open_by_handler= 0;
+ mark_tmp_table_for_reuse(table);
}
/* Mark table as closed, ready for re-open if necessary. */
tables->table= NULL;
+ /* Safety, cleanup the pointer to satisfy MDL assertions. */
+ tables->mdl_request.ticket= NULL;
}
/*
@@ -192,13 +177,19 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
TABLE_LIST *hash_tables = NULL;
char *db, *name, *alias;
uint dblen, namelen, aliaslen, counter;
- int error;
+ bool error;
TABLE *backup_open_tables;
+ MDL_savepoint mdl_savepoint;
DBUG_ENTER("mysql_ha_open");
DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d",
tables->db, tables->table_name, tables->alias,
(int) reopen));
+ if (thd->locked_tables_mode)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
if (tables->schema_table)
{
my_error(ER_WRONG_USAGE, MYF(0), "HANDLER OPEN",
@@ -207,139 +198,166 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
DBUG_RETURN(TRUE);
}
- if (! hash_inited(&thd->handler_tables_hash))
+ if (! my_hash_inited(&thd->handler_tables_hash))
{
/*
HASH entries are of type TABLE_LIST.
*/
- if (hash_init(&thd->handler_tables_hash, &my_charset_latin1,
- HANDLER_TABLES_HASH_SIZE, 0, 0,
- (hash_get_key) mysql_ha_hash_get_key,
- (hash_free_key) mysql_ha_hash_free, 0))
- goto err;
+ if (my_hash_init(&thd->handler_tables_hash, &my_charset_latin1,
+ HANDLER_TABLES_HASH_SIZE, 0, 0,
+ (my_hash_get_key) mysql_ha_hash_get_key,
+ (my_hash_free_key) mysql_ha_hash_free, 0))
+ {
+ DBUG_PRINT("exit",("ERROR"));
+ DBUG_RETURN(TRUE);
+ }
}
else if (! reopen) /* Otherwise we have 'tables' already. */
{
- if (hash_search(&thd->handler_tables_hash, (uchar*) tables->alias,
- strlen(tables->alias) + 1))
+ if (my_hash_search(&thd->handler_tables_hash, (uchar*) tables->alias,
+ strlen(tables->alias) + 1))
{
DBUG_PRINT("info",("duplicate '%s'", tables->alias));
+ DBUG_PRINT("exit",("ERROR"));
my_error(ER_NONUNIQ_TABLE, MYF(0), tables->alias);
- goto err;
+ DBUG_RETURN(TRUE);
}
}
+ if (! reopen)
+ {
+ /* copy the TABLE_LIST struct */
+ dblen= strlen(tables->db) + 1;
+ namelen= strlen(tables->table_name) + 1;
+ aliaslen= strlen(tables->alias) + 1;
+ if (!(my_multi_malloc(MYF(MY_WME),
+ &hash_tables, (uint) sizeof(*hash_tables),
+ &db, (uint) dblen,
+ &name, (uint) namelen,
+ &alias, (uint) aliaslen,
+ NullS)))
+ {
+ DBUG_PRINT("exit",("ERROR"));
+ DBUG_RETURN(TRUE);
+ }
+ /* structure copy */
+ *hash_tables= *tables;
+ hash_tables->db= db;
+ hash_tables->table_name= name;
+ hash_tables->alias= alias;
+ memcpy(hash_tables->db, tables->db, dblen);
+ memcpy(hash_tables->table_name, tables->table_name, namelen);
+ memcpy(hash_tables->alias, tables->alias, aliaslen);
+ /*
+ We can't request lock with explicit duration for this table
+ right from the start as open_tables() can't handle properly
+ back-off for such locks.
+ */
+ hash_tables->mdl_request.init(MDL_key::TABLE, db, name, MDL_SHARED,
+ MDL_TRANSACTION);
+ /* for now HANDLER can be used only for real TABLES */
+ hash_tables->required_type= FRMTYPE_TABLE;
+
+ /* add to hash */
+ if (my_hash_insert(&thd->handler_tables_hash, (uchar*) hash_tables))
+ {
+ my_free(hash_tables);
+ DBUG_PRINT("exit",("ERROR"));
+ DBUG_RETURN(TRUE);
+ }
+ }
+ else
+ hash_tables= tables;
+
/*
Save and reset the open_tables list so that open_tables() won't
be able to access (or know about) the previous list. And on return
from open_tables(), thd->open_tables will contain only the opened
table.
- The thd->handler_tables list is kept as-is to avoid deadlocks if
- open_table(), called by open_tables(), needs to back-off because
- of a pending name-lock on the table being opened.
-
See open_table() back-off comments for more details.
*/
backup_open_tables= thd->open_tables;
- thd->open_tables= NULL;
+ thd->set_open_tables(NULL);
+ mdl_savepoint= thd->mdl_context.mdl_savepoint();
/*
- open_tables() will set 'tables->table' if successful.
+ open_tables() will set 'hash_tables->table' if successful.
It must be NULL for a real open when calling open_tables().
*/
- DBUG_ASSERT(! tables->table);
+ DBUG_ASSERT(! hash_tables->table);
- /* for now HANDLER can be used only for real TABLES */
- tables->required_type= FRMTYPE_TABLE;
/*
We use open_tables() here, rather than, say,
open_ltable() or open_table() because we would like to be able
to open a temporary table.
*/
- error= open_tables(thd, &tables, &counter, 0);
- if (thd->open_tables)
+ error= open_tables(thd, &hash_tables, &counter, 0);
+
+ if (! error &&
+ ! (hash_tables->table->file->ha_table_flags() & HA_CAN_SQL_HANDLER))
{
- if (thd->open_tables->next)
- {
- /*
- We opened something that is more than a single table.
- This happens with MERGE engine. Don't try to link
- this mess into thd->handler_tables list, close it
- and report an error. We must do it right away
- because mysql_ha_close_table(), called down the road,
- can close a single table only.
- */
- close_thread_tables(thd);
- my_error(ER_ILLEGAL_HA, MYF(0), tables->alias);
- error= 1;
- }
+ my_error(ER_ILLEGAL_HA, MYF(0), tables->alias);
+ error= TRUE;
+ }
+ if (!error &&
+ hash_tables->mdl_request.ticket &&
+ thd->mdl_context.has_lock(mdl_savepoint,
+ hash_tables->mdl_request.ticket))
+ {
+ /* The ticket returned is within a savepoint. Make a copy. */
+ error= thd->mdl_context.clone_ticket(&hash_tables->mdl_request);
+ hash_tables->table->mdl_ticket= hash_tables->mdl_request.ticket;
+ }
+ if (error)
+ {
+ /*
+ No need to rollback statement transaction, it's not started.
+ If called with reopen flag, no need to rollback either,
+ it will be done at statement end.
+ */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ close_thread_tables(thd);
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+ thd->set_open_tables(backup_open_tables);
+ if (!reopen)
+ my_hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
else
{
- /* Merge the opened table into handler_tables list. */
- thd->open_tables->next= thd->handler_tables;
- thd->handler_tables= thd->open_tables;
+ hash_tables->table= NULL;
+ /* Safety, cleanup the pointer to satisfy MDL assertions. */
+ hash_tables->mdl_request.ticket= NULL;
}
+ DBUG_PRINT("exit",("ERROR"));
+ DBUG_RETURN(TRUE);
}
-
- /* Restore the state. */
- thd->open_tables= backup_open_tables;
-
- if (error)
- goto err;
-
- /* There can be only one table in '*tables'. */
- if (! (tables->table->file->ha_table_flags() & HA_CAN_SQL_HANDLER))
+ thd->set_open_tables(backup_open_tables);
+ if (hash_tables->mdl_request.ticket)
{
- my_error(ER_ILLEGAL_HA, MYF(0), tables->alias);
- goto err;
- }
-
- if (! reopen)
- {
- /* copy the TABLE_LIST struct */
- dblen= strlen(tables->db) + 1;
- namelen= strlen(tables->table_name) + 1;
- aliaslen= strlen(tables->alias) + 1;
- if (!(my_multi_malloc(MYF(MY_WME),
- &hash_tables, (uint) sizeof(*hash_tables),
- &db, (uint) dblen,
- &name, (uint) namelen,
- &alias, (uint) aliaslen,
- NullS)))
- goto err;
- /* structure copy */
- *hash_tables= *tables;
- hash_tables->db= db;
- hash_tables->table_name= name;
- hash_tables->alias= alias;
- memcpy(hash_tables->db, tables->db, dblen);
- memcpy(hash_tables->table_name, tables->table_name, namelen);
- memcpy(hash_tables->alias, tables->alias, aliaslen);
-
- /* add to hash */
- if (my_hash_insert(&thd->handler_tables_hash, (uchar*) hash_tables))
- goto err;
+ thd->mdl_context.set_lock_duration(hash_tables->mdl_request.ticket,
+ MDL_EXPLICIT);
+ thd->mdl_context.set_needs_thr_lock_abort(TRUE);
}
/*
+ Assert that the above check prevents opening of views and merge tables.
+ For temporary tables, TABLE::next can be set even if only one table
+ was opened for HANDLER as it is used to link them together
+ (see thd->temporary_tables).
+ */
+ DBUG_ASSERT(hash_tables->table->next == NULL ||
+ hash_tables->table->s->tmp_table);
+ /*
If it's a temp table, don't reset table->query_id as the table is
- being used by this handler. Otherwise, no meaning at all.
+ being used by this handler. For non-temp tables we use this flag
+ in asserts.
*/
- tables->table->open_by_handler= 1;
+ hash_tables->table->open_by_handler= 1;
if (! reopen)
my_ok(thd);
DBUG_PRINT("exit",("OK"));
DBUG_RETURN(FALSE);
-
-err:
- if (hash_tables)
- my_free((char*) hash_tables, MYF(0));
- if (tables->table)
- mysql_ha_close_table(thd, tables, FALSE);
- DBUG_PRINT("exit",("ERROR"));
- DBUG_RETURN(TRUE);
}
@@ -367,12 +385,17 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
tables->db, tables->table_name, tables->alias));
- if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
- (uchar*) tables->alias,
- strlen(tables->alias) + 1)))
+ if (thd->locked_tables_mode)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ if ((hash_tables= (TABLE_LIST*) my_hash_search(&thd->handler_tables_hash,
+ (uchar*) tables->alias,
+ strlen(tables->alias) + 1)))
{
- mysql_ha_close_table(thd, hash_tables, FALSE);
- hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
+ mysql_ha_close_table(thd, hash_tables);
+ my_hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
}
else
{
@@ -381,12 +404,69 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
DBUG_RETURN(TRUE);
}
+ /*
+ Mark MDL_context as no longer breaking protocol if we have
+ closed last HANDLER.
+ */
+ if (! thd->handler_tables_hash.records)
+ thd->mdl_context.set_needs_thr_lock_abort(FALSE);
+
my_ok(thd);
DBUG_PRINT("exit", ("OK"));
DBUG_RETURN(FALSE);
}
+/**
+ A helper class to process an error from mysql_lock_tables().
+ HANDLER READ statement's attempt to lock the subject table
+ may get aborted if there is a pending DDL. In that case
+ we close the table, reopen it, and try to read again.
+ This is implicit and obscure, since HANDLER position
+ is lost in the process, but it's the legacy server
+ behaviour we should preserve.
+*/
+
+class Sql_handler_lock_error_handler: public Internal_error_handler
+{
+public:
+ virtual
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char *sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR **cond_hdl);
+
+ bool need_reopen() const { return m_need_reopen; };
+ void init() { m_need_reopen= FALSE; };
+private:
+ bool m_need_reopen;
+};
+
+
+/**
+ Handle an error from mysql_lock_tables().
+ Ignore ER_LOCK_ABORTED errors.
+*/
+
+bool
+Sql_handler_lock_error_handler::
+handle_condition(THD *thd,
+ uint sql_errno,
+ const char *sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR **cond_hdl)
+{
+ *cond_hdl= NULL;
+ if (sql_errno == ER_LOCK_ABORTED)
+ m_need_reopen= TRUE;
+
+ return m_need_reopen;
+}
+
+
/*
Read from a HANDLER table.
@@ -424,11 +504,17 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
uint num_rows;
uchar *UNINIT_VAR(key);
uint UNINIT_VAR(key_len);
- bool need_reopen;
+ Sql_handler_lock_error_handler sql_handler_lock_error;
DBUG_ENTER("mysql_ha_read");
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
tables->db, tables->table_name, tables->alias));
+ if (thd->locked_tables_mode)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
thd->lex->select_lex.context.resolve_in_table_list_only(tables);
list.push_front(new Item_field(&thd->lex->select_lex.context,
NULL, NULL, "*"));
@@ -436,9 +522,9 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
it++;
retry:
- if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
- (uchar*) tables->alias,
- strlen(tables->alias) + 1)))
+ if ((hash_tables= (TABLE_LIST*) my_hash_search(&thd->handler_tables_hash,
+ (uchar*) tables->alias,
+ strlen(tables->alias) + 1)))
{
table= hash_tables->table;
DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' table: 0x%lx",
@@ -460,60 +546,52 @@ retry:
hash_tables->db, hash_tables->table_name,
hash_tables->alias, table));
}
-
-#if MYSQL_VERSION_ID < 40100
- if (*tables->db && strcmp(table->table_cache_key, tables->db))
- {
- DBUG_PRINT("info",("wrong db"));
- table= NULL;
- }
-#endif
}
else
table= NULL;
if (!table)
{
-#if MYSQL_VERSION_ID < 40100
- char buff[MAX_DBKEY_LENGTH];
- if (*tables->db)
- strxnmov(buff, sizeof(buff)-1, tables->db, ".", tables->table_name,
- NullS);
- else
- strncpy(buff, tables->alias, sizeof(buff));
- my_error(ER_UNKNOWN_TABLE, MYF(0), buff, "HANDLER");
-#else
my_error(ER_UNKNOWN_TABLE, MYF(0), tables->alias, "HANDLER");
-#endif
goto err0;
}
- tables->table=table;
/* save open_tables state */
backup_open_tables= thd->open_tables;
+ /* Always a one-element list, see mysql_ha_open(). */
+ DBUG_ASSERT(hash_tables->table->next == NULL ||
+ hash_tables->table->s->tmp_table);
/*
mysql_lock_tables() needs thd->open_tables to be set correctly to
- be able to handle aborts properly. When the abort happens, it's
- safe to not protect thd->handler_tables because it won't close any
- tables.
+ be able to handle aborts properly.
*/
- thd->open_tables= thd->handler_tables;
+ thd->set_open_tables(hash_tables->table);
+
+
+ sql_handler_lock_error.init();
+ thd->push_internal_handler(&sql_handler_lock_error);
- lock= mysql_lock_tables(thd, &tables->table, 1,
- MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen);
+ lock= mysql_lock_tables(thd, &thd->open_tables, 1, 0);
- /* restore previous context */
- thd->open_tables= backup_open_tables;
+ thd->pop_internal_handler();
+ /*
+ In 5.1 and earlier, mysql_lock_tables() could replace the TABLE
+ object with another one (reopen it). This is no longer the case
+ with new MDL.
+ */
+ DBUG_ASSERT(hash_tables->table == thd->open_tables);
+ /* Restore previous context. */
+ thd->set_open_tables(backup_open_tables);
- if (need_reopen)
+ if (sql_handler_lock_error.need_reopen())
{
- mysql_ha_close_table(thd, hash_tables, FALSE);
+ DBUG_ASSERT(!lock && !thd->is_error());
/*
- The lock might have been aborted, we need to manually reset
- thd->some_tables_deleted because handler's tables are closed
- in a non-standard way. Otherwise we might loop indefinitely.
+ Always close statement transaction explicitly,
+ so that the engine doesn't have to count locks.
*/
- thd->some_tables_deleted= 0;
+ trans_rollback_stmt(thd);
+ mysql_ha_close_table(thd, hash_tables);
goto retry;
}
@@ -521,7 +599,8 @@ retry:
goto err0; // mysql_lock_tables() printed error message already
// Always read all columns
- tables->table->read_set= &tables->table->s->all_set;
+ hash_tables->table->read_set= &hash_tables->table->s->all_set;
+ tables->table= hash_tables->table;
if (cond)
{
@@ -553,7 +632,7 @@ retry:
tables->db, tables->alias, &it, 0))
goto err;
- protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
+ protocol->send_result_set_metadata(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
/*
In ::external_lock InnoDB resets the fields which tell it that
@@ -681,32 +760,35 @@ retry:
goto ok;
}
if (cond && !cond->val_int())
+ {
+ if (thd->is_error())
+ goto err;
continue;
+ }
if (num_rows >= offset_limit_cnt)
{
- Item *item;
protocol->prepare_for_resend();
- it.rewind();
- while ((item=it++))
- {
- if (item->send(thd->protocol, &buffer))
- {
- protocol->free(); // Free used
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
- goto err;
- }
- }
+
+ if (protocol->send_result_set_row(&list))
+ goto err;
+
protocol->write();
}
num_rows++;
}
ok:
+ /*
+ Always close statement transaction explicitly,
+ so that the engine doesn't have to count locks.
+ */
+ trans_commit_stmt(thd);
mysql_unlock_tables(thd,lock);
my_eof(thd);
DBUG_PRINT("exit",("OK"));
DBUG_RETURN(FALSE);
err:
+ trans_rollback_stmt(thd);
mysql_unlock_tables(thd,lock);
err0:
DBUG_PRINT("exit",("ERROR"));
@@ -733,7 +815,7 @@ static TABLE_LIST *mysql_ha_find(THD *thd, TABLE_LIST *tables)
/* search for all handlers with matching table names */
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
{
- hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
+ hash_tables= (TABLE_LIST*) my_hash_element(&thd->handler_tables_hash, i);
for (tables= first; tables; tables= tables->next_local)
{
if ((! *tables->db ||
@@ -758,12 +840,11 @@ static TABLE_LIST *mysql_ha_find(THD *thd, TABLE_LIST *tables)
@param thd Thread identifier.
@param tables The list of tables to remove.
- @param is_locked If LOCK_open is locked.
@note Broadcasts refresh if it closed a table with old version.
*/
-void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked)
+void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables)
{
TABLE_LIST *hash_tables, *next;
DBUG_ENTER("mysql_ha_rm_tables");
@@ -776,11 +857,47 @@ void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked)
{
next= hash_tables->next_local;
if (hash_tables->table)
- mysql_ha_close_table(thd, hash_tables, is_locked);
- hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
+ mysql_ha_close_table(thd, hash_tables);
+ my_hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
hash_tables= next;
}
+ /*
+ Mark MDL_context as no longer breaking protocol if we have
+ closed last HANDLER.
+ */
+ if (! thd->handler_tables_hash.records)
+ thd->mdl_context.set_needs_thr_lock_abort(FALSE);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Close cursors of matching tables from the HANDLER's hash table.
+
+ @param thd Thread identifier.
+ @param tables The list of tables to flush.
+*/
+
+void mysql_ha_flush_tables(THD *thd, TABLE_LIST *all_tables)
+{
+ DBUG_ENTER("mysql_ha_flush_tables");
+
+ for (TABLE_LIST *table_list= all_tables; table_list;
+ table_list= table_list->next_global)
+ {
+ TABLE_LIST *hash_tables= mysql_ha_find(thd, table_list);
+ /* Close all aliases of the same table. */
+ while (hash_tables)
+ {
+ TABLE_LIST *next_local= hash_tables->next_local;
+ if (hash_tables->table)
+ mysql_ha_close_table(thd, hash_tables);
+ hash_tables= next_local;
+ }
+ }
+
DBUG_VOID_RETURN;
}
@@ -799,13 +916,28 @@ void mysql_ha_flush(THD *thd)
TABLE_LIST *hash_tables;
DBUG_ENTER("mysql_ha_flush");
- safe_mutex_assert_owner(&LOCK_open);
+ mysql_mutex_assert_not_owner(&LOCK_open);
+
+ /*
+ Don't try to flush open HANDLERs when we're working with
+ system tables. The main MDL context is backed up and we can't
+ properly release HANDLER locks stored there.
+ */
+ if (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)
+ DBUG_VOID_RETURN;
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
{
- hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
- if (hash_tables->table && hash_tables->table->needs_reopen_or_name_lock())
- mysql_ha_close_table(thd, hash_tables, TRUE);
+ hash_tables= (TABLE_LIST*) my_hash_element(&thd->handler_tables_hash, i);
+ /*
+ TABLE::mdl_ticket is 0 for temporary tables so we need extra check.
+ */
+ if (hash_tables->table &&
+ ((hash_tables->table->mdl_ticket &&
+ hash_tables->table->mdl_ticket->has_pending_conflicting_lock()) ||
+ (!hash_tables->table->s->tmp_table &&
+ hash_tables->table->s->has_old_version())))
+ mysql_ha_close_table(thd, hash_tables);
}
DBUG_VOID_RETURN;
@@ -827,13 +959,36 @@ void mysql_ha_cleanup(THD *thd)
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
{
- hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
+ hash_tables= (TABLE_LIST*) my_hash_element(&thd->handler_tables_hash, i);
if (hash_tables->table)
- mysql_ha_close_table(thd, hash_tables, FALSE);
- }
+ mysql_ha_close_table(thd, hash_tables);
+ }
+
+ my_hash_free(&thd->handler_tables_hash);
+
+ DBUG_VOID_RETURN;
+}
- hash_free(&thd->handler_tables_hash);
+/**
+ Set explicit duration for metadata locks corresponding to open HANDLERs
+ to protect them from being released at the end of transaction.
+
+ @param thd Thread identifier.
+*/
+
+void mysql_ha_set_explicit_lock_duration(THD *thd)
+{
+ TABLE_LIST *hash_tables;
+ DBUG_ENTER("mysql_ha_set_explicit_lock_duration");
+
+ for (uint i= 0; i < thd->handler_tables_hash.records; i++)
+ {
+ hash_tables= (TABLE_LIST*) my_hash_element(&thd->handler_tables_hash, i);
+ if (hash_tables->table && hash_tables->table->mdl_ticket)
+ thd->mdl_context.set_lock_duration(hash_tables->table->mdl_ticket,
+ MDL_EXPLICIT);
+ }
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_handler.h b/sql/sql_handler.h
new file mode 100644
index 00000000000..2eea552d7c9
--- /dev/null
+++ b/sql/sql_handler.h
@@ -0,0 +1,36 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_HANDLER_INCLUDED
+#define SQL_HANDLER_INCLUDED
+
+#include "sql_class.h" /* enum_ha_read_mode */
+#include "my_base.h" /* ha_rkey_function, ha_rows */
+#include "sql_list.h" /* List */
+
+class THD;
+struct TABLE_LIST;
+
+bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen);
+bool mysql_ha_close(THD *thd, TABLE_LIST *tables);
+bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
+ List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
+void mysql_ha_flush(THD *thd);
+void mysql_ha_flush_tables(THD *thd, TABLE_LIST *all_tables);
+void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables);
+void mysql_ha_cleanup(THD *thd);
+void mysql_ha_set_explicit_lock_duration(THD *thd);
+
+#endif /* SQL_HANDLER_INCLUDED */
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index c21968cb86e..7d106fbe936 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -13,7 +13,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_help.h"
+#include "sql_table.h" // primary_key_name
+#include "sql_base.h" // REPORT_ALL_ERRORS, setup_tables
+#include "opt_range.h" // SQL_SELECT
+#include "records.h" // init_read_record, end_read_record
struct st_find_field
{
@@ -431,7 +437,7 @@ int send_answer_1(Protocol *protocol, String *s1, String *s2, String *s3)
field_list.push_back(new Item_empty_string("description",1000));
field_list.push_back(new Item_empty_string("example",1000));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(1);
@@ -463,7 +469,7 @@ int send_answer_1(Protocol *protocol, String *s1, String *s2, String *s3)
+- -+
RETURN VALUES
- result of protocol->send_fields
+ result of protocol->send_result_set_metadata
*/
int send_header_2(Protocol *protocol, bool for_category)
@@ -474,7 +480,7 @@ int send_header_2(Protocol *protocol, bool for_category)
field_list.push_back(new Item_empty_string("source_category_name",64));
field_list.push_back(new Item_empty_string("name",64));
field_list.push_back(new Item_empty_string("is_it_category",1));
- DBUG_RETURN(protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+ DBUG_RETURN(protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF));
}
@@ -637,24 +643,31 @@ bool mysqld_help(THD *thd, const char *mask)
MEM_ROOT *mem_root= thd->mem_root;
DBUG_ENTER("mysqld_help");
- bzero((uchar*)tables,sizeof(tables));
- tables[0].alias= tables[0].table_name= (char*) "help_topic";
- tables[0].lock_type= TL_READ;
+ tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("help_topic"),
+ "help_topic", TL_READ);
+ tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("help_category"),
+ "help_category", TL_READ);
+ tables[2].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("help_relation"),
+ "help_relation", TL_READ);
+ tables[3].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("help_keyword"),
+ "help_keyword", TL_READ);
tables[0].next_global= tables[0].next_local=
tables[0].next_name_resolution_table= &tables[1];
- tables[1].alias= tables[1].table_name= (char*) "help_category";
- tables[1].lock_type= TL_READ;
tables[1].next_global= tables[1].next_local=
tables[1].next_name_resolution_table= &tables[2];
- tables[2].alias= tables[2].table_name= (char*) "help_relation";
- tables[2].lock_type= TL_READ;
tables[2].next_global= tables[2].next_local=
tables[2].next_name_resolution_table= &tables[3];
- tables[3].alias= tables[3].table_name= (char*) "help_keyword";
- tables[3].lock_type= TL_READ;
- tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql";
- Open_tables_state open_tables_state_backup;
+ /*
+ HELP must be available under LOCK TABLES.
+ Reset and backup the current open tables state to
+ make it possible.
+ */
+ Open_tables_backup open_tables_state_backup;
if (open_system_tables_for_read(thd, tables, &open_tables_state_backup))
goto error2;
diff --git a/sql/sql_help.h b/sql/sql_help.h
new file mode 100644
index 00000000000..74cff691730
--- /dev/null
+++ b/sql/sql_help.h
@@ -0,0 +1,28 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_HELP_INCLUDED
+#define SQL_HELP_INCLUDED
+
+class THD;
+
+
+/*
+ Function prototypes
+*/
+
+bool mysqld_help (THD *thd, const char *text);
+
+#endif /* SQL_HELP_INCLUDED */
diff --git a/sql/sql_hset.h b/sql/sql_hset.h
new file mode 100644
index 00000000000..2ea70b91da8
--- /dev/null
+++ b/sql/sql_hset.h
@@ -0,0 +1,97 @@
+#ifndef SQL_HSET_INCLUDED
+#define SQL_HSET_INCLUDED
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "my_global.h"
+#include "hash.h"
+
+
+/**
+ A type-safe wrapper around mysys HASH.
+*/
+
+template <typename T, my_hash_get_key K>
+class Hash_set
+{
+public:
+ typedef T Value_type;
+ enum { START_SIZE= 8 };
+ /**
+ Constructs an empty hash. Does not allocate memory, it is done upon
+ the first insert. Thus does not cause or return errors.
+ */
+ Hash_set()
+ {
+ my_hash_clear(&m_hash);
+ }
+ /**
+ Destroy the hash by freeing the buckets table. Does
+ not call destructors for the elements.
+ */
+ ~Hash_set()
+ {
+ my_hash_free(&m_hash);
+ }
+ /**
+ Insert a single value into a hash. Does not tell whether
+ the value was inserted -- if an identical value existed,
+ it is not replaced.
+
+ @retval TRUE Out of memory.
+ @retval FALSE OK. The value either was inserted or existed
+ in the hash.
+ */
+ bool insert(T *value)
+ {
+ my_hash_init_opt(&m_hash, &my_charset_bin, START_SIZE, 0, 0, K, 0, MYF(0));
+ size_t key_len;
+ const uchar *key= K(reinterpret_cast<uchar*>(value), &key_len, FALSE);
+ if (my_hash_search(&m_hash, key, key_len) == NULL)
+ return my_hash_insert(&m_hash, reinterpret_cast<uchar *>(value));
+ return FALSE;
+ }
+ /** Is this hash set empty? */
+ bool is_empty() const { return m_hash.records == 0; }
+ /** Returns the number of unique elements. */
+ size_t size() const { return static_cast<size_t>(m_hash.records); }
+ /** An iterator over hash elements. Is not insert-stable. */
+ class Iterator
+ {
+ public:
+ Iterator(Hash_set &hash_set)
+ : m_hash(&hash_set.m_hash),
+ m_idx(0)
+ {}
+ /**
+ Return the current element and reposition the iterator to the next
+ element.
+ */
+ inline T *operator++(int)
+ {
+ if (m_idx < m_hash->records)
+ return reinterpret_cast<T*>(my_hash_element(m_hash, m_idx++));
+ return NULL;
+ }
+ void rewind() { m_idx= 0; }
+ private:
+ HASH *m_hash;
+ uint m_idx;
+ };
+private:
+ HASH m_hash;
+};
+
+#endif // SQL_HSET_INCLUDED
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index f0735a9e093..0b463ff1202 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -54,16 +54,31 @@
*/
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_insert.h"
+#include "sql_update.h" // compare_record
+#include "sql_base.h" // close_thread_tables
+#include "sql_cache.h" // query_cache_*
+#include "key.h" // key_copy
+#include "lock.h" // mysql_unlock_tables
#include "sp_head.h"
+#include "sql_view.h" // check_key_in_view, insert_view_fields
+#include "sql_table.h" // mysql_create_table_no_lock
+#include "sql_acl.h" // *_ACL, check_grant_all_columns
#include "sql_trigger.h"
#include "sql_select.h"
#include "sql_show.h"
#include "slave.h"
+#include "sql_parse.h" // end_active_trans
#include "rpl_mi.h"
+#include "transaction.h"
+#include "sql_audit.h"
#ifndef EMBEDDED_LIBRARY
-static bool delayed_get_table(THD *thd, TABLE_LIST *table_list);
+static bool delayed_get_table(THD *thd, MDL_request *grl_protection_request,
+ TABLE_LIST *table_list);
static int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
LEX_STRING query, bool ignore, bool log_on);
static void end_delayed_insert(THD *thd);
@@ -79,7 +94,7 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
#define my_safe_afree(ptr, size, min_length) my_afree(ptr)
#else
#define my_safe_alloca(size, min_length) ((size <= min_length) ? my_alloca(size) : my_malloc(size,MYF(0)))
-#define my_safe_afree(ptr, size, min_length) if (size > min_length) my_free(ptr,MYF(0))
+#define my_safe_afree(ptr, size, min_length) if (size > min_length) my_free(ptr)
#endif
/*
@@ -107,8 +122,8 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
1 Error
*/
-bool check_view_single_update(List<Item> &fields, TABLE_LIST *view,
- table_map *map)
+bool check_view_single_update(List<Item> &fields, List<Item> *values,
+ TABLE_LIST *view, table_map *map)
{
/* it is join view => we need to find the table for update */
List_iterator_fast<Item> it(fields);
@@ -119,6 +134,17 @@ bool check_view_single_update(List<Item> &fields, TABLE_LIST *view,
while ((item= it++))
tables|= item->used_tables();
+ if (values)
+ {
+ it.init(*values);
+ while ((item= it++))
+ tables|= item->used_tables();
+ }
+
+ /* Convert to real table bits */
+ tables&= ~PSEUDO_TABLE_BITS;
+
+
/* Check found map against provided map */
if (*map)
{
@@ -165,7 +191,9 @@ error:
static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, List<Item> &values,
- bool check_unique, table_map *map)
+ bool check_unique,
+ bool fields_and_values_from_different_maps,
+ table_map *map)
{
TABLE *table= table_list->table;
@@ -238,7 +266,10 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE)
{
- if (check_view_single_update(fields, table_list, map))
+ if (check_view_single_update(fields,
+ fields_and_values_from_different_maps ?
+ (List<Item>*) 0 : &values,
+ table_list, map))
return -1;
table= table_list->table;
}
@@ -298,7 +329,8 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
*/
static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
- List<Item> &update_fields, table_map *map)
+ List<Item> &update_fields,
+ List<Item> &update_values, table_map *map)
{
TABLE *table= insert_table_list->table;
my_bool timestamp_mark= 0;
@@ -318,7 +350,8 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
return -1;
if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE &&
- check_view_single_update(update_fields, insert_table_list, map))
+ check_view_single_update(update_fields, &update_values,
+ insert_table_list, map))
return -1;
if (table->timestamp_field)
@@ -387,8 +420,7 @@ void prepare_triggers_for_insert_stmt(TABLE *table)
static
void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
- enum_duplicates duplic,
- bool is_multi_insert)
+ enum_duplicates duplic)
{
if (duplic == DUP_UPDATE ||
(duplic == DUP_REPLACE && *lock_type == TL_WRITE_CONCURRENT_INSERT))
@@ -423,7 +455,7 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
*/
if (specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE) ||
thd->variables.max_insert_delayed_threads == 0 ||
- thd->prelocked_mode ||
+ thd->locked_tables_mode > LTM_LOCK_TABLES ||
thd->lex->uses_stored_routines())
{
*lock_type= TL_WRITE;
@@ -437,10 +469,9 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
return;
}
- bool log_on= (thd->options & OPTION_BIN_LOG ||
- ! (thd->security_ctx->master_access & SUPER_ACL));
+ bool log_on= (thd->variables.option_bits & OPTION_BIN_LOG);
if (global_system_variables.binlog_format == BINLOG_FORMAT_STMT &&
- log_on && mysql_bin_log.is_open() && is_multi_insert)
+ log_on && mysql_bin_log.is_open())
{
/*
Statement-based binary logging does not work in this case, because:
@@ -497,47 +528,78 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
static
bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
{
+ MDL_request protection_request;
DBUG_ENTER("open_and_lock_for_insert_delayed");
#ifndef EMBEDDED_LIBRARY
- if (thd->locked_tables && thd->global_read_lock)
- {
- /*
- If this connection has the global read lock, the handler thread
- will not be able to lock the table. It will wait for the global
- read lock to go away, but this will never happen since the
- connection thread will be stuck waiting for the handler thread
- to open and lock the table.
- If we are not in locked tables mode, INSERT will seek protection
- against the global read lock (and fail), thus we will only get
- to this point in locked tables mode.
- */
- my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0));
+ /*
+ In order for the deadlock detector to be able to find any deadlocks
+ caused by the handler thread waiting for GRL or this table, we acquire
+ protection against GRL (global IX metadata lock) and metadata lock on
+ table to being inserted into inside the connection thread.
+ If this goes ok, the tickets are cloned and added to the list of granted
+ locks held by the handler thread.
+ */
+ if (thd->global_read_lock.can_acquire_protection())
DBUG_RETURN(TRUE);
- }
- if (delayed_get_table(thd, table_list))
+ protection_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_STATEMENT);
+
+ if (thd->mdl_context.acquire_lock(&protection_request,
+ thd->variables.lock_wait_timeout))
DBUG_RETURN(TRUE);
- if (table_list->table)
+ if (thd->mdl_context.acquire_lock(&table_list->mdl_request,
+ thd->variables.lock_wait_timeout))
+ /*
+ If a lock can't be acquired, it makes no sense to try normal insert.
+ Therefore we just abort the statement.
+ */
+ DBUG_RETURN(TRUE);
+
+ bool error= FALSE;
+ if (delayed_get_table(thd, &protection_request, table_list))
+ error= TRUE;
+ else if (table_list->table)
{
/*
Open tables used for sub-selects or in stored functions, will also
cache these functions.
*/
- if (open_and_lock_tables(thd, table_list->next_global))
+ if (open_and_lock_tables(thd, table_list->next_global, TRUE, 0))
{
end_delayed_insert(thd);
- DBUG_RETURN(TRUE);
+ error= TRUE;
+ }
+ else
+ {
+ /*
+ First table was not processed by open_and_lock_tables(),
+ we need to set updatability flag "by hand".
+ */
+ if (!table_list->derived && !table_list->view)
+ table_list->updatable= 1; // usual table
}
- /*
- First table was not processed by open_and_lock_tables(),
- we need to set updatability flag "by hand".
- */
- if (!table_list->derived && !table_list->view)
- table_list->updatable= 1; // usual table
- DBUG_RETURN(FALSE);
}
+
+ /*
+ We can't release protection against GRL and metadata lock on the table
+ being inserted into here. These locks might be required, for example,
+ because this INSERT DELAYED calls functions which may try to update
+ this or another tables (updating the same table is of course illegal,
+ but such an attempt can be discovered only later during statement
+ execution).
+ */
+
+ /*
+ Reset the ticket in case we end up having to use normal insert and
+ therefore will reopen the table and reacquire the metadata lock.
+ */
+ table_list->mdl_request.ticket= NULL;
+
+ if (error || table_list->table)
+ DBUG_RETURN(error);
#endif
/*
* This is embedded library and we don't have auxiliary
@@ -549,7 +611,31 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
Use a normal insert.
*/
table_list->lock_type= TL_WRITE;
- DBUG_RETURN(open_and_lock_tables(thd, table_list));
+ DBUG_RETURN(open_and_lock_tables(thd, table_list, TRUE, 0));
+}
+
+
+/**
+ Create a new query string for removing DELAYED keyword for
+ multi INSERT DEALAYED statement.
+
+ @param[in] thd Thread handler
+ @param[in] buf Query string
+
+ @return
+ 0 ok
+ 1 error
+*/
+static int
+create_insert_stmt_from_insert_delayed(THD *thd, String *buf)
+{
+ /* Make a copy of thd->query() and then remove the "DELAYED" keyword */
+ if (buf->append(thd->query()) ||
+ buf->replace(thd->lex->keyword_delayed_begin_offset,
+ thd->lex->keyword_delayed_end_offset -
+ thd->lex->keyword_delayed_begin_offset, 0))
+ return 1;
+ return 0;
}
@@ -587,10 +673,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
/*
log_on is about delayed inserts only.
By default, both logs are enabled (this won't cause problems if the server
- runs without --log-update or --log-bin).
+ runs without --log-bin).
*/
- bool log_on= ((thd->options & OPTION_BIN_LOG) ||
- (!(thd->security_ctx->master_access & SUPER_ACL)));
+ bool log_on= (thd->variables.option_bits & OPTION_BIN_LOG);
#endif
thr_lock_type lock_type;
Item *unused_conds= 0;
@@ -600,8 +685,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
Upgrade lock type if the requested lock is incompatible with
the current connection mode or table operation.
*/
- upgrade_lock_type(thd, &table_list->lock_type, duplic,
- values_list.elements > 1);
+ upgrade_lock_type(thd, &table_list->lock_type, duplic);
/*
We can't write-delayed into a table locked with LOCK TABLES:
@@ -609,8 +693,10 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
never be able to get a lock on the table. QQQ: why not
upgrade the lock here instead?
*/
- if (table_list->lock_type == TL_WRITE_DELAYED && thd->locked_tables &&
- find_locked_table(thd, table_list->db, table_list->table_name))
+ if (table_list->lock_type == TL_WRITE_DELAYED &&
+ thd->locked_tables_mode &&
+ find_locked_table(thd->open_tables, table_list->db,
+ table_list->table_name))
{
my_error(ER_DELAYED_INSERT_TABLE_LOCKED, MYF(0),
table_list->table_name);
@@ -624,7 +710,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
}
else
{
- if (open_and_lock_tables(thd, table_list))
+ if (open_and_lock_tables(thd, table_list, TRUE, 0))
DBUG_RETURN(TRUE);
}
lock_type= table_list->lock_type;
@@ -738,7 +824,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
{
if (duplic != DUP_ERROR || ignore)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- if (!thd->prelocked_mode)
+ /**
+ This is a simple check for the case when the table has a trigger
+ that reads from it, or when the statement invokes a stored function
+ that reads from the table being inserted to.
+ Engines can't handle a bulk insert in parallel with a read form the
+ same table in the same connection.
+ */
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
table->file->ha_start_bulk_insert(values_list.elements);
}
@@ -835,7 +928,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
error=write_record(thd, table ,&info);
if (error)
break;
- thd->row_count++;
+ thd->warning_info->inc_current_row_for_warning();
}
free_underlaid_joins(thd, &thd->lex->select_lex);
@@ -862,7 +955,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
auto_inc values from the delayed_insert thread as they share TABLE.
*/
table->file->ha_release_auto_increment();
- if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+ table->file->ha_end_bulk_insert() && !error)
{
table->file->print_error(my_errno,MYF(0));
error=1;
@@ -881,6 +975,10 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
*/
query_cache_invalidate3(thd, table_list, 1);
}
+
+ if (thd->transaction.stmt.modified_non_trans_table)
+ thd->transaction.all.modified_non_trans_table= TRUE;
+
if ((changed && error <= 0) ||
thd->transaction.stmt.modified_non_trans_table ||
was_insert_delayed)
@@ -895,7 +993,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->net.last_error/errno. For example if there has
been a disk full error when writing the row, and it was
MyISAM, then thd->net.last_error/errno will be set to
- "disk full"... and the my_pwrite() will wait until free
+ "disk full"... and the mysql_file_pwrite() will wait until free
space appears, and so when it finishes then the
write_row() was entirely successful
*/
@@ -918,16 +1016,29 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
such case the flag is ignored for constructing binlog event.
*/
DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0);
- if (thd->binlog_query(THD::ROW_QUERY_TYPE,
- thd->query(), thd->query_length(),
- transactional_table, FALSE,
- errcode))
+ if (was_insert_delayed && table_list->lock_type == TL_WRITE)
{
- error=1;
- }
+ /* Binlog INSERT DELAYED as INSERT without DELAYED. */
+ String log_query;
+ if (create_insert_stmt_from_insert_delayed(thd, &log_query))
+ {
+ sql_print_error("Event Error: An error occurred while creating query string"
+ "for INSERT DELAYED stmt, before writing it into binary log.");
+
+ error= 1;
+ }
+ else if (thd->binlog_query(THD::ROW_QUERY_TYPE,
+ log_query.c_ptr(), log_query.length(),
+ transactional_table, FALSE, FALSE,
+ errcode))
+ error= 1;
+ }
+ else if (thd->binlog_query(THD::ROW_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ transactional_table, FALSE, FALSE,
+ errcode))
+ error= 1;
}
- if (thd->transaction.stmt.modified_non_trans_table)
- thd->transaction.all.modified_non_trans_table= TRUE;
}
DBUG_ASSERT(transactional_table || !changed ||
thd->transaction.stmt.modified_non_trans_table);
@@ -958,13 +1069,13 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (error)
goto abort;
- if (values_list.elements == 1 && (!(thd->options & OPTION_WARNINGS) ||
+ if (values_list.elements == 1 && (!(thd->variables.option_bits & OPTION_WARNINGS) ||
!thd->cuted_fields))
{
- thd->row_count_func= info.copied + info.deleted +
- ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
- info.touched : info.updated);
- my_ok(thd, (ulong) thd->row_count_func, id);
+ my_ok(thd, info.copied + info.deleted +
+ ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
+ info.touched : info.updated),
+ id);
}
else
{
@@ -974,12 +1085,13 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (ignore)
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
(lock_type == TL_WRITE_DELAYED) ? (ulong) 0 :
- (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
+ (ulong) (info.records - info.copied),
+ (ulong) thd->warning_info->statement_warn_count());
else
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
- (ulong) (info.deleted + updated), (ulong) thd->cuted_fields);
- thd->row_count_func= info.copied + info.deleted + updated;
- ::my_ok(thd, (ulong) thd->row_count_func, id, buff);
+ (ulong) (info.deleted + updated),
+ (ulong) thd->warning_info->statement_warn_count());
+ ::my_ok(thd, info.copied + info.deleted + updated, id, buff);
}
thd->abort_on_warning= 0;
DBUG_RETURN(FALSE);
@@ -1038,7 +1150,7 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view)
DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
- VOID(bitmap_init(&used_fields, used_fields_buff, table->s->fields, 0));
+ (void) bitmap_init(&used_fields, used_fields_buff, table->s->fields, 0);
bitmap_clear_all(&used_fields);
view->contain_auto_increment= 0;
@@ -1265,9 +1377,9 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
- res= check_insert_fields(thd, context->table_list, fields, *values,
- !insert_into_view, &map) ||
- setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0);
+ res= (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0) ||
+ check_insert_fields(thd, context->table_list, fields, *values,
+ !insert_into_view, 0, &map));
if (!res && check_fields)
{
@@ -1280,18 +1392,19 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
thd->abort_on_warning= saved_abort_on_warning;
}
+ if (!res)
+ res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
+
if (!res && duplic == DUP_UPDATE)
{
select_lex->no_wrap_view_item= TRUE;
- res= check_update_fields(thd, context->table_list, update_fields, &map);
+ res= check_update_fields(thd, context->table_list, update_fields,
+ update_values, &map);
select_lex->no_wrap_view_item= FALSE;
}
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
-
- if (!res)
- res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
}
if (res)
@@ -1326,6 +1439,23 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
static int last_uniq_key(TABLE *table,uint keynr)
{
+ /*
+ When an underlying storage engine informs that the unique key
+ conflicts are not reported in the ascending order by setting
+ the HA_DUPLICATE_KEY_NOT_IN_ORDER flag, we cannot rely on this
+ information to determine the last key conflict.
+
+ The information about the last key conflict will be used to
+ do a replace of the new row on the conflicting row, rather
+ than doing a delete (of old row) + insert (of new row).
+
+ Hence check for this flag and disable replacing the last row
+ by returning 0 always. Returning 0 will result in doing
+ a delete + insert always.
+ */
+ if (table->file->ha_table_flags() & HA_DUPLICATE_KEY_NOT_IN_ORDER)
+ return 0;
+
while (++keynr < table->s->keys)
if (table->key_info[keynr].flags & HA_NOSAME)
return 0;
@@ -1714,8 +1844,8 @@ public:
{}
~delayed_row()
{
- x_free(query.str);
- x_free(record);
+ my_free(query.str);
+ my_free(record);
}
};
@@ -1732,47 +1862,66 @@ class Delayed_insert :public ilink {
public:
THD thd;
TABLE *table;
- pthread_mutex_t mutex;
- pthread_cond_t cond,cond_client;
+ mysql_mutex_t mutex;
+ mysql_cond_t cond, cond_client;
volatile uint tables_in_use,stacked_inserts;
- volatile bool status,dead;
+ volatile bool status;
+ /**
+ When the handler thread starts, it clones a metadata lock ticket
+ which protects against GRL and ticket for the table to be inserted.
+ This is done to allow the deadlock detector to detect deadlocks
+ resulting from these locks.
+ Before this is done, the connection thread cannot safely exit
+ without causing problems for clone_ticket().
+ Once handler_thread_initialized has been set, it is safe for the
+ connection thread to exit.
+ Access to handler_thread_initialized is protected by di->mutex.
+ */
+ bool handler_thread_initialized;
COPY_INFO info;
I_List<delayed_row> rows;
ulong group_count;
TABLE_LIST table_list; // Argument
+ /**
+ Request for IX metadata lock protecting against GRL which is
+ passed from connection thread to the handler thread.
+ */
+ MDL_request grl_protection;
Delayed_insert()
- :locks_in_memory(0),
- table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
- group_count(0)
+ :locks_in_memory(0), table(0),tables_in_use(0),stacked_inserts(0),
+ status(0), handler_thread_initialized(FALSE), group_count(0)
{
- thd.security_ctx->user=thd.security_ctx->priv_user=(char*) delayed_user;
+ DBUG_ENTER("Delayed_insert constructor");
+ thd.security_ctx->user=(char*) delayed_user;
thd.security_ctx->host=(char*) my_localhost;
+ strmake(thd.security_ctx->priv_user, thd.security_ctx->user,
+ USERNAME_LENGTH);
thd.current_tablenr=0;
- thd.version=refresh_version;
thd.command=COM_DELAYED_INSERT;
thd.lex->current_select= 0; // for my_message_sql
thd.lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock()
/*
- Statement-based replication of INSERT DELAYED has problems with RAND()
- and user vars, so in mixed mode we go to row-based.
+ Prevent changes to global.lock_wait_timeout from affecting
+ delayed insert threads as any timeouts in delayed inserts
+ are not communicated to the client.
*/
- thd.lex->set_stmt_unsafe();
- thd.set_current_stmt_binlog_row_based_if_mixed();
+ thd.variables.lock_wait_timeout= LONG_TIMEOUT;
bzero((char*) &thd.net, sizeof(thd.net)); // Safety
bzero((char*) &table_list, sizeof(table_list)); // Safety
thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT;
thd.security_ctx->host_or_ip= "";
bzero((char*) &info,sizeof(info));
- pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST);
- pthread_cond_init(&cond,NULL);
- pthread_cond_init(&cond_client,NULL);
- VOID(pthread_mutex_lock(&LOCK_thread_count));
+ mysql_mutex_init(key_delayed_insert_mutex, &mutex, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_delayed_insert_cond, &cond, NULL);
+ mysql_cond_init(key_delayed_insert_cond_client, &cond_client, NULL);
+ mysql_mutex_lock(&LOCK_thread_count);
delayed_insert_threads++;
delayed_lock= global_system_variables.low_priority_updates ?
TL_WRITE_LOW_PRIORITY : TL_WRITE;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_mutex_unlock(&LOCK_thread_count);
+ DBUG_VOID_RETURN;
}
~Delayed_insert()
{
@@ -1781,18 +1930,21 @@ public:
while ((row=rows.get()))
delete row;
if (table)
+ {
close_thread_tables(&thd);
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- pthread_mutex_destroy(&mutex);
- pthread_cond_destroy(&cond);
- pthread_cond_destroy(&cond_client);
+ thd.mdl_context.release_transactional_locks();
+ }
+ mysql_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_destroy(&mutex);
+ mysql_cond_destroy(&cond);
+ mysql_cond_destroy(&cond_client);
thd.unlink(); // Must be unlinked under lock
- x_free(thd.query());
+ my_free(thd.query());
thd.security_ctx->user= thd.security_ctx->host=0;
thread_count--;
delayed_insert_threads--;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- VOID(pthread_cond_broadcast(&COND_thread_count)); /* Tell main we are ready */
+ mysql_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_broadcast(&COND_thread_count); /* Tell main we are ready */
}
/* The following is for checking when we can delete ourselves */
@@ -1802,22 +1954,23 @@ public:
}
void unlock()
{
- pthread_mutex_lock(&LOCK_delayed_insert);
+ mysql_mutex_lock(&LOCK_delayed_insert);
if (!--locks_in_memory)
{
- pthread_mutex_lock(&mutex);
+ mysql_mutex_lock(&mutex);
if (thd.killed && ! stacked_inserts && ! tables_in_use)
{
- pthread_cond_signal(&cond);
+ mysql_cond_signal(&cond);
status=1;
}
- pthread_mutex_unlock(&mutex);
+ mysql_mutex_unlock(&mutex);
}
- pthread_mutex_unlock(&LOCK_delayed_insert);
+ mysql_mutex_unlock(&LOCK_delayed_insert);
}
inline uint lock_count() { return locks_in_memory; }
TABLE* get_local_table(THD* client_thd);
+ bool open_and_lock_table();
bool handle_inserts(void);
};
@@ -1834,7 +1987,7 @@ static
Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
{
thd_proc_info(thd, "waiting for delay_list");
- pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list
+ mysql_mutex_lock(&LOCK_delayed_insert); // Protect master list
I_List_iterator<Delayed_insert> it(delayed_threads);
Delayed_insert *di;
while ((di= it++))
@@ -1846,7 +1999,7 @@ Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
break;
}
}
- pthread_mutex_unlock(&LOCK_delayed_insert); // For unlink from list
+ mysql_mutex_unlock(&LOCK_delayed_insert); // For unlink from list
return di;
}
@@ -1891,13 +2044,13 @@ Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
a given consumer (delayed insert thread), only at different
stages of producer-consumer relationship.
- 'dead' and 'status' variables in Delayed_insert are redundant
- too, since there is already 'di->thd.killed' and
- di->stacked_inserts.
+ The 'status' variable in Delayed_insert is redundant
+ too, since there is already di->stacked_inserts.
*/
static
-bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
+bool delayed_get_table(THD *thd, MDL_request *grl_protection_request,
+ TABLE_LIST *table_list)
{
int error;
Delayed_insert *di;
@@ -1916,7 +2069,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads)
DBUG_RETURN(0);
thd_proc_info(thd, "Creating delayed handler");
- pthread_mutex_lock(&LOCK_delayed_create);
+ mysql_mutex_lock(&LOCK_delayed_create);
/*
The first search above was done without LOCK_delayed_create.
Another thread might have created the handler in between. Search again.
@@ -1924,50 +2077,66 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
if (! (di= find_handler(thd, table_list)))
{
if (!(di= new Delayed_insert()))
- {
- thd->fatal_error();
goto end_create;
- }
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thread_count++;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
di->thd.set_db(table_list->db, (uint) strlen(table_list->db));
- di->thd.set_query(my_strdup(table_list->table_name, MYF(MY_WME)), 0);
+ di->thd.set_query(my_strdup(table_list->table_name,
+ MYF(MY_WME | ME_FATALERROR)),
+ 0, system_charset_info);
if (di->thd.db == NULL || di->thd.query() == NULL)
{
/* The error is reported */
delete di;
- thd->fatal_error();
goto end_create;
}
di->table_list= *table_list; // Needed to open table
/* Replace volatile strings with local copies */
di->table_list.alias= di->table_list.table_name= di->thd.query();
di->table_list.db= di->thd.db;
+ /* We need the tickets so that they can be cloned in handle_delayed_insert */
+ di->grl_protection.init(MDL_key::GLOBAL, "", "",
+ MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT);
+ di->grl_protection.ticket= grl_protection_request->ticket;
+ init_mdl_requests(&di->table_list);
+ di->table_list.mdl_request.ticket= table_list->mdl_request.ticket;
+
di->lock();
- pthread_mutex_lock(&di->mutex);
- if ((error= pthread_create(&di->thd.real_id, &connection_attrib,
- handle_delayed_insert, (void*) di)))
+ mysql_mutex_lock(&di->mutex);
+ if ((error= mysql_thread_create(key_thread_delayed_insert,
+ &di->thd.real_id, &connection_attrib,
+ handle_delayed_insert, (void*) di)))
{
DBUG_PRINT("error",
("Can't create thread to handle delayed insert (error %d)",
error));
- pthread_mutex_unlock(&di->mutex);
+ mysql_mutex_unlock(&di->mutex);
di->unlock();
delete di;
- my_error(ER_CANT_CREATE_THREAD, MYF(0), error);
- thd->fatal_error();
+ my_error(ER_CANT_CREATE_THREAD, MYF(ME_FATALERROR), error);
goto end_create;
}
- /* Wait until table is open */
+ /*
+ Wait until table is open unless the handler thread or the connection
+ thread has been killed. Note that we in all cases must wait until the
+ handler thread has been properly initialized before exiting. Otherwise
+ we risk doing clone_ticket() on a ticket that is no longer valid.
+ */
thd_proc_info(thd, "waiting for handler open");
- while (!di->thd.killed && !di->table && !thd->killed)
+ while (!di->handler_thread_initialized ||
+ (!di->thd.killed && !di->table && !thd->killed))
{
- pthread_cond_wait(&di->cond_client, &di->mutex);
+ mysql_cond_wait(&di->cond_client, &di->mutex);
}
- pthread_mutex_unlock(&di->mutex);
+ mysql_mutex_unlock(&di->mutex);
thd_proc_info(thd, "got old table");
+ if (thd->killed)
+ {
+ di->unlock();
+ goto end_create;
+ }
if (di->thd.killed)
{
if (di->thd.is_error())
@@ -1975,30 +2144,29 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
/*
Copy the error message. Note that we don't treat fatal
errors in the delayed thread as fatal errors in the
- main thread. Use of my_message will enable stored
- procedures continue handlers.
+ main thread. If delayed thread was killed, we don't
+ want to send "Server shutdown in progress" in the
+ INSERT THREAD.
*/
- my_message(di->thd.main_da.sql_errno(), di->thd.main_da.message(),
- MYF(0));
- }
- di->unlock();
+ if (di->thd.stmt_da->sql_errno() == ER_SERVER_SHUTDOWN)
+ my_message(ER_QUERY_INTERRUPTED, ER(ER_QUERY_INTERRUPTED), MYF(0));
+ else
+ my_message(di->thd.stmt_da->sql_errno(), di->thd.stmt_da->message(),
+ MYF(0));
+ }
+ di->unlock();
goto end_create;
}
- if (thd->killed)
- {
- di->unlock();
- goto end_create;
- }
- pthread_mutex_lock(&LOCK_delayed_insert);
+ mysql_mutex_lock(&LOCK_delayed_insert);
delayed_threads.append(di);
- pthread_mutex_unlock(&LOCK_delayed_insert);
+ mysql_mutex_unlock(&LOCK_delayed_insert);
}
- pthread_mutex_unlock(&LOCK_delayed_create);
+ mysql_mutex_unlock(&LOCK_delayed_create);
}
- pthread_mutex_lock(&di->mutex);
+ mysql_mutex_lock(&di->mutex);
table_list->table= di->get_local_table(thd);
- pthread_mutex_unlock(&di->mutex);
+ mysql_mutex_unlock(&di->mutex);
if (table_list->table)
{
DBUG_ASSERT(! thd->is_error());
@@ -2009,7 +2177,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN((table_list->table == NULL));
end_create:
- pthread_mutex_unlock(&LOCK_delayed_create);
+ mysql_mutex_unlock(&LOCK_delayed_create);
DBUG_RETURN(thd->is_error());
}
@@ -2045,17 +2213,33 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
if (!thd.lock) // Table is not locked
{
thd_proc_info(client_thd, "waiting for handler lock");
- pthread_cond_signal(&cond); // Tell handler to lock table
- while (!dead && !thd.lock && ! client_thd->killed)
+ mysql_cond_signal(&cond); // Tell handler to lock table
+ while (!thd.killed && !thd.lock && ! client_thd->killed)
{
- pthread_cond_wait(&cond_client,&mutex);
+ mysql_cond_wait(&cond_client, &mutex);
}
thd_proc_info(client_thd, "got handler lock");
if (client_thd->killed)
goto error;
- if (dead)
+ if (thd.killed)
{
- my_message(thd.main_da.sql_errno(), thd.main_da.message(), MYF(0));
+ /*
+ Copy the error message. Note that we don't treat fatal
+ errors in the delayed thread as fatal errors in the
+ main thread. If delayed thread was killed, we don't
+ want to send "Server shutdown in progress" in the
+ INSERT THREAD.
+
+ The thread could be killed with an error message if
+ di->handle_inserts() or di->open_and_lock_table() fails.
+ The thread could be killed without an error message if
+ killed using mysql_notify_thread_having_shared_lock() or
+ kill_delayed_threads_for_table().
+ */
+ if (!thd.is_error() || thd.stmt_da->sql_errno() == ER_SERVER_SHUTDOWN)
+ my_message(ER_QUERY_INTERRUPTED, ER(ER_QUERY_INTERRUPTED), MYF(0));
+ else
+ my_message(thd.stmt_da->sql_errno(), thd.stmt_da->message(), MYF(0));
goto error;
}
}
@@ -2135,7 +2319,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
error:
tables_in_use--;
status=1;
- pthread_cond_signal(&cond); // Inform thread about abort
+ mysql_cond_signal(&cond); // Inform thread about abort
DBUG_RETURN(0);
}
@@ -2154,9 +2338,9 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
(ulong) query.length));
thd_proc_info(thd, "waiting for handler insert");
- pthread_mutex_lock(&di->mutex);
+ mysql_mutex_lock(&di->mutex);
while (di->stacked_inserts >= delayed_queue_size && !thd->killed)
- pthread_cond_wait(&di->cond_client,&di->mutex);
+ mysql_cond_wait(&di->cond_client, &di->mutex);
thd_proc_info(thd, "storing row into queue");
if (thd->killed)
@@ -2178,7 +2362,7 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
row= new delayed_row(query, duplic, ignore, log_on);
if (row == NULL)
{
- my_free(query.str, MYF(MY_WME));
+ my_free(query.str);
goto err;
}
@@ -2231,15 +2415,15 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
di->status=1;
if (table->s->blob_fields)
unlink_blobs(table);
- pthread_cond_signal(&di->cond);
+ mysql_cond_signal(&di->cond);
thread_safe_increment(delayed_rows_in_use,&LOCK_delayed_status);
- pthread_mutex_unlock(&di->mutex);
+ mysql_mutex_unlock(&di->mutex);
DBUG_RETURN(0);
err:
delete row;
- pthread_mutex_unlock(&di->mutex);
+ mysql_mutex_unlock(&di->mutex);
DBUG_RETURN(1);
}
@@ -2252,14 +2436,14 @@ static void end_delayed_insert(THD *thd)
{
DBUG_ENTER("end_delayed_insert");
Delayed_insert *di=thd->di;
- pthread_mutex_lock(&di->mutex);
+ mysql_mutex_lock(&di->mutex);
DBUG_PRINT("info",("tables in use: %d",di->tables_in_use));
if (!--di->tables_in_use || di->thd.killed)
{ // Unlock table
di->status=1;
- pthread_cond_signal(&di->cond);
+ mysql_cond_signal(&di->cond);
}
- pthread_mutex_unlock(&di->mutex);
+ mysql_mutex_unlock(&di->mutex);
DBUG_VOID_RETURN;
}
@@ -2268,7 +2452,7 @@ static void end_delayed_insert(THD *thd)
void kill_delayed_threads(void)
{
- VOID(pthread_mutex_lock(&LOCK_delayed_insert)); // For unlink from list
+ mysql_mutex_lock(&LOCK_delayed_insert); // For unlink from list
I_List_iterator<Delayed_insert> it(delayed_threads);
Delayed_insert *di;
@@ -2277,7 +2461,7 @@ void kill_delayed_threads(void)
di->thd.killed= THD::KILL_CONNECTION;
if (di->thd.mysys_var)
{
- pthread_mutex_lock(&di->thd.mysys_var->mutex);
+ mysql_mutex_lock(&di->thd.mysys_var->mutex);
if (di->thd.mysys_var->current_cond)
{
/*
@@ -2285,210 +2469,113 @@ void kill_delayed_threads(void)
in handle_delayed_insert()
*/
if (&di->mutex != di->thd.mysys_var->current_mutex)
- pthread_mutex_lock(di->thd.mysys_var->current_mutex);
- pthread_cond_broadcast(di->thd.mysys_var->current_cond);
+ mysql_mutex_lock(di->thd.mysys_var->current_mutex);
+ mysql_cond_broadcast(di->thd.mysys_var->current_cond);
if (&di->mutex != di->thd.mysys_var->current_mutex)
- pthread_mutex_unlock(di->thd.mysys_var->current_mutex);
+ mysql_mutex_unlock(di->thd.mysys_var->current_mutex);
}
- pthread_mutex_unlock(&di->thd.mysys_var->mutex);
+ mysql_mutex_unlock(&di->thd.mysys_var->mutex);
}
}
- VOID(pthread_mutex_unlock(&LOCK_delayed_insert)); // For unlink from list
+ mysql_mutex_unlock(&LOCK_delayed_insert); // For unlink from list
}
-static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di)
+/**
+ A strategy for the prelocking algorithm which prevents the
+ delayed insert thread from opening tables with engines which
+ do not support delayed inserts.
+
+ Particularly it allows to abort open_tables() as soon as we
+ discover that we have opened a MERGE table, without acquiring
+ metadata locks on underlying tables.
+*/
+
+class Delayed_prelocking_strategy : public Prelocking_strategy
{
- DBUG_ENTER("handle_delayed_insert_impl");
- thd->thread_stack= (char*) &thd;
- if (init_thr_lock() || thd->store_globals())
- {
- /* Can't use my_error since store_globals has perhaps failed */
- thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES,
- ER(ER_OUT_OF_RESOURCES));
- thd->fatal_error();
- goto err;
- }
+public:
+ virtual bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
+ Sroutine_hash_entry *rt, sp_head *sp,
+ bool *need_prelocking);
+ virtual bool handle_table(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking);
+ virtual bool handle_view(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking);
+};
- /*
- Open table requires an initialized lex in case the table is
- partitioned. The .frm file contains a partial SQL string which is
- parsed using a lex, that depends on initialized thd->lex.
- */
- lex_start(thd);
- thd->lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock()
- /*
- Statement-based replication of INSERT DELAYED has problems with RAND()
- and user vars, so in mixed mode we go to row-based.
- */
- thd->lex->set_stmt_unsafe();
- thd->set_current_stmt_binlog_row_based_if_mixed();
- /* Open table */
- if (!(di->table= open_n_lock_single_table(thd, &di->table_list,
- TL_WRITE_DELAYED)))
- {
- thd->fatal_error(); // Abort waiting inserts
- goto err;
- }
- if (!(di->table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED))
- {
- thd->fatal_error();
- my_error(ER_DELAYED_NOT_SUPPORTED, MYF(0), di->table_list.table_name);
- goto err;
- }
- if (di->table->triggers)
+bool Delayed_prelocking_strategy::
+handle_table(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking)
+{
+ DBUG_ASSERT(table_list->lock_type == TL_WRITE_DELAYED);
+
+ if (!(table_list->table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED))
{
- /*
- Table has triggers. This is not an error, but we do
- not support triggers with delayed insert. Terminate the delayed
- thread without an error and thus request lock upgrade.
- */
- goto err;
+ my_error(ER_DELAYED_NOT_SUPPORTED, MYF(0), table_list->table_name);
+ return TRUE;
}
- di->table->copy_blobs=1;
+ return FALSE;
+}
- /* Tell client that the thread is initialized */
- pthread_cond_signal(&di->cond_client);
- /* Now wait until we get an insert or lock to handle */
- /* We will not abort as long as a client thread uses this thread */
+bool Delayed_prelocking_strategy::
+handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
+ Sroutine_hash_entry *rt, sp_head *sp,
+ bool *need_prelocking)
+{
+ /* LEX used by the delayed insert thread has no routines. */
+ DBUG_ASSERT(0);
+ return FALSE;
+}
- for (;;)
- {
- if (thd->killed == THD::KILL_CONNECTION)
- {
- uint lock_count;
- /*
- Remove this from delay insert list so that no one can request a
- table from this
- */
- pthread_mutex_unlock(&di->mutex);
- pthread_mutex_lock(&LOCK_delayed_insert);
- di->unlink();
- lock_count=di->lock_count();
- pthread_mutex_unlock(&LOCK_delayed_insert);
- pthread_mutex_lock(&di->mutex);
- if (!lock_count && !di->tables_in_use && !di->stacked_inserts)
- break; // Time to die
- }
- if (!di->status && !di->stacked_inserts)
- {
- struct timespec abstime;
- set_timespec(abstime, delayed_insert_timeout);
+bool Delayed_prelocking_strategy::
+handle_view(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list, bool *need_prelocking)
+{
+ /* We don't open views in the delayed insert thread. */
+ DBUG_ASSERT(0);
+ return FALSE;
+}
- /* Information for pthread_kill */
- di->thd.mysys_var->current_mutex= &di->mutex;
- di->thd.mysys_var->current_cond= &di->cond;
- thd_proc_info(&(di->thd), "Waiting for INSERT");
- DBUG_PRINT("info",("Waiting for someone to insert rows"));
- while (!thd->killed)
- {
- int error;
-#if defined(HAVE_BROKEN_COND_TIMEDWAIT)
- error=pthread_cond_wait(&di->cond,&di->mutex);
-#else
- error=pthread_cond_timedwait(&di->cond,&di->mutex,&abstime);
-#ifdef EXTRA_DEBUG
- if (error && error != EINTR && error != ETIMEDOUT)
- {
- fprintf(stderr, "Got error %d from pthread_cond_timedwait\n",error);
- DBUG_PRINT("error",("Got error %d from pthread_cond_timedwait",
- error));
- }
-#endif
-#endif
- if (thd->killed || di->status)
- break;
- if (error == ETIMEDOUT || error == ETIME)
- {
- thd->killed= THD::KILL_CONNECTION;
- break;
- }
- }
- /* We can't lock di->mutex and mysys_var->mutex at the same time */
- pthread_mutex_unlock(&di->mutex);
- pthread_mutex_lock(&di->thd.mysys_var->mutex);
- di->thd.mysys_var->current_mutex= 0;
- di->thd.mysys_var->current_cond= 0;
- pthread_mutex_unlock(&di->thd.mysys_var->mutex);
- pthread_mutex_lock(&di->mutex);
- }
- thd_proc_info(&(di->thd), 0);
+/**
+ Open and lock table for use by delayed thread and check that
+ this table is suitable for delayed inserts.
- if (di->tables_in_use && ! thd->lock)
- {
- bool not_used;
- /*
- Request for new delayed insert.
- Lock the table, but avoid to be blocked by a global read lock.
- If we got here while a global read lock exists, then one or more
- inserts started before the lock was requested. These are allowed
- to complete their work before the server returns control to the
- client which requested the global read lock. The delayed insert
- handler will close the table and finish when the outstanding
- inserts are done.
- */
- if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1,
- MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK,
- &not_used)))
- {
- /* Fatal error */
- di->dead= 1;
- thd->killed= THD::KILL_CONNECTION;
- }
- pthread_cond_broadcast(&di->cond_client);
- }
- if (di->stacked_inserts)
- {
- if (di->handle_inserts())
- {
- /* Some fatal error */
- di->dead= 1;
- thd->killed= THD::KILL_CONNECTION;
- }
- }
- di->status=0;
- if (!di->stacked_inserts && !di->tables_in_use && thd->lock)
- {
- /*
- No one is doing a insert delayed
- Unlock table so that other threads can use it
- */
- MYSQL_LOCK *lock=thd->lock;
- thd->lock=0;
- pthread_mutex_unlock(&di->mutex);
- /*
- We need to release next_insert_id before unlocking. This is
- enforced by handler::ha_external_lock().
- */
- di->table->file->ha_release_auto_increment();
- mysql_unlock_tables(thd, lock);
- ha_autocommit_or_rollback(thd, 0);
- di->group_count=0;
- pthread_mutex_lock(&di->mutex);
- }
- if (di->tables_in_use)
- pthread_cond_broadcast(&di->cond_client); // If waiting clients
- }
+ @retval FALSE - Success.
+ @retval TRUE - Failure.
+*/
+
+bool Delayed_insert::open_and_lock_table()
+{
+ Delayed_prelocking_strategy prelocking_strategy;
-err:
/*
- mysql_lock_tables() can potentially start a transaction and write
- a table map. In the event of an error, that transaction has to be
- rolled back. We only need to roll back a potential statement
- transaction, since real transactions are rolled back in
- close_thread_tables().
-
- TODO: This is not true any more, table maps are generated on the
- first call to ha_*_row() instead. Remove code that are used to
- cover for the case outlined above.
- */
- ha_autocommit_or_rollback(thd, 1);
+ Use special prelocking strategy to get ER_DELAYED_NOT_SUPPORTED
+ error for tables with engines which don't support delayed inserts.
+ */
+ if (!(table= open_n_lock_single_table(&thd, &table_list,
+ TL_WRITE_DELAYED,
+ MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK,
+ &prelocking_strategy)))
+ {
+ thd.fatal_error(); // Abort waiting inserts
+ return TRUE;
+ }
- DBUG_VOID_RETURN;
+ if (table->triggers)
+ {
+ /*
+ Table has triggers. This is not an error, but we do
+ not support triggers with delayed insert. Terminate the delayed
+ thread without an error and thus request lock upgrade.
+ */
+ return TRUE;
+ }
+ table->copy_blobs= 1;
+ return FALSE;
}
@@ -2503,54 +2590,216 @@ pthread_handler_t handle_delayed_insert(void *arg)
pthread_detach_this_thread();
/* Add thread to THD list so that's it's visible in 'show processlist' */
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
thd->set_current_time();
threads.append(thd);
thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ mysql_thread_set_psi_id(thd->thread_id);
/*
- Wait until the client runs into pthread_cond_wait(),
+ Wait until the client runs into mysql_cond_wait(),
where we free it after the table is opened and di linked in the list.
If we did not wait here, the client might detect the opened table
before it is linked to the list. It would release LOCK_delayed_create
and allow another thread to create another handler for the same table,
since it does not find one in the list.
*/
- pthread_mutex_lock(&di->mutex);
-#if !defined( __WIN__) /* Win32 calls this in pthread_create */
+ mysql_mutex_lock(&di->mutex);
if (my_thread_init())
{
/* Can't use my_error since store_globals has not yet been called */
- thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES,
- ER(ER_OUT_OF_RESOURCES));
- goto end;
+ thd->stmt_da->set_error_status(thd, ER_OUT_OF_RESOURCES,
+ ER(ER_OUT_OF_RESOURCES), NULL);
+ di->handler_thread_initialized= TRUE;
}
-#endif
+ else
+ {
+ DBUG_ENTER("handle_delayed_insert");
+ thd->thread_stack= (char*) &thd;
+ if (init_thr_lock() || thd->store_globals())
+ {
+ /* Can't use my_error since store_globals has perhaps failed */
+ thd->stmt_da->set_error_status(thd, ER_OUT_OF_RESOURCES,
+ ER(ER_OUT_OF_RESOURCES), NULL);
+ di->handler_thread_initialized= TRUE;
+ thd->fatal_error();
+ goto err;
+ }
+
+ thd->lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock()
+
+ /*
+ INSERT DELAYED has to go to row-based format because the time
+ at which rows are inserted cannot be determined in mixed mode.
+ */
+ thd->set_current_stmt_binlog_format_row_if_mixed();
- handle_delayed_insert_impl(thd, di);
+ /*
+ Clone tickets representing protection against GRL and the lock on
+ the target table for the insert and add them to the list of granted
+ metadata locks held by the handler thread. This is safe since the
+ handler thread is not holding nor waiting on any metadata locks.
+ */
+ if (thd->mdl_context.clone_ticket(&di->grl_protection) ||
+ thd->mdl_context.clone_ticket(&di->table_list.mdl_request))
+ {
+ thd->mdl_context.release_transactional_locks();
+ di->handler_thread_initialized= TRUE;
+ goto err;
+ }
-#ifndef __WIN__
-end:
+ /*
+ Now that the ticket has been cloned, it is safe for the connection
+ thread to exit.
+ */
+ di->handler_thread_initialized= TRUE;
+ di->table_list.mdl_request.ticket= NULL;
+
+ if (di->open_and_lock_table())
+ goto err;
+
+ /* Tell client that the thread is initialized */
+ mysql_cond_signal(&di->cond_client);
+
+ /* Now wait until we get an insert or lock to handle */
+ /* We will not abort as long as a client thread uses this thread */
+
+ for (;;)
+ {
+ if (thd->killed)
+ {
+ uint lock_count;
+ /*
+ Remove this from delay insert list so that no one can request a
+ table from this
+ */
+ mysql_mutex_unlock(&di->mutex);
+ mysql_mutex_lock(&LOCK_delayed_insert);
+ di->unlink();
+ lock_count=di->lock_count();
+ mysql_mutex_unlock(&LOCK_delayed_insert);
+ mysql_mutex_lock(&di->mutex);
+ if (!lock_count && !di->tables_in_use && !di->stacked_inserts)
+ break; // Time to die
+ }
+
+ /* Shouldn't wait if killed or an insert is waiting. */
+ if (!thd->killed && !di->status && !di->stacked_inserts)
+ {
+ struct timespec abstime;
+ set_timespec(abstime, delayed_insert_timeout);
+
+ /* Information for pthread_kill */
+ di->thd.mysys_var->current_mutex= &di->mutex;
+ di->thd.mysys_var->current_cond= &di->cond;
+ thd_proc_info(&(di->thd), "Waiting for INSERT");
+
+ DBUG_PRINT("info",("Waiting for someone to insert rows"));
+ while (!thd->killed && !di->status)
+ {
+ int error;
+ mysql_audit_release(thd);
+#if defined(HAVE_BROKEN_COND_TIMEDWAIT)
+ error= mysql_cond_wait(&di->cond, &di->mutex);
+#else
+ error= mysql_cond_timedwait(&di->cond, &di->mutex, &abstime);
+#ifdef EXTRA_DEBUG
+ if (error && error != EINTR && error != ETIMEDOUT)
+ {
+ fprintf(stderr, "Got error %d from mysql_cond_timedwait\n", error);
+ DBUG_PRINT("error", ("Got error %d from mysql_cond_timedwait",
+ error));
+ }
#endif
- /*
- di should be unlinked from the thread handler list and have no active
- clients
- */
+#endif
+ if (error == ETIMEDOUT || error == ETIME)
+ thd->killed= THD::KILL_CONNECTION;
+ }
+ /* We can't lock di->mutex and mysys_var->mutex at the same time */
+ mysql_mutex_unlock(&di->mutex);
+ mysql_mutex_lock(&di->thd.mysys_var->mutex);
+ di->thd.mysys_var->current_mutex= 0;
+ di->thd.mysys_var->current_cond= 0;
+ mysql_mutex_unlock(&di->thd.mysys_var->mutex);
+ mysql_mutex_lock(&di->mutex);
+ }
+ thd_proc_info(&(di->thd), 0);
+
+ if (di->tables_in_use && ! thd->lock && !thd->killed)
+ {
+ /*
+ Request for new delayed insert.
+ Lock the table, but avoid to be blocked by a global read lock.
+ If we got here while a global read lock exists, then one or more
+ inserts started before the lock was requested. These are allowed
+ to complete their work before the server returns control to the
+ client which requested the global read lock. The delayed insert
+ handler will close the table and finish when the outstanding
+ inserts are done.
+ */
+ if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, 0)))
+ {
+ /* Fatal error */
+ thd->killed= THD::KILL_CONNECTION;
+ }
+ mysql_cond_broadcast(&di->cond_client);
+ }
+ if (di->stacked_inserts)
+ {
+ if (di->handle_inserts())
+ {
+ /* Some fatal error */
+ thd->killed= THD::KILL_CONNECTION;
+ }
+ }
+ di->status=0;
+ if (!di->stacked_inserts && !di->tables_in_use && thd->lock)
+ {
+ /*
+ No one is doing a insert delayed
+ Unlock table so that other threads can use it
+ */
+ MYSQL_LOCK *lock=thd->lock;
+ thd->lock=0;
+ mysql_mutex_unlock(&di->mutex);
+ /*
+ We need to release next_insert_id before unlocking. This is
+ enforced by handler::ha_external_lock().
+ */
+ di->table->file->ha_release_auto_increment();
+ mysql_unlock_tables(thd, lock);
+ trans_commit_stmt(thd);
+ di->group_count=0;
+ mysql_audit_release(thd);
+ mysql_mutex_lock(&di->mutex);
+ }
+ if (di->tables_in_use)
+ mysql_cond_broadcast(&di->cond_client); // If waiting clients
+ }
+
+ err:
+ DBUG_LEAVE;
+ }
close_thread_tables(thd); // Free the table
+ thd->mdl_context.release_transactional_locks();
di->table=0;
- di->dead= 1; // If error
thd->killed= THD::KILL_CONNECTION; // If error
- pthread_cond_broadcast(&di->cond_client); // Safety
- pthread_mutex_unlock(&di->mutex);
+ mysql_cond_broadcast(&di->cond_client); // Safety
+ mysql_mutex_unlock(&di->mutex);
- pthread_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table
- pthread_mutex_lock(&LOCK_delayed_insert);
+ mysql_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table
+ mysql_mutex_lock(&LOCK_delayed_insert);
+ /*
+ di should be unlinked from the thread handler list and have no active
+ clients
+ */
delete di;
- pthread_mutex_unlock(&LOCK_delayed_insert);
- pthread_mutex_unlock(&LOCK_delayed_create);
+ mysql_mutex_unlock(&LOCK_delayed_insert);
+ mysql_mutex_unlock(&LOCK_delayed_create);
my_thread_end();
pthread_exit(0);
@@ -2580,7 +2829,7 @@ static void free_delayed_insert_blobs(register TABLE *table)
{
uchar *str;
((Field_blob *) (*ptr))->get_ptr(&str);
- my_free(str,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(str);
((Field_blob *) (*ptr))->reset();
}
}
@@ -2591,19 +2840,21 @@ bool Delayed_insert::handle_inserts(void)
{
int error;
ulong max_rows;
+ bool has_trans = TRUE;
bool using_ignore= 0, using_opt_replace= 0,
using_bin_log= mysql_bin_log.is_open();
delayed_row *row;
DBUG_ENTER("handle_inserts");
/* Allow client to insert new rows */
- pthread_mutex_unlock(&mutex);
+ mysql_mutex_unlock(&mutex);
table->next_number_field=table->found_next_number_field;
table->use_all_columns();
thd_proc_info(&thd, "upgrading lock");
- if (thr_upgrade_write_delay_lock(*thd.lock->locks, delayed_lock))
+ if (thr_upgrade_write_delay_lock(*thd.lock->locks, delayed_lock,
+ thd.variables.lock_wait_timeout))
{
/*
This can happen if thread is killed either by a shutdown
@@ -2617,7 +2868,7 @@ bool Delayed_insert::handle_inserts(void)
thd_proc_info(&thd, "insert");
max_rows= delayed_insert_limit;
- if (thd.killed || table->needs_reopen_or_name_lock())
+ if (thd.killed || table->s->has_old_version())
{
thd.killed= THD::KILL_CONNECTION;
max_rows= ULONG_MAX; // Do as much as possible
@@ -2630,12 +2881,12 @@ bool Delayed_insert::handle_inserts(void)
*/
if (!using_bin_log)
table->file->extra(HA_EXTRA_WRITE_CACHE);
- pthread_mutex_lock(&mutex);
+ mysql_mutex_lock(&mutex);
while ((row=rows.get()))
{
stacked_inserts--;
- pthread_mutex_unlock(&mutex);
+ mysql_mutex_unlock(&mutex);
memcpy(table->record[0],row->record,table->s->reclength);
thd.start_time=row->start_time;
@@ -2651,6 +2902,13 @@ bool Delayed_insert::handle_inserts(void)
if (log_query)
{
/*
+ Guaranteed that the INSERT DELAYED STMT will not be here
+ in SBR when mysql binlog is enabled.
+ */
+ DBUG_ASSERT(!(mysql_bin_log.is_open() &&
+ !thd.is_current_stmt_binlog_format_row()));
+
+ /*
This is the first value of an INSERT statement.
It is the right place to clear a forced insert_id.
This is usually done after the last value of an INSERT statement,
@@ -2717,44 +2975,17 @@ bool Delayed_insert::handle_inserts(void)
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
}
- if (log_query && mysql_bin_log.is_open())
- {
- bool backup_time_zone_used = thd.time_zone_used;
- Time_zone *backup_time_zone = thd.variables.time_zone;
- if (row->time_zone != NULL)
- {
- thd.time_zone_used = true;
- thd.variables.time_zone = row->time_zone;
- }
-
- /* if the delayed insert was killed, the killed status is
- ignored while binlogging */
- int errcode= 0;
- if (thd.killed == THD::NOT_KILLED)
- errcode= query_error_code(&thd, TRUE);
-
- /*
- If the query has several rows to insert, only the first row will come
- here. In row-based binlogging, this means that the first row will be
- written to binlog as one Table_map event and one Rows event (due to an
- event flush done in binlog_query()), then all other rows of this query
- will be binlogged together as one single Table_map event and one
- single Rows event.
- */
- if (thd.binlog_query(THD::ROW_QUERY_TYPE,
- row->query.str, row->query.length,
- FALSE, FALSE, errcode))
- goto err;
-
- thd.time_zone_used = backup_time_zone_used;
- thd.variables.time_zone = backup_time_zone;
- }
-
if (table->s->blob_fields)
free_delayed_insert_blobs(table);
thread_safe_decrement(delayed_rows_in_use,&LOCK_delayed_status);
thread_safe_increment(delayed_insert_writes,&LOCK_delayed_status);
- pthread_mutex_lock(&mutex);
+ mysql_mutex_lock(&mutex);
+
+ /*
+ Reset the table->auto_increment_field_not_null as it is valid for
+ only one row.
+ */
+ table->auto_increment_field_not_null= FALSE;
delete row;
/*
@@ -2770,19 +3001,20 @@ bool Delayed_insert::handle_inserts(void)
if (stacked_inserts || tables_in_use) // Let these wait a while
{
if (tables_in_use)
- pthread_cond_broadcast(&cond_client); // If waiting clients
+ mysql_cond_broadcast(&cond_client); // If waiting clients
thd_proc_info(&thd, "reschedule");
- pthread_mutex_unlock(&mutex);
+ mysql_mutex_unlock(&mutex);
if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
{
/* This should never happen */
table->file->print_error(error,MYF(0));
- sql_print_error("%s", thd.main_da.message());
+ sql_print_error("%s", thd.stmt_da->message());
DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed in loop"));
goto err;
}
query_cache_invalidate3(&thd, table, 1);
- if (thr_reschedule_write_lock(*thd.lock->locks))
+ if (thr_reschedule_write_lock(*thd.lock->locks,
+ thd.variables.lock_wait_timeout))
{
/* This is not known to happen. */
my_error(ER_DELAYED_CANT_CHANGE_LOCK,MYF(ME_FATALERROR),
@@ -2791,15 +3023,15 @@ bool Delayed_insert::handle_inserts(void)
}
if (!using_bin_log)
table->file->extra(HA_EXTRA_WRITE_CACHE);
- pthread_mutex_lock(&mutex);
+ mysql_mutex_lock(&mutex);
thd_proc_info(&thd, "insert");
}
if (tables_in_use)
- pthread_cond_broadcast(&cond_client); // If waiting clients
+ mysql_cond_broadcast(&cond_client); // If waiting clients
}
}
thd_proc_info(&thd, 0);
- pthread_mutex_unlock(&mutex);
+ mysql_mutex_unlock(&mutex);
/*
We need to flush the pending event when using row-based
@@ -2812,20 +3044,22 @@ bool Delayed_insert::handle_inserts(void)
or trigger.
TODO: Move the logging to last in the sequence of rows.
- */
- if (thd.current_stmt_binlog_row_based &&
- thd.binlog_flush_pending_rows_event(TRUE))
+ */
+ has_trans= thd.lex->sql_command == SQLCOM_CREATE_TABLE ||
+ table->file->has_transactions();
+ if (thd.is_current_stmt_binlog_format_row() &&
+ thd.binlog_flush_pending_rows_event(TRUE, has_trans))
goto err;
if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
{ // This shouldn't happen
table->file->print_error(error,MYF(0));
- sql_print_error("%s", thd.main_da.message());
+ sql_print_error("%s", thd.stmt_da->message());
DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed after loop"));
goto err;
}
query_cache_invalidate3(&thd, table, 1);
- pthread_mutex_lock(&mutex);
+ mysql_mutex_lock(&mutex);
DBUG_RETURN(0);
err:
@@ -2849,7 +3083,7 @@ bool Delayed_insert::handle_inserts(void)
}
DBUG_PRINT("error", ("dropped %lu rows after an error", max_rows));
thread_safe_increment(delayed_insert_errors, &LOCK_delayed_status);
- pthread_mutex_lock(&mutex);
+ mysql_mutex_lock(&mutex);
DBUG_RETURN(1);
}
#endif /* EMBEDDED_LIBRARY */
@@ -2879,19 +3113,6 @@ bool mysql_insert_select_prepare(THD *thd)
DBUG_ENTER("mysql_insert_select_prepare");
/*
- Statement-based replication of INSERT ... SELECT ... LIMIT is not safe
- as order of rows is not defined, so in mixed mode we go to row-based.
-
- Note that we may consider a statement as safe if ORDER BY primary_key
- is present or we SELECT a constant. However it may confuse users to
- see very similiar statements replicated differently.
- */
- if (lex->current_select->select_limit)
- {
- lex->set_stmt_unsafe();
- thd->set_current_stmt_binlog_row_based_if_mixed();
- }
- /*
SELECT_LEX do not belong to INSERT statement, so we can't add WHERE
clause if table is VIEW
*/
@@ -2962,9 +3183,9 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
/* Errors during check_insert_fields() should not be ignored. */
lex->current_select->no_error= FALSE;
- res= check_insert_fields(thd, table_list, *fields, values,
- !insert_into_view, &map) ||
- setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0);
+ res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) ||
+ check_insert_fields(thd, table_list, *fields, values,
+ !insert_into_view, 1, &map));
if (!res && fields->elements)
{
@@ -2991,7 +3212,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
lex->select_lex.no_wrap_view_item= TRUE;
res= res || check_update_fields(thd, context->table_list,
- *info.update_fields, &map);
+ *info.update_fields, *info.update_values,
+ &map);
lex->select_lex.no_wrap_view_item= FALSE;
/*
When we are not using GROUP BY and there are no ungrouped aggregate functions
@@ -3053,7 +3275,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
}
else if (!(lex->current_select->options & OPTION_BUFFER_RESULT) &&
- !thd->prelocked_mode)
+ thd->locked_tables_mode <= LTM_LOCK_TABLES)
{
/*
We must not yet prepare the result table if it is the same as one of the
@@ -3119,7 +3341,7 @@ int select_insert::prepare2(void)
{
DBUG_ENTER("select_insert::prepare2");
if (thd->lex->current_select->options & OPTION_BUFFER_RESULT &&
- !thd->prelocked_mode)
+ thd->locked_tables_mode <= LTM_LOCK_TABLES)
table->file->ha_start_bulk_insert((ha_rows) 0);
DBUG_RETURN(0);
}
@@ -3174,7 +3396,7 @@ bool select_insert::send_data(List<Item> &values)
DBUG_RETURN(1);
}
}
-
+
// Release latches in case bulk insert takes a long time
ha_release_temporary_latches(thd);
@@ -3239,14 +3461,18 @@ bool select_insert::send_eof()
{
int error;
bool const trans_table= table->file->has_transactions();
- ulonglong id;
+ ulonglong id, row_count;
bool changed;
THD::killed_state killed_status= thd->killed;
DBUG_ENTER("select_insert::send_eof");
DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
trans_table, table->file->table_type()));
- error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert():0;
+ error= (thd->locked_tables_mode <= LTM_LOCK_TABLES ?
+ table->file->ha_end_bulk_insert() : 0);
+ if (!error && thd->is_error())
+ error= thd->stmt_da->sql_errno();
+
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
@@ -3258,15 +3484,17 @@ bool select_insert::send_eof()
and ha_autocommit_or_rollback.
*/
query_cache_invalidate3(thd, table, 1);
- if (thd->transaction.stmt.modified_non_trans_table)
- thd->transaction.all.modified_non_trans_table= TRUE;
}
+
+ if (thd->transaction.stmt.modified_non_trans_table)
+ thd->transaction.all.modified_non_trans_table= TRUE;
+
DBUG_ASSERT(trans_table || !changed ||
thd->transaction.stmt.modified_non_trans_table);
/*
Write to binlog before commiting transaction. No statement will
- be written by the write_to_binlog() below in RBR mode. All the
+ be written by the binlog_query() below in RBR mode. All the
events are in the transaction cache and will be written when
ha_autocommit_or_rollback() is issued below.
*/
@@ -3278,8 +3506,9 @@ bool select_insert::send_eof()
thd->clear_error();
else
errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
-
- if (write_to_binlog(trans_table, errcode))
+ if (thd->binlog_query(THD::ROW_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ trans_table, FALSE, FALSE, errcode))
{
table->file->ha_release_auto_increment();
DBUG_RETURN(1);
@@ -3295,26 +3524,27 @@ bool select_insert::send_eof()
char buff[160];
if (info.ignore)
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
- (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
+ (ulong) (info.records - info.copied),
+ (ulong) thd->warning_info->statement_warn_count());
else
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
- (ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields);
- thd->row_count_func= info.copied + info.deleted +
- ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
- info.touched : info.updated);
-
+ (ulong) (info.deleted+info.updated),
+ (ulong) thd->warning_info->statement_warn_count());
+ row_count= info.copied + info.deleted +
+ ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
+ info.touched : info.updated);
id= (thd->first_successful_insert_id_in_cur_stmt > 0) ?
thd->first_successful_insert_id_in_cur_stmt :
(thd->arg_of_last_insert_id_function ?
thd->first_successful_insert_id_in_prev_stmt :
(info.copied ? autoinc_value_of_last_inserted_row : 0));
- ::my_ok(thd, (ulong) thd->row_count_func, id, buff);
+ ::my_ok(thd, row_count, id, buff);
DBUG_RETURN(0);
}
-void select_insert::abort() {
+void select_insert::abort_result_set() {
- DBUG_ENTER("select_insert::abort");
+ DBUG_ENTER("select_insert::abort_result_set");
/*
If the creation of the table failed (due to a syntax error, for
example), no table will have been opened and therefore 'table'
@@ -3328,7 +3558,7 @@ void select_insert::abort() {
If we are not in prelocked mode, we end the bulk insert started
before.
*/
- if (!thd->prelocked_mode)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
table->file->ha_end_bulk_insert();
/*
@@ -3349,14 +3579,17 @@ void select_insert::abort() {
transactional_table= table->file->has_transactions();
if (thd->transaction.stmt.modified_non_trans_table)
{
+ if (!can_rollback_data())
+ thd->transaction.all.modified_non_trans_table= TRUE;
+
if (mysql_bin_log.is_open())
{
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
/* error of writing binary log is ignored */
- write_to_binlog(transactional_table, errcode);
+ (void) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(),
+ thd->query_length(),
+ transactional_table, FALSE, FALSE, errcode);
}
- if (!thd->current_stmt_binlog_row_based && !can_rollback_data())
- thd->transaction.all.modified_non_trans_table= TRUE;
if (changed)
query_cache_invalidate3(thd, table, 1);
}
@@ -3368,148 +3601,48 @@ void select_insert::abort() {
DBUG_VOID_RETURN;
}
-int select_insert::write_to_binlog(bool is_trans, int errcode)
-{
- /* It is only for statement mode */
- if (thd->current_stmt_binlog_row_based)
- return 0;
-
- return thd->binlog_query(THD::ROW_QUERY_TYPE,
- thd->query(), thd->query_length(),
- is_trans, FALSE, errcode);
-}
-
-/* Override the select_insert::write_to_binlog */
-int select_create::write_to_binlog(bool is_trans, int errcode)
-{
- /* It is only for statement mode */
- if (thd->current_stmt_binlog_row_based)
- return 0;
-
- /*
- WL#5370 Keep the compatibility between 5.1 master and 5.5 slave.
- Binlog a 'INSERT ... SELECT' statement only when it has the option
- 'IF NOT EXISTS' and the table already exists as a base table.
- */
- if ((create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) &&
- create_info->table_existed)
- {
- String query;
- int result;
-
- thd->binlog_start_trans_and_stmt();
- /* Binlog the CREATE TABLE IF NOT EXISTS statement */
- result= binlog_show_create_table(&table, 1, 0);
- if (result)
- return result;
-
- uint db_len= strlen(create_table->db);
- uint table_len= strlen(create_info->alias);
- uint select_len= thd->query_length() - thd->lex->create_select_pos;
- uint field_len= (table->s->fields - (field - table->field)) *
- (MAX_FIELD_NAME + 3);
-
- /*
- pre-allocating memory reduces the times of reallocating memory,
- when calling query.appen().
- 40bytes is enough for other words("INSERT IGNORE INTO", etc.).
- */
- if (query.real_alloc(40 + db_len + table_len + field_len + select_len))
- return 1;
-
- if (thd->lex->create_select_in_comment)
- query.append(STRING_WITH_LEN("/*! "));
- if (thd->lex->ignore)
- query.append(STRING_WITH_LEN("INSERT IGNORE INTO `"));
- else if (thd->lex->duplicates == DUP_REPLACE)
- query.append(STRING_WITH_LEN("REPLACE INTO `"));
- else
- query.append(STRING_WITH_LEN("INSERT INTO `"));
-
- query.append(create_table->db, db_len);
- query.append(STRING_WITH_LEN("`.`"));
- query.append(create_info->alias, table_len);
- query.append(STRING_WITH_LEN("` "));
-
- /*
- The insert items.
- Field is the the rightmost columns that the rows are inster in.
- */
- query.append(STRING_WITH_LEN("("));
- for (Field **f= field ; *f ; f++)
- {
- if (f != field)
- query.append(STRING_WITH_LEN(","));
-
- query.append(STRING_WITH_LEN("`"));
- query.append((*f)->field_name, strlen((*f)->field_name));
- query.append(STRING_WITH_LEN("`"));
- }
- query.append(STRING_WITH_LEN(") "));
-
- /* The SELECT clause*/
- DBUG_ASSERT(thd->lex->create_select_pos);
- if (thd->lex->create_select_start_with_brace)
- query.append(STRING_WITH_LEN("("));
- if (query.append(thd->query() + thd->lex->create_select_pos, select_len))
- return 1;
-
- /*
- Avoid to use thd->binlog_query() twice, otherwise it will print the unsafe
- warning twice.
- */
- Query_log_event ev(thd, query.c_ptr_safe(), query.length(), is_trans,
- FALSE, errcode);
- return mysql_bin_log.write(&ev);
- }
- else
- return select_insert::write_to_binlog(is_trans, errcode);
-}
/***************************************************************************
CREATE TABLE (SELECT) ...
***************************************************************************/
-/*
+/**
Create table from lists of fields and items (or just return TABLE
object for pre-opened existing table).
- SYNOPSIS
- create_table_from_items()
- thd in Thread object
- create_info in Create information (like MAX_ROWS, ENGINE or
- temporary table flag)
- create_table in Pointer to TABLE_LIST object providing database
- and name for table to be created or to be open
- alter_info in/out Initial list of columns and indexes for the table
- to be created
- items in List of items which should be used to produce rest
- of fields for the table (corresponding fields will
- be added to the end of alter_info->create_list)
- lock out Pointer to the MYSQL_LOCK object for table created
- (or open temporary table) will be returned in this
- parameter. Since this table is not included in
- THD::lock caller is responsible for explicitly
- unlocking this table.
- hooks
-
- NOTES
- This function behaves differently for base and temporary tables:
- - For base table we assume that either table exists and was pre-opened
- and locked at open_and_lock_tables() stage (and in this case we just
- emit error or warning and return pre-opened TABLE object) or special
- placeholder was put in table cache that guarantees that this table
- won't be created or opened until the placeholder will be removed
- (so there is an exclusive lock on this table).
- - We don't pre-open existing temporary table, instead we either open
- or create and then open table in this function.
-
+ @param thd [in] Thread object
+ @param create_info [in] Create information (like MAX_ROWS, ENGINE or
+ temporary table flag)
+ @param create_table [in] Pointer to TABLE_LIST object providing database
+ and name for table to be created or to be open
+ @param alter_info [in/out] Initial list of columns and indexes for the
+ table to be created
+ @param items [in] List of items which should be used to produce
+ rest of fields for the table (corresponding
+ fields will be added to the end of
+ alter_info->create_list)
+ @param lock [out] Pointer to the MYSQL_LOCK object for table
+ created will be returned in this parameter.
+ Since this table is not included in THD::lock
+ caller is responsible for explicitly unlocking
+ this table.
+ @param hooks [in] Hooks to be invoked before and after obtaining
+ table lock on the table being created.
+
+ @note
+ This function assumes that either table exists and was pre-opened and
+ locked at open_and_lock_tables() stage (and in this case we just emit
+ error or warning and return pre-opened TABLE object) or an exclusive
+ metadata lock was acquired on table so we can safely create, open and
+ lock table in it (we don't acquire metadata lock if this create is
+ for temporary table).
+
+ @note
Since this function contains some logic specific to CREATE TABLE ...
SELECT it should be changed before it can be used in other contexts.
- RETURN VALUES
- non-zero Pointer to TABLE object for table created or opened
- 0 Error
+ @retval non-zero Pointer to TABLE object for table created or opened
+ @retval 0 Error
*/
static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
@@ -3527,7 +3660,6 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
List_iterator_fast<Item> it(*items);
Item *item;
Field *tmp_field;
- bool not_used;
DBUG_ENTER("create_table_from_items");
tmp_table.alias= 0;
@@ -3584,30 +3716,21 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
open_table().
*/
{
- tmp_disable_binlog(thd);
if (!mysql_create_table_no_lock(thd, create_table->db,
create_table->table_name,
create_info, alter_info, 0,
- select_field_count))
+ select_field_count, NULL))
{
- if (create_info->table_existed &&
- !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
- {
- /*
- This means that someone created table underneath server
- or it was created via different mysqld front-end to the
- cluster. We don't have much options but throw an error.
- */
- my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name);
- DBUG_RETURN(0);
- }
-
DBUG_EXECUTE_IF("sleep_create_select_before_open", my_sleep(6000000););
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
{
- VOID(pthread_mutex_lock(&LOCK_open));
- if (reopen_name_locked_table(thd, create_table, FALSE))
+ Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
+ /*
+ Here we open the destination table, on which we already have
+ an exclusive metadata lock.
+ */
+ if (open_table(thd, create_table, thd->mem_root, &ot_ctx))
{
quick_rm_table(create_info->db_type, create_table->db,
table_case_name(create_info, create_table->table_name),
@@ -3615,24 +3738,23 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
}
else
table= create_table->table;
- VOID(pthread_mutex_unlock(&LOCK_open));
}
else
{
- if (!(table= open_table(thd, create_table, thd->mem_root, (bool*) 0,
- MYSQL_OPEN_TEMPORARY_ONLY)) &&
- !create_info->table_existed)
+ Open_table_context ot_ctx(thd, MYSQL_OPEN_TEMPORARY_ONLY);
+ if (open_table(thd, create_table, thd->mem_root, &ot_ctx))
{
/*
This shouldn't happen as creation of temporary table should make
it preparable for open. But let us do close_temporary_table() here
just in case.
*/
- drop_temporary_table(thd, create_table);
+ drop_temporary_table(thd, create_table, NULL);
}
+ else
+ table= create_table->table;
}
}
- reenable_binlog(thd);
if (!table) // open failed
DBUG_RETURN(0);
}
@@ -3641,8 +3763,12 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
table->reginfo.lock_type=TL_WRITE;
hooks->prelock(&table, 1); // Call prelock hooks
- if (! ((*lock)= mysql_lock_tables(thd, &table, 1,
- MYSQL_LOCK_IGNORE_FLUSH, &not_used)) ||
+ /*
+ mysql_lock_tables() below should never fail with request to reopen table
+ since it won't wait for the table lock (we have exclusive metadata lock on
+ the table) and thus can't get aborted.
+ */
+ if (! ((*lock)= mysql_lock_tables(thd, &table, 1, 0)) ||
hooks->postlock(&table, 1))
{
if (*lock)
@@ -3650,9 +3776,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
mysql_unlock_tables(thd, *lock);
*lock= 0;
}
-
- if (!create_info->table_existed)
- drop_open_table(thd, table, create_table->db, create_table->table_name);
+ drop_open_table(thd, table, create_table->db, create_table->table_name);
DBUG_RETURN(0);
}
DBUG_RETURN(table);
@@ -3686,34 +3810,42 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
class MY_HOOKS : public TABLEOP_HOOKS {
public:
- MY_HOOKS(select_create *x, TABLE_LIST *create_table,
- TABLE_LIST *select_tables)
- : ptr(x), all_tables(*create_table)
+ MY_HOOKS(select_create *x, TABLE_LIST *create_table_arg,
+ TABLE_LIST *select_tables_arg)
+ : ptr(x),
+ create_table(create_table_arg),
+ select_tables(select_tables_arg)
{
- all_tables.next_global= select_tables;
}
private:
virtual int do_postlock(TABLE **tables, uint count)
{
+ int error;
THD *thd= const_cast<THD*>(ptr->get_thd());
- if (int error= decide_logging_format(thd, &all_tables))
+ TABLE_LIST *save_next_global= create_table->next_global;
+
+ create_table->next_global= select_tables;
+
+ error= thd->decide_logging_format(create_table);
+
+ create_table->next_global= save_next_global;
+
+ if (error)
return error;
TABLE const *const table = *tables;
- if (thd->current_stmt_binlog_row_based &&
- !table->s->tmp_table &&
- !ptr->get_create_info()->table_existed)
+ if (thd->is_current_stmt_binlog_format_row() &&
+ !table->s->tmp_table)
{
- int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
- if (int error= ptr->binlog_show_create_table(tables, count, errcode))
+ if (int error= ptr->binlog_show_create_table(tables, count))
return error;
}
return 0;
}
-
select_create *ptr;
- TABLE_LIST all_tables;
+ TABLE_LIST *create_table;
+ TABLE_LIST *select_tables;
};
MY_HOOKS hooks(this, create_table, select_tables);
@@ -3727,44 +3859,21 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
temporary table, we need to start a statement transaction.
*/
if ((thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) == 0 &&
- thd->current_stmt_binlog_row_based &&
+ thd->is_current_stmt_binlog_format_row() &&
mysql_bin_log.is_open())
{
thd->binlog_start_trans_and_stmt();
}
+ DBUG_ASSERT(create_table->table == NULL);
+
DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000););
- if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
- (create_table->table && create_table->table->db_stat))
- {
- /* Table already exists and was open at open_and_lock_tables() stage. */
- if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
- {
- /* Mark that table existed */
- create_info->table_existed= 1;
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
- create_table->table_name);
- if (thd->current_stmt_binlog_row_based)
- {
- int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
- binlog_show_create_table(&(create_table->table), 1, errcode);
- }
- table= create_table->table;
- }
- else
- {
- my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name);
- DBUG_RETURN(-1);
- }
- }
- else
- if (!(table= create_table_from_items(thd, create_info, create_table,
- alter_info, &values,
- &extra_lock, hook_ptr)))
- /* abort() deletes table */
- DBUG_RETURN(-1);
+ if (!(table= create_table_from_items(thd, create_info, create_table,
+ alter_info, &values,
+ &extra_lock, hook_ptr)))
+ /* abort() deletes table */
+ DBUG_RETURN(-1);
if (extra_lock)
{
@@ -3804,7 +3913,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
if (info.handle_duplicates == DUP_UPDATE)
table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
- if (!thd->prelocked_mode)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
table->file->ha_start_bulk_insert((ha_rows) 0);
thd->abort_on_warning= (!info.ignore &&
(thd->variables.sql_mode &
@@ -3818,10 +3927,10 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
}
int
-select_create::binlog_show_create_table(TABLE **tables, uint count, int errcode)
+select_create::binlog_show_create_table(TABLE **tables, uint count)
{
/*
- Note 1: We generate a CREATE TABLE statement for the
+ Note 1: In RBR mode, we generate a CREATE TABLE statement for the
created table by calling store_create_info() (behaves as SHOW
CREATE TABLE). In the event of an error, nothing should be
written to the binary log, even if the table is non-transactional;
@@ -3837,6 +3946,7 @@ select_create::binlog_show_create_table(TABLE **tables, uint count, int errcode)
schema that will do a close_thread_tables(), destroying the
statement transaction cache.
*/
+ DBUG_ASSERT(thd->is_current_stmt_binlog_format_row());
DBUG_ASSERT(tables && *tables && count > 0);
char buf[2048];
@@ -3854,9 +3964,11 @@ select_create::binlog_show_create_table(TABLE **tables, uint count, int errcode)
if (mysql_bin_log.is_open())
{
+ int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
result= thd->binlog_query(THD::STMT_QUERY_TYPE,
query.ptr(), query.length(),
/* is_trans */ TRUE,
+ /* direct */ FALSE,
/* suppress_use */ FALSE,
errcode);
}
@@ -3876,15 +3988,11 @@ void select_create::send_error(uint errcode,const char *err)
DBUG_PRINT("info",
("Current statement %s row-based",
- thd->current_stmt_binlog_row_based ? "is" : "is NOT"));
+ thd->is_current_stmt_binlog_format_row() ? "is" : "is NOT"));
DBUG_PRINT("info",
("Current table (at 0x%lu) %s a temporary (or non-existant) table",
(ulong) table,
table && !table->s->tmp_table ? "is NOT" : "is"));
- DBUG_PRINT("info",
- ("Table %s prior to executing this statement",
- get_create_info()->table_existed ? "existed" : "did not exist"));
-
/*
This will execute any rollbacks that are necessary before writing
the transcation cache.
@@ -3908,7 +4016,7 @@ bool select_create::send_eof()
{
bool tmp=select_insert::send_eof();
if (tmp)
- abort();
+ abort_result_set();
else
{
/*
@@ -3918,8 +4026,8 @@ bool select_create::send_eof()
*/
if (!table->s->tmp_table)
{
- ha_autocommit_or_rollback(thd, 0);
- end_active_trans(thd);
+ trans_commit_stmt(thd);
+ trans_commit_implicit(thd);
}
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
@@ -3935,12 +4043,12 @@ bool select_create::send_eof()
}
-void select_create::abort()
+void select_create::abort_result_set()
{
- DBUG_ENTER("select_create::abort");
+ DBUG_ENTER("select_create::abort_result_set");
/*
- In select_insert::abort() we roll back the statement, including
+ In select_insert::abort_result_set() we roll back the statement, including
truncating the transaction cache of the binary log. To do this, we
pretend that the statement is transactional, even though it might
be the case that it was not.
@@ -3955,11 +4063,11 @@ void select_create::abort()
log state.
*/
tmp_disable_binlog(thd);
- select_insert::abort();
+ select_insert::abort_result_set();
thd->transaction.stmt.modified_non_trans_table= FALSE;
reenable_binlog(thd);
/* possible error of writing binary log is ignored deliberately */
- (void)thd->binlog_flush_pending_rows_event(TRUE);
+ (void) thd->binlog_flush_pending_rows_event(TRUE, TRUE);
if (m_plock)
{
@@ -3970,21 +4078,10 @@ void select_create::abort()
if (table)
{
- if (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
- thd->current_stmt_binlog_row_based &&
- !(thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- mysql_bin_log.is_open())
- {
- /*
- This should be removed after BUG#47899.
- */
- mysql_bin_log.reset_gathered_updates(thd);
- }
-
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
- if (!create_info->table_existed)
- drop_open_table(thd, table, create_table->db, create_table->table_name);
+ table->auto_increment_field_not_null= FALSE;
+ drop_open_table(thd, table, create_table->db, create_table->table_name);
table=0; // Safety
}
DBUG_VOID_RETURN;
diff --git a/sql/sql_insert.h b/sql/sql_insert.h
new file mode 100644
index 00000000000..9511cee8526
--- /dev/null
+++ b/sql/sql_insert.h
@@ -0,0 +1,49 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_INSERT_INCLUDED
+#define SQL_INSERT_INCLUDED
+
+#include "sql_class.h" /* enum_duplicates */
+#include "sql_list.h"
+
+/* Instead of including sql_lex.h we add this typedef here */
+typedef List<Item> List_item;
+typedef struct st_copy_info COPY_INFO;
+
+bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
+ List<Item> &fields, List_item *values,
+ List<Item> &update_fields,
+ List<Item> &update_values, enum_duplicates duplic,
+ COND **where, bool select_insert,
+ bool check_fields, bool abort_on_warning);
+bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
+ List<List_item> &values, List<Item> &update_fields,
+ List<Item> &update_values, enum_duplicates flag,
+ bool ignore);
+void upgrade_lock_type_for_insert(THD *thd, thr_lock_type *lock_type,
+ enum_duplicates duplic,
+ bool is_multi_insert);
+int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
+ TABLE_LIST *table_list);
+void prepare_triggers_for_insert_stmt(TABLE *table);
+int write_record(THD *thd, TABLE *table, COPY_INFO *info);
+void kill_delayed_threads(void);
+
+#ifdef EMBEDDED_LIBRARY
+inline void kill_delayed_threads(void) {}
+#endif
+
+#endif /* SQL_INSERT_INCLUDED */
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 24c51be2512..7a8a86d3ca4 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -17,13 +17,19 @@
/* A lexical scanner on a temporary buffer with a yacc interface */
#define MYSQL_LEX 1
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_class.h" // sql_lex.h: SQLCOM_END
+#include "sql_lex.h"
+#include "sql_parse.h" // add_to_list
#include "item_create.h"
#include <m_ctype.h>
#include <hash.h>
#include "sp.h"
#include "sp_head.h"
+static int lex_one_token(void *arg, void *yythd);
+
/*
We are using pointer to this variable for distinguishing between assignment
to NEW row field (when parsing trigger definition) and structured variable.
@@ -31,7 +37,33 @@
sys_var *trg_new_row_fake_var= (sys_var*) 0x01;
+/**
+ LEX_STRING constant for null-string to be used in parser and other places.
+*/
+const LEX_STRING null_lex_str= {NULL, 0};
+const LEX_STRING empty_lex_str= {(char *) "", 0};
+/**
+ @note The order of the elements of this array must correspond to
+ the order of elements in enum_binlog_stmt_unsafe.
+*/
+const int
+Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] =
+{
+ ER_BINLOG_UNSAFE_LIMIT,
+ ER_BINLOG_UNSAFE_INSERT_DELAYED,
+ ER_BINLOG_UNSAFE_SYSTEM_TABLE,
+ ER_BINLOG_UNSAFE_AUTOINC_COLUMNS,
+ ER_BINLOG_UNSAFE_UDF,
+ ER_BINLOG_UNSAFE_SYSTEM_VARIABLE,
+ ER_BINLOG_UNSAFE_SYSTEM_FUNCTION,
+ ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS,
+ ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE,
+ ER_BINLOG_UNSAFE_MIXED_STATEMENT,
+};
+
+
/* Longest standard keyword name */
+
#define TOCK_NAME_LENGTH 24
/*
@@ -111,7 +143,18 @@ st_parsing_options::reset()
}
-bool Lex_input_stream::init(THD *thd, char *buff, unsigned int length)
+/**
+ Perform initialization of Lex_input_stream instance.
+
+ Basically, a buffer for pre-processed query. This buffer should be large
+ enough to keep multi-statement query. The allocation is done once in
+ Lex_input_stream::init() in order to prevent memory pollution when
+ the server is processing large multi-statement queries.
+*/
+
+bool Lex_input_stream::init(THD *thd,
+ char* buff,
+ unsigned int length)
{
DBUG_EXECUTE_IF("bug42064_simulate_oom",
DBUG_SET("+d,simulate_out_of_memory"););
@@ -124,19 +167,54 @@ bool Lex_input_stream::init(THD *thd, char *buff, unsigned int length)
if (m_cpp_buf == NULL)
return TRUE;
- m_cpp_ptr= m_cpp_buf;
m_thd= thd;
- m_ptr= buff;
- m_end_of_query= buff + length;
- m_buf= buff;
- m_buf_length= length;
- ignore_space= test(thd->variables.sql_mode & MODE_IGNORE_SPACE);
+ reset(buff, length);
return FALSE;
}
/**
+ Prepare Lex_input_stream instance state for use for handling next SQL statement.
+
+ It should be called between two statements in a multi-statement query.
+ The operation resets the input stream to the beginning-of-parse state,
+ but does not reallocate m_cpp_buf.
+*/
+
+void
+Lex_input_stream::reset(char *buffer, unsigned int length)
+{
+ yylineno= 1;
+ yytoklen= 0;
+ yylval= NULL;
+ lookahead_token= -1;
+ lookahead_yylval= NULL;
+ m_ptr= buffer;
+ m_tok_start= NULL;
+ m_tok_end= NULL;
+ m_end_of_query= buffer + length;
+ m_tok_start_prev= NULL;
+ m_buf= buffer;
+ m_buf_length= length;
+ m_echo= TRUE;
+ m_cpp_tok_start= NULL;
+ m_cpp_tok_start_prev= NULL;
+ m_cpp_tok_end= NULL;
+ m_body_utf8= NULL;
+ m_cpp_utf8_processed_ptr= NULL;
+ next_state= MY_LEX_START;
+ found_semicolon= NULL;
+ ignore_space= test(m_thd->variables.sql_mode & MODE_IGNORE_SPACE);
+ stmt_prepare_mode= FALSE;
+ multi_statements= TRUE;
+ in_comment=NO_COMMENT;
+ m_underscore_cs= NULL;
+ m_cpp_ptr= m_cpp_buf;
+}
+
+
+/**
The operation is called from the parser in order to
1) designate the intention to have utf8 body;
1) Indicate to the lexer that we will need a utf8 representation of this
@@ -307,7 +385,6 @@ void lex_start(THD *thd)
lex->subqueries= FALSE;
lex->view_prepare_mode= FALSE;
lex->derived_tables= 0;
- lex->lock_option= TL_READ;
lex->safe_to_cache_query= 1;
lex->leaf_tables_insert= 0;
lex->parsing_options.reset();
@@ -320,12 +397,12 @@ void lex_start(THD *thd)
lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc;
lex->select_lex.group_list.empty();
lex->select_lex.order_list.empty();
- lex->sql_command= SQLCOM_END;
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
lex->spname= NULL;
lex->sphead= NULL;
lex->spcont= NULL;
+ lex->m_stmt= NULL;
lex->proc_list.first= 0;
lex->escape_used= FALSE;
lex->query_tables= 0;
@@ -340,7 +417,6 @@ void lex_start(THD *thd)
lex->nest_level=0 ;
lex->allow_sum_func= 0;
lex->in_sum_func= NULL;
- lex->protect_against_global_read_lock= FALSE;
/*
ok, there must be a better solution for this, long-term
I tried "bzero" in the sql_yacc.yy code, but that for
@@ -367,10 +443,16 @@ void lex_end(LEX *lex)
DBUG_PRINT("enter", ("lex: 0x%lx", (long) lex));
/* release used plugins */
- plugin_unlock_list(0, (plugin_ref*)lex->plugins.buffer,
- lex->plugins.elements);
+ if (lex->plugins.elements) /* No function call and no mutex if no plugins. */
+ {
+ plugin_unlock_list(0, (plugin_ref*)lex->plugins.buffer,
+ lex->plugins.elements);
+ }
reset_dynamic(&lex->plugins);
+ delete lex->sphead;
+ lex->sphead= NULL;
+
DBUG_VOID_RETURN;
}
@@ -378,8 +460,8 @@ Yacc_state::~Yacc_state()
{
if (yacc_yyss)
{
- my_free(yacc_yyss, MYF(0));
- my_free(yacc_yyvs, MYF(0));
+ my_free(yacc_yyss);
+ my_free(yacc_yyvs);
}
}
@@ -772,6 +854,60 @@ bool consume_comment(Lex_input_stream *lip, int remaining_recursions_permitted)
int MYSQLlex(void *arg, void *yythd)
{
+ THD *thd= (THD *)yythd;
+ Lex_input_stream *lip= & thd->m_parser_state->m_lip;
+ YYSTYPE *yylval=(YYSTYPE*) arg;
+ int token;
+
+ if (lip->lookahead_token >= 0)
+ {
+ /*
+ The next token was already parsed in advance,
+ return it.
+ */
+ token= lip->lookahead_token;
+ lip->lookahead_token= -1;
+ *yylval= *(lip->lookahead_yylval);
+ lip->lookahead_yylval= NULL;
+ return token;
+ }
+
+ token= lex_one_token(arg, yythd);
+
+ switch(token) {
+ case WITH:
+ /*
+ Parsing 'WITH' 'ROLLUP' or 'WITH' 'CUBE' requires 2 look ups,
+ which makes the grammar LALR(2).
+ Replace by a single 'WITH_ROLLUP' or 'WITH_CUBE' token,
+ to transform the grammar into a LALR(1) grammar,
+ which sql_yacc.yy can process.
+ */
+ token= lex_one_token(arg, yythd);
+ switch(token) {
+ case CUBE_SYM:
+ return WITH_CUBE_SYM;
+ case ROLLUP_SYM:
+ return WITH_ROLLUP_SYM;
+ default:
+ /*
+ Save the token following 'WITH'
+ */
+ lip->lookahead_yylval= lip->yylval;
+ lip->yylval= NULL;
+ lip->lookahead_token= token;
+ return WITH;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return token;
+}
+
+int lex_one_token(void *arg, void *yythd)
+{
reg1 uchar c= 0;
bool comment_closed;
int tokval, result_state;
@@ -1497,7 +1633,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
keys_onoff(rhs.keys_onoff),
tablespace_op(rhs.tablespace_op),
partition_names(rhs.partition_names, mem_root),
- no_parts(rhs.no_parts),
+ num_parts(rhs.num_parts),
change_level(rhs.change_level),
datetime_field(rhs.datetime_field),
error_if_not_empty(rhs.error_if_not_empty)
@@ -1607,7 +1743,6 @@ void st_select_lex::init_query()
parent_lex->push_context(&context);
cond_count= between_count= with_wild= 0;
max_equal_elems= 0;
- conds_processed_with_permanent_arena= 0;
ref_pointer_array= 0;
select_n_where_fields= 0;
select_n_having_items= 0;
@@ -1620,7 +1755,6 @@ void st_select_lex::init_query()
exclude_from_table_unique_test= no_wrap_view_item= FALSE;
nest_level= 0;
link_next= 0;
- lock_option= TL_READ_DEFAULT;
}
void st_select_lex::init_select()
@@ -1866,6 +2000,7 @@ TABLE_LIST *st_select_lex_node::add_table_to_list (THD *thd, Table_ident *table,
LEX_STRING *alias,
ulong table_join_options,
thr_lock_type flags,
+ enum_mdl_type mdl_type,
List<Index_hint> *hints,
LEX_STRING *option)
{
@@ -2091,7 +2226,7 @@ void st_select_lex::print_limit(THD *thd,
to implement the clean up.
*/
-void st_lex::cleanup_lex_after_parse_error(THD *thd)
+void LEX::cleanup_lex_after_parse_error(THD *thd)
{
/*
Delete sphead for the side effect of restoring of the original
@@ -2131,6 +2266,7 @@ void st_lex::cleanup_lex_after_parse_error(THD *thd)
void Query_tables_list::reset_query_tables_list(bool init)
{
+ sql_command= SQLCOM_END;
if (!init && query_tables)
{
TABLE_LIST *table= query_tables;
@@ -2151,7 +2287,7 @@ void Query_tables_list::reset_query_tables_list(bool init)
We delay real initialization of hash (and therefore related
memory allocation) until first insertion into this hash.
*/
- hash_clear(&sroutines);
+ my_hash_clear(&sroutines);
}
else if (sroutines.records)
{
@@ -2162,6 +2298,7 @@ void Query_tables_list::reset_query_tables_list(bool init)
sroutines_list_own_last= sroutines_list.next;
sroutines_list_own_elements= 0;
binlog_stmt_flags= 0;
+ stmt_accessed_table_flag= 0;
}
@@ -2174,7 +2311,7 @@ void Query_tables_list::reset_query_tables_list(bool init)
void Query_tables_list::destroy_query_tables_list()
{
- hash_free(&sroutines);
+ my_hash_free(&sroutines);
}
@@ -2182,7 +2319,7 @@ void Query_tables_list::destroy_query_tables_list()
Initialize LEX object.
SYNOPSIS
- st_lex::st_lex()
+ LEX::LEX()
NOTE
LEX object initialized with this constructor can be used as part of
@@ -2192,9 +2329,8 @@ void Query_tables_list::destroy_query_tables_list()
for this.
*/
-st_lex::st_lex()
- :result(0),
- sql_command(SQLCOM_END), option_type(OPT_DEFAULT), is_lex_started(0)
+LEX::LEX()
+ :result(0), option_type(OPT_DEFAULT), is_lex_started(0)
{
my_init_dynamic_array2(&plugins, sizeof(plugin_ref),
@@ -2209,7 +2345,7 @@ st_lex::st_lex()
Check whether the merging algorithm can be used on this VIEW
SYNOPSIS
- st_lex::can_be_merged()
+ LEX::can_be_merged()
DESCRIPTION
We can apply merge algorithm if it is single SELECT view with
@@ -2223,7 +2359,7 @@ st_lex::st_lex()
TRUE - merge algorithm can be used
*/
-bool st_lex::can_be_merged()
+bool LEX::can_be_merged()
{
// TODO: do not forget implement case when select_lex.table_list.elements==0
@@ -2260,19 +2396,19 @@ bool st_lex::can_be_merged()
check if command can use VIEW with MERGE algorithm (for top VIEWs)
SYNOPSIS
- st_lex::can_use_merged()
+ LEX::can_use_merged()
DESCRIPTION
Only listed here commands can use merge algorithm in top level
SELECT_LEX (for subqueries will be used merge algorithm if
- st_lex::can_not_use_merged() is not TRUE).
+ LEX::can_not_use_merged() is not TRUE).
RETURN
FALSE - command can't use merged VIEWs
TRUE - VIEWs with MERGE algorithms can be used
*/
-bool st_lex::can_use_merged()
+bool LEX::can_use_merged()
{
switch (sql_command)
{
@@ -2297,18 +2433,18 @@ bool st_lex::can_use_merged()
Check if command can't use merged views in any part of command
SYNOPSIS
- st_lex::can_not_use_merged()
+ LEX::can_not_use_merged()
DESCRIPTION
Temporary table algorithm will be used on all SELECT levels for queries
- listed here (see also st_lex::can_use_merged()).
+ listed here (see also LEX::can_use_merged()).
RETURN
FALSE - command can't use merged VIEWs
TRUE - VIEWs with MERGE algorithms can be used
*/
-bool st_lex::can_not_use_merged()
+bool LEX::can_not_use_merged()
{
switch (sql_command)
{
@@ -2337,7 +2473,7 @@ bool st_lex::can_not_use_merged()
FALSE no, we need data
*/
-bool st_lex::only_view_structure()
+bool LEX::only_view_structure()
{
switch (sql_command) {
case SQLCOM_SHOW_CREATE:
@@ -2366,7 +2502,7 @@ bool st_lex::only_view_structure()
*/
-bool st_lex::need_correct_ident()
+bool LEX::need_correct_ident()
{
switch(sql_command)
{
@@ -2396,7 +2532,7 @@ bool st_lex::need_correct_ident()
VIEW_CHECK_CASCADED CHECK OPTION CASCADED
*/
-uint8 st_lex::get_effective_with_check(TABLE_LIST *view)
+uint8 LEX::get_effective_with_check(TABLE_LIST *view)
{
if (view->select_lex->master_unit() == &unit &&
which_check_option_applicable())
@@ -2425,7 +2561,7 @@ uint8 st_lex::get_effective_with_check(TABLE_LIST *view)
*/
bool
-st_lex::copy_db_to(char **p_db, size_t *p_db_length) const
+LEX::copy_db_to(char **p_db, size_t *p_db_length) const
{
if (sphead)
{
@@ -2502,7 +2638,7 @@ void st_select_lex_unit::set_limit(st_select_lex *sl)
clause.
*/
-void st_lex::set_trg_event_type_for_tables()
+void LEX::set_trg_event_type_for_tables()
{
uint8 new_trg_event_map= 0;
@@ -2645,7 +2781,7 @@ void st_lex::set_trg_event_type_for_tables()
In this case link_to_local is set.
*/
-TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
+TABLE_LIST *LEX::unlink_first_table(bool *link_to_local)
{
TABLE_LIST *first;
if ((first= query_tables))
@@ -2685,7 +2821,7 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
table list
SYNOPSYS
- st_lex::first_lists_tables_same()
+ LEX::first_lists_tables_same()
NOTES
In many cases (for example, usual INSERT/DELETE/...) the first table of
@@ -2696,7 +2832,7 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
the global list first.
*/
-void st_lex::first_lists_tables_same()
+void LEX::first_lists_tables_same()
{
TABLE_LIST *first_table= select_lex.table_list.first;
if (query_tables != first_table && first_table != 0)
@@ -2732,7 +2868,7 @@ void st_lex::first_lists_tables_same()
global list
*/
-void st_lex::link_first_table_back(TABLE_LIST *first,
+void LEX::link_first_table_back(TABLE_LIST *first,
bool link_to_local)
{
if (first)
@@ -2759,7 +2895,7 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
cleanup lex for case when we open table by table for processing
SYNOPSIS
- st_lex::cleanup_after_one_table_open()
+ LEX::cleanup_after_one_table_open()
NOTE
This method is mostly responsible for cleaning up of selects lists and
@@ -2767,7 +2903,7 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
to call Query_tables_list::reset_query_tables_list(FALSE).
*/
-void st_lex::cleanup_after_one_table_open()
+void LEX::cleanup_after_one_table_open()
{
/*
thd->lex->derived_tables & additional units may be set if we open
@@ -2802,7 +2938,7 @@ void st_lex::cleanup_after_one_table_open()
backup Pointer to Query_tables_list instance to be used for backup
*/
-void st_lex::reset_n_backup_query_tables_list(Query_tables_list *backup)
+void LEX::reset_n_backup_query_tables_list(Query_tables_list *backup)
{
backup->set_query_tables_list(this);
/*
@@ -2821,7 +2957,7 @@ void st_lex::reset_n_backup_query_tables_list(Query_tables_list *backup)
backup Pointer to Query_tables_list instance used for backup
*/
-void st_lex::restore_backup_query_tables_list(Query_tables_list *backup)
+void LEX::restore_backup_query_tables_list(Query_tables_list *backup)
{
this->destroy_query_tables_list();
this->set_query_tables_list(backup);
@@ -2832,14 +2968,14 @@ void st_lex::restore_backup_query_tables_list(Query_tables_list *backup)
Checks for usage of routines and/or tables in a parsed statement
SYNOPSIS
- st_lex:table_or_sp_used()
+ LEX:table_or_sp_used()
RETURN
FALSE No routines and tables used
TRUE Either or both routines and tables are used.
*/
-bool st_lex::table_or_sp_used()
+bool LEX::table_or_sp_used()
{
DBUG_ENTER("table_or_sp_used");
@@ -3000,10 +3136,157 @@ bool st_select_lex::add_index_hint (THD *thd, char *str, uint length)
@retval FALSE No, not a management partition command
*/
-bool st_lex::is_partition_management() const
+bool LEX::is_partition_management() const
{
return (sql_command == SQLCOM_ALTER_TABLE &&
(alter_info.flags == ALTER_ADD_PARTITION ||
alter_info.flags == ALTER_REORGANIZE_PARTITION));
}
+
+#ifdef MYSQL_SERVER
+uint binlog_unsafe_map[256];
+
+#define UNSAFE(a, b, c) \
+ { \
+ DBUG_PRINT("unsafe_mixed_statement", ("SETTING BASE VALUES: %s, %s, %02X\n", \
+ LEX::stmt_accessed_table_string(a), \
+ LEX::stmt_accessed_table_string(b), \
+ c)); \
+ unsafe_mixed_statement(a, b, c); \
+ }
+
+/*
+ Sets the combination given by "a" and "b" and automatically combinations
+ given by other types of access, i.e. 2^(8 - 2), as unsafe.
+
+ It may happen a colision when automatically defining a combination as unsafe.
+ For that reason, a combination has its unsafe condition redefined only when
+ the new_condition is greater then the old. For instance,
+
+ . (BINLOG_DIRECT_ON & TRX_CACHE_NOT_EMPTY) is never overwritten by
+ . (BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF).
+*/
+void unsafe_mixed_statement(LEX::enum_stmt_accessed_table a,
+ LEX::enum_stmt_accessed_table b, uint condition)
+{
+ int type= 0;
+ int index= (1U << a) | (1U << b);
+
+
+ for (type= 0; type < 256; type++)
+ {
+ if ((type & index) == index)
+ {
+ binlog_unsafe_map[type] |= condition;
+ }
+ }
+}
+/*
+ The BINLOG_* AND TRX_CACHE_* values can be combined by using '&' or '|',
+ which means that both conditions need to be satisfied or any of them is
+ enough. For example,
+
+ . BINLOG_DIRECT_ON & TRX_CACHE_NOT_EMPTY means that the statment is
+ unsafe when the option is on and trx-cache is not empty;
+
+ . BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF means the statement is unsafe
+ in all cases.
+
+ . TRX_CACHE_EMPTY | TRX_CACHE_NOT_EMPTY means the statement is unsafe
+ in all cases. Similar as above.
+*/
+void binlog_unsafe_map_init()
+{
+ memset((void*) binlog_unsafe_map, 0, sizeof(uint) * 256);
+
+ /*
+ Classify a statement as unsafe when there is a mixed statement and an
+ on-going transaction at any point of the execution if:
+
+ 1. The mixed statement is about to update a transactional table and
+ a non-transactional table.
+
+ 2. The mixed statement is about to update a transactional table and
+ read from a non-transactional table.
+
+ 3. The mixed statement is about to update a non-transactional table
+ and temporary transactional table.
+
+ 4. The mixed statement is about to update a temporary transactional
+ table and read from a non-transactional table.
+
+ 5. The mixed statement is about to update a transactional table and
+ a temporary non-transactional table.
+
+ 6. The mixed statement is about to update a transactional table and
+ read from a temporary non-transactional table.
+
+ 7. The mixed statement is about to update a temporary transactional
+ table and temporary non-transactional table.
+
+ 8. The mixed statement is about to update a temporary transactional
+ table and read from a temporary non-transactional table.
+
+ After updating a transactional table if:
+
+ 9. The mixed statement is about to update a non-transactional table
+ and read from a transactional table.
+
+ 10. The mixed statement is about to update a non-transactional table
+ and read from a temporary transactional table.
+
+ 11. The mixed statement is about to update a temporary non-transactional
+ table and read from a transactional table.
+
+ 12. The mixed statement is about to update a temporary non-transactional
+ table and read from a temporary transactional table.
+
+ 13. The mixed statement is about to update a temporary non-transactional
+ table and read from a non-transactional table.
+
+ The reason for this is that locks acquired may not protected a concurrent
+ transaction of interfering in the current execution and by consequence in
+ the result.
+ */
+ /* Case 1. */
+ UNSAFE(LEX::STMT_WRITES_TRANS_TABLE, LEX::STMT_WRITES_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF);
+ /* Case 2. */
+ UNSAFE(LEX::STMT_WRITES_TRANS_TABLE, LEX::STMT_READS_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF);
+ /* Case 3. */
+ UNSAFE(LEX::STMT_WRITES_NON_TRANS_TABLE, LEX::STMT_WRITES_TEMP_TRANS_TABLE,
+ BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF);
+ /* Case 4. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_TRANS_TABLE, LEX::STMT_READS_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF);
+ /* Case 5. */
+ UNSAFE(LEX::STMT_WRITES_TRANS_TABLE, LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON);
+ /* Case 6. */
+ UNSAFE(LEX::STMT_WRITES_TRANS_TABLE, LEX::STMT_READS_TEMP_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON);
+ /* Case 7. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_TRANS_TABLE, LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON);
+ /* Case 8. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_TRANS_TABLE, LEX::STMT_READS_TEMP_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON);
+ /* Case 9. */
+ UNSAFE(LEX::STMT_WRITES_NON_TRANS_TABLE, LEX::STMT_READS_TRANS_TABLE,
+ (BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF) & TRX_CACHE_NOT_EMPTY);
+ /* Case 10 */
+ UNSAFE(LEX::STMT_WRITES_NON_TRANS_TABLE, LEX::STMT_READS_TEMP_TRANS_TABLE,
+ (BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF) & TRX_CACHE_NOT_EMPTY);
+ /* Case 11. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE, LEX::STMT_READS_TRANS_TABLE,
+ BINLOG_DIRECT_ON & TRX_CACHE_NOT_EMPTY);
+ /* Case 12. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE, LEX::STMT_READS_TEMP_TRANS_TABLE,
+ BINLOG_DIRECT_ON & TRX_CACHE_NOT_EMPTY);
+ /* Case 13. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE, LEX::STMT_READS_NON_TRANS_TABLE,
+ BINLOG_DIRECT_OFF & TRX_CACHE_NOT_EMPTY);
+}
+#endif
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 9131cec9d04..191562bd3e8 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -17,6 +17,14 @@
@defgroup Semantic_Analysis Semantic Analysis
*/
+#ifndef SQL_LEX_INCLUDED
+#define SQL_LEX_INCLUDED
+
+#include "violite.h" /* SSL_type */
+#include "sql_trigger.h"
+#include "item.h" /* From item_subselect.h: subselect_union_engine */
+#include "thr_lock.h" /* thr_lock_type, TL_UNLOCK */
+
/* YACC and LEX Definitions */
/* These may not be declared yet */
@@ -30,20 +38,82 @@ class sp_pcontext;
class st_alter_tablespace;
class partition_info;
class Event_parse_data;
+class set_var_base;
+class sys_var;
+class Item_func_match;
+class Alter_drop;
+class Alter_column;
+class Key;
+class File_parser;
+class Key_part_spec;
#ifdef MYSQL_SERVER
/*
- The following hack is needed because mysql_yacc.cc does not define
- YYSTYPE before including this file
+ There are 8 different type of table access so there is no more than
+ combinations 2^8 = 256:
+
+ . STMT_READS_TRANS_TABLE
+
+ . STMT_READS_NON_TRANS_TABLE
+
+ . STMT_READS_TEMP_TRANS_TABLE
+
+ . STMT_READS_TEMP_NON_TRANS_TABLE
+
+ . STMT_WRITES_TRANS_TABLE
+
+ . STMT_WRITES_NON_TRANS_TABLE
+
+ . STMT_WRITES_TEMP_TRANS_TABLE
+
+ . STMT_WRITES_TEMP_NON_TRANS_TABLE
+
+ The unsafe conditions for each combination is represented within a byte
+ and stores the status of the option --binlog-direct-non-trans-updates,
+ whether the trx-cache is empty or not, and whether the isolation level
+ is lower than ISO_REPEATABLE_READ:
+
+ . option (OFF/ON)
+ . trx-cache (empty/not empty)
+ . isolation (>= ISO_REPEATABLE_READ / < ISO_REPEATABLE_READ)
+
+ bits 0 : . OFF, . empty, . >= ISO_REPEATABLE_READ
+ bits 1 : . OFF, . empty, . < ISO_REPEATABLE_READ
+ bits 2 : . OFF, . not empty, . >= ISO_REPEATABLE_READ
+ bits 3 : . OFF, . not empty, . < ISO_REPEATABLE_READ
+ bits 4 : . ON, . empty, . >= ISO_REPEATABLE_READ
+ bits 5 : . ON, . empty, . < ISO_REPEATABLE_READ
+ bits 6 : . ON, . not empty, . >= ISO_REPEATABLE_READ
+ bits 7 : . ON, . not empty, . < ISO_REPEATABLE_READ
+*/
+extern uint binlog_unsafe_map[256];
+/*
+ Initializes the array with unsafe combinations and its respective
+ conditions.
*/
+void binlog_unsafe_map_init();
+#endif
-#include "set_var.h"
+/**
+ used by the parser to store internal variable name
+*/
+struct sys_var_with_base
+{
+ sys_var *var;
+ LEX_STRING base_name;
+};
+#ifdef MYSQL_SERVER
+/*
+ The following hack is needed because mysql_yacc.cc does not define
+ YYSTYPE before including this file
+*/
#ifdef MYSQL_YACC
#define LEX_YYSTYPE void *
#else
#include "lex_symbol.h"
#if MYSQL_LEX
+#include "item_func.h" /* Cast_target used in sql_yacc.h */
#include "sql_yacc.h"
#define LEX_YYSTYPE YYSTYPE *
#else
@@ -86,15 +156,15 @@ enum enum_sql_command {
SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT,
SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT,
SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
- SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER,
- SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE,
+ SQLCOM_BEGIN, SQLCOM_CHANGE_MASTER,
+ SQLCOM_RENAME_TABLE,
SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS,
- SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA,
+ SQLCOM_SHOW_OPEN_TABLES,
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI,
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
- SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES,
+ SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES,
SQLCOM_HELP, SQLCOM_CREATE_USER, SQLCOM_DROP_USER, SQLCOM_RENAME_USER,
SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM,
SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL,
@@ -118,7 +188,8 @@ enum enum_sql_command {
SQLCOM_SHOW_CREATE_TRIGGER,
SQLCOM_ALTER_DB_UPGRADE,
SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES,
-
+ SQLCOM_SIGNAL, SQLCOM_RESIGNAL,
+ SQLCOM_SHOW_RELAYLOG_EVENTS,
/*
When a command is added here, be sure it's also added in mysqld.cc
in "struct show_var_st status_vars[]= {" ...
@@ -180,6 +251,12 @@ enum enum_drop_mode
DROP_RESTRICT // RESTRICT option
};
+/* Options to add_table_to_list() */
+#define TL_OPTION_UPDATING 1
+#define TL_OPTION_FORCE_INDEX 2
+#define TL_OPTION_IGNORE_LEAVES 4
+#define TL_OPTION_ALIAS 8
+
typedef List<Item> List_item;
/* SERVERS CACHE CHANGES */
@@ -203,17 +280,19 @@ typedef struct st_lex_master_info
{
char *host, *user, *password, *log_file_name;
uint port, connect_retry;
+ float heartbeat_period;
ulonglong pos;
ulong server_id;
/*
Enum is used for making it possible to detect if the user
changed variable or if it should be left at old value
*/
- enum {SSL_UNCHANGED, SSL_DISABLE, SSL_ENABLE}
- ssl, ssl_verify_server_cert;
+ enum {LEX_MI_UNCHANGED, LEX_MI_DISABLE, LEX_MI_ENABLE}
+ ssl, ssl_verify_server_cert, heartbeat_opt, repl_ignore_server_ids_opt;
char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher;
char *relay_log_name;
ulong relay_log_pos;
+ DYNAMIC_ARRAY repl_ignore_server_ids;
} LEX_MASTER_INFO;
@@ -394,9 +473,11 @@ public:
Base class for st_select_lex (SELECT_LEX) &
st_select_lex_unit (SELECT_LEX_UNIT)
*/
-struct st_lex;
+struct LEX;
class st_select_lex;
class st_select_lex_unit;
+
+
class st_select_lex_node {
protected:
st_select_lex_node *next, **prev, /* neighbor list */
@@ -434,8 +515,17 @@ public:
{ return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
- st_select_lex_node(): linkage(UNSPECIFIED_TYPE) {}
+
+ // Ensures that at least all members used during cleanup() are initialized.
+ st_select_lex_node()
+ : next(NULL), prev(NULL),
+ master(NULL), slave(NULL),
+ link_next(NULL), link_prev(NULL),
+ linkage(UNSPECIFIED_TYPE)
+ {
+ }
virtual ~st_select_lex_node() {}
+
inline st_select_lex_node* get_master() { return master; }
virtual void init_query();
virtual void init_select();
@@ -459,12 +549,13 @@ public:
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
+ enum_mdl_type mdl_type= MDL_SHARED_READ,
List<Index_hint> *hints= 0,
LEX_STRING *option= 0);
virtual void set_lock_for_tables(thr_lock_type lock_type) {}
friend class st_select_lex_unit;
- friend bool mysql_new_select(struct st_lex *lex, bool move_down);
+ friend bool mysql_new_select(LEX *lex, bool move_down);
friend bool mysql_make_view(THD *thd, File_parser *parser,
TABLE_LIST *table, uint flags);
private:
@@ -481,6 +572,8 @@ class select_result;
class JOIN;
class select_union;
class Procedure;
+
+
class st_select_lex_unit: public st_select_lex_node {
protected:
TABLE_LIST result_table_list;
@@ -492,6 +585,14 @@ protected:
bool saved_error;
public:
+ // Ensures that at least all members used during cleanup() are initialized.
+ st_select_lex_unit()
+ : union_result(NULL), table(NULL), result(NULL),
+ cleaned(false),
+ fake_select_lex(NULL)
+ {
+ }
+
bool prepared, // prepare phase already performed for UNION (unit)
optimized, // optimize phase already performed for UNION (unit)
executed, // already executed
@@ -535,11 +636,11 @@ public:
st_select_lex* outer_select();
st_select_lex* first_select()
{
- return my_reinterpret_cast(st_select_lex*)(slave);
+ return reinterpret_cast<st_select_lex*>(slave);
}
st_select_lex_unit* next_unit()
{
- return my_reinterpret_cast(st_select_lex_unit*)(next);
+ return reinterpret_cast<st_select_lex_unit*>(next);
}
st_select_lex* return_after_parsing() { return return_to; }
void exclude_level();
@@ -584,7 +685,7 @@ public:
/* Saved values of the WHERE and HAVING clauses*/
Item::cond_result cond_value, having_value;
/* point on lex in which it was created, used in view subquery detection */
- st_lex *parent_lex;
+ LEX *parent_lex;
enum olap_type olap;
/* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */
SQL_I_List<TABLE_LIST> table_list;
@@ -632,11 +733,6 @@ public:
uint select_n_where_fields;
enum_parsing_place parsing_place; /* where we are parsing expression */
bool with_sum_func; /* sum function indicator */
- /*
- PS or SP cond natural joins was alredy processed with permanent
- arena and all additional items which we need alredy stored in it
- */
- bool conds_processed_with_permanent_arena;
ulong table_join_options;
uint in_sum_expr;
@@ -691,14 +787,6 @@ public:
List<udf_func> udf_list; /* udf function calls stack */
- /**
- Per sub-query locking strategy.
- Note: This variable might interfer with the corresponding statement-level
- variable Lex::lock_option because on how different parser rules depend
- on eachother.
- */
- thr_lock_type lock_option;
-
/*
This is a copy of the original JOIN USING list that comes from
the parser. The parser :
@@ -759,6 +847,7 @@ public:
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
+ enum_mdl_type mdl_type= MDL_SHARED_READ,
List<Index_hint> *hints= 0,
LEX_STRING *option= 0);
TABLE_LIST* get_table_list();
@@ -869,6 +958,7 @@ inline bool st_select_lex_unit::is_union ()
#define ALTER_ALL_PARTITION (1L << 21)
#define ALTER_REMOVE_PARTITIONING (1L << 22)
#define ALTER_FOREIGN_KEY (1L << 23)
+#define ALTER_TRUNCATE_PARTITION (1L << 24)
enum enum_alter_table_change_level
{
@@ -877,6 +967,24 @@ enum enum_alter_table_change_level
ALTER_TABLE_INDEX_CHANGED= 2
};
+
+/**
+ Temporary hack to enable a class bound forward declaration
+ of the enum_alter_table_change_level enumeration. To be
+ removed once Alter_info is moved to the sql_alter.h
+ header.
+*/
+class Alter_table_change_level
+{
+private:
+ typedef enum enum_alter_table_change_level enum_type;
+ enum_type value;
+public:
+ void operator = (enum_type v) { value = v; }
+ operator enum_type () { return value; }
+};
+
+
/**
@brief Parsing data for CREATE or ALTER TABLE.
@@ -895,7 +1003,7 @@ public:
enum enum_enable_or_disable keys_onoff;
enum tablespace_op_type tablespace_op;
List<char> partition_names;
- uint no_parts;
+ uint num_parts;
enum_alter_table_change_level change_level;
Create_field *datetime_field;
bool error_if_not_empty;
@@ -905,7 +1013,7 @@ public:
flags(0),
keys_onoff(LEAVE_AS_IS),
tablespace_op(NO_TABLESPACE_OP),
- no_parts(0),
+ num_parts(0),
change_level(ALTER_TABLE_METADATA_ONLY),
datetime_field(NULL),
error_if_not_empty(FALSE)
@@ -920,7 +1028,7 @@ public:
flags= 0;
keys_onoff= LEAVE_AS_IS;
tablespace_op= NO_TABLESPACE_OP;
- no_parts= 0;
+ num_parts= 0;
partition_names.empty();
change_level= ALTER_TABLE_METADATA_ONLY;
datetime_field= 0;
@@ -940,6 +1048,8 @@ struct st_sp_chistics
enum enum_sp_data_access daccess;
};
+extern const LEX_STRING null_lex_str;
+extern const LEX_STRING empty_lex_str;
struct st_trg_chistics
{
@@ -952,23 +1062,34 @@ extern sys_var *trg_new_row_fake_var;
enum xa_option_words {XA_NONE, XA_JOIN, XA_RESUME, XA_ONE_PHASE,
XA_SUSPEND, XA_FOR_MIGRATE};
+extern const LEX_STRING null_lex_str;
-struct Sroutine_hash_entry;
+class Sroutine_hash_entry;
/*
- Class representing list of all tables used by statement.
- It also contains information about stored functions used by statement
+ Class representing list of all tables used by statement and other
+ information which is necessary for opening and locking its tables,
+ like SQL command for this statement.
+
+ Also contains information about stored functions used by statement
since during its execution we may have to add all tables used by its
stored functions/triggers to this list in order to pre-open and lock
them.
- Also used by st_lex::reset_n_backup/restore_backup_query_tables_list()
+ Also used by LEX::reset_n_backup/restore_backup_query_tables_list()
methods to save and restore this information.
*/
class Query_tables_list
{
public:
+ /**
+ SQL command for this statement. Part of this class since the
+ process of opening and locking tables for the statement needs
+ this information to determine correct type of lock for some of
+ the tables.
+ */
+ enum_sql_command sql_command;
/* Global list of all tables used by this statement */
TABLE_LIST *query_tables;
/* Pointer to next_global member of last element in the previous list. */
@@ -1047,25 +1168,393 @@ public:
}
}
+ /** Return a pointer to the last element in query table list. */
+ TABLE_LIST *last_table()
+ {
+ /* Don't use offsetof() macro in order to avoid warnings. */
+ return query_tables ?
+ (TABLE_LIST*) ((char*) query_tables_last -
+ ((char*) &(query_tables->next_global) -
+ (char*) query_tables)) :
+ 0;
+ }
+
/**
- Has the parser/scanner detected that this statement is unsafe?
- */
+ Enumeration listing of all types of unsafe statement.
+
+ @note The order of elements of this enumeration type must
+ correspond to the order of the elements of the @c explanations
+ array defined in the body of @c THD::issue_unsafe_warnings.
+ */
+ enum enum_binlog_stmt_unsafe {
+ /**
+ SELECT..LIMIT is unsafe because the set of rows returned cannot
+ be predicted.
+ */
+ BINLOG_STMT_UNSAFE_LIMIT= 0,
+ /**
+ INSERT DELAYED is unsafe because the time when rows are inserted
+ cannot be predicted.
+ */
+ BINLOG_STMT_UNSAFE_INSERT_DELAYED,
+ /**
+ Access to log tables is unsafe because slave and master probably
+ log different things.
+ */
+ BINLOG_STMT_UNSAFE_SYSTEM_TABLE,
+ /**
+ Inserting into an autoincrement column in a stored routine is unsafe.
+ Even with just one autoincrement column, if the routine is invoked more than
+ once slave is not guaranteed to execute the statement graph same way as
+ the master.
+ And since it's impossible to estimate how many times a routine can be invoked at
+ the query pre-execution phase (see lock_tables), the statement is marked
+ pessimistically unsafe.
+ */
+ BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS,
+ /**
+ Using a UDF (user-defined function) is unsafe.
+ */
+ BINLOG_STMT_UNSAFE_UDF,
+ /**
+ Using most system variables is unsafe, because slave may run
+ with different options than master.
+ */
+ BINLOG_STMT_UNSAFE_SYSTEM_VARIABLE,
+ /**
+ Using some functions is unsafe (e.g., UUID).
+ */
+ BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION,
+
+ /**
+ Mixing transactional and non-transactional statements are unsafe if
+ non-transactional reads or writes are occur after transactional
+ reads or writes inside a transaction.
+ */
+ BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS,
+
+ /**
+ Mixing self-logging and non-self-logging engines in a statement
+ is unsafe.
+ */
+ BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE,
+
+ /**
+ Statements that read from both transactional and non-transactional
+ tables and write to any of them are unsafe.
+ */
+ BINLOG_STMT_UNSAFE_MIXED_STATEMENT,
+
+ /* The last element of this enumeration type. */
+ BINLOG_STMT_UNSAFE_COUNT
+ };
+ /**
+ This has all flags from 0 (inclusive) to BINLOG_STMT_FLAG_COUNT
+ (exclusive) set.
+ */
+ static const int BINLOG_STMT_UNSAFE_ALL_FLAGS=
+ ((1 << BINLOG_STMT_UNSAFE_COUNT) - 1);
+
+ /**
+ Maps elements of enum_binlog_stmt_unsafe to error codes.
+ */
+ static const int binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT];
+
+ /**
+ Determine if this statement is marked as unsafe.
+
+ @retval 0 if the statement is not marked as unsafe.
+ @retval nonzero if the statement is marked as unsafe.
+ */
inline bool is_stmt_unsafe() const {
- return binlog_stmt_flags & (1U << BINLOG_STMT_FLAG_UNSAFE);
+ return get_stmt_unsafe_flags() != 0;
}
/**
- Flag the current (top-level) statement as unsafe.
+ Flag the current (top-level) statement as unsafe.
+ The flag will be reset after the statement has finished.
- The flag will be reset after the statement has finished.
+ @param unsafe_type The type of unsafety: one of the @c
+ BINLOG_STMT_FLAG_UNSAFE_* flags in @c enum_binlog_stmt_flag.
+ */
+ inline void set_stmt_unsafe(enum_binlog_stmt_unsafe unsafe_type) {
+ DBUG_ENTER("set_stmt_unsafe");
+ DBUG_ASSERT(unsafe_type >= 0 && unsafe_type < BINLOG_STMT_UNSAFE_COUNT);
+ binlog_stmt_flags|= (1U << unsafe_type);
+ DBUG_VOID_RETURN;
+ }
- */
- inline void set_stmt_unsafe() {
- binlog_stmt_flags|= (1U << BINLOG_STMT_FLAG_UNSAFE);
+ /**
+ Set the bits of binlog_stmt_flags determining the type of
+ unsafeness of the current statement. No existing bits will be
+ cleared, but new bits may be set.
+
+ @param flags A binary combination of zero or more bits, (1<<flag)
+ where flag is a member of enum_binlog_stmt_unsafe.
+ */
+ inline void set_stmt_unsafe_flags(uint32 flags) {
+ DBUG_ENTER("set_stmt_unsafe_flags");
+ DBUG_ASSERT((flags & ~BINLOG_STMT_UNSAFE_ALL_FLAGS) == 0);
+ binlog_stmt_flags|= flags;
+ DBUG_VOID_RETURN;
}
+ /**
+ Return a binary combination of all unsafe warnings for the
+ statement. If the statement has been marked as unsafe by the
+ 'flag' member of enum_binlog_stmt_unsafe, then the return value
+ from this function has bit (1<<flag) set to 1.
+ */
+ inline uint32 get_stmt_unsafe_flags() const {
+ DBUG_ENTER("get_stmt_unsafe_flags");
+ DBUG_RETURN(binlog_stmt_flags & BINLOG_STMT_UNSAFE_ALL_FLAGS);
+ }
+
+ /**
+ Mark the current statement as safe; i.e., clear all bits in
+ binlog_stmt_flags that correspond to elements of
+ enum_binlog_stmt_unsafe.
+ */
inline void clear_stmt_unsafe() {
- binlog_stmt_flags&= ~(1U << BINLOG_STMT_FLAG_UNSAFE);
+ DBUG_ENTER("clear_stmt_unsafe");
+ binlog_stmt_flags&= ~BINLOG_STMT_UNSAFE_ALL_FLAGS;
+ DBUG_VOID_RETURN;
+ }
+
+ /**
+ Determine if this statement is a row injection.
+
+ @retval 0 if the statement is not a row injection
+ @retval nonzero if the statement is a row injection
+ */
+ inline bool is_stmt_row_injection() const {
+ return binlog_stmt_flags &
+ (1U << (BINLOG_STMT_UNSAFE_COUNT + BINLOG_STMT_TYPE_ROW_INJECTION));
+ }
+
+ /**
+ Flag the statement as a row injection. A row injection is either
+ a BINLOG statement, or a row event in the relay log executed by
+ the slave SQL thread.
+ */
+ inline void set_stmt_row_injection() {
+ DBUG_ENTER("set_stmt_row_injection");
+ binlog_stmt_flags|=
+ (1U << (BINLOG_STMT_UNSAFE_COUNT + BINLOG_STMT_TYPE_ROW_INJECTION));
+ DBUG_VOID_RETURN;
+ }
+
+ enum enum_stmt_accessed_table
+ {
+ /*
+ If a transactional table is about to be read. Note that
+ a write implies a read.
+ */
+ STMT_READS_TRANS_TABLE= 0,
+ /*
+ If a non-transactional table is about to be read. Note that
+ a write implies a read.
+ */
+ STMT_READS_NON_TRANS_TABLE,
+ /*
+ If a temporary transactional table is about to be read. Note
+ that a write implies a read.
+ */
+ STMT_READS_TEMP_TRANS_TABLE,
+ /*
+ If a temporary non-transactional table is about to be read. Note
+ that a write implies a read.
+ */
+ STMT_READS_TEMP_NON_TRANS_TABLE,
+ /*
+ If a transactional table is about to be updated.
+ */
+ STMT_WRITES_TRANS_TABLE,
+ /*
+ If a non-transactional table is about to be updated.
+ */
+ STMT_WRITES_NON_TRANS_TABLE,
+ /*
+ If a temporary transactional table is about to be updated.
+ */
+ STMT_WRITES_TEMP_TRANS_TABLE,
+ /*
+ If a temporary non-transactional table is about to be updated.
+ */
+ STMT_WRITES_TEMP_NON_TRANS_TABLE,
+ /*
+ The last element of the enumeration. Please, if necessary add
+ anything before this.
+ */
+ STMT_ACCESS_TABLE_COUNT
+ };
+
+#ifndef DBUG_OFF
+ static inline const char *stmt_accessed_table_string(enum_stmt_accessed_table accessed_table)
+ {
+ switch (accessed_table)
+ {
+ case STMT_READS_TRANS_TABLE:
+ return "STMT_READS_TRANS_TABLE";
+ break;
+ case STMT_READS_NON_TRANS_TABLE:
+ return "STMT_READS_NON_TRANS_TABLE";
+ break;
+ case STMT_READS_TEMP_TRANS_TABLE:
+ return "STMT_READS_TEMP_TRANS_TABLE";
+ break;
+ case STMT_READS_TEMP_NON_TRANS_TABLE:
+ return "STMT_READS_TEMP_NON_TRANS_TABLE";
+ break;
+ case STMT_WRITES_TRANS_TABLE:
+ return "STMT_WRITES_TRANS_TABLE";
+ break;
+ case STMT_WRITES_NON_TRANS_TABLE:
+ return "STMT_WRITES_NON_TRANS_TABLE";
+ break;
+ case STMT_WRITES_TEMP_TRANS_TABLE:
+ return "STMT_WRITES_TEMP_TRANS_TABLE";
+ break;
+ case STMT_WRITES_TEMP_NON_TRANS_TABLE:
+ return "STMT_WRITES_TEMP_NON_TRANS_TABLE";
+ break;
+ case STMT_ACCESS_TABLE_COUNT:
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+ MY_ASSERT_UNREACHABLE();
+ return "";
+ }
+#endif /* DBUG */
+
+ #define BINLOG_DIRECT_ON 0xF0 /* unsafe when
+ --binlog-direct-non-trans-updates
+ is ON */
+
+ #define BINLOG_DIRECT_OFF 0xF /* unsafe when
+ --binlog-direct-non-trans-updates
+ is OFF */
+
+ #define TRX_CACHE_EMPTY 0x33 /* unsafe when trx-cache is empty */
+
+ #define TRX_CACHE_NOT_EMPTY 0xCC /* unsafe when trx-cache is not empty */
+
+ #define IL_LT_REPEATABLE 0xAA /* unsafe when < ISO_REPEATABLE_READ */
+
+ #define IL_GTE_REPEATABLE 0x55 /* unsafe when >= ISO_REPEATABLE_READ */
+
+ /**
+ Sets the type of table that is about to be accessed while executing a
+ statement.
+
+ @param accessed_table Enumeration type that defines the type of table,
+ e.g. temporary, transactional, non-transactional.
+ */
+ inline void set_stmt_accessed_table(enum_stmt_accessed_table accessed_table)
+ {
+ DBUG_ENTER("LEX::set_stmt_accessed_table");
+
+ DBUG_ASSERT(accessed_table >= 0 && accessed_table < STMT_ACCESS_TABLE_COUNT);
+ stmt_accessed_table_flag |= (1U << accessed_table);
+
+ DBUG_VOID_RETURN;
+ }
+
+ /**
+ Checks if a type of table is about to be accessed while executing a
+ statement.
+
+ @param accessed_table Enumeration type that defines the type of table,
+ e.g. temporary, transactional, non-transactional.
+
+ @return
+ @retval TRUE if the type of the table is about to be accessed
+ @retval FALSE otherwise
+ */
+ inline bool stmt_accessed_table(enum_stmt_accessed_table accessed_table)
+ {
+ DBUG_ENTER("LEX::stmt_accessed_table");
+
+ DBUG_ASSERT(accessed_table >= 0 && accessed_table < STMT_ACCESS_TABLE_COUNT);
+
+ DBUG_RETURN((stmt_accessed_table_flag & (1U << accessed_table)) != 0);
+ }
+
+ /**
+ Checks if a temporary non-transactional table is about to be accessed
+ while executing a statement.
+
+ @return
+ @retval TRUE if a temporary non-transactional table is about to be
+ accessed
+ @retval FALSE otherwise
+ */
+ inline bool stmt_accessed_non_trans_temp_table()
+ {
+ DBUG_ENTER("THD::stmt_accessed_non_trans_temp_table");
+
+ DBUG_RETURN((stmt_accessed_table_flag &
+ ((1U << STMT_READS_TEMP_NON_TRANS_TABLE) |
+ (1U << STMT_WRITES_TEMP_NON_TRANS_TABLE))) != 0);
+ }
+
+ /*
+ Checks if a mixed statement is unsafe.
+
+
+ @param in_multi_stmt_transaction_mode defines if there is an on-going
+ multi-transactional statement.
+ @param binlog_direct defines if --binlog-direct-non-trans-updates is
+ active.
+ @param trx_cache_is_not_empty defines if the trx-cache is empty or not.
+ @param trx_isolation defines the isolation level.
+
+ @return
+ @retval TRUE if the mixed statement is unsafe
+ @retval FALSE otherwise
+ */
+ inline bool is_mixed_stmt_unsafe(bool in_multi_stmt_transaction_mode,
+ bool binlog_direct,
+ bool trx_cache_is_not_empty,
+ uint tx_isolation)
+ {
+ bool unsafe= FALSE;
+
+ if (in_multi_stmt_transaction_mode)
+ {
+ uint condition=
+ (binlog_direct ? BINLOG_DIRECT_ON : BINLOG_DIRECT_OFF) &
+ (trx_cache_is_not_empty ? TRX_CACHE_NOT_EMPTY : TRX_CACHE_EMPTY) &
+ (tx_isolation >= ISO_REPEATABLE_READ ? IL_GTE_REPEATABLE : IL_LT_REPEATABLE);
+
+ unsafe= (binlog_unsafe_map[stmt_accessed_table_flag] & condition);
+
+#if !defined(DBUG_OFF)
+ DBUG_PRINT("LEX::is_mixed_stmt_unsafe", ("RESULT %02X %02X %02X\n", condition,
+ binlog_unsafe_map[stmt_accessed_table_flag],
+ (binlog_unsafe_map[stmt_accessed_table_flag] & condition)));
+
+ int type_in= 0;
+ for (; type_in < STMT_ACCESS_TABLE_COUNT; type_in++)
+ {
+ if (stmt_accessed_table((enum_stmt_accessed_table) type_in))
+ DBUG_PRINT("LEX::is_mixed_stmt_unsafe", ("ACCESSED %s ",
+ stmt_accessed_table_string((enum_stmt_accessed_table) type_in)));
+ }
+#endif
+ }
+
+ if (stmt_accessed_table(STMT_WRITES_NON_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_READS_TRANS_TABLE) &&
+ tx_isolation < ISO_REPEATABLE_READ)
+ unsafe= TRUE;
+ else if (stmt_accessed_table(STMT_WRITES_TEMP_NON_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_READS_TRANS_TABLE) &&
+ tx_isolation < ISO_REPEATABLE_READ)
+ unsafe= TRUE;
+
+ return(unsafe);
}
/**
@@ -1076,18 +1565,45 @@ public:
{ return sroutines_list.elements != 0; }
private:
- enum enum_binlog_stmt_flag {
- BINLOG_STMT_FLAG_UNSAFE,
- BINLOG_STMT_FLAG_COUNT
+
+ /**
+ Enumeration listing special types of statements.
+
+ Currently, the only possible type is ROW_INJECTION.
+ */
+ enum enum_binlog_stmt_type {
+ /**
+ The statement is a row injection (i.e., either a BINLOG
+ statement or a row event executed by the slave SQL thread).
+ */
+ BINLOG_STMT_TYPE_ROW_INJECTION = 0,
+
+ /** The last element of this enumeration type. */
+ BINLOG_STMT_TYPE_COUNT
};
- /*
- Tells if the parsing stage detected properties of the statement,
- for example: that some items require row-based binlogging to give
- a reliable binlog/replication, or if we will use stored functions
- or triggers which themselves need require row-based binlogging.
+ /**
+ Bit field indicating the type of statement.
+
+ There are two groups of bits:
+
+ - The low BINLOG_STMT_UNSAFE_COUNT bits indicate the types of
+ unsafeness that the current statement has.
+
+ - The next BINLOG_STMT_TYPE_COUNT bits indicate if the statement
+ is of some special type.
+
+ This must be a member of LEX, not of THD: each stored procedure
+ needs to remember its unsafeness state between calls and each
+ stored procedure has its own LEX object (but no own THD object).
*/
uint32 binlog_stmt_flags;
+
+ /**
+ Bit field that determines the type of tables that are about to be
+ be accessed while executing a statement.
+ */
+ uint32 stmt_accessed_table_flag;
};
@@ -1149,24 +1665,7 @@ enum enum_comment_state
class Lex_input_stream
{
public:
- Lex_input_stream() :
- yylineno(1),
- yytoklen(0),
- yylval(NULL),
- m_tok_start(NULL),
- m_tok_end(NULL),
- m_tok_start_prev(NULL),
- m_echo(TRUE),
- m_cpp_tok_start(NULL),
- m_cpp_tok_start_prev(NULL),
- m_cpp_tok_end(NULL),
- m_body_utf8(NULL),
- m_cpp_utf8_processed_ptr(NULL),
- next_state(MY_LEX_START),
- found_semicolon(NULL),
- stmt_prepare_mode(FALSE),
- in_comment(NO_COMMENT),
- m_underscore_cs(NULL)
+ Lex_input_stream()
{
}
@@ -1181,6 +1680,9 @@ public:
@retval TRUE Error
*/
bool init(THD *thd, char *buff, unsigned int length);
+
+ void reset(char *buff, unsigned int length);
+
/**
Set the echo mode.
@@ -1452,6 +1954,17 @@ public:
/** Interface with bison, value of the last token parsed. */
LEX_YYSTYPE yylval;
+ /**
+ LALR(2) resolution, look ahead token.
+ Value of the next token to return, if any,
+ or -1, if no token was parsed in advance.
+ Note: 0 is a legal token, and represents YYEOF.
+ */
+ int lookahead_token;
+
+ /** LALR(2) resolution, value of the look ahead token.*/
+ LEX_YYSTYPE lookahead_yylval;
+
private:
/** Pointer to the current position in the raw input stream. */
char *m_ptr;
@@ -1533,9 +2046,13 @@ public:
/**
TRUE if we're parsing a prepared statement: in this mode
- we should allow placeholders and disallow multi-statements.
+ we should allow placeholders.
*/
bool stmt_prepare_mode;
+ /**
+ TRUE if we should allow multi-statements.
+ */
+ bool multi_statements;
/** State of the lexical analyser for comments. */
enum_comment_state in_comment;
@@ -1565,10 +2082,66 @@ public:
CHARSET_INFO *m_underscore_cs;
};
+/**
+ Abstract representation of a statement.
+ This class is an interface between the parser and the runtime.
+ The parser builds the appropriate sub classes of Sql_statement
+ to represent a SQL statement in the parsed tree.
+ The execute() method in the sub classes contain the runtime implementation.
+ Note that this interface is used for SQL statement recently implemented,
+ the code for older statements tend to load the LEX structure with more
+ attributes instead.
+ The recommended way to implement new statements is to sub-class
+ Sql_statement, as this improves code modularity (see the 'big switch' in
+ dispatch_command()), and decrease the total size of the LEX structure
+ (therefore saving memory in stored programs).
+*/
+class Sql_statement : public Sql_alloc
+{
+public:
+ /**
+ Execute this SQL statement.
+ @param thd the current thread.
+ @return 0 on success.
+ */
+ virtual bool execute(THD *thd) = 0;
+
+protected:
+ /**
+ Constructor.
+ @param lex the LEX structure that represents parts of this statement.
+ */
+ Sql_statement(LEX *lex)
+ : m_lex(lex)
+ {}
+
+ /** Destructor. */
+ virtual ~Sql_statement()
+ {
+ /*
+ Sql_statement objects are allocated in thd->mem_root.
+ In MySQL, the C++ destructor is never called, the underlying MEM_ROOT is
+ simply destroyed instead.
+ Do not rely on the destructor for any cleanup.
+ */
+ DBUG_ASSERT(FALSE);
+ }
+
+protected:
+ /**
+ The legacy LEX structure for this statement.
+ The LEX structure contains the existing properties of the parsed tree.
+ TODO: with time, attributes from LEX should move to sub classes of
+ Sql_statement, so that the parser only builds Sql_statement objects
+ with the minimum set of attributes, instead of a LEX structure that
+ contains the collection of every possible attribute.
+ */
+ LEX *m_lex;
+};
/* The state of the lex parsing. This is saved in the THD struct */
-typedef struct st_lex : public Query_tables_list
+struct LEX: public Query_tables_list
{
SELECT_LEX_UNIT unit; /* most upper unit */
SELECT_LEX select_lex; /* first SELECT_LEX */
@@ -1666,7 +2239,9 @@ typedef struct st_lex : public Query_tables_list
the variable can contain 0 or 1 for each nest level.
*/
nesting_map allow_sum_func;
- enum_sql_command sql_command;
+
+ Sql_statement *m_stmt;
+
/*
Usually `expr` rule of yacc is quite reused but some commands better
not support subqueries which comes standard with this rule, like
@@ -1675,7 +2250,6 @@ typedef struct st_lex : public Query_tables_list
*/
bool expr_allows_subselect;
- thr_lock_type lock_option;
enum SSL_type ssl_type; /* defined in violite.h */
enum enum_duplicates duplicates;
enum enum_tx_isolation tx_isolation;
@@ -1692,7 +2266,9 @@ typedef struct st_lex : public Query_tables_list
uint profile_options;
uint uint_geom_type;
uint grant, grant_tot_col, which_columns;
- uint fk_delete_opt, fk_update_opt, fk_match_option;
+ enum Foreign_key::fk_match_opt fk_match_option;
+ enum Foreign_key::fk_option fk_update_opt;
+ enum Foreign_key::fk_option fk_delete_opt;
uint slave_thd_opt, start_transaction_opt;
int nest_level;
/*
@@ -1714,7 +2290,7 @@ typedef struct st_lex : public Query_tables_list
bool autocommit;
bool verbose, no_write_to_binlog;
- bool tx_chain, tx_release;
+ enum enum_yes_no_unknown tx_chain, tx_release;
/*
Special JOIN::prepare mode: changing of query is prohibited.
When creating a view, we need to just check its syntax omitting
@@ -1727,6 +2303,12 @@ typedef struct st_lex : public Query_tables_list
bool subqueries, ignore;
st_parsing_options parsing_options;
Alter_info alter_info;
+ /*
+ For CREATE TABLE statement last element of table list which is not
+ part of SELECT or LIKE part (i.e. either element for table we are
+ creating or last of tables referenced by foreign keys).
+ */
+ TABLE_LIST *create_last_non_select_table;
/* Prepared statements SQL syntax:*/
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
/*
@@ -1742,6 +2324,7 @@ typedef struct st_lex : public Query_tables_list
sp_name *spname;
bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */
bool all_privileges;
+ bool proxy_priv;
sp_pcontext *spcont;
st_sp_chistics sp_chistics;
@@ -1779,10 +2362,20 @@ typedef struct st_lex : public Query_tables_list
This pointer is required to add possibly omitted DEFINER-clause to the
DDL-statement before dumping it to the binlog.
+
+ keyword_delayed_begin_offset is the offset to the beginning of the DELAYED
+ keyword in INSERT DELAYED statement. keyword_delayed_end_offset is the
+ offset to the character right after the DELAYED keyword.
*/
- const char *stmt_definition_begin;
+ union {
+ const char *stmt_definition_begin;
+ uint keyword_delayed_begin_offset;
+ };
- const char *stmt_definition_end;
+ union {
+ const char *stmt_definition_end;
+ uint keyword_delayed_end_offset;
+ };
/**
During name resolution search only in the table list given by
@@ -1801,42 +2394,9 @@ typedef struct st_lex : public Query_tables_list
bool escape_used;
bool is_lex_started; /* If lex_start() did run. For debugging. */
- /*
- Special case for SELECT .. FOR UPDATE and LOCK TABLES .. WRITE.
+ LEX();
- Protect from a impending GRL as otherwise the thread might deadlock
- if it starts waiting for the GRL in mysql_lock_tables.
-
- The protection is needed because there is a race between setting
- the global read lock and waiting for all open tables to be closed.
- The problem is a circular wait where a thread holding "old" open
- tables will wait for the global read lock to be released while the
- thread holding the global read lock will wait for all "old" open
- tables to be closed -- the flush part of flush tables with read
- lock.
- */
- bool protect_against_global_read_lock;
-
- /*
- The following three variables are used in 'CREATE TABLE IF NOT EXISTS ...
- SELECT' statement. They are used to binlog the statement.
-
- create_select_start_with_brace will be set if there is a '(' before
- the first SELECT clause
-
- create_select_pos records the relative position of the SELECT clause
- in the whole statement.
-
- create_select_in_comment will be set if SELECT keyword is in conditional
- comment.
- */
- bool create_select_start_with_brace;
- uint create_select_pos;
- bool create_select_in_comment;
-
- st_lex();
-
- virtual ~st_lex()
+ virtual ~LEX()
{
destroy_query_tables_list();
plugin_unlock_list(NULL, (plugin_ref *)plugins.buffer, plugins.elements);
@@ -1878,7 +2438,7 @@ typedef struct st_lex : public Query_tables_list
Is this update command where 'WHITH CHECK OPTION' clause is important
SYNOPSIS
- st_lex::which_check_option_applicable()
+ LEX::which_check_option_applicable()
RETURN
TRUE have to take 'WHITH CHECK OPTION' clause into account
@@ -1950,7 +2510,37 @@ typedef struct st_lex : public Query_tables_list
}
return FALSE;
}
-} LEX;
+};
+
+
+/**
+ Set_signal_information is a container used in the parsed tree to represent
+ the collection of assignments to condition items in the SIGNAL and RESIGNAL
+ statements.
+*/
+class Set_signal_information
+{
+public:
+ /** Empty default constructor, use clear() */
+ Set_signal_information() {}
+
+ /** Copy constructor. */
+ Set_signal_information(const Set_signal_information& set);
+
+ /** Destructor. */
+ ~Set_signal_information()
+ {}
+
+ /** Clear all items. */
+ void clear();
+
+ /**
+ For each condition item assignment, m_item[] contains the parsed tree
+ that represents the expression assigned, if any.
+ m_item[] is an array indexed by Diag_condition_item_name.
+ */
+ Item *m_item[LAST_DIAG_SET_PROPERTY+1];
+};
/**
@@ -1962,12 +2552,32 @@ class Yacc_state
{
public:
Yacc_state()
- : yacc_yyss(NULL), yacc_yyvs(NULL)
- {}
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ yacc_yyss= NULL;
+ yacc_yyvs= NULL;
+ m_set_signal_info.clear();
+ m_lock_type= TL_READ_DEFAULT;
+ m_mdl_type= MDL_SHARED_READ;
+ }
~Yacc_state();
/**
+ Reset part of the state which needs resetting before parsing
+ substatement.
+ */
+ void reset_before_substatement()
+ {
+ m_lock_type= TL_READ_DEFAULT;
+ m_mdl_type= MDL_SHARED_READ;
+ }
+
+ /**
Bison internal state stack, yyss, when dynamically allocated using
my_yyoverflow().
*/
@@ -1979,6 +2589,37 @@ public:
*/
uchar *yacc_yyvs;
+ /**
+ Fragments of parsed tree,
+ used during the parsing of SIGNAL and RESIGNAL.
+ */
+ Set_signal_information m_set_signal_info;
+
+ /**
+ Type of lock to be used for tables being added to the statement's
+ table list in table_factor, table_alias_ref, single_multi and
+ table_wild_one rules.
+ Statements which use these rules but require lock type different
+ from one specified by this member have to override it by using
+ st_select_lex::set_lock_for_tables() method.
+
+ The default value of this member is TL_READ_DEFAULT. The only two
+ cases in which we change it are:
+ - When parsing SELECT HIGH_PRIORITY.
+ - Rule for DELETE. In which we use this member to pass information
+ about type of lock from delete to single_multi part of rule.
+
+ We should try to avoid introducing new use cases as we would like
+ to get rid of this member eventually.
+ */
+ thr_lock_type m_lock_type;
+
+ /**
+ The type of requested metadata lock for tables added to
+ the statement table list.
+ */
+ enum_mdl_type m_mdl_type;
+
/*
TODO: move more attributes from the LEX structure here.
*/
@@ -2013,10 +2654,16 @@ public:
Lex_input_stream m_lip;
Yacc_state m_yacc;
+
+ void reset(char *found_semicolon, unsigned int length)
+ {
+ m_lip.reset(found_semicolon, length);
+ m_yacc.reset();
+ }
};
-struct st_lex_local: public st_lex
+struct st_lex_local: public LEX
{
static void *operator new(size_t size) throw()
{
@@ -2046,6 +2693,8 @@ extern bool is_lex_native_function(const LEX_STRING *name);
@} (End of group Semantic_Analysis)
*/
-int my_missing_function_error(const LEX_STRING &token, const char *name);
+void my_missing_function_error(const LEX_STRING &token, const char *name);
+bool is_keyword(const char *name, uint len);
#endif /* MYSQL_SERVER */
+#endif /* SQL_LEX_INCLUDED */
diff --git a/sql/sql_list.cc b/sql/sql_list.cc
index 49b649133d0..31f0ba28b85 100644
--- a/sql/sql_list.cc
+++ b/sql/sql_list.cc
@@ -18,7 +18,8 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "unireg.h"
+#include "sql_list.h"
list_node end_of_list;
diff --git a/sql/sql_list.h b/sql/sql_list.h
index c61846c22cd..5cd24236644 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -15,11 +15,22 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "my_global.h"
+#include "my_sys.h"
+#include "m_string.h" /* for TRASH */
+
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
+void *sql_alloc(size_t);
+
+#include "my_sys.h" /* alloc_root, TRASH, MY_WME,
+ MY_FAE, MY_ALLOW_ZERO_PTR */
+#include "m_string.h" /* bfill */
+#include "thr_malloc.h" /* sql_alloc */
+
/* mysql standard class memory allocator */
class Sql_alloc
@@ -519,11 +530,11 @@ struct ilink
struct ilink **prev,*next;
static void *operator new(size_t size) throw ()
{
- return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE));
+ return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE | ME_FATALERROR));
}
static void operator delete(void* ptr_arg, size_t size)
{
- my_free((uchar*)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
+ my_free(ptr_arg);
}
inline ilink()
@@ -565,15 +576,12 @@ public:
template <class T> class I_List_iterator;
-/*
- WARNING: copy constructor of this class does not create a usable
- copy, as its members may point at each other.
-*/
class base_ilist
{
+ struct ilink *first;
+ struct ilink last;
public:
- struct ilink *first,last;
inline void empty() { first= &last; last.prev= &first; }
base_ilist() { empty(); }
inline bool is_empty() { return first == &last; }
@@ -601,7 +609,31 @@ public:
{
return (first != &last) ? first : 0;
}
- friend class base_list_iterator;
+
+ /**
+ Moves list elements to new owner, and empties current owner (i.e. this).
+
+ @param[in,out] new_owner The new owner of the list elements.
+ Should be empty in input.
+ */
+
+ void move_elements_to(base_ilist *new_owner)
+ {
+ DBUG_ASSERT(new_owner->is_empty());
+ new_owner->first= first;
+ new_owner->last= last;
+ empty();
+ }
+
+ friend class base_ilist_iterator;
+ private:
+ /*
+ We don't want to allow copying of this class, as that would give us
+ two list heads containing the same elements.
+ So we declare, but don't define copy CTOR and assignment operator.
+ */
+ base_ilist(const base_ilist&);
+ void operator=(const base_ilist&);
};
@@ -634,6 +666,9 @@ public:
inline void push_back(T* a) { base_ilist::push_back(a); }
inline T* get() { return (T*) base_ilist::get(); }
inline T* head() { return (T*) base_ilist::head(); }
+ inline void move_elements_to(I_List<T>* new_owner) {
+ base_ilist::move_elements_to(new_owner);
+ }
#ifndef _lint
friend class I_List_iterator<T>;
#endif
@@ -674,4 +709,7 @@ list_copy_and_replace_each_value(List<T> &list, MEM_ROOT *mem_root)
it.replace(el->clone(mem_root));
}
+void free_list(I_List <i_string_pair> *list);
+void free_list(I_List <i_string> *list);
+
#endif // INCLUDES_MYSQL_SQL_LIST_H
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index f2aedf5d0aa..5ec6e4a0467 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2006 MySQL AB
+/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,14 +15,46 @@
/* Copy data from a textfile to table */
-#include "mysql_priv.h"
+/* 2006-12 Erik Wetterberg : LOAD XML added */
+
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_load.h"
+#include "sql_load.h"
+#include "sql_cache.h" // query_cache_*
+#include "sql_base.h" // fill_record_n_invoke_before_triggers
#include <my_dir.h>
+#include "sql_view.h" // check_key_in_view
+#include "sql_insert.h" // check_that_all_fields_are_given_values,
+ // prepare_triggers_for_insert_stmt,
+ // write_record
+#include "sql_acl.h" // INSERT_ACL, UPDATE_ACL
+#include "log_event.h" // Delete_file_log_event,
+ // Execute_load_query_log_event,
+ // LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F
#include <m_ctype.h>
#include "rpl_mi.h"
#include "sql_repl.h"
#include "sp_head.h"
#include "sql_trigger.h"
+class XML_TAG {
+public:
+ int level;
+ String field;
+ String value;
+ XML_TAG(int l, String f, String v);
+};
+
+
+XML_TAG::XML_TAG(int l, String f, String v)
+{
+ level= l;
+ field.append(f);
+ value.append(v);
+}
+
+
class READ_INFO {
File file;
uchar *buffer, /* Buffer for read text */
@@ -37,6 +69,7 @@ class READ_INFO {
bool need_end_io_cache;
IO_CACHE cache;
NET *io_net;
+ int level; /* for load xml */
public:
bool error,line_cuted,found_null,enclosed;
@@ -54,6 +87,12 @@ public:
char unescape(char chr);
int terminator(char *ptr,uint length);
bool find_start_of_fields();
+ /* load xml */
+ List<XML_TAG> taglist;
+ int read_value(int delim, String *val);
+ int read_xml();
+ int clear_level(int level);
+
/*
We need to force cache close before destructor is invoked to log
the last read block
@@ -82,10 +121,18 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
List<Item> &set_values, READ_INFO &read_info,
String &enclosed, ulong skip_lines,
bool ignore_check_option_errors);
+
+static int read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
+ List<Item> &fields_vars, List<Item> &set_fields,
+ List<Item> &set_values, READ_INFO &read_info,
+ String &enclosed, ulong skip_lines,
+ bool ignore_check_option_errors);
+
#ifndef EMBEDDED_LIBRARY
static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
const char* db_arg, /* table's database */
const char* table_name_arg,
+ bool is_concurrent,
enum enum_duplicates duplicates,
bool ignore,
bool transactional_table,
@@ -128,7 +175,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
bool is_fifo=0;
#ifndef EMBEDDED_LIBRARY
LOAD_FILE_INFO lf_info;
- THD::killed_state killed_status;
+ THD::killed_state killed_status= THD::NOT_KILLED;
#endif
char *db = table_list->db; // This is never null
/*
@@ -139,6 +186,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
char *tdb= thd->db ? thd->db : db; // Result is never null
ulong skip_lines= ex->skip_lines;
bool transactional_table;
+ bool is_concurrent;
DBUG_ENTER("mysql_load");
/*
@@ -147,7 +195,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
load data infile, so in mixed mode we go to row-based for
avoiding the problem.
*/
- thd->set_current_stmt_binlog_row_based_if_mixed();
+ thd->set_current_stmt_binlog_format_row_if_mixed();
#ifdef EMBEDDED_LIBRARY
read_file_from_client = 0; //server is always in the same process
@@ -170,7 +218,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
ER(WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED));
}
- if (open_and_lock_tables(thd, table_list))
+ if (open_and_lock_tables(thd, table_list, TRUE, 0))
DBUG_RETURN(TRUE);
if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
&thd->lex->select_lex.top_join_list,
@@ -207,6 +255,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table= table_list->table;
transactional_table= table->file->has_transactions();
+ is_concurrent= (table_list->lock_type == TL_WRITE_CONCURRENT_INSERT);
if (!fields_vars.elements)
{
@@ -314,9 +363,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
(void) fn_format(name, ex->file_name, mysql_real_data_home, "",
MY_RELATIVE_PATH | MY_UNPACK_FILENAME |
MY_RETURN_REAL_PATH);
-#if !defined(__WIN__) && ! defined(__NETWARE__)
+#if !defined(__WIN__)
MY_STAT stat_info;
- if (!my_stat(name,&stat_info,MYF(MY_WME)))
+ if (!mysql_file_stat(key_file_load, name, &stat_info, MYF(MY_WME)))
DBUG_RETURN(TRUE);
// if we are not in slave thread, the file must be:
@@ -364,7 +413,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
}
}
- if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
+ if ((file= mysql_file_open(key_file_load,
+ name, O_RDONLY, MYF(MY_WME))) < 0)
DBUG_RETURN(TRUE);
}
@@ -382,8 +432,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
info.escape_char, read_file_from_client, is_fifo);
if (read_info.error)
{
- if (file >= 0)
- my_close(file,MYF(0)); // no files in net reading
+ if (file >= 0)
+ mysql_file_close(file, MYF(0)); // no files in net reading
DBUG_RETURN(TRUE); // Can't allocate buffers
}
@@ -401,7 +451,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */
thd->cuted_fields=0L;
/* Skip lines if there is a line terminator */
- if (ex->line_term->length())
+ if (ex->line_term->length() && ex->filetype != FILETYPE_XML)
{
/* ex->skip_lines needs to be preserved for logging */
while (skip_lines > 0)
@@ -423,7 +473,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
(!table->triggers ||
!table->triggers->has_delete_triggers()))
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
- if (!thd->prelocked_mode)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
table->file->ha_start_bulk_insert((ha_rows) 0);
table->copy_blobs=1;
@@ -432,7 +482,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
- if (!field_term->length() && !enclosed->length())
+ if (ex->filetype == FILETYPE_XML) /* load xml */
+ error= read_xml_field(thd, info, table_list, fields_vars,
+ set_fields, set_values, read_info,
+ *(ex->line_term), skip_lines, ignore);
+ else if (!field_term->length() && !enclosed->length())
error= read_fixed_length(thd, info, table_list, fields_vars,
set_fields, set_values, read_info,
skip_lines, ignore);
@@ -440,7 +494,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
error= read_sep_field(thd, info, table_list, fields_vars,
set_fields, set_values, read_info,
*enclosed, skip_lines, ignore);
- if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+ table->file->ha_end_bulk_insert() && !error)
{
table->file->print_error(my_errno, MYF(0));
error= 1;
@@ -450,7 +505,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table->next_number_field=0;
}
if (file >= 0)
- my_close(file,MYF(0));
+ mysql_file_close(file, MYF(0));
free_blobs(table); /* if pack_blob was used */
table->copy_blobs=0;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -510,13 +565,14 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (lf_info.wrote_create_file)
{
int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
-
+
/* since there is already an error, the possible error of
writing binary log will be ignored */
if (thd->transaction.stmt.modified_non_trans_table)
(void) write_execute_load_query_log_event(thd, ex,
table_list->db,
table_list->table_name,
+ is_concurrent,
handle_duplicates, ignore,
transactional_table,
errcode);
@@ -533,7 +589,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
goto err;
}
sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
- (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
+ (ulong) (info.records - info.copied),
+ (ulong) thd->warning_info->statement_warn_count());
if (thd->transaction.stmt.modified_non_trans_table)
thd->transaction.all.modified_non_trans_table= TRUE;
@@ -548,8 +605,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
version for the binary log to mark that table maps are invalid
after this point.
*/
- if (thd->current_stmt_binlog_row_based)
- error= thd->binlog_flush_pending_rows_event(true);
+ if (thd->is_current_stmt_binlog_format_row())
+ error= thd->binlog_flush_pending_rows_event(TRUE, transactional_table);
else
{
/*
@@ -563,6 +620,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
error= write_execute_load_query_log_event(thd, ex,
table_list->db, table_list->table_name,
+ is_concurrent,
handle_duplicates, ignore,
transactional_table,
errcode);
@@ -598,6 +656,7 @@ err:
static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
const char* db_arg, /* table's database */
const char* table_name_arg,
+ bool is_concurrent,
enum enum_duplicates duplicates,
bool ignore,
bool transactional_table,
@@ -633,8 +692,8 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
tbl= string_buf.c_ptr_safe();
}
- Load_log_event lle(thd, ex, tdb, tbl, fv, duplicates,
- ignore, transactional_table);
+ Load_log_event lle(thd, ex, tdb, tbl, fv, is_concurrent,
+ duplicates, ignore, transactional_table);
/*
force in a LOCAL if there was one in the original.
@@ -656,7 +715,7 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
{
if (n++)
pfields.append(", ");
- if (item->name)
+ if (item->type() == Item::FIELD_ITEM)
{
pfields.append("`");
pfields.append(item->name);
@@ -708,7 +767,7 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
(uint) ((char*) fname_end - load_data_query),
(duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
(ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
- transactional_table, FALSE, errcode);
+ transactional_table, FALSE, FALSE, errcode);
return mysql_bin_log.write(&e);
}
@@ -774,9 +833,10 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (pos == read_info.row_end)
{
thd->cuted_fields++; /* Not enough fields */
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_TOO_FEW_RECORDS,
- ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_TOO_FEW_RECORDS,
+ ER(ER_WARN_TOO_FEW_RECORDS),
+ thd->warning_info->current_row_for_warning());
if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
((Field_timestamp*) field)->set_time();
}
@@ -797,9 +857,10 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (pos != read_info.row_end)
{
thd->cuted_fields++; /* To long row */
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_TOO_MANY_RECORDS,
- ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count);
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_TOO_MANY_RECORDS,
+ ER(ER_WARN_TOO_MANY_RECORDS),
+ thd->warning_info->current_row_for_warning());
}
if (thd->killed ||
@@ -832,11 +893,12 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (read_info.line_cuted)
{
thd->cuted_fields++; /* To long row */
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_TOO_MANY_RECORDS,
- ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count);
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_TOO_MANY_RECORDS,
+ ER(ER_WARN_TOO_MANY_RECORDS),
+ thd->warning_info->current_row_for_warning());
}
- thd->row_count++;
+ thd->warning_info->inc_current_row_for_warning();
continue_loop:;
}
DBUG_RETURN(test(read_info.error));
@@ -900,7 +962,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (field->reset())
{
my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
- thd->row_count);
+ thd->warning_info->current_row_for_warning());
DBUG_RETURN(1);
}
field->set_null();
@@ -972,7 +1034,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (field->reset())
{
my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
- thd->row_count);
+ thd->warning_info->current_row_for_warning());
DBUG_RETURN(1);
}
if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
@@ -986,7 +1048,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
thd->cuted_fields++;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_TOO_FEW_RECORDS,
- ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
+ ER(ER_WARN_TOO_FEW_RECORDS),
+ thd->warning_info->current_row_for_warning());
}
else if (item->type() == Item::STRING_ITEM)
{
@@ -1030,19 +1093,184 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (read_info.line_cuted)
{
thd->cuted_fields++; /* To long row */
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS),
- thd->row_count);
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS),
+ thd->warning_info->current_row_for_warning());
if (thd->killed)
DBUG_RETURN(1);
}
- thd->row_count++;
+ thd->warning_info->inc_current_row_for_warning();
continue_loop:;
}
DBUG_RETURN(test(read_info.error));
}
+/****************************************************************************
+** Read rows in xml format
+****************************************************************************/
+static int
+read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
+ List<Item> &fields_vars, List<Item> &set_fields,
+ List<Item> &set_values, READ_INFO &read_info,
+ String &row_tag, ulong skip_lines,
+ bool ignore_check_option_errors)
+{
+ List_iterator_fast<Item> it(fields_vars);
+ Item *item;
+ TABLE *table= table_list->table;
+ bool no_trans_update_stmt;
+ CHARSET_INFO *cs= read_info.read_charset;
+ DBUG_ENTER("read_xml_field");
+
+ no_trans_update_stmt= !table->file->has_transactions();
+
+ for ( ; ; it.rewind())
+ {
+ if (thd->killed)
+ {
+ thd->send_kill_message();
+ DBUG_RETURN(1);
+ }
+
+ // read row tag and save values into tag list
+ if (read_info.read_xml())
+ break;
+
+ List_iterator_fast<XML_TAG> xmlit(read_info.taglist);
+ xmlit.rewind();
+ XML_TAG *tag= NULL;
+
+#ifndef DBUG_OFF
+ DBUG_PRINT("read_xml_field", ("skip_lines=%d", (int) skip_lines));
+ while ((tag= xmlit++))
+ {
+ DBUG_PRINT("read_xml_field", ("got tag:%i '%s' '%s'",
+ tag->level, tag->field.c_ptr(),
+ tag->value.c_ptr()));
+ }
+#endif
+
+ restore_record(table, s->default_values);
+
+ while ((item= it++))
+ {
+ /* If this line is to be skipped we don't want to fill field or var */
+ if (skip_lines)
+ continue;
+
+ /* find field in tag list */
+ xmlit.rewind();
+ tag= xmlit++;
+
+ while(tag && strcmp(tag->field.c_ptr(), item->name) != 0)
+ tag= xmlit++;
+
+ if (!tag) // found null
+ {
+ if (item->type() == Item::FIELD_ITEM)
+ {
+ Field *field= ((Item_field *) item)->field;
+ field->reset();
+ field->set_null();
+ if (field == table->next_number_field)
+ table->auto_increment_field_not_null= TRUE;
+ if (!field->maybe_null())
+ {
+ if (field->type() == FIELD_TYPE_TIMESTAMP)
+ ((Field_timestamp *) field)->set_time();
+ else if (field != table->next_number_field)
+ field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_NULL_TO_NOTNULL, 1);
+ }
+ }
+ else
+ ((Item_user_var_as_out_param *) item)->set_null_value(cs);
+ continue;
+ }
+
+ if (item->type() == Item::FIELD_ITEM)
+ {
+
+ Field *field= ((Item_field *)item)->field;
+ field->set_notnull();
+ if (field == table->next_number_field)
+ table->auto_increment_field_not_null= TRUE;
+ field->store((char *) tag->value.ptr(), tag->value.length(), cs);
+ }
+ else
+ ((Item_user_var_as_out_param *) item)->set_value(
+ (char *) tag->value.ptr(),
+ tag->value.length(), cs);
+ }
+
+ if (read_info.error)
+ break;
+
+ if (skip_lines)
+ {
+ skip_lines--;
+ continue;
+ }
+
+ if (item)
+ {
+ /* Have not read any field, thus input file is simply ended */
+ if (item == fields_vars.head())
+ break;
+
+ for ( ; item; item= it++)
+ {
+ if (item->type() == Item::FIELD_ITEM)
+ {
+ /*
+ QQ: We probably should not throw warning for each field.
+ But how about intention to always have the same number
+ of warnings in THD::cuted_fields (and get rid of cuted_fields
+ in the end ?)
+ */
+ thd->cuted_fields++;
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_TOO_FEW_RECORDS,
+ ER(ER_WARN_TOO_FEW_RECORDS),
+ thd->warning_info->current_row_for_warning());
+ }
+ else
+ ((Item_user_var_as_out_param *)item)->set_null_value(cs);
+ }
+ }
+
+ if (thd->killed ||
+ fill_record_n_invoke_before_triggers(thd, set_fields, set_values,
+ ignore_check_option_errors,
+ table->triggers,
+ TRG_EVENT_INSERT))
+ DBUG_RETURN(1);
+
+ switch (table_list->view_check_option(thd,
+ ignore_check_option_errors)) {
+ case VIEW_CHECK_SKIP:
+ read_info.next_line();
+ goto continue_loop;
+ case VIEW_CHECK_ERROR:
+ DBUG_RETURN(-1);
+ }
+
+ if (write_record(thd, table, &info))
+ DBUG_RETURN(1);
+
+ /*
+ We don't need to reset auto-increment field since we are restoring
+ its default value at the beginning of each loop iteration.
+ */
+ thd->transaction.stmt.modified_non_trans_table= no_trans_update_stmt;
+ thd->warning_info->inc_current_row_for_warning();
+ continue_loop:;
+ }
+ DBUG_RETURN(test(read_info.error) || thd->is_error());
+} /* load xml end */
+
+
/* Unescape all escape characters, mark \N as null */
char
@@ -1081,6 +1309,7 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
field_term_length= field_term.length();
line_term_ptr=(char*) line_term.ptr();
line_term_length= line_term.length();
+ level= 0; /* for load xml */
if (line_start.length() == 0)
{
line_start_ptr=0;
@@ -1122,7 +1351,7 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
(is_fifo ? READ_FIFO : READ_CACHE),0L,1,
MYF(MY_WME)))
{
- my_free((uchar*) buffer,MYF(0)); /* purecov: inspected */
+ my_free(buffer); /* purecov: inspected */
buffer= NULL;
error=1;
}
@@ -1153,7 +1382,12 @@ READ_INFO::~READ_INFO()
if (!error && need_end_io_cache)
::end_io_cache(&cache);
- my_free(buffer, MYF(MY_ALLOW_ZERO_PTR));
+ if (buffer != NULL)
+ my_free(buffer);
+ List_iterator<XML_TAG> xmlit(taglist);
+ XML_TAG *t;
+ while ((t= xmlit++))
+ delete(t);
}
@@ -1496,3 +1730,319 @@ bool READ_INFO::find_start_of_fields()
}
return 0;
}
+
+
+/*
+ Clear taglist from tags with a specified level
+*/
+int READ_INFO::clear_level(int level_arg)
+{
+ DBUG_ENTER("READ_INFO::read_xml clear_level");
+ List_iterator<XML_TAG> xmlit(taglist);
+ xmlit.rewind();
+ XML_TAG *tag;
+
+ while ((tag= xmlit++))
+ {
+ if(tag->level >= level_arg)
+ {
+ xmlit.remove();
+ delete tag;
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Convert an XML entity to Unicode value.
+ Return -1 on error;
+*/
+static int
+my_xml_entity_to_char(const char *name, uint length)
+{
+ if (length == 2)
+ {
+ if (!memcmp(name, "gt", length))
+ return '>';
+ if (!memcmp(name, "lt", length))
+ return '<';
+ }
+ else if (length == 3)
+ {
+ if (!memcmp(name, "amp", length))
+ return '&';
+ }
+ else if (length == 4)
+ {
+ if (!memcmp(name, "quot", length))
+ return '"';
+ if (!memcmp(name, "apos", length))
+ return '\'';
+ }
+ return -1;
+}
+
+
+/**
+ @brief Convert newline, linefeed, tab to space
+
+ @param chr character
+
+ @details According to the "XML 1.0" standard,
+ only space (#x20) characters, carriage returns,
+ line feeds or tabs are considered as spaces.
+ Convert all of them to space (#x20) for parsing simplicity.
+*/
+static int
+my_tospace(int chr)
+{
+ return (chr == '\t' || chr == '\r' || chr == '\n') ? ' ' : chr;
+}
+
+
+/*
+ Read an xml value: handle multibyte and xml escape
+*/
+int READ_INFO::read_value(int delim, String *val)
+{
+ int chr;
+ String tmp;
+
+ for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF;)
+ {
+#ifdef USE_MB
+ if (my_mbcharlen(read_charset, chr) > 1)
+ {
+ DBUG_PRINT("read_xml",("multi byte"));
+ int i, ml= my_mbcharlen(read_charset, chr);
+ for (i= 1; i < ml; i++)
+ {
+ val->append(chr);
+ /*
+ Don't use my_tospace() in the middle of a multi-byte character
+ TODO: check that the multi-byte sequence is valid.
+ */
+ chr= GET;
+ if (chr == my_b_EOF)
+ return chr;
+ }
+ }
+#endif
+ if(chr == '&')
+ {
+ tmp.length(0);
+ for (chr= my_tospace(GET) ; chr != ';' ; chr= my_tospace(GET))
+ {
+ if (chr == my_b_EOF)
+ return chr;
+ tmp.append(chr);
+ }
+ if ((chr= my_xml_entity_to_char(tmp.ptr(), tmp.length())) >= 0)
+ val->append(chr);
+ else
+ {
+ val->append('&');
+ val->append(tmp);
+ val->append(';');
+ }
+ }
+ else
+ val->append(chr);
+ chr= GET;
+ }
+ return my_tospace(chr);
+}
+
+
+/*
+ Read a record in xml format
+ tags and attributes are stored in taglist
+ when tag set in ROWS IDENTIFIED BY is closed, we are ready and return
+*/
+int READ_INFO::read_xml()
+{
+ DBUG_ENTER("READ_INFO::read_xml");
+ int chr, chr2, chr3;
+ int delim= 0;
+ String tag, attribute, value;
+ bool in_tag= false;
+
+ tag.length(0);
+ attribute.length(0);
+ value.length(0);
+
+ for (chr= my_tospace(GET); chr != my_b_EOF ; )
+ {
+ switch(chr){
+ case '<': /* read tag */
+ /* TODO: check if this is a comment <!-- comment --> */
+ chr= my_tospace(GET);
+ if(chr == '!')
+ {
+ chr2= GET;
+ chr3= GET;
+
+ if(chr2 == '-' && chr3 == '-')
+ {
+ chr2= 0;
+ chr3= 0;
+ chr= my_tospace(GET);
+
+ while(chr != '>' || chr2 != '-' || chr3 != '-')
+ {
+ if(chr == '-')
+ {
+ chr3= chr2;
+ chr2= chr;
+ }
+ else if (chr2 == '-')
+ {
+ chr2= 0;
+ chr3= 0;
+ }
+ chr= my_tospace(GET);
+ if (chr == my_b_EOF)
+ goto found_eof;
+ }
+ break;
+ }
+ }
+
+ tag.length(0);
+ while(chr != '>' && chr != ' ' && chr != '/' && chr != my_b_EOF)
+ {
+ if(chr != delim) /* fix for the '<field name =' format */
+ tag.append(chr);
+ chr= my_tospace(GET);
+ }
+
+ // row tag should be in ROWS IDENTIFIED BY '<row>' - stored in line_term
+ if((tag.length() == line_term_length -2) &&
+ (strncmp(tag.c_ptr_safe(), line_term_ptr + 1, tag.length()) == 0))
+ {
+ DBUG_PRINT("read_xml", ("start-of-row: %i %s %s",
+ level,tag.c_ptr_safe(), line_term_ptr));
+ }
+
+ if(chr == ' ' || chr == '>')
+ {
+ level++;
+ clear_level(level + 1);
+ }
+
+ if (chr == ' ')
+ in_tag= true;
+ else
+ in_tag= false;
+ break;
+
+ case ' ': /* read attribute */
+ while(chr == ' ') /* skip blanks */
+ chr= my_tospace(GET);
+
+ if(!in_tag)
+ break;
+
+ while(chr != '=' && chr != '/' && chr != '>' && chr != my_b_EOF)
+ {
+ attribute.append(chr);
+ chr= my_tospace(GET);
+ }
+ break;
+
+ case '>': /* end tag - read tag value */
+ in_tag= false;
+ chr= read_value('<', &value);
+ if(chr == my_b_EOF)
+ goto found_eof;
+
+ /* save value to list */
+ if(tag.length() > 0 && value.length() > 0)
+ {
+ DBUG_PRINT("read_xml", ("lev:%i tag:%s val:%s",
+ level,tag.c_ptr_safe(), value.c_ptr_safe()));
+ taglist.push_front( new XML_TAG(level, tag, value));
+ }
+ tag.length(0);
+ value.length(0);
+ attribute.length(0);
+ break;
+
+ case '/': /* close tag */
+ level--;
+ chr= my_tospace(GET);
+ if(chr != '>') /* if this is an empty tag <tag /> */
+ tag.length(0); /* we should keep tag value */
+ while(chr != '>' && chr != my_b_EOF)
+ {
+ tag.append(chr);
+ chr= my_tospace(GET);
+ }
+
+ if((tag.length() == line_term_length -2) &&
+ (strncmp(tag.c_ptr_safe(), line_term_ptr + 1, tag.length()) == 0))
+ {
+ DBUG_PRINT("read_xml", ("found end-of-row %i %s",
+ level, tag.c_ptr_safe()));
+ DBUG_RETURN(0); //normal return
+ }
+ chr= my_tospace(GET);
+ break;
+
+ case '=': /* attribute name end - read the value */
+ //check for tag field and attribute name
+ if(!memcmp(tag.c_ptr_safe(), STRING_WITH_LEN("field")) &&
+ !memcmp(attribute.c_ptr_safe(), STRING_WITH_LEN("name")))
+ {
+ /*
+ this is format <field name="xx">xx</field>
+ where actual fieldname is in attribute
+ */
+ delim= my_tospace(GET);
+ tag.length(0);
+ attribute.length(0);
+ chr= '<'; /* we pretend that it is a tag */
+ level--;
+ break;
+ }
+
+ //check for " or '
+ chr= GET;
+ if (chr == my_b_EOF)
+ goto found_eof;
+ if(chr == '"' || chr == '\'')
+ {
+ delim= chr;
+ }
+ else
+ {
+ delim= ' '; /* no delimiter, use space */
+ PUSH(chr);
+ }
+
+ chr= read_value(delim, &value);
+ if(attribute.length() > 0 && value.length() > 0)
+ {
+ DBUG_PRINT("read_xml", ("lev:%i att:%s val:%s\n",
+ level + 1,
+ attribute.c_ptr_safe(),
+ value.c_ptr_safe()));
+ taglist.push_front(new XML_TAG(level + 1, attribute, value));
+ }
+ attribute.length(0);
+ value.length(0);
+ if (chr != ' ')
+ chr= my_tospace(GET);
+ break;
+
+ default:
+ chr= my_tospace(GET);
+ } /* end switch */
+ } /* end while */
+
+found_eof:
+ DBUG_PRINT("read_xml",("Found eof"));
+ eof= 1;
+ DBUG_RETURN(1);
+}
diff --git a/sql/sql_load.h b/sql/sql_load.h
new file mode 100644
index 00000000000..344b869854a
--- /dev/null
+++ b/sql/sql_load.h
@@ -0,0 +1,34 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_LOAD_INCLUDED
+#define SQL_LOAD_INCLUDED
+
+#include "sql_list.h" /* List */
+
+class Item;
+
+#include "sql_class.h" /* enum_duplicates */
+
+class sql_exchange;
+
+int mysql_load(THD *thd, sql_exchange *ex, TABLE_LIST *table_list,
+ List<Item> &fields_vars, List<Item> &set_fields,
+ List<Item> &set_values_list,
+ enum enum_duplicates handle_duplicates, bool ignore,
+ bool local_file);
+
+
+#endif /* SQL_LOAD_INCLUDED */
diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc
index 5ddf65cd1b7..c8aee307362 100644
--- a/sql/sql_locale.cc
+++ b/sql/sql_locale.cc
@@ -20,7 +20,48 @@
!! This file is built from my_locale.pl !!
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_locale.h"
+#include "sql_class.h" // THD
+#include "my_sys.h" // MY_*, NullS, NULL
+
+
+enum err_msgs_index
+{
+ en_US= 0, cs_CZ, da_DK, nl_NL, et_EE, fr_FR, de_DE, el_GR, hu_HU, it_IT,
+ ja_JP, ko_KR, no_NO, nn_NO, pl_PL, pt_PT, ro_RO, ru_RU, sr_RS, sk_SK,
+ es_ES, sv_SE, uk_UA
+} ERR_MSGS_INDEX;
+
+
+MY_LOCALE_ERRMSGS global_errmsgs[]=
+{
+ {"english", NULL},
+ {"czech", NULL},
+ {"danish", NULL},
+ {"dutch", NULL},
+ {"estonian", NULL},
+ {"french", NULL},
+ {"german", NULL},
+ {"greek", NULL},
+ {"hungarian", NULL},
+ {"italian", NULL},
+ {"japanese", NULL},
+ {"korean", NULL},
+ {"norwegian", NULL},
+ {"norwegian-ny", NULL},
+ {"polish", NULL},
+ {"portuguese", NULL},
+ {"romanian", NULL},
+ {"russian", NULL},
+ {"serbian", NULL},
+ {"slovak", NULL},
+ {"spanish", NULL},
+ {"swedish", NULL},
+ {"ukrainian", NULL},
+ {NULL, NULL}
+};
/***** LOCALE BEGIN ar_AE: Arabic - United Arab Emirates *****/
@@ -51,7 +92,11 @@ MY_LOCALE my_locale_ar_AE
&my_locale_typelib_day_names_ar_AE,
&my_locale_typelib_ab_day_names_ar_AE,
6,
- 8
+ 8,
+ '.', /* decimal point ar_AE */
+ ',', /* thousands_sep ar_AE */
+ "\x03", /* grouping ar_AE */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_AE *****/
@@ -83,7 +128,11 @@ MY_LOCALE my_locale_ar_BH
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_BH */
+ ',', /* thousands_sep ar_BH */
+ "\x03", /* grouping ar_BH */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_BH *****/
@@ -115,7 +164,11 @@ MY_LOCALE my_locale_ar_JO
&my_locale_typelib_day_names_ar_JO,
&my_locale_typelib_ab_day_names_ar_JO,
12,
- 8
+ 8,
+ '.', /* decimal point ar_JO */
+ ',', /* thousands_sep ar_JO */
+ "\x03", /* grouping ar_JO */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_JO *****/
@@ -147,7 +200,11 @@ MY_LOCALE my_locale_ar_SA
&my_locale_typelib_day_names_ar_SA,
&my_locale_typelib_ab_day_names_ar_SA,
12,
- 8
+ 8,
+ '.', /* decimal point ar_SA */
+ '\0', /* thousands_sep ar_SA */
+ "\x80", /* grouping ar_SA */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_SA *****/
@@ -179,7 +236,11 @@ MY_LOCALE my_locale_ar_SY
&my_locale_typelib_day_names_ar_SY,
&my_locale_typelib_ab_day_names_ar_SY,
12,
- 8
+ 8,
+ '.', /* decimal point ar_SY */
+ ',', /* thousands_sep ar_SY */
+ "\x03", /* grouping ar_SY */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_SY *****/
@@ -211,7 +272,11 @@ MY_LOCALE my_locale_be_BY
&my_locale_typelib_day_names_be_BY,
&my_locale_typelib_ab_day_names_be_BY,
10,
- 10
+ 10,
+ ',', /* decimal point be_BY */
+ '.', /* thousands_sep be_BY */
+ "\x03\x03", /* grouping be_BY */
+ &global_errmsgs[en_US]
);
/***** LOCALE END be_BY *****/
@@ -243,7 +308,11 @@ MY_LOCALE my_locale_bg_BG
&my_locale_typelib_day_names_bg_BG,
&my_locale_typelib_ab_day_names_bg_BG,
9,
- 10
+ 10,
+ ',', /* decimal point bg_BG */
+ '\0', /* thousands_sep bg_BG */
+ "\x03\x03", /* grouping bg_BG */
+ &global_errmsgs[en_US]
);
/***** LOCALE END bg_BG *****/
@@ -275,7 +344,11 @@ MY_LOCALE my_locale_ca_ES
&my_locale_typelib_day_names_ca_ES,
&my_locale_typelib_ab_day_names_ca_ES,
8,
- 9
+ 9,
+ ',', /* decimal point ca_ES */
+ '\0', /* thousands_sep ca_ES */
+ "\x80\x80", /* grouping ca_ES */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ca_ES *****/
@@ -307,7 +380,11 @@ MY_LOCALE my_locale_cs_CZ
&my_locale_typelib_day_names_cs_CZ,
&my_locale_typelib_ab_day_names_cs_CZ,
8,
- 7
+ 7,
+ ',', /* decimal point cs_CZ */
+ ' ', /* thousands_sep cs_CZ */
+ "\x03\x03", /* grouping cs_CZ */
+ &global_errmsgs[cs_CZ]
);
/***** LOCALE END cs_CZ *****/
@@ -339,7 +416,11 @@ MY_LOCALE my_locale_da_DK
&my_locale_typelib_day_names_da_DK,
&my_locale_typelib_ab_day_names_da_DK,
9,
- 7
+ 7,
+ ',', /* decimal point da_DK */
+ '.', /* thousands_sep da_DK */
+ "\x03\x03", /* grouping da_DK */
+ &global_errmsgs[da_DK]
);
/***** LOCALE END da_DK *****/
@@ -371,7 +452,11 @@ MY_LOCALE my_locale_de_AT
&my_locale_typelib_day_names_de_AT,
&my_locale_typelib_ab_day_names_de_AT,
9,
- 10
+ 10,
+ ',', /* decimal point de_AT */
+ '\0', /* thousands_sep de_AT */
+ "\x80\x80", /* grouping de_AT */
+ &global_errmsgs[de_DE]
);
/***** LOCALE END de_AT *****/
@@ -403,7 +488,11 @@ MY_LOCALE my_locale_de_DE
&my_locale_typelib_day_names_de_DE,
&my_locale_typelib_ab_day_names_de_DE,
9,
- 10
+ 10,
+ ',', /* decimal point de_DE */
+ '.', /* thousands_sep de_DE */
+ "\x03\x03", /* grouping de_DE */
+ &global_errmsgs[de_DE]
);
/***** LOCALE END de_DE *****/
@@ -435,7 +524,11 @@ MY_LOCALE my_locale_en_US
&my_locale_typelib_day_names_en_US,
&my_locale_typelib_ab_day_names_en_US,
9,
- 9
+ 9,
+ '.', /* decimal point en_US */
+ ',', /* thousands_sep en_US */
+ "\x03\x03", /* grouping en_US */
+ &global_errmsgs[en_US]
);
/***** LOCALE END en_US *****/
@@ -467,7 +560,11 @@ MY_LOCALE my_locale_es_ES
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ ',', /* decimal point es_ES */
+ '\0', /* thousands_sep es_ES */
+ "\x80\x80", /* grouping es_ES */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_ES *****/
@@ -499,7 +596,11 @@ MY_LOCALE my_locale_et_EE
&my_locale_typelib_day_names_et_EE,
&my_locale_typelib_ab_day_names_et_EE,
9,
- 9
+ 9,
+ ',', /* decimal point et_EE */
+ ' ', /* thousands_sep et_EE */
+ "\x03\x03", /* grouping et_EE */
+ &global_errmsgs[et_EE]
);
/***** LOCALE END et_EE *****/
@@ -531,7 +632,11 @@ MY_LOCALE my_locale_eu_ES
&my_locale_typelib_day_names_eu_ES,
&my_locale_typelib_ab_day_names_eu_ES,
9,
- 10
+ 10,
+ ',', /* decimal point eu_ES */
+ '\0', /* thousands_sep eu_ES */
+ "\x80\x80", /* grouping eu_ES */
+ &global_errmsgs[en_US]
);
/***** LOCALE END eu_ES *****/
@@ -563,7 +668,11 @@ MY_LOCALE my_locale_fi_FI
&my_locale_typelib_day_names_fi_FI,
&my_locale_typelib_ab_day_names_fi_FI,
9,
- 11
+ 11,
+ ',', /* decimal point fi_FI */
+ ' ', /* thousands_sep fi_FI */
+ "\x03\x03", /* grouping fi_FI */
+ &global_errmsgs[en_US]
);
/***** LOCALE END fi_FI *****/
@@ -595,7 +704,11 @@ MY_LOCALE my_locale_fo_FO
&my_locale_typelib_day_names_fo_FO,
&my_locale_typelib_ab_day_names_fo_FO,
9,
- 12
+ 12,
+ ',', /* decimal point fo_FO */
+ '.', /* thousands_sep fo_FO */
+ "\x03\x03", /* grouping fo_FO */
+ &global_errmsgs[en_US]
);
/***** LOCALE END fo_FO *****/
@@ -627,7 +740,11 @@ MY_LOCALE my_locale_fr_FR
&my_locale_typelib_day_names_fr_FR,
&my_locale_typelib_ab_day_names_fr_FR,
9,
- 8
+ 8,
+ ',', /* decimal point fr_FR */
+ '\0', /* thousands_sep fr_FR */
+ "\x80\x80", /* grouping fr_FR */
+ &global_errmsgs[fr_FR]
);
/***** LOCALE END fr_FR *****/
@@ -659,7 +776,11 @@ MY_LOCALE my_locale_gl_ES
&my_locale_typelib_day_names_gl_ES,
&my_locale_typelib_ab_day_names_gl_ES,
8,
- 8
+ 8,
+ ',', /* decimal point gl_ES */
+ '\0', /* thousands_sep gl_ES */
+ "\x80\x80", /* grouping gl_ES */
+ &global_errmsgs[en_US]
);
/***** LOCALE END gl_ES *****/
@@ -691,7 +812,11 @@ MY_LOCALE my_locale_gu_IN
&my_locale_typelib_day_names_gu_IN,
&my_locale_typelib_ab_day_names_gu_IN,
10,
- 8
+ 8,
+ '.', /* decimal point gu_IN */
+ ',', /* thousands_sep gu_IN */
+ "\x03", /* grouping gu_IN */
+ &global_errmsgs[en_US]
);
/***** LOCALE END gu_IN *****/
@@ -723,7 +848,11 @@ MY_LOCALE my_locale_he_IL
&my_locale_typelib_day_names_he_IL,
&my_locale_typelib_ab_day_names_he_IL,
7,
- 5
+ 5,
+ '.', /* decimal point he_IL */
+ ',', /* thousands_sep he_IL */
+ "\x03\x03", /* grouping he_IL */
+ &global_errmsgs[en_US]
);
/***** LOCALE END he_IL *****/
@@ -755,7 +884,11 @@ MY_LOCALE my_locale_hi_IN
&my_locale_typelib_day_names_hi_IN,
&my_locale_typelib_ab_day_names_hi_IN,
7,
- 9
+ 9,
+ '.', /* decimal point hi_IN */
+ ',', /* thousands_sep hi_IN */
+ "\x03", /* grouping hi_IN */
+ &global_errmsgs[en_US]
);
/***** LOCALE END hi_IN *****/
@@ -787,7 +920,11 @@ MY_LOCALE my_locale_hr_HR
&my_locale_typelib_day_names_hr_HR,
&my_locale_typelib_ab_day_names_hr_HR,
8,
- 11
+ 11,
+ ',', /* decimal point hr_HR */
+ '\0', /* thousands_sep hr_HR */
+ "\x80\x80", /* grouping hr_HR */
+ &global_errmsgs[en_US]
);
/***** LOCALE END hr_HR *****/
@@ -819,7 +956,11 @@ MY_LOCALE my_locale_hu_HU
&my_locale_typelib_day_names_hu_HU,
&my_locale_typelib_ab_day_names_hu_HU,
10,
- 9
+ 9,
+ ',', /* decimal point hu_HU */
+ '.', /* thousands_sep hu_HU */
+ "\x03\x03", /* grouping hu_HU */
+ &global_errmsgs[hu_HU]
);
/***** LOCALE END hu_HU *****/
@@ -851,7 +992,11 @@ MY_LOCALE my_locale_id_ID
&my_locale_typelib_day_names_id_ID,
&my_locale_typelib_ab_day_names_id_ID,
9,
- 6
+ 6,
+ ',', /* decimal point id_ID */
+ '.', /* thousands_sep id_ID */
+ "\x03\x03", /* grouping id_ID */
+ &global_errmsgs[en_US]
);
/***** LOCALE END id_ID *****/
@@ -883,7 +1028,11 @@ MY_LOCALE my_locale_is_IS
&my_locale_typelib_day_names_is_IS,
&my_locale_typelib_ab_day_names_is_IS,
9,
- 12
+ 12,
+ ',', /* decimal point is_IS */
+ '.', /* thousands_sep is_IS */
+ "\x03\x03", /* grouping is_IS */
+ &global_errmsgs[en_US]
);
/***** LOCALE END is_IS *****/
@@ -915,7 +1064,11 @@ MY_LOCALE my_locale_it_CH
&my_locale_typelib_day_names_it_CH,
&my_locale_typelib_ab_day_names_it_CH,
9,
- 9
+ 9,
+ ',', /* decimal point it_CH */
+ '\'', /* thousands_sep it_CH */
+ "\x03\x03", /* grouping it_CH */
+ &global_errmsgs[it_IT]
);
/***** LOCALE END it_CH *****/
@@ -947,7 +1100,11 @@ MY_LOCALE my_locale_ja_JP
&my_locale_typelib_day_names_ja_JP,
&my_locale_typelib_ab_day_names_ja_JP,
3,
- 3
+ 3,
+ '.', /* decimal point ja_JP */
+ ',', /* thousands_sep ja_JP */
+ "\x03", /* grouping ja_JP */
+ &global_errmsgs[ja_JP]
);
/***** LOCALE END ja_JP *****/
@@ -979,7 +1136,11 @@ MY_LOCALE my_locale_ko_KR
&my_locale_typelib_day_names_ko_KR,
&my_locale_typelib_ab_day_names_ko_KR,
3,
- 3
+ 3,
+ '.', /* decimal point ko_KR */
+ ',', /* thousands_sep ko_KR */
+ "\x03\x03", /* grouping ko_KR */
+ &global_errmsgs[ko_KR]
);
/***** LOCALE END ko_KR *****/
@@ -1011,7 +1172,11 @@ MY_LOCALE my_locale_lt_LT
&my_locale_typelib_day_names_lt_LT,
&my_locale_typelib_ab_day_names_lt_LT,
9,
- 14
+ 14,
+ ',', /* decimal point lt_LT */
+ '.', /* thousands_sep lt_LT */
+ "\x03\x03", /* grouping lt_LT */
+ &global_errmsgs[en_US]
);
/***** LOCALE END lt_LT *****/
@@ -1043,7 +1208,11 @@ MY_LOCALE my_locale_lv_LV
&my_locale_typelib_day_names_lv_LV,
&my_locale_typelib_ab_day_names_lv_LV,
10,
- 11
+ 11,
+ ',', /* decimal point lv_LV */
+ ' ', /* thousands_sep lv_LV */
+ "\x03\x03", /* grouping lv_LV */
+ &global_errmsgs[en_US]
);
/***** LOCALE END lv_LV *****/
@@ -1075,7 +1244,11 @@ MY_LOCALE my_locale_mk_MK
&my_locale_typelib_day_names_mk_MK,
&my_locale_typelib_ab_day_names_mk_MK,
9,
- 10
+ 10,
+ ',', /* decimal point mk_MK */
+ ' ', /* thousands_sep mk_MK */
+ "\x03\x03", /* grouping mk_MK */
+ &global_errmsgs[en_US]
);
/***** LOCALE END mk_MK *****/
@@ -1107,7 +1280,11 @@ MY_LOCALE my_locale_mn_MN
&my_locale_typelib_day_names_mn_MN,
&my_locale_typelib_ab_day_names_mn_MN,
18,
- 6
+ 6,
+ ',', /* decimal point mn_MN */
+ '.', /* thousands_sep mn_MN */
+ "\x03\x03", /* grouping mn_MN */
+ &global_errmsgs[en_US]
);
/***** LOCALE END mn_MN *****/
@@ -1139,7 +1316,11 @@ MY_LOCALE my_locale_ms_MY
&my_locale_typelib_day_names_ms_MY,
&my_locale_typelib_ab_day_names_ms_MY,
9,
- 6
+ 6,
+ '.', /* decimal point ms_MY */
+ ',', /* thousands_sep ms_MY */
+ "\x03", /* grouping ms_MY */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ms_MY *****/
@@ -1171,7 +1352,11 @@ MY_LOCALE my_locale_nb_NO
&my_locale_typelib_day_names_nb_NO,
&my_locale_typelib_ab_day_names_nb_NO,
9,
- 7
+ 7,
+ ',', /* decimal point nb_NO */
+ '.', /* thousands_sep nb_NO */
+ "\x03\x03", /* grouping nb_NO */
+ &global_errmsgs[no_NO]
);
/***** LOCALE END nb_NO *****/
@@ -1203,7 +1388,11 @@ MY_LOCALE my_locale_nl_NL
&my_locale_typelib_day_names_nl_NL,
&my_locale_typelib_ab_day_names_nl_NL,
9,
- 9
+ 9,
+ ',', /* decimal point nl_NL */
+ '\0', /* thousands_sep nl_NL */
+ "\x80\x80", /* grouping nl_NL */
+ &global_errmsgs[nl_NL]
);
/***** LOCALE END nl_NL *****/
@@ -1235,7 +1424,11 @@ MY_LOCALE my_locale_pl_PL
&my_locale_typelib_day_names_pl_PL,
&my_locale_typelib_ab_day_names_pl_PL,
11,
- 12
+ 12,
+ ',', /* decimal point pl_PL */
+ '\0', /* thousands_sep pl_PL */
+ "\x80\x80", /* grouping pl_PL */
+ &global_errmsgs[pl_PL]
);
/***** LOCALE END pl_PL *****/
@@ -1267,7 +1460,11 @@ MY_LOCALE my_locale_pt_BR
&my_locale_typelib_day_names_pt_BR,
&my_locale_typelib_ab_day_names_pt_BR,
9,
- 7
+ 7,
+ ',', /* decimal point pt_BR */
+ '\0', /* thousands_sep pt_BR */
+ "\x80\x80", /* grouping pt_BR */
+ &global_errmsgs[pt_PT]
);
/***** LOCALE END pt_BR *****/
@@ -1299,7 +1496,11 @@ MY_LOCALE my_locale_pt_PT
&my_locale_typelib_day_names_pt_PT,
&my_locale_typelib_ab_day_names_pt_PT,
9,
- 7
+ 7,
+ ',', /* decimal point pt_PT */
+ '\0', /* thousands_sep pt_PT */
+ "\x80\x80", /* grouping pt_PT */
+ &global_errmsgs[pt_PT]
);
/***** LOCALE END pt_PT *****/
@@ -1331,7 +1532,11 @@ MY_LOCALE my_locale_ro_RO
&my_locale_typelib_day_names_ro_RO,
&my_locale_typelib_ab_day_names_ro_RO,
10,
- 8
+ 8,
+ ',', /* decimal point ro_RO */
+ '.', /* thousands_sep ro_RO */
+ "\x03\x03", /* grouping ro_RO */
+ &global_errmsgs[ro_RO]
);
/***** LOCALE END ro_RO *****/
@@ -1363,7 +1568,11 @@ MY_LOCALE my_locale_ru_RU
&my_locale_typelib_day_names_ru_RU,
&my_locale_typelib_ab_day_names_ru_RU,
8,
- 11
+ 11,
+ ',', /* decimal point ru_RU */
+ ' ', /* thousands_sep ru_RU */
+ "\x03\x03", /* grouping ru_RU */
+ &global_errmsgs[ru_RU]
);
/***** LOCALE END ru_RU *****/
@@ -1395,7 +1604,11 @@ MY_LOCALE my_locale_ru_UA
&my_locale_typelib_day_names_ru_UA,
&my_locale_typelib_ab_day_names_ru_UA,
8,
- 11
+ 11,
+ ',', /* decimal point ru_UA */
+ '.', /* thousands_sep ru_UA */
+ "\x03\x03", /* grouping ru_UA */
+ &global_errmsgs[ru_RU]
);
/***** LOCALE END ru_UA *****/
@@ -1427,7 +1640,11 @@ MY_LOCALE my_locale_sk_SK
&my_locale_typelib_day_names_sk_SK,
&my_locale_typelib_ab_day_names_sk_SK,
9,
- 8
+ 8,
+ ',', /* decimal point sk_SK */
+ ' ', /* thousands_sep sk_SK */
+ "\x03\x03", /* grouping sk_SK */
+ &global_errmsgs[sk_SK]
);
/***** LOCALE END sk_SK *****/
@@ -1459,7 +1676,11 @@ MY_LOCALE my_locale_sl_SI
&my_locale_typelib_day_names_sl_SI,
&my_locale_typelib_ab_day_names_sl_SI,
9,
- 10
+ 10,
+ ',', /* decimal point sl_SI */
+ ' ', /* thousands_sep sl_SI */
+ "\x80\x80", /* grouping sl_SI */
+ &global_errmsgs[en_US]
);
/***** LOCALE END sl_SI *****/
@@ -1491,41 +1712,67 @@ MY_LOCALE my_locale_sq_AL
&my_locale_typelib_day_names_sq_AL,
&my_locale_typelib_ab_day_names_sq_AL,
7,
- 10
+ 10,
+ ',', /* decimal point sq_AL */
+ '.', /* thousands_sep sq_AL */
+ "\x03", /* grouping sq_AL */
+ &global_errmsgs[en_US]
);
/***** LOCALE END sq_AL *****/
-/***** LOCALE BEGIN sr_YU: Servian - Yugoslavia *****/
-static const char *my_locale_month_names_sr_YU[13] =
+/***** LOCALE BEGIN sr_RS: Serbian - Serbia *****/
+static const char *my_locale_month_names_sr_RS[13] =
{"januar","februar","mart","april","maj","juni","juli","avgust","septembar","oktobar","novembar","decembar", NullS };
-static const char *my_locale_ab_month_names_sr_YU[13] =
+static const char *my_locale_ab_month_names_sr_RS[13] =
{"jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec", NullS };
-static const char *my_locale_day_names_sr_YU[8] =
+static const char *my_locale_day_names_sr_RS[8] =
{"ponedeljak","utorak","sreda","Äetvrtak","petak","subota","nedelja", NullS };
-static const char *my_locale_ab_day_names_sr_YU[8] =
+static const char *my_locale_ab_day_names_sr_RS[8] =
{"pon","uto","sre","Äet","pet","sub","ned", NullS };
-static TYPELIB my_locale_typelib_month_names_sr_YU =
- { array_elements(my_locale_month_names_sr_YU)-1, "", my_locale_month_names_sr_YU, NULL };
-static TYPELIB my_locale_typelib_ab_month_names_sr_YU =
- { array_elements(my_locale_ab_month_names_sr_YU)-1, "", my_locale_ab_month_names_sr_YU, NULL };
-static TYPELIB my_locale_typelib_day_names_sr_YU =
- { array_elements(my_locale_day_names_sr_YU)-1, "", my_locale_day_names_sr_YU, NULL };
-static TYPELIB my_locale_typelib_ab_day_names_sr_YU =
- { array_elements(my_locale_ab_day_names_sr_YU)-1, "", my_locale_ab_day_names_sr_YU, NULL };
-MY_LOCALE my_locale_sr_YU
+static TYPELIB my_locale_typelib_month_names_sr_RS =
+ { array_elements(my_locale_month_names_sr_RS)-1, "", my_locale_month_names_sr_RS, NULL };
+static TYPELIB my_locale_typelib_ab_month_names_sr_RS =
+ { array_elements(my_locale_ab_month_names_sr_RS)-1, "", my_locale_ab_month_names_sr_RS, NULL };
+static TYPELIB my_locale_typelib_day_names_sr_RS =
+ { array_elements(my_locale_day_names_sr_RS)-1, "", my_locale_day_names_sr_RS, NULL };
+static TYPELIB my_locale_typelib_ab_day_names_sr_RS =
+ { array_elements(my_locale_ab_day_names_sr_RS)-1, "", my_locale_ab_day_names_sr_RS, NULL };
+MY_LOCALE my_locale_sr_YU /* Deprecated, use sr_RS instead */
(
48,
"sr_YU",
- "Servian - Yugoslavia",
+ "Serbian - Yugoslavia",
FALSE,
- &my_locale_typelib_month_names_sr_YU,
- &my_locale_typelib_ab_month_names_sr_YU,
- &my_locale_typelib_day_names_sr_YU,
- &my_locale_typelib_ab_day_names_sr_YU,
+ &my_locale_typelib_month_names_sr_RS,
+ &my_locale_typelib_ab_month_names_sr_RS,
+ &my_locale_typelib_day_names_sr_RS,
+ &my_locale_typelib_ab_day_names_sr_RS,
9,
- 10
+ 10,
+ '.', /* decimal point sr_RS */
+ '\0', /* thousands_sep sr_RS */
+ "\x80", /* grouping sr_RS */
+ &global_errmsgs[sr_RS]
);
-/***** LOCALE END sr_YU *****/
+
+MY_LOCALE my_locale_sr_RS
+(
+ 48,
+ "sr_RS",
+ "Serbian - Serbia",
+ FALSE,
+ &my_locale_typelib_month_names_sr_RS,
+ &my_locale_typelib_ab_month_names_sr_RS,
+ &my_locale_typelib_day_names_sr_RS,
+ &my_locale_typelib_ab_day_names_sr_RS,
+ 9,
+ 10,
+ '.', /* decimal point sr_RS */
+ '\0', /* thousands_sep sr_RS */
+ "\x80", /* grouping sr_RS */
+ &global_errmsgs[sr_RS]
+);
+/***** LOCALE END sr_RS *****/
/***** LOCALE BEGIN sv_SE: Swedish - Sweden *****/
static const char *my_locale_month_names_sv_SE[13] =
@@ -1555,7 +1802,11 @@ MY_LOCALE my_locale_sv_SE
&my_locale_typelib_day_names_sv_SE,
&my_locale_typelib_ab_day_names_sv_SE,
9,
- 7
+ 7,
+ ',', /* decimal point sv_SE */
+ ' ', /* thousands_sep sv_SE */
+ "\x03\x03", /* grouping sv_SE */
+ &global_errmsgs[sv_SE]
);
/***** LOCALE END sv_SE *****/
@@ -1587,7 +1838,11 @@ MY_LOCALE my_locale_ta_IN
&my_locale_typelib_day_names_ta_IN,
&my_locale_typelib_ab_day_names_ta_IN,
10,
- 8
+ 8,
+ '.', /* decimal point ta_IN */
+ ',', /* thousands_sep ta_IN */
+ "\x03\x02", /* grouping ta_IN */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ta_IN *****/
@@ -1619,7 +1874,11 @@ MY_LOCALE my_locale_te_IN
&my_locale_typelib_day_names_te_IN,
&my_locale_typelib_ab_day_names_te_IN,
10,
- 9
+ 9,
+ '.', /* decimal point te_IN */
+ ',', /* thousands_sep te_IN */
+ "\x03\x02", /* grouping te_IN */
+ &global_errmsgs[en_US]
);
/***** LOCALE END te_IN *****/
@@ -1651,7 +1910,11 @@ MY_LOCALE my_locale_th_TH
&my_locale_typelib_day_names_th_TH,
&my_locale_typelib_ab_day_names_th_TH,
10,
- 8
+ 8,
+ '.', /* decimal point th_TH */
+ ',', /* thousands_sep th_TH */
+ "\x03", /* grouping th_TH */
+ &global_errmsgs[en_US]
);
/***** LOCALE END th_TH *****/
@@ -1683,7 +1946,11 @@ MY_LOCALE my_locale_tr_TR
&my_locale_typelib_day_names_tr_TR,
&my_locale_typelib_ab_day_names_tr_TR,
7,
- 9
+ 9,
+ ',', /* decimal point tr_TR */
+ '.', /* thousands_sep tr_TR */
+ "\x03\x03", /* grouping tr_TR */
+ &global_errmsgs[en_US]
);
/***** LOCALE END tr_TR *****/
@@ -1715,7 +1982,11 @@ MY_LOCALE my_locale_uk_UA
&my_locale_typelib_day_names_uk_UA,
&my_locale_typelib_ab_day_names_uk_UA,
8,
- 9
+ 9,
+ ',', /* decimal point uk_UA */
+ '.', /* thousands_sep uk_UA */
+ "\x03\x03", /* grouping uk_UA */
+ &global_errmsgs[uk_UA]
);
/***** LOCALE END uk_UA *****/
@@ -1747,7 +2018,11 @@ MY_LOCALE my_locale_ur_PK
&my_locale_typelib_day_names_ur_PK,
&my_locale_typelib_ab_day_names_ur_PK,
6,
- 6
+ 6,
+ '.', /* decimal point ur_PK */
+ ',', /* thousands_sep ur_PK */
+ "\x03\x03", /* grouping ur_PK */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ur_PK *****/
@@ -1779,7 +2054,11 @@ MY_LOCALE my_locale_vi_VN
&my_locale_typelib_day_names_vi_VN,
&my_locale_typelib_ab_day_names_vi_VN,
16,
- 11
+ 11,
+ ',', /* decimal point vi_VN */
+ '.', /* thousands_sep vi_VN */
+ "\x03\x03", /* grouping vi_VN */
+ &global_errmsgs[en_US]
);
/***** LOCALE END vi_VN *****/
@@ -1811,7 +2090,11 @@ MY_LOCALE my_locale_zh_CN
&my_locale_typelib_day_names_zh_CN,
&my_locale_typelib_ab_day_names_zh_CN,
3,
- 3
+ 3,
+ '.', /* decimal point zh_CN */
+ ',', /* thousands_sep zh_CN */
+ "\x03", /* grouping zh_CN */
+ &global_errmsgs[en_US]
);
/***** LOCALE END zh_CN *****/
@@ -1843,7 +2126,11 @@ MY_LOCALE my_locale_zh_TW
&my_locale_typelib_day_names_zh_TW,
&my_locale_typelib_ab_day_names_zh_TW,
3,
- 2
+ 2,
+ '.', /* decimal point zh_TW */
+ ',', /* thousands_sep zh_TW */
+ "\x03", /* grouping zh_TW */
+ &global_errmsgs[en_US]
);
/***** LOCALE END zh_TW *****/
@@ -1859,7 +2146,11 @@ MY_LOCALE my_locale_ar_DZ
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_DZ */
+ ',', /* thousands_sep ar_DZ */
+ "\x03", /* grouping ar_DZ */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_DZ *****/
@@ -1875,7 +2166,11 @@ MY_LOCALE my_locale_ar_EG
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_EG */
+ ',', /* thousands_sep ar_EG */
+ "\x03", /* grouping ar_EG */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_EG *****/
@@ -1891,7 +2186,11 @@ MY_LOCALE my_locale_ar_IN
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_IN */
+ ',', /* thousands_sep ar_IN */
+ "\x03", /* grouping ar_IN */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_IN *****/
@@ -1907,7 +2206,11 @@ MY_LOCALE my_locale_ar_IQ
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_IQ */
+ ',', /* thousands_sep ar_IQ */
+ "\x03", /* grouping ar_IQ */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_IQ *****/
@@ -1923,7 +2226,11 @@ MY_LOCALE my_locale_ar_KW
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_KW */
+ ',', /* thousands_sep ar_KW */
+ "\x03", /* grouping ar_KW */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_KW *****/
@@ -1939,7 +2246,11 @@ MY_LOCALE my_locale_ar_LB
&my_locale_typelib_day_names_ar_JO,
&my_locale_typelib_ab_day_names_ar_JO,
12,
- 8
+ 8,
+ '.', /* decimal point ar_LB */
+ ',', /* thousands_sep ar_LB */
+ "\x03", /* grouping ar_LB */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_LB *****/
@@ -1955,7 +2266,11 @@ MY_LOCALE my_locale_ar_LY
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_LY */
+ ',', /* thousands_sep ar_LY */
+ "\x03", /* grouping ar_LY */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_LY *****/
@@ -1971,7 +2286,11 @@ MY_LOCALE my_locale_ar_MA
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_MA */
+ ',', /* thousands_sep ar_MA */
+ "\x03", /* grouping ar_MA */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_MA *****/
@@ -1987,7 +2306,11 @@ MY_LOCALE my_locale_ar_OM
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_OM */
+ ',', /* thousands_sep ar_OM */
+ "\x03", /* grouping ar_OM */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_OM *****/
@@ -2003,7 +2326,11 @@ MY_LOCALE my_locale_ar_QA
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_QA */
+ ',', /* thousands_sep ar_QA */
+ "\x03", /* grouping ar_QA */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_QA *****/
@@ -2019,7 +2346,11 @@ MY_LOCALE my_locale_ar_SD
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_SD */
+ ',', /* thousands_sep ar_SD */
+ "\x03", /* grouping ar_SD */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_SD *****/
@@ -2035,7 +2366,11 @@ MY_LOCALE my_locale_ar_TN
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_TN */
+ ',', /* thousands_sep ar_TN */
+ "\x03", /* grouping ar_TN */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_TN *****/
@@ -2051,7 +2386,11 @@ MY_LOCALE my_locale_ar_YE
&my_locale_typelib_day_names_ar_BH,
&my_locale_typelib_ab_day_names_ar_BH,
6,
- 8
+ 8,
+ '.', /* decimal point ar_YE */
+ ',', /* thousands_sep ar_YE */
+ "\x03", /* grouping ar_YE */
+ &global_errmsgs[en_US]
);
/***** LOCALE END ar_YE *****/
@@ -2067,7 +2406,11 @@ MY_LOCALE my_locale_de_BE
&my_locale_typelib_day_names_de_DE,
&my_locale_typelib_ab_day_names_de_DE,
9,
- 10
+ 10,
+ ',', /* decimal point de_BE */
+ '.', /* thousands_sep de_BE */
+ "\x03\x03", /* grouping de_BE */
+ &global_errmsgs[de_DE]
);
/***** LOCALE END de_BE *****/
@@ -2083,7 +2426,11 @@ MY_LOCALE my_locale_de_CH
&my_locale_typelib_day_names_de_DE,
&my_locale_typelib_ab_day_names_de_DE,
9,
- 10
+ 10,
+ '.', /* decimal point de_CH */
+ '\'', /* thousands_sep de_CH */
+ "\x03\x03", /* grouping de_CH */
+ &global_errmsgs[de_DE]
);
/***** LOCALE END de_CH *****/
@@ -2099,7 +2446,11 @@ MY_LOCALE my_locale_de_LU
&my_locale_typelib_day_names_de_DE,
&my_locale_typelib_ab_day_names_de_DE,
9,
- 10
+ 10,
+ ',', /* decimal point de_LU */
+ '.', /* thousands_sep de_LU */
+ "\x03\x03", /* grouping de_LU */
+ &global_errmsgs[de_DE]
);
/***** LOCALE END de_LU *****/
@@ -2115,7 +2466,11 @@ MY_LOCALE my_locale_en_AU
&my_locale_typelib_day_names_en_US,
&my_locale_typelib_ab_day_names_en_US,
9,
- 9
+ 9,
+ '.', /* decimal point en_AU */
+ ',', /* thousands_sep en_AU */
+ "\x03\x03", /* grouping en_AU */
+ &global_errmsgs[en_US]
);
/***** LOCALE END en_AU *****/
@@ -2131,7 +2486,11 @@ MY_LOCALE my_locale_en_CA
&my_locale_typelib_day_names_en_US,
&my_locale_typelib_ab_day_names_en_US,
9,
- 9
+ 9,
+ '.', /* decimal point en_CA */
+ ',', /* thousands_sep en_CA */
+ "\x03\x03", /* grouping en_CA */
+ &global_errmsgs[en_US]
);
/***** LOCALE END en_CA *****/
@@ -2147,7 +2506,11 @@ MY_LOCALE my_locale_en_GB
&my_locale_typelib_day_names_en_US,
&my_locale_typelib_ab_day_names_en_US,
9,
- 9
+ 9,
+ '.', /* decimal point en_GB */
+ ',', /* thousands_sep en_GB */
+ "\x03\x03", /* grouping en_GB */
+ &global_errmsgs[en_US]
);
/***** LOCALE END en_GB *****/
@@ -2163,7 +2526,11 @@ MY_LOCALE my_locale_en_IN
&my_locale_typelib_day_names_en_US,
&my_locale_typelib_ab_day_names_en_US,
9,
- 9
+ 9,
+ '.', /* decimal point en_IN */
+ ',', /* thousands_sep en_IN */
+ "\x03\x02", /* grouping en_IN */
+ &global_errmsgs[en_US]
);
/***** LOCALE END en_IN *****/
@@ -2179,7 +2546,11 @@ MY_LOCALE my_locale_en_NZ
&my_locale_typelib_day_names_en_US,
&my_locale_typelib_ab_day_names_en_US,
9,
- 9
+ 9,
+ '.', /* decimal point en_NZ */
+ ',', /* thousands_sep en_NZ */
+ "\x03\x03", /* grouping en_NZ */
+ &global_errmsgs[en_US]
);
/***** LOCALE END en_NZ *****/
@@ -2195,7 +2566,11 @@ MY_LOCALE my_locale_en_PH
&my_locale_typelib_day_names_en_US,
&my_locale_typelib_ab_day_names_en_US,
9,
- 9
+ 9,
+ '.', /* decimal point en_PH */
+ ',', /* thousands_sep en_PH */
+ "\x03", /* grouping en_PH */
+ &global_errmsgs[en_US]
);
/***** LOCALE END en_PH *****/
@@ -2211,7 +2586,11 @@ MY_LOCALE my_locale_en_ZA
&my_locale_typelib_day_names_en_US,
&my_locale_typelib_ab_day_names_en_US,
9,
- 9
+ 9,
+ '.', /* decimal point en_ZA */
+ ',', /* thousands_sep en_ZA */
+ "\x03\x03", /* grouping en_ZA */
+ &global_errmsgs[en_US]
);
/***** LOCALE END en_ZA *****/
@@ -2227,7 +2606,11 @@ MY_LOCALE my_locale_en_ZW
&my_locale_typelib_day_names_en_US,
&my_locale_typelib_ab_day_names_en_US,
9,
- 9
+ 9,
+ '.', /* decimal point en_ZW */
+ ',', /* thousands_sep en_ZW */
+ "\x03\x03", /* grouping en_ZW */
+ &global_errmsgs[en_US]
);
/***** LOCALE END en_ZW *****/
@@ -2243,7 +2626,11 @@ MY_LOCALE my_locale_es_AR
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ ',', /* decimal point es_AR */
+ '.', /* thousands_sep es_AR */
+ "\x03\x03", /* grouping es_AR */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_AR *****/
@@ -2259,7 +2646,11 @@ MY_LOCALE my_locale_es_BO
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ ',', /* decimal point es_BO */
+ '\0', /* thousands_sep es_BO */
+ "\x80\x80", /* grouping es_BO */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_BO *****/
@@ -2275,7 +2666,11 @@ MY_LOCALE my_locale_es_CL
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ ',', /* decimal point es_CL */
+ '\0', /* thousands_sep es_CL */
+ "\x80\x80", /* grouping es_CL */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_CL *****/
@@ -2291,7 +2686,11 @@ MY_LOCALE my_locale_es_CO
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ ',', /* decimal point es_CO */
+ '\0', /* thousands_sep es_CO */
+ "\x80\x80", /* grouping es_CO */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_CO *****/
@@ -2307,7 +2706,11 @@ MY_LOCALE my_locale_es_CR
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_CR */
+ '\0', /* thousands_sep es_CR */
+ "\x80\x80", /* grouping es_CR */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_CR *****/
@@ -2323,7 +2726,11 @@ MY_LOCALE my_locale_es_DO
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_DO */
+ '\0', /* thousands_sep es_DO */
+ "\x80\x80", /* grouping es_DO */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_DO *****/
@@ -2339,7 +2746,11 @@ MY_LOCALE my_locale_es_EC
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ ',', /* decimal point es_EC */
+ '\0', /* thousands_sep es_EC */
+ "\x80\x80", /* grouping es_EC */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_EC *****/
@@ -2355,7 +2766,11 @@ MY_LOCALE my_locale_es_GT
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_GT */
+ '\0', /* thousands_sep es_GT */
+ "\x80\x80", /* grouping es_GT */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_GT *****/
@@ -2371,7 +2786,11 @@ MY_LOCALE my_locale_es_HN
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_HN */
+ '\0', /* thousands_sep es_HN */
+ "\x80\x80", /* grouping es_HN */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_HN *****/
@@ -2387,7 +2806,11 @@ MY_LOCALE my_locale_es_MX
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_MX */
+ '\0', /* thousands_sep es_MX */
+ "\x80\x80", /* grouping es_MX */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_MX *****/
@@ -2403,7 +2826,11 @@ MY_LOCALE my_locale_es_NI
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_NI */
+ '\0', /* thousands_sep es_NI */
+ "\x80\x80", /* grouping es_NI */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_NI *****/
@@ -2419,7 +2846,11 @@ MY_LOCALE my_locale_es_PA
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_PA */
+ '\0', /* thousands_sep es_PA */
+ "\x80\x80", /* grouping es_PA */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_PA *****/
@@ -2435,7 +2866,11 @@ MY_LOCALE my_locale_es_PE
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_PE */
+ '\0', /* thousands_sep es_PE */
+ "\x80\x80", /* grouping es_PE */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_PE *****/
@@ -2451,7 +2886,11 @@ MY_LOCALE my_locale_es_PR
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_PR */
+ '\0', /* thousands_sep es_PR */
+ "\x80\x80", /* grouping es_PR */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_PR *****/
@@ -2467,7 +2906,11 @@ MY_LOCALE my_locale_es_PY
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ ',', /* decimal point es_PY */
+ '\0', /* thousands_sep es_PY */
+ "\x80\x80", /* grouping es_PY */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_PY *****/
@@ -2483,7 +2926,11 @@ MY_LOCALE my_locale_es_SV
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_SV */
+ '\0', /* thousands_sep es_SV */
+ "\x80\x80", /* grouping es_SV */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_SV *****/
@@ -2499,7 +2946,11 @@ MY_LOCALE my_locale_es_US
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ '.', /* decimal point es_US */
+ ',', /* thousands_sep es_US */
+ "\x03\x03", /* grouping es_US */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_US *****/
@@ -2515,7 +2966,11 @@ MY_LOCALE my_locale_es_UY
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ ',', /* decimal point es_UY */
+ '\0', /* thousands_sep es_UY */
+ "\x80\x80", /* grouping es_UY */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_UY *****/
@@ -2531,7 +2986,11 @@ MY_LOCALE my_locale_es_VE
&my_locale_typelib_day_names_es_ES,
&my_locale_typelib_ab_day_names_es_ES,
10,
- 9
+ 9,
+ ',', /* decimal point es_VE */
+ '\0', /* thousands_sep es_VE */
+ "\x80\x80", /* grouping es_VE */
+ &global_errmsgs[es_ES]
);
/***** LOCALE END es_VE *****/
@@ -2547,7 +3006,11 @@ MY_LOCALE my_locale_fr_BE
&my_locale_typelib_day_names_fr_FR,
&my_locale_typelib_ab_day_names_fr_FR,
9,
- 8
+ 8,
+ ',', /* decimal point fr_BE */
+ '.', /* thousands_sep fr_BE */
+ "\x80\x80", /* grouping fr_BE */
+ &global_errmsgs[fr_FR]
);
/***** LOCALE END fr_BE *****/
@@ -2563,7 +3026,11 @@ MY_LOCALE my_locale_fr_CA
&my_locale_typelib_day_names_fr_FR,
&my_locale_typelib_ab_day_names_fr_FR,
9,
- 8
+ 8,
+ ',', /* decimal point fr_CA */
+ ' ', /* thousands_sep fr_CA */
+ "\x80\x80", /* grouping fr_CA */
+ &global_errmsgs[fr_FR]
);
/***** LOCALE END fr_CA *****/
@@ -2579,7 +3046,11 @@ MY_LOCALE my_locale_fr_CH
&my_locale_typelib_day_names_fr_FR,
&my_locale_typelib_ab_day_names_fr_FR,
9,
- 8
+ 8,
+ ',', /* decimal point fr_CH */
+ '\0', /* thousands_sep fr_CH */
+ "\x80\x80", /* grouping fr_CH */
+ &global_errmsgs[fr_FR]
);
/***** LOCALE END fr_CH *****/
@@ -2595,7 +3066,11 @@ MY_LOCALE my_locale_fr_LU
&my_locale_typelib_day_names_fr_FR,
&my_locale_typelib_ab_day_names_fr_FR,
9,
- 8
+ 8,
+ ',', /* decimal point fr_LU */
+ '\0', /* thousands_sep fr_LU */
+ "\x80\x80", /* grouping fr_LU */
+ &global_errmsgs[fr_FR]
);
/***** LOCALE END fr_LU *****/
@@ -2611,7 +3086,11 @@ MY_LOCALE my_locale_it_IT
&my_locale_typelib_day_names_it_CH,
&my_locale_typelib_ab_day_names_it_CH,
9,
- 9
+ 9,
+ ',', /* decimal point it_IT */
+ '\0', /* thousands_sep it_IT */
+ "\x80\x80", /* grouping it_IT */
+ &global_errmsgs[it_IT]
);
/***** LOCALE END it_IT *****/
@@ -2627,7 +3106,11 @@ MY_LOCALE my_locale_nl_BE
&my_locale_typelib_day_names_nl_NL,
&my_locale_typelib_ab_day_names_nl_NL,
9,
- 9
+ 9,
+ ',', /* decimal point nl_BE */
+ '.', /* thousands_sep nl_BE */
+ "\x80\x80", /* grouping nl_BE */
+ &global_errmsgs[nl_NL]
);
/***** LOCALE END nl_BE *****/
@@ -2643,7 +3126,11 @@ MY_LOCALE my_locale_no_NO
&my_locale_typelib_day_names_nb_NO,
&my_locale_typelib_ab_day_names_nb_NO,
9,
- 7
+ 7,
+ ',', /* decimal point no_NO */
+ '.', /* thousands_sep no_NO */
+ "\x03\x03", /* grouping no_NO */
+ &global_errmsgs[no_NO]
);
/***** LOCALE END no_NO *****/
@@ -2659,7 +3146,11 @@ MY_LOCALE my_locale_sv_FI
&my_locale_typelib_day_names_sv_SE,
&my_locale_typelib_ab_day_names_sv_SE,
9,
- 7
+ 7,
+ ',', /* decimal point sv_FI */
+ ' ', /* thousands_sep sv_FI */
+ "\x03\x03", /* grouping sv_FI */
+ &global_errmsgs[sv_SE]
);
/***** LOCALE END sv_FI *****/
@@ -2675,11 +3166,87 @@ MY_LOCALE my_locale_zh_HK
&my_locale_typelib_day_names_zh_CN,
&my_locale_typelib_ab_day_names_zh_CN,
3,
- 3
+ 3,
+ '.', /* decimal point zh_HK */
+ ',', /* thousands_sep zh_HK */
+ "\x03", /* grouping zh_HK */
+ &global_errmsgs[en_US]
);
/***** LOCALE END zh_HK *****/
+/***** LOCALE BEGIN el_GR: Greek - Greece *****/
+static const char *my_locale_month_names_el_GR[13]=
+{
+ "ΙανουάÏιος", "ΦεβÏουάÏιος", "ΜάÏτιος",
+ "ΑπÏίλιος", "Μάιος", "ΙοÏνιος",
+ "ΙοÏλιος", "ΑÏγουστος", "ΣεπτέμβÏιος",
+ "ΟκτώβÏιος", "ÎοέμβÏιος", "ΔεκέμβÏιος", NullS
+};
+
+static const char *my_locale_ab_month_names_el_GR[13]=
+{
+ "Ιαν", "Φεβ", "ΜάÏ",
+ "ΑπÏ", "Μάι", "ΙοÏν",
+ "ΙοÏλ","ΑÏγ", "Σεπ",
+ "Οκτ", "Îοέ", "Δεκ", NullS
+};
+
+static const char *my_locale_day_names_el_GR[8] =
+{
+ "ΔευτέÏα", "ΤÏίτη", "ΤετάÏτη", "Πέμπτη",
+ "ΠαÏασκευή", "Σάββατο", "ΚυÏιακή", NullS
+};
+
+static const char *my_locale_ab_day_names_el_GR[8]=
+{
+ "Δευ", "ΤÏί", "Τετ", "Πέμ",
+ "ΠαÏ", "Σάβ", "ΚυÏ", NullS
+};
+
+static TYPELIB my_locale_typelib_month_names_el_GR=
+{
+ array_elements(my_locale_month_names_el_GR) - 1,
+ "", my_locale_month_names_el_GR, NULL
+};
+
+static TYPELIB my_locale_typelib_ab_month_names_el_GR=
+{
+ array_elements(my_locale_ab_month_names_el_GR)-1,
+ "", my_locale_ab_month_names_el_GR, NULL
+};
+
+static TYPELIB my_locale_typelib_day_names_el_GR=
+{
+ array_elements(my_locale_day_names_el_GR)-1,
+ "", my_locale_day_names_el_GR, NULL
+};
+
+static TYPELIB my_locale_typelib_ab_day_names_el_GR=
+{
+ array_elements(my_locale_ab_day_names_el_GR) - 1,
+ "", my_locale_ab_day_names_el_GR, NULL
+};
+
+MY_LOCALE my_locale_el_GR
+(
+ 109,
+ "el_GR",
+ "Greek - Greece",
+ FALSE,
+ &my_locale_typelib_month_names_el_GR,
+ &my_locale_typelib_ab_month_names_el_GR,
+ &my_locale_typelib_day_names_el_GR,
+ &my_locale_typelib_ab_day_names_el_GR,
+ 11, /* max mon name length */
+ 9, /* max day name length */
+ ',', /* decimal point el_GR */
+ '.', /* thousands_sep el_GR */
+ "\x80", /* grouping el_GR */
+ &global_errmsgs[el_GR]
+);
+/***** LOCALE END el_GR *****/
+
/*
The list of all locales.
Note, locales must be ordered according to their
@@ -2736,7 +3303,7 @@ MY_LOCALE *my_locales[]=
&my_locale_sk_SK,
&my_locale_sl_SI,
&my_locale_sq_AL,
- &my_locale_sr_YU,
+ &my_locale_sr_RS,
&my_locale_ta_IN,
&my_locale_te_IN,
&my_locale_th_TH,
@@ -2797,10 +3364,18 @@ MY_LOCALE *my_locales[]=
&my_locale_no_NO,
&my_locale_sv_FI,
&my_locale_zh_HK,
+ &my_locale_el_GR,
NULL
};
+MY_LOCALE *my_locales_deprecated[]=
+{
+ &my_locale_sr_YU,
+ NULL
+};
+
+
MY_LOCALE *my_locale_by_number(uint number)
{
MY_LOCALE *locale;
@@ -2813,17 +3388,60 @@ MY_LOCALE *my_locale_by_number(uint number)
}
-MY_LOCALE *my_locale_by_name(const char *name)
+static MY_LOCALE*
+my_locale_by_name(MY_LOCALE** locales, const char *name)
{
MY_LOCALE **locale;
- for (locale= my_locales; *locale != NULL; locale++)
+ for (locale= locales; *locale != NULL; locale++)
{
if (!my_strcasecmp(&my_charset_latin1, (*locale)->name, name))
- {
- // Check that locale is on its correct position in the array
- DBUG_ASSERT((*locale) == my_locales[(*locale)->number]);
return *locale;
- }
}
return NULL;
}
+
+
+MY_LOCALE *my_locale_by_name(const char *name)
+{
+ MY_LOCALE *locale;
+
+ if ((locale= my_locale_by_name(my_locales, name)))
+ {
+ // Check that locale is on its correct position in the array
+ DBUG_ASSERT(locale == my_locales[locale->number]);
+ return locale;
+ }
+ else if ((locale= my_locale_by_name(my_locales_deprecated, name)))
+ {
+ THD *thd= current_thd;
+ /*
+ Replace the deprecated locale to the corresponding
+ 'fresh' locale with the same ID.
+ */
+ locale= my_locales[locale->number];
+ if (thd)
+ {
+ // Send a warning to the client
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX),
+ name, locale->name);
+ }
+ else
+ {
+ // Send a warning to mysqld error log
+ sql_print_warning("The syntax '%s' is deprecated and will be removed. "
+ "Please use %s instead.",
+ name, locale->name);
+ }
+ }
+ return locale;
+}
+
+
+void cleanup_errmsgs()
+{
+ for (MY_LOCALE_ERRMSGS *msgs= global_errmsgs; msgs->language; msgs++)
+ {
+ my_free(msgs->errmsgs);
+ }
+}
diff --git a/sql/sql_locale.h b/sql/sql_locale.h
new file mode 100644
index 00000000000..e62660aaa47
--- /dev/null
+++ b/sql/sql_locale.h
@@ -0,0 +1,78 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_LOCALE_INCLUDED
+#define SQL_LOCALE_INCLUDED
+
+typedef struct my_locale_errmsgs
+{
+ const char *language;
+ const char **errmsgs;
+} MY_LOCALE_ERRMSGS;
+
+#include "my_global.h" /* uint */
+
+typedef struct st_typelib TYPELIB;
+
+class MY_LOCALE
+{
+public:
+ uint number;
+ const char *name;
+ const char *description;
+ const bool is_ascii;
+ TYPELIB *month_names;
+ TYPELIB *ab_month_names;
+ TYPELIB *day_names;
+ TYPELIB *ab_day_names;
+ uint max_month_name_length;
+ uint max_day_name_length;
+ uint decimal_point;
+ uint thousand_sep;
+ const char *grouping;
+ MY_LOCALE_ERRMSGS *errmsgs;
+ MY_LOCALE(uint number_par,
+ const char *name_par, const char *descr_par, bool is_ascii_par,
+ TYPELIB *month_names_par, TYPELIB *ab_month_names_par,
+ TYPELIB *day_names_par, TYPELIB *ab_day_names_par,
+ uint max_month_name_length_par, uint max_day_name_length_par,
+ uint decimal_point_par, uint thousand_sep_par,
+ const char *grouping_par, MY_LOCALE_ERRMSGS *errmsgs_par) :
+ number(number_par),
+ name(name_par), description(descr_par), is_ascii(is_ascii_par),
+ month_names(month_names_par), ab_month_names(ab_month_names_par),
+ day_names(day_names_par), ab_day_names(ab_day_names_par),
+ max_month_name_length(max_month_name_length_par),
+ max_day_name_length(max_day_name_length_par),
+ decimal_point(decimal_point_par),
+ thousand_sep(thousand_sep_par),
+ grouping(grouping_par),
+ errmsgs(errmsgs_par)
+ {}
+};
+/* Exported variables */
+
+extern MY_LOCALE my_locale_en_US;
+extern MY_LOCALE *my_locales[];
+extern MY_LOCALE *my_default_lc_messages;
+extern MY_LOCALE *my_default_lc_time_names;
+
+/* Exported functions */
+
+MY_LOCALE *my_locale_by_name(const char *name);
+MY_LOCALE *my_locale_by_number(uint number);
+void cleanup_errmsgs(void);
+
+#endif /* SQL_LOCALE_INCLUDED */
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index b082f65bfb9..e3929066361 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000, 2002, 2005 MySQL AB
+/* Copyright (C) 2000, 2002, 2005 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -21,15 +21,17 @@
* o Berkeley DB: removing unneeded log files.
*/
-#include "mysql_priv.h"
-
+#include "sql_priv.h"
+#include "sql_manager.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_base.h" // flush_tables
static bool volatile manager_thread_in_use;
static bool abort_manager;
pthread_t manager_thread;
-pthread_mutex_t LOCK_manager;
-pthread_cond_t COND_manager;
+mysql_mutex_t LOCK_manager;
+mysql_cond_t COND_manager;
struct handler_cb {
struct handler_cb *next;
@@ -42,7 +44,7 @@ bool mysql_manager_submit(void (*action)())
{
bool result= FALSE;
struct handler_cb * volatile *cb;
- pthread_mutex_lock(&LOCK_manager);
+ mysql_mutex_lock(&LOCK_manager);
cb= &cb_list;
while (*cb && (*cb)->action != action)
cb= &(*cb)->next;
@@ -57,7 +59,7 @@ bool mysql_manager_submit(void (*action)())
(*cb)->action= action;
}
}
- pthread_mutex_unlock(&LOCK_manager);
+ mysql_mutex_unlock(&LOCK_manager);
return result;
}
@@ -76,7 +78,7 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
for (;;)
{
- pthread_mutex_lock(&LOCK_manager);
+ mysql_mutex_lock(&LOCK_manager);
/* XXX: This will need to be made more general to handle different
* polling needs. */
if (flush_time)
@@ -87,26 +89,26 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
reset_flush_time = FALSE;
}
while ((!error || error == EINTR) && !abort_manager)
- error= pthread_cond_timedwait(&COND_manager, &LOCK_manager, &abstime);
+ error= mysql_cond_timedwait(&COND_manager, &LOCK_manager, &abstime);
}
else
{
while ((!error || error == EINTR) && !abort_manager)
- error= pthread_cond_wait(&COND_manager, &LOCK_manager);
+ error= mysql_cond_wait(&COND_manager, &LOCK_manager);
}
if (cb == NULL)
{
cb= cb_list;
cb_list= NULL;
}
- pthread_mutex_unlock(&LOCK_manager);
+ mysql_mutex_unlock(&LOCK_manager);
if (abort_manager)
break;
if (error == ETIMEDOUT || error == ETIME)
{
- flush_tables();
+ tdc_flush_unused_tables();
error = 0;
reset_flush_time = TRUE;
}
@@ -115,7 +117,7 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
{
struct handler_cb *next= cb->next;
cb->action();
- my_free((uchar*)cb, MYF(0));
+ my_free(cb);
cb= next;
}
}
@@ -134,7 +136,8 @@ void start_handle_manager()
if (flush_time && flush_time != ~(ulong) 0L)
{
pthread_t hThread;
- if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
+ if (mysql_thread_create(key_thread_handle_manager,
+ &hThread, &connection_attrib, handle_manager, 0))
sql_print_warning("Can't create handle_manager thread");
}
DBUG_VOID_RETURN;
@@ -146,14 +149,14 @@ void stop_handle_manager()
{
DBUG_ENTER("stop_handle_manager");
abort_manager = true;
- pthread_mutex_lock(&LOCK_manager);
+ mysql_mutex_lock(&LOCK_manager);
if (manager_thread_in_use)
{
DBUG_PRINT("quit", ("initiate shutdown of handle manager thread: 0x%lx",
(ulong)manager_thread));
- pthread_cond_signal(&COND_manager);
+ mysql_cond_signal(&COND_manager);
}
- pthread_mutex_unlock(&LOCK_manager);
+ mysql_mutex_unlock(&LOCK_manager);
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_manager.h b/sql/sql_manager.h
new file mode 100644
index 00000000000..a0ef8080aa7
--- /dev/null
+++ b/sql/sql_manager.h
@@ -0,0 +1,23 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_MANAGER_INCLUDED
+#define SQL_MANAGER_INCLUDED
+
+void start_handle_manager();
+void stop_handle_manager();
+bool mysql_manager_submit(void (*action)());
+
+#endif /* SQL_MANAGER_INCLUDED */
diff --git a/sql/sql_map.cc b/sql/sql_map.cc
deleted file mode 100644
index 55f9b08d3fe..00000000000
--- a/sql/sql_map.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-/* Copyright (C) 2000-2001, 2004-2005 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-
-#ifdef USE_PRAGMA_IMPLEMENTATION
-#pragma implementation // gcc: Class implementation
-#endif
-
-#include "mysql_priv.h"
-#include <sys/stat.h>
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-
-mapped_files::mapped_files(const char * filename,uchar *magic,uint magic_length)
-{
-#ifdef HAVE_MMAP
- name=my_strdup(filename,MYF(0));
- use_count=1;
- error=0;
- map=0;
- size=0;
- if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) >= 0)
- {
- struct stat stat_buf;
- if (!fstat(file,&stat_buf))
- {
- if (!(map=(uchar*) my_mmap(0,(size_t)(size= stat_buf.st_size),PROT_READ,
- MAP_SHARED | MAP_NORESERVE,file,
- 0L)))
- {
- error=errno;
- my_error(ER_NO_FILE_MAPPING, MYF(0), (char *) name, error);
- }
- }
- if (map && memcmp(map,magic,magic_length))
- {
- my_error(ER_WRONG_MAGIC, MYF(0), name);
- VOID(my_munmap((char*) map,(size_t)size));
- map=0;
- }
- if (!map)
- {
- VOID(my_close(file,MYF(0)));
- file= -1;
- }
- }
-#endif
-}
-
-
-mapped_files::~mapped_files()
-{
-#ifdef HAVE_MMAP
- if (file >= 0)
- {
- VOID(my_munmap((char*) map,(size_t)size));
- VOID(my_close(file,MYF(0)));
- file= -1; map=0;
- }
- my_free(name,MYF(0));
-#endif
-}
-
-
-static I_List<mapped_files> maps_in_use;
-
-/*
-** Check if a file is mapped. If it is, then return pointer to old map,
-** else alloc new object
-*/
-
-mapped_files *map_file(const char * name,uchar *magic,uint magic_length)
-{
-#ifdef HAVE_MMAP
- VOID(pthread_mutex_lock(&LOCK_mapped_file));
- I_List_iterator<mapped_files> list(maps_in_use);
- mapped_files *map;
- char path[FN_REFLEN];
- sprintf(path,"%s/%s/%s.uniq",mysql_data_home,current_thd->db,name);
- (void) unpack_filename(path,path);
-
- while ((map=list++))
- {
- if (!strcmp(path,map->name))
- break;
- }
- if (!map)
- {
- map=new mapped_files(path,magic,magic_length);
- maps_in_use.append(map);
- }
- else
- {
- map->use_count++;
- if (!map->map)
- my_error(ER_NO_FILE_MAPPING, MYF(0), path, map->error);
- }
- VOID(pthread_mutex_unlock(&LOCK_mapped_file));
- return map;
-#else
- return NULL;
-#endif
-}
-
-/*
-** free the map if there are no more users for it
-*/
-
-void unmap_file(mapped_files *map)
-{
-#ifdef HAVE_MMAP
- VOID(pthread_mutex_lock(&LOCK_mapped_file));
- if (!map->use_count--)
- delete map;
- VOID(pthread_mutex_unlock(&LOCK_mapped_file));
-#endif
-}
-
-/*****************************************************************************
-** Instansiate templates
-*****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-/* Used templates */
-template class I_List<mapped_files>;
-template class I_List_iterator<mapped_files>;
-#endif
diff --git a/sql/sql_map.h b/sql/sql_map.h
deleted file mode 100644
index a1efba0da6f..00000000000
--- a/sql/sql_map.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (C) 2000-2001, 2005 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-
-/* interface for memory mapped files */
-
-#ifdef USE_PRAGMA_INTERFACE
-#pragma interface /* gcc class implementation */
-#endif
-
-class mapped_files;
-mapped_files *map_file(const char * name,uchar *magic,uint magic_length);
-void unmap_file(mapped_files *map);
-
-class mapped_files :public ilink {
- uchar *map;
- ha_rows size;
- char *name; // name of mapped file
- File file; // >= 0 if open
- int error; // If not mapped
- uint use_count;
-
-public:
- mapped_files(const char * name,uchar *magic,uint magic_length);
- ~mapped_files();
-
- friend class mapped_file;
- friend mapped_files *map_file(const char * name,uchar *magic,
- uint magic_length);
- friend void unmap_file(mapped_files *map);
-};
-
-
-class mapped_file
-{
- mapped_files *file;
-public:
- mapped_file(const char * name,uchar *magic,uint magic_length)
- {
- file=map_file(name,magic,magic_length); /* old or new map */
- }
- ~mapped_file()
- {
- unmap_file(file); /* free map */
- }
- uchar *map()
- {
- return file->map;
- }
-};
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
deleted file mode 100644
index 21deef8c664..00000000000
--- a/sql/sql_olap.cc
+++ /dev/null
@@ -1,187 +0,0 @@
-/* Copyright (C) 2000-2006 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-
-/*
- OLAP implementation by Sinisa Milivojevic <sinisa@mysql.com>
- Inspired by code submitted by Srilakshmi <lakshmi@gdit.iiit.net>
-
- The ROLLUP code in this file has to be complitely rewritten as it's
- not good enough to satisfy the goals of MySQL.
-
- In 4.1 we will replace this with a working, superior implementation
- of ROLLUP.
-*/
-
-#ifdef DISABLED_UNTIL_REWRITTEN_IN_4_1
-
-#ifdef USE_PRAGMA_IMPLEMENTATION
-#pragma implementation // gcc: Class implementation
-#endif
-
-#include "mysql_priv.h"
-#include "sql_select.h"
-
-
-/****************************************************************************
- Functions that recursively actually creates new SELECT's
- Returns 0 if OK, 1 if error, -1 if error already printed to client
-****************************************************************************/
-
-
-static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new_fields)
-{
- THD *thd=current_thd;
- Item *item, *new_item;
- Item_null *constant= new Item_null("ALL");
-
- SELECT_LEX *new_select = (SELECT_LEX *) thd->memdup((char*) select_lex, sizeof(*select_lex));
- if (!new_select)
- return 1;
- lex->last_selects->next=new_select;
- new_select->linkage=OLAP_TYPE;
- new_select->olap=NON_EXISTING_ONE;
- new_select->group_list.elements=0;
- new_select->group_list.first=(uchar *)0;
- new_select->group_list.next=(uchar **)&new_select->group_list.first;
- List<Item> privlist;
-
- List_iterator<Item> list_it(select_lex->item_list);
- List_iterator<Item> new_it(new_fields);
-
- while ((item=list_it++))
- {
- bool not_found= TRUE;
- if (item->type()==Item::FIELD_ITEM)
- {
- Item_field *iif = (Item_field *)item;
- new_it.rewind();
- while ((new_item=new_it++))
- {
- if (new_item->type()==Item::FIELD_ITEM &&
- !strcmp(((Item_field*)new_item)->table_name,iif->table_name) &&
- !strcmp(((Item_field*)new_item)->field_name,iif->field_name))
- {
- not_found= 0;
- ((Item_field*)new_item)->db_name=iif->db_name;
- Item_field *new_one=new Item_field(&select_lex->context,
- iif->db_name, iif->table_name, iif->field_name);
- privlist.push_back(new_one);
- if (add_to_list(new_select->group_list,new_one,1))
- return 1;
- break;
- }
- }
- }
- if (not_found)
- {
- if (item->type() == Item::FIELD_ITEM)
- privlist.push_back(constant);
- else
- privlist.push_back((Item*)thd->memdup((char *)item,item->size_of()));
- }
- }
- new_select->item_list=privlist;
-
- lex->last_selects = new_select;
- return 0;
-}
-
-/****************************************************************************
- Functions that recursively creates combinations of queries for OLAP
- Returns 0 if OK, 1 if error, -1 if error already printed to client
-****************************************************************************/
-
-static int olap_combos(List<Item> old_fields, List<Item> new_fields, Item *item, LEX *lex,
- SELECT_LEX *select_lex, int position, int selection, int num_fields,
- int num_new_fields)
-{
- int sl_return = 0;
- if (position == num_new_fields)
- {
- if (item)
- new_fields.push_front(item);
- sl_return = make_new_olap_select(lex, select_lex, new_fields);
- }
- else
- {
- if (item)
- new_fields.push_front(item);
- while ((num_fields - num_new_fields >= selection - position) && !sl_return)
- {
- item = old_fields.pop();
- sl_return = olap_combos(old_fields, new_fields, item, lex, select_lex, position+1, ++selection, num_fields, num_new_fields);
- }
- }
- return sl_return;
-}
-
-
-/****************************************************************************
- Top level function for converting OLAP clauses to multiple selects
- This is also a place where clauses treatment depends on OLAP type
- Returns 0 if OK, 1 if error, -1 if error already printed to client
-****************************************************************************/
-
-int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
-{
- List<Item> item_list_copy, new_item_list;
- item_list_copy.empty();
- new_item_list.empty();
- int count=select_lex->group_list.elements;
- int sl_return=0;
-
-
- lex->last_selects=select_lex;
-
- for (ORDER *order= select_lex->group_list.first ; order ; order=order->next)
- item_list_copy.push_back(*(order->item));
-
- List<Item> all_fields(select_lex->item_list);
-
-
- if (setup_tables(lex->thd, &select_lex->context, &select_lex->top_join_list,
- select_lex->table_list.first
- &select_lex->leaf_tables, FALSE) ||
- setup_fields(lex->thd, 0, select_lex->item_list, MARK_COLUMNS_READ,
- &all_fields,1) ||
- setup_fields(lex->thd, 0, item_list_copy, MARK_COLUMNS_READ,
- &all_fields, 1))
- return -1;
-
- if (select_lex->olap == CUBE_TYPE)
- {
- for ( int i=count-1; i>=0 && !sl_return; i--)
- sl_return=olap_combos(item_list_copy, new_item_list, (Item *)0, lex, select_lex, 0, 0, count, i);
- }
- else if (select_lex->olap == ROLLUP_TYPE)
- {
- for ( int i=count-1; i>=0 && !sl_return; i--)
- {
- Item *item;
- item_list_copy.pop();
- List_iterator<Item> it(item_list_copy);
- new_item_list.empty();
- while ((item = it++))
- new_item_list.push_front(item);
- sl_return=make_new_olap_select(lex, select_lex, new_item_list);
- }
- }
- else
- sl_return=1; // impossible
- return sl_return;
-}
-
-#endif /* DISABLED_UNTIL_REWRITTEN_IN_4_1 */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index c81bd36cfad..bcf487334a0 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -14,20 +14,88 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define MYSQL_LEX 1
-#include "mysql_priv.h"
+#include "my_global.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_parse.h" // sql_kill, *_precheck, *_prepare
+#include "lock.h" // try_transactional_lock,
+ // check_transactional_lock,
+ // set_handler_table_locks,
+ // lock_global_read_lock,
+ // make_global_read_lock_block_commit
+#include "sql_base.h" // find_temporary_tablesx
+#include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE, query_cache_*
+#include "sql_show.h" // mysqld_list_*, mysqld_show_*,
+ // calc_sum_of_all_status
+#include "mysqld.h"
+#include "sql_locale.h" // my_locale_en_US
+#include "log.h" // flush_error_log
+#include "sql_view.h" // mysql_create_view, mysql_drop_view
+#include "sql_delete.h" // mysql_delete
+#include "sql_insert.h" // mysql_insert
+#include "sql_update.h" // mysql_update, mysql_multi_update
+#include "sql_partition.h" // struct partition_info
+#include "sql_db.h" // mysql_change_db, mysql_create_db,
+ // mysql_rm_db, mysql_upgrade_db,
+ // mysql_alter_db,
+ // check_db_dir_existence,
+ // my_dbopt_cleanup
+#include "sql_table.h" // mysql_create_like_table,
+ // mysql_create_table,
+ // mysql_alter_table,
+ // mysql_recreate_table,
+ // mysql_backup_table,
+ // mysql_restore_table
+#include "sql_reload.h" // reload_acl_and_cache
+#include "sql_admin.h" // mysql_assign_to_keycache
+#include "sql_connect.h" // check_user,
+ // decrease_user_connections,
+ // thd_init_client_charset, check_mqh,
+ // reset_mqh
+#include "sql_rename.h" // mysql_rename_table
+#include "sql_tablespace.h" // mysql_alter_tablespace
+#include "hostname.h" // hostname_cache_refresh
+#include "sql_acl.h" // *_ACL, check_grant, is_acl_user,
+ // has_any_table_level_privileges,
+ // mysql_drop_user, mysql_rename_user,
+ // check_grant_routine,
+ // mysql_routine_grant,
+ // mysql_show_grants,
+ // sp_grant_privileges, ...
+#include "sql_test.h" // mysql_print_status
+#include "sql_select.h" // handle_select, mysql_select,
+ // mysql_explain_union
+#include "sql_load.h" // mysql_load
+#include "sql_servers.h" // create_servers, alter_servers,
+ // drop_servers, servers_reload
+#include "sql_handler.h" // mysql_ha_open, mysql_ha_close,
+ // mysql_ha_read
+#include "sql_binlog.h" // mysql_client_binlog_statement
+#include "sql_do.h" // mysql_do
+#include "sql_help.h" // mysqld_help
+#include "rpl_constants.h" // Incident, INCIDENT_LOST_EVENTS
+#include "log_event.h"
#include "sql_repl.h"
#include "rpl_filter.h"
#include "repl_failsafe.h"
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>
+#include "rpl_handler.h"
#include "sp_head.h"
#include "sp.h"
#include "sp_cache.h"
#include "events.h"
#include "sql_trigger.h"
+#include "transaction.h"
+#include "sql_audit.h"
+#include "sql_prepare.h"
#include "debug_sync.h"
+#include "probes_mysql.h"
+#include "set_var.h"
+
+#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
/**
@defgroup Runtime_Environment Runtime Environment
@@ -45,7 +113,7 @@
"FUNCTION" : "PROCEDURE")
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
-static bool check_show_create_table_access(THD *thd, TABLE_LIST *table);
+static void sql_kill(THD *thd, ulong id, bool only_kill_query);
const char *any_db="*any*"; // Special symbol for check_access
@@ -87,127 +155,6 @@ const char *xa_state_names[]={
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED", "ROLLBACK ONLY"
};
-/**
- Mark a XA transaction as rollback-only if the RM unilaterally
- rolled back the transaction branch.
-
- @note If a rollback was requested by the RM, this function sets
- the appropriate rollback error code and transits the state
- to XA_ROLLBACK_ONLY.
-
- @return TRUE if transaction was rolled back or if the transaction
- state is XA_ROLLBACK_ONLY. FALSE otherwise.
-*/
-static bool xa_trans_rolled_back(XID_STATE *xid_state)
-{
- if (xid_state->rm_error)
- {
- switch (xid_state->rm_error) {
- case ER_LOCK_WAIT_TIMEOUT:
- my_error(ER_XA_RBTIMEOUT, MYF(0));
- break;
- case ER_LOCK_DEADLOCK:
- my_error(ER_XA_RBDEADLOCK, MYF(0));
- break;
- default:
- my_error(ER_XA_RBROLLBACK, MYF(0));
- }
- xid_state->xa_state= XA_ROLLBACK_ONLY;
- }
-
- return (xid_state->xa_state == XA_ROLLBACK_ONLY);
-}
-
-/**
- Rollback work done on behalf of at ransaction branch.
-*/
-static bool xa_trans_rollback(THD *thd)
-{
- /*
- Resource Manager error is meaningless at this point, as we perform
- explicit rollback request by user. We must reset rm_error before
- calling ha_rollback(), so thd->transaction.xid structure gets reset
- by ha_rollback()/THD::transaction::cleanup().
- */
- thd->transaction.xid_state.rm_error= 0;
-
- bool status= test(ha_rollback(thd));
-
- thd->options&= ~(ulong) OPTION_BEGIN;
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- xid_cache_delete(&thd->transaction.xid_state);
- thd->transaction.xid_state.xa_state= XA_NOTR;
-
- return status;
-}
-
-static void unlock_locked_tables(THD *thd)
-{
- if (thd->locked_tables)
- {
- thd->lock=thd->locked_tables;
- thd->locked_tables=0; // Will be automatically closed
- close_thread_tables(thd); // Free tables
- }
-}
-
-
-bool end_active_trans(THD *thd)
-{
- int error=0;
- DBUG_ENTER("end_active_trans");
- if (unlikely(thd->in_sub_stmt))
- {
- my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
- DBUG_RETURN(1);
- }
- if (thd->transaction.xid_state.xa_state != XA_NOTR)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- DBUG_RETURN(1);
- }
- if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
- OPTION_TABLE_LOCK))
- {
- DBUG_PRINT("info",("options: 0x%llx", thd->options));
- /* Safety if one did "drop table" on locked tables */
- if (!thd->locked_tables)
- thd->options&= ~OPTION_TABLE_LOCK;
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (ha_commit(thd))
- error=1;
- }
- thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- DBUG_RETURN(error);
-}
-
-
-bool begin_trans(THD *thd)
-{
- int error=0;
- if (unlikely(thd->in_sub_stmt))
- {
- my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
- return 1;
- }
- if (thd->locked_tables)
- {
- thd->lock=thd->locked_tables;
- thd->locked_tables=0; // Will be automatically closed
- close_thread_tables(thd); // Free tables
- }
- if (end_active_trans(thd))
- error= -1;
- else
- {
- thd->options|= OPTION_BEGIN;
- thd->server_status|= SERVER_STATUS_IN_TRANS;
- }
- return error;
-}
#ifdef HAVE_REPLICATION
/**
@@ -226,14 +173,49 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
for (TABLE_LIST *table= tables; table; table= table->next_global)
{
DBUG_ASSERT(table->db && table->table_name);
- if (table->updating &&
- !find_temporary_table(thd, table->db, table->table_name))
+ if (table->updating && !find_temporary_table(thd, table))
return 1;
}
return 0;
}
+/*
+ Implicitly commit a active transaction if statement requires so.
+
+ @param thd Thread handle.
+ @param mask Bitmask used for the SQL command match.
+
+*/
+static bool stmt_causes_implicit_commit(THD *thd, uint mask)
+{
+ LEX *lex= thd->lex;
+ bool skip= FALSE;
+ DBUG_ENTER("stmt_causes_implicit_commit");
+
+ if (!(sql_command_flags[lex->sql_command] & mask))
+ DBUG_RETURN(FALSE);
+
+ switch (lex->sql_command) {
+ case SQLCOM_DROP_TABLE:
+ skip= lex->drop_temporary;
+ break;
+ case SQLCOM_ALTER_TABLE:
+ case SQLCOM_CREATE_TABLE:
+ /* If CREATE TABLE of non-temporary table, do implicit commit */
+ skip= (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE);
+ break;
+ case SQLCOM_SET_OPTION:
+ skip= lex->autocommit ? FALSE : TRUE;
+ break;
+ default:
+ break;
+ }
+
+ DBUG_RETURN(!skip);
+}
+
+
/**
Mark all commands that somehow changes a table.
@@ -248,48 +230,79 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
*/
uint sql_command_flags[SQLCOM_END+1];
+uint server_command_flags[COM_END+1];
void init_update_queries(void)
{
- bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags));
-
- sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
- sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
- sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_BACKUP_TABLE]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_RESTORE_TABLE]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA;
-
- sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
- CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
- CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
- CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
- CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
- CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
- CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
- CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
- CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE;
+ /* Initialize the server command flags array. */
+ memset(server_command_flags, 0, sizeof(server_command_flags));
+
+ server_command_flags[COM_STATISTICS]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS;
+ server_command_flags[COM_PING]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS;
+ server_command_flags[COM_STMT_PREPARE]= CF_SKIP_QUESTIONS;
+ server_command_flags[COM_STMT_CLOSE]= CF_SKIP_QUESTIONS;
+ server_command_flags[COM_STMT_RESET]= CF_SKIP_QUESTIONS;
+
+ /* Initialize the sql command flags array. */
+ memset(sql_command_flags, 0, sizeof(sql_command_flags));
+
+ /*
+ In general, DDL statements do not generate row events and do not go
+ through a cache before being written to the binary log. However, the
+ CREATE TABLE...SELECT is an exception because it may generate row
+ events. For that reason, the SQLCOM_CREATE_TABLE which represents
+ a CREATE TABLE, including the CREATE TABLE...SELECT, has the
+ CF_CAN_GENERATE_ROW_EVENTS flag. The distinction between a regular
+ CREATE TABLE and the CREATE TABLE...SELECT is made in other parts of
+ the code, in particular in the Query_log_event's constructor.
+ */
+ sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_AUTO_COMMIT_TRANS |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
+ CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
+ CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_TRIGGER]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_TRIGGER]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+
+ sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
@@ -303,35 +316,35 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_SHOW_NEW_MASTER]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_NEW_MASTER]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_BINLOG_EVENTS]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_COLUMN_TYPES]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_STORAGE_ENGINES]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_AUTHORS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_AUTHORS]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CONTRIBUTORS]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_PRIVILEGES]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_PRIVILEGES]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT;
+ sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT;
sql_command_flags[SQLCOM_SHOW_ENGINE_STATUS]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_ENGINE_MUTEX]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_ENGINE_LOGS]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_PROCESSLIST]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_GRANTS]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_GRANTS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_SHOW_PROC_CODE]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
+ sql_command_flags[SQLCOM_SHOW_PROC_CODE]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_BINLOG_BASE64_EVENT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_TABLES]= (CF_STATUS_COMMAND |
CF_SHOW_TABLE_COMMAND |
@@ -340,25 +353,65 @@ void init_update_queries(void)
CF_SHOW_TABLE_COMMAND |
CF_REEXECUTION_FRAGILE);
+
+ sql_command_flags[SQLCOM_CREATE_USER]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_RENAME_USER]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_DROP_USER]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_GRANT]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_REVOKE]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_OPTIMIZE]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_CREATE_FUNCTION]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_CREATE_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_SPFUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_FUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_FUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_INSTALL_PLUGIN]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_UNINSTALL_PLUGIN]= CF_CHANGES_DATA;
+
/*
The following is used to preserver CF_ROW_COUNT during the
a CALL or EXECUTE statement, so the value generated by the
last called (or executed) statement is preserved.
See mysql_execute_command() for how CF_ROW_COUNT is used.
*/
- sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT | CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_EXECUTE]= CF_HAS_ROW_COUNT;
+ sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS;
+ sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS;
/*
The following admin table operations are allowed
on log tables.
*/
- sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND;
- sql_command_flags[SQLCOM_OPTIMIZE]= CF_WRITE_LOGS_COMMAND;
- sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND;
+ sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_OPTIMIZE]|= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CHECK]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
+
+ sql_command_flags[SQLCOM_CREATE_USER]|= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_USER]|= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_RENAME_USER]|= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_REVOKE_ALL]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_REVOKE]|= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_GRANT]|= CF_AUTO_COMMIT_TRANS;
+
+ sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_PRELOAD_KEYS]= CF_AUTO_COMMIT_TRANS;
+
+ sql_command_flags[SQLCOM_FLUSH]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_RESET]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_SERVER]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS;
}
-
+bool sqlcom_can_generate_row_events(const THD *thd)
+{
+ return (sql_command_flags[thd->lex->sql_command] &
+ CF_CAN_GENERATE_ROW_EVENTS);
+}
+
bool is_update_query(enum enum_sql_command command)
{
DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
@@ -376,25 +429,34 @@ bool is_log_table_write_query(enum enum_sql_command command)
return (sql_command_flags[command] & CF_WRITE_LOGS_COMMAND) != 0;
}
-void execute_init_command(THD *thd, sys_var_str *init_command_var,
- rw_lock_t *var_mutex)
+void execute_init_command(THD *thd, LEX_STRING *init_command,
+ mysql_rwlock_t *var_lock)
{
Vio* save_vio;
ulong save_client_capabilities;
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+ mysql_rwlock_rdlock(var_lock);
+ if (!init_command->length)
+ {
+ mysql_rwlock_unlock(var_lock);
+ return;
+ }
+
+ /*
+ copy the value under a lock, and release the lock.
+ init_command has to be executed without a lock held,
+ as it may try to change itself
+ */
+ size_t len= init_command->length;
+ char *buf= thd->strmake(init_command->str, len);
+ mysql_rwlock_unlock(var_lock);
+
+#if defined(ENABLED_PROFILING)
thd->profiling.start_new_query();
- thd->profiling.set_query_source(init_command_var->value,
- init_command_var->value_length);
+ thd->profiling.set_query_source(buf, len);
#endif
thd_proc_info(thd, "Execution of init_command");
- /*
- We need to lock init_command_var because
- during execution of init_command_var query
- values of init_command_var can't be changed
- */
- rw_rdlock(var_mutex);
save_client_capabilities= thd->client_capabilities;
thd->client_capabilities|= CLIENT_MULTI_QUERIES;
/*
@@ -403,14 +465,11 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
*/
save_vio= thd->net.vio;
thd->net.vio= 0;
- dispatch_command(COM_QUERY, thd,
- init_command_var->value,
- init_command_var->value_length);
- rw_unlock(var_mutex);
+ dispatch_command(COM_QUERY, thd, buf, len);
thd->client_capabilities= save_client_capabilities;
thd->net.vio= save_vio;
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
thd->profiling.finish_current_query();
#endif
}
@@ -418,9 +477,8 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
static void handle_bootstrap_impl(THD *thd)
{
- FILE *file=bootstrap_file;
+ MYSQL_FILE *file= bootstrap_file;
char *buff;
- const char* found_semicolon= NULL;
DBUG_ENTER("handle_bootstrap");
@@ -429,14 +487,9 @@ static void handle_bootstrap_impl(THD *thd)
thd->thread_stack= (char*) &thd;
#endif /* EMBEDDED_LIBRARY */
- if (thd->variables.max_join_size == HA_POS_ERROR)
- thd->options |= OPTION_BIG_SELECTS;
-
thd_proc_info(thd, 0);
- thd->version=refresh_version;
- thd->security_ctx->priv_user=
- thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
- thd->security_ctx->priv_host[0]=0;
+ thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
+ thd->security_ctx->priv_user[0]= thd->security_ctx->priv_host[0]=0;
/*
Make the "client" handle multiple results. This is necessary
to enable stored procedures with SELECTs and Dynamic SQL
@@ -446,12 +499,12 @@ static void handle_bootstrap_impl(THD *thd)
buff= (char*) thd->net.buff;
thd->init_for_queries();
- while (fgets(buff, thd->net.max_packet, file))
+ while (mysql_file_fgets(buff, thd->net.max_packet, file))
{
- char *query, *res;
- /* strlen() can't be deleted because fgets() doesn't return length */
+ char *query;
+ /* strlen() can't be deleted because mysql_file_fgets() doesn't return length */
ulong length= (ulong) strlen(buff);
- while (buff[length-1] != '\n' && !feof(file))
+ while (buff[length-1] != '\n' && !mysql_file_feof(file))
{
/*
We got only a part of the current string. Will try to increase
@@ -460,18 +513,12 @@ static void handle_bootstrap_impl(THD *thd)
/* purecov: begin tested */
if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
{
- net_end_statement(thd);
+ thd->protocol->end_statement();
bootstrap_error= 1;
break;
}
buff= (char*) thd->net.buff;
- res= fgets(buff + length, thd->net.max_packet - length, file);
- if (!res && !feof(file))
- {
- net_end_statement(thd);
- bootstrap_error= 1;
- break;
- }
+ mysql_file_fgets(buff + length, thd->net.max_packet - length, file);
length+= (ulong) strlen(buff + length);
/* purecov: end */
}
@@ -490,9 +537,9 @@ static void handle_bootstrap_impl(THD *thd)
query= (char *) thd->memdup_w_gap(buff, length + 1,
thd->db_length + 1 +
QUERY_CACHE_FLAGS_SIZE);
- thd->set_query(query, length);
- DBUG_PRINT("query",("%-.4096s", thd->query()));
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+ thd->set_query_and_id(query, length, thd->charset(), next_query_id());
+ DBUG_PRINT("query",("%-.4096s",thd->query()));
+#if defined(ENABLED_PROFILING)
thd->profiling.start_new_query();
thd->profiling.set_query_source(thd->query(), length);
#endif
@@ -501,15 +548,21 @@ static void handle_bootstrap_impl(THD *thd)
We don't need to obtain LOCK_thread_count here because in bootstrap
mode we have only one thread.
*/
- thd->query_id=next_query_id();
thd->set_time();
- mysql_parse(thd, thd->query(), length, & found_semicolon);
- close_thread_tables(thd); // Free tables
+ Parser_state parser_state;
+ if (parser_state.init(thd, thd->query(), length))
+ {
+ thd->protocol->end_statement();
+ bootstrap_error= 1;
+ break;
+ }
+
+ mysql_parse(thd, thd->query(), length, &parser_state);
bootstrap_error= thd->is_error();
- net_end_statement(thd);
+ thd->protocol->end_statement();
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
thd->profiling.finish_current_query();
#endif
@@ -517,9 +570,7 @@ static void handle_bootstrap_impl(THD *thd)
break;
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
-#ifdef USING_TRANSACTIONS
free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
-#endif
}
DBUG_VOID_RETURN;
@@ -536,6 +587,14 @@ pthread_handler_t handle_bootstrap(void *arg)
{
THD *thd=(THD*) arg;
+ mysql_thread_set_psi_id(thd->thread_id);
+
+ do_handle_bootstrap(thd);
+ return 0;
+}
+
+void do_handle_bootstrap(THD *thd)
+{
/* The following must be called before DBUG_ENTER */
thd->thread_stack= (char*) &thd;
if (my_thread_init() || thd->store_globals())
@@ -555,59 +614,19 @@ end:
delete thd;
#ifndef EMBEDDED_LIBRARY
- (void) pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thread_count--;
in_bootstrap= FALSE;
- (void) pthread_cond_broadcast(&COND_thread_count);
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
my_thread_end();
pthread_exit(0);
#endif
- return 0;
+ return;
}
-/**
- @brief Check access privs for a MERGE table and fix children lock types.
-
- @param[in] thd thread handle
- @param[in] db database name
- @param[in,out] table_list list of child tables (merge_list)
- lock_type and optionally db set per table
-
- @return status
- @retval 0 OK
- @retval != 0 Error
-
- @detail
- This function is used for write access to MERGE tables only
- (CREATE TABLE, ALTER TABLE ... UNION=(...)). Set TL_WRITE for
- every child. Set 'db' for every child if not present.
-*/
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-static bool check_merge_table_access(THD *thd, char *db,
- TABLE_LIST *table_list)
-{
- int error= 0;
-
- if (table_list)
- {
- /* Check that all tables use the current database */
- TABLE_LIST *tlist;
-
- for (tlist= table_list; tlist; tlist= tlist->next_local)
- {
- if (!tlist->db || !tlist->db[0])
- tlist->db= db; /* purecov: inspected */
- }
- error= check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
- table_list, UINT_MAX, FALSE);
- }
- return error;
-}
-#endif
-
/* This works because items are allocated with sql_alloc() */
void free_items(Item *item)
@@ -634,154 +653,6 @@ void cleanup_items(Item *item)
DBUG_VOID_RETURN;
}
-/**
- Handle COM_TABLE_DUMP command.
-
- @param thd thread handle
- @param db database name or an empty string. If empty,
- the current database of the connection is used
- @param tbl_name name of the table to dump
-
- @note
- This function is written to handle one specific command only.
-
- @retval
- 0 success
- @retval
- 1 error, the error message is set in THD
-*/
-
-static
-int mysql_table_dump(THD *thd, LEX_STRING *db, LEX_STRING *table_name)
-{
- TABLE* table;
- TABLE_LIST* table_list;
- int error = 0;
- DBUG_ENTER("mysql_table_dump");
- if (db->length == 0)
- {
- db->str= thd->db; /* purecov: inspected */
- db->length= thd->db_length; /* purecov: inspected */
- }
- if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
- DBUG_RETURN(1); // out of memory
- table_list->db= db->str;
- table_list->table_name= table_list->alias= table_name->str;
- table_list->lock_type= TL_READ_NO_INSERT;
- table_list->prev_global= &table_list; // can be removed after merge with 4.1
-
- if (check_db_name(db))
- {
- /* purecov: begin inspected */
- my_error(ER_WRONG_DB_NAME ,MYF(0), db->str ? db->str : "NULL");
- goto err;
- /* purecov: end */
- }
- if (!table_name->length ||
- check_table_name(table_name->str, table_name->length, TRUE))
- {
- my_error(ER_WRONG_TABLE_NAME, MYF(0),
- table_name->str ? table_name->str : "NULL");
- error= 1;
- goto err;
- }
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, table_name->str);
-
- if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT, 0)))
- DBUG_RETURN(1);
-
- if (check_one_table_access(thd, SELECT_ACL, table_list))
- goto err;
- thd->free_list = 0;
- thd->set_query(table_name->str, table_name->length);
- if ((error = mysqld_dump_create_info(thd, table_list, -1)))
- {
- my_error(ER_GET_ERRNO, MYF(0), my_errno);
- goto err;
- }
- net_flush(&thd->net);
- if ((error= table->file->dump(thd,-1)))
- my_error(ER_GET_ERRNO, MYF(0), error);
-
-err:
- DBUG_RETURN(error);
-}
-
-/**
- Ends the current transaction and (maybe) begin the next.
-
- @param thd Current thread
- @param completion Completion type
-
- @retval
- 0 OK
-*/
-
-int end_trans(THD *thd, enum enum_mysql_completiontype completion)
-{
- bool do_release= 0;
- int res= 0;
- DBUG_ENTER("end_trans");
-
- if (unlikely(thd->in_sub_stmt))
- {
- my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
- DBUG_RETURN(1);
- }
- if (thd->transaction.xid_state.xa_state != XA_NOTR)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- DBUG_RETURN(1);
- }
- switch (completion) {
- case COMMIT:
- /*
- We don't use end_active_trans() here to ensure that this works
- even if there is a problem with the OPTION_AUTO_COMMIT flag
- (Which of course should never happen...)
- */
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- res= ha_commit(thd);
- thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- break;
- case COMMIT_RELEASE:
- do_release= 1; /* fall through */
- case COMMIT_AND_CHAIN:
- res= end_active_trans(thd);
- if (!res && completion == COMMIT_AND_CHAIN)
- res= begin_trans(thd);
- break;
- case ROLLBACK_RELEASE:
- do_release= 1; /* fall through */
- case ROLLBACK:
- case ROLLBACK_AND_CHAIN:
- {
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (ha_rollback(thd))
- res= -1;
- thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- if (!res && (completion == ROLLBACK_AND_CHAIN))
- res= begin_trans(thd);
- break;
- }
- default:
- res= -1;
- my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
- DBUG_RETURN(-1);
- }
-
- if (res < 0)
- my_error(thd->killed_errno(), MYF(0));
- else if ((res == 0) && do_release)
- thd->killed= THD::KILL_CONNECTION;
-
- DBUG_RETURN(res);
-}
-
#ifndef EMBEDDED_LIBRARY
/**
@@ -815,7 +686,7 @@ bool do_command(THD *thd)
This thread will do a blocking read from the client which
will be interrupted when the next command is received from
the client, the connection is closed or "net_wait_timeout"
- number of seconds has passed
+ number of seconds has passed.
*/
my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
@@ -824,15 +695,27 @@ bool do_command(THD *thd)
Consider moving to init_connect() instead.
*/
thd->clear_error(); // Clear error message
- thd->main_da.reset_diagnostics_area();
+ thd->stmt_da->reset_diagnostics_area();
net_new_transaction(net);
- packet_length= my_net_read(net);
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
- thd->profiling.start_new_query();
-#endif
- if (packet_length == packet_error)
+ /*
+ Synchronization point for testing of KILL_CONNECTION.
+ This sync point can wait here, to simulate slow code execution
+ between the last test of thd->killed and blocking in read().
+
+ The goal of this test is to verify that a connection does not
+ hang, if it is killed at this point of execution.
+ (Bug#37780 - main.kill fails randomly)
+
+ Note that the sync point wait itself will be terminated by a
+ kill. In this case it consumes a condition broadcast, but does
+ not change anything else. The consumed broadcast should not
+ matter here, because the read/recv() below doesn't use it.
+ */
+ DEBUG_SYNC(thd, "before_do_command_net_read");
+
+ if ((packet_length= my_net_read(net)) == packet_error)
{
DBUG_PRINT("info",("Got error %d reading command from socket %s",
net->error,
@@ -842,7 +725,7 @@ bool do_command(THD *thd)
/* The error must be set. */
DBUG_ASSERT(thd->is_error());
- net_end_statement(thd);
+ thd->protocol->end_statement();
if (net->error != 3)
{
@@ -889,9 +772,6 @@ bool do_command(THD *thd)
return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));
out:
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
- thd->profiling.finish_current_query();
-#endif
DBUG_RETURN(return_value);
}
#endif /* EMBEDDED_LIBRARY */
@@ -993,6 +873,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_ENTER("dispatch_command");
DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command));
+#if defined(ENABLED_PROFILING)
+ thd->profiling.start_new_query();
+#endif
+ MYSQL_COMMAND_START(thd->thread_id, command,
+ thd->security_ctx->priv_user,
+ (char *) thd->security_ctx->host_or_ip);
+
thd->command=command;
/*
Commands which always take a long time are logged into
@@ -1013,30 +900,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->security_ctx->master_access|= SHUTDOWN_ACL;
command= COM_SHUTDOWN;
}
-
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id= global_query_id;
-
- switch( command ) {
- /* Ignore these statements. */
- case COM_STATISTICS:
- case COM_PING:
- break;
- /* Only increase id on these statements but don't count them. */
- case COM_STMT_PREPARE:
- case COM_STMT_CLOSE:
- case COM_STMT_RESET:
- next_query_id();
- break;
- /* Increase id and count all other statements. */
- default:
- statistic_increment(thd->status_var.questions, &LOCK_status);
+ thd->set_query_id(get_query_id());
+ if (!(server_command_flags[command] & CF_SKIP_QUERY_ID))
next_query_id();
- }
+ inc_thread_running();
- thread_running++;
- /* TODO: set thd->lex->sql_command to SQLCOM_END here */
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ if (!(server_command_flags[command] & CF_SKIP_QUESTIONS))
+ statistic_increment(thd->status_var.questions, &LOCK_status);
/**
Clear the set of flags that are expected to be cleared at the
@@ -1065,133 +935,37 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
#endif
- case COM_TABLE_DUMP:
- {
- LEX_STRING db, table;
- /* Safe because there is always a trailing \0 at the end of the packet */
- uint db_len= *(uchar*) packet;
- if (db_len + 1 > packet_length || db_len > NAME_LEN)
- {
- my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
- break;
- }
- /* Safe because there is always a trailing \0 at the end of the packet */
- uint tbl_len= *(uchar*) (packet + db_len + 1);
- if (db_len + tbl_len + 2 > packet_length || tbl_len > NAME_LEN)
- {
- my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
- break;
- }
-
- status_var_increment(thd->status_var.com_other);
- thd->enable_slow_log= opt_log_slow_admin_statements;
- db.str= (char*) thd->alloc(db_len + tbl_len + 2);
- if (!db.str)
- {
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
- break;
- }
- db.length= db_len;
- table.length= tbl_len;
- table.str= strmake(db.str, packet + 1, db_len) + 1;
- strmake(table.str, packet + db_len + 2, tbl_len);
- if (mysql_table_dump(thd, &db, &table) == 0)
- thd->main_da.disable_status();
- break;
- }
case COM_CHANGE_USER:
{
status_var_increment(thd->status_var.com_other);
- char *user= (char*) packet, *packet_end= packet + packet_length;
- /* Safe because there is always a trailing \0 at the end of the packet */
- char *passwd= strend(user)+1;
thd->change_user();
thd->clear_error(); // if errors from rollback
- /*
- Old clients send null-terminated string ('\0' for empty string) for
- password. New clients send the size (1 byte) + string (not null
- terminated, so also '\0' for empty string).
+ /* acl_authenticate() takes the data from net->read_pos */
+ net->read_pos= (uchar*)packet;
- Cast *passwd to an unsigned char, so that it doesn't extend the sign
- for *passwd > 127 and become 2**32-127 after casting to uint.
- */
- char db_buff[NAME_LEN+1]; // buffer to store db in utf8
- char *db= passwd;
- char *save_db;
- /*
- If there is no password supplied, the packet must contain '\0',
- in any type of handshake (4.1 or pre-4.1).
- */
- if (passwd >= packet_end)
- {
- my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
- break;
- }
- uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- (uchar)(*passwd++) : strlen(passwd));
- uint dummy_errors, save_db_length, db_length;
- int res;
+ uint save_db_length= thd->db_length;
+ char *save_db= thd->db;
+ USER_CONN *save_user_connect= thd->user_connect;
Security_context save_security_ctx= *thd->security_ctx;
- USER_CONN *save_user_connect;
-
- db+= passwd_len + 1;
- /*
- Database name is always NUL-terminated, so in case of empty database
- the packet must contain at least the trailing '\0'.
- */
- if (db >= packet_end)
- {
- my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
- break;
- }
- db_length= strlen(db);
-
- char *ptr= db + db_length + 1;
- uint cs_number= 0;
+ CHARSET_INFO *save_character_set_client=
+ thd->variables.character_set_client;
+ CHARSET_INFO *save_collation_connection=
+ thd->variables.collation_connection;
+ CHARSET_INFO *save_character_set_results=
+ thd->variables.character_set_results;
- if (ptr < packet_end)
+ if (acl_authenticate(thd, 0, packet_length))
{
- if (ptr + 2 > packet_end)
- {
- my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
- break;
- }
-
- cs_number= uint2korr(ptr);
- }
-
- /* Convert database name to utf8 */
- db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
- system_charset_info, db, db_length,
- thd->charset(), &dummy_errors)]= 0;
- db= db_buff;
-
- /* Save user and privileges */
- save_db_length= thd->db_length;
- save_db= thd->db;
- save_user_connect= thd->user_connect;
-
- if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
- {
- thd->security_ctx->user= save_security_ctx.user;
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
- break;
- }
-
- /* Clear variables that are allocated */
- thd->user_connect= 0;
- thd->security_ctx->priv_user= thd->security_ctx->user;
- res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
-
- if (res)
- {
- x_free(thd->security_ctx->user);
+ my_free(thd->security_ctx->user);
*thd->security_ctx= save_security_ctx;
thd->user_connect= save_user_connect;
- thd->db= save_db;
- thd->db_length= save_db_length;
+ thd->reset_db (save_db, save_db_length);
+ thd->variables.character_set_client= save_character_set_client;
+ thd->variables.collation_connection= save_collation_connection;
+ thd->variables.character_set_results= save_character_set_results;
+ thd->update_charset();
}
else
{
@@ -1200,14 +974,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (save_user_connect)
decrease_user_connections(save_user_connect);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
- x_free(save_db);
- x_free(save_security_ctx.user);
-
- if (cs_number)
- {
- thd_init_client_charset(thd, cs_number);
- thd->update_charset();
- }
+ my_free(save_db);
+ my_free(save_security_ctx.user);
}
break;
}
@@ -1245,31 +1013,36 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
if (alloc_query(thd, packet, packet_length))
break; // fatal error is set
+ MYSQL_QUERY_START(thd->query(), thd->thread_id,
+ (char *) (thd->db ? thd->db : ""),
+ thd->security_ctx->priv_user,
+ (char *) thd->security_ctx->host_or_ip);
char *packet_end= thd->query() + thd->query_length();
/* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */
- const char* end_of_stmt= NULL;
general_log_write(thd, command, thd->query(), thd->query_length());
DBUG_PRINT("query",("%-.4096s",thd->query()));
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
thd->profiling.set_query_source(thd->query(), thd->query_length());
#endif
+ Parser_state parser_state;
+ if (parser_state.init(thd, thd->query(), thd->query_length()))
+ break;
- if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),QUERY_PRIOR);
-
- mysql_parse(thd, thd->query(), thd->query_length(), &end_of_stmt);
+ mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
- while (!thd->killed && (end_of_stmt != NULL) && ! thd->is_error())
+ while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) &&
+ ! thd->is_error())
{
- char *beginning_of_next_stmt= (char*) end_of_stmt;
-
- net_end_statement(thd);
- query_cache_end_of_result(thd);
/*
Multiple queries exits, execute them individually
*/
- close_thread_tables(thd);
+ char *beginning_of_next_stmt= (char*) parser_state.m_lip.found_semicolon;
+
+ /* Finalize server status flags after executing a statement. */
+ thd->update_server_status();
+ thd->protocol->end_statement();
+ query_cache_end_of_result(thd);
ulong length= (ulong)(packet_end - beginning_of_next_stmt);
log_slow_statement(thd);
@@ -1281,27 +1054,34 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
length--;
}
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+ if (MYSQL_QUERY_DONE_ENABLED())
+ {
+ MYSQL_QUERY_DONE(thd->is_error());
+ }
+
+#if defined(ENABLED_PROFILING)
thd->profiling.finish_current_query();
thd->profiling.start_new_query("continuing");
thd->profiling.set_query_source(beginning_of_next_stmt, length);
#endif
- thd->set_query(beginning_of_next_stmt, length);
- VOID(pthread_mutex_lock(&LOCK_thread_count));
+ MYSQL_QUERY_START(beginning_of_next_stmt, thd->thread_id,
+ (char *) (thd->db ? thd->db : ""),
+ thd->security_ctx->priv_user,
+ (char *) thd->security_ctx->host_or_ip);
+
+ thd->set_query_and_id(beginning_of_next_stmt, length,
+ thd->charset(), next_query_id());
/*
Count each statement from the client.
*/
statistic_increment(thd->status_var.questions, &LOCK_status);
- thd->query_id= next_query_id();
thd->set_time(); /* Reset the query start time. */
+ parser_state.reset(beginning_of_next_stmt, length);
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- mysql_parse(thd, beginning_of_next_stmt, length, &end_of_stmt);
+ mysql_parse(thd, beginning_of_next_stmt, length, &parser_state);
}
- if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),WAIT_PRIOR);
DBUG_PRINT("info",("query ready"));
break;
}
@@ -1315,40 +1095,56 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
char *fields, *packet_end= packet + packet_length, *arg_end;
/* Locked closure of all tables */
TABLE_LIST table_list;
- LEX_STRING conv_name;
-
- /* used as fields initializator */
- lex_start(thd);
+ LEX_STRING table_name;
+ LEX_STRING db;
+ /*
+ SHOW statements should not add the used tables to the list of tables
+ used in a transaction.
+ */
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]);
- bzero((char*) &table_list,sizeof(table_list));
- if (thd->copy_db_to(&table_list.db, &table_list.db_length))
+ if (thd->copy_db_to(&db.str, &db.length))
break;
/*
We have name + wildcard in packet, separated by endzero
*/
arg_end= strend(packet);
uint arg_length= arg_end - packet;
-
+
/* Check given table name length. */
if (arg_length >= packet_length || arg_length > NAME_LEN)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
- thd->convert_string(&conv_name, system_charset_info,
+ thd->convert_string(&table_name, system_charset_info,
packet, arg_length, thd->charset());
- if (check_table_name(conv_name.str, conv_name.length, FALSE))
+ if (check_table_name(table_name.str, table_name.length, FALSE))
{
/* this is OK due to convert_string() null-terminating the string */
- my_error(ER_WRONG_TABLE_NAME, MYF(0), conv_name.str);
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str);
break;
}
-
- table_list.alias= table_list.table_name= conv_name.str;
packet= arg_end + 1;
+ mysql_reset_thd_for_next_command(thd);
+ lex_start(thd);
+ /* Must be before we init the table list. */
+ if (lower_case_table_names)
+ table_name.length= my_casedn_str(files_charset_info, table_name.str);
+ table_list.init_one_table(db.str, db.length, table_name.str,
+ table_name.length, table_name.str, TL_READ);
+ /*
+ Init TABLE_LIST members necessary when the undelrying
+ table is view.
+ */
+ table_list.select_lex= &(thd->lex->select_lex);
+ thd->lex->
+ select_lex.table_list.link_in_list(&table_list,
+ &table_list.next_local);
+ thd->lex->add_to_query_tables(&table_list);
- if (is_schema_db(table_list.db, table_list.db_length))
+ if (is_infoschema_db(table_list.db, table_list.db_length))
{
ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
if (schema_table)
@@ -1360,29 +1156,23 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
thd->set_query(fields, query_length);
general_log_print(thd, command, "%s %s", table_list.table_name, fields);
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, table_list.table_name);
- if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
- 0, 0, test(table_list.schema_table)))
- break;
- if (check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
+ if (check_table_access(thd, SELECT_ACL, &table_list,
+ TRUE, UINT_MAX, FALSE))
break;
- /* init structures for VIEW processing */
- table_list.select_lex= &(thd->lex->select_lex);
-
- lex_start(thd);
- mysql_reset_thd_for_next_command(thd);
-
- thd->lex->
- select_lex.table_list.link_in_list(&table_list,
- &table_list.next_local);
- thd->lex->add_to_query_tables(&table_list);
-
- /* switch on VIEW optimisation: do not fill temporary tables */
+ /*
+ Turn on an optimization relevant if the underlying table
+ is a view: do not fill derived tables.
+ */
thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
+
mysqld_list_fields(thd,&table_list,fields);
thd->lex->unit.cleanup();
+ /* No need to rollback statement transaction, it's not started. */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ close_thread_tables(thd);
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+
thd->cleanup_after_query();
break;
}
@@ -1391,58 +1181,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* We don't calculate statistics for this command */
general_log_print(thd, command, NullS);
net->error=0; // Don't give 'abort' message
- thd->main_da.disable_status(); // Don't send anything back
+ thd->stmt_da->disable_status(); // Don't send anything back
error=TRUE; // End server
break;
-
-#ifdef REMOVED
- case COM_CREATE_DB: // QQ: To be removed
- {
- LEX_STRING db, alias;
- HA_CREATE_INFO create_info;
-
- status_var_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB]);
- if (thd->make_lex_string(&db, packet, packet_length, FALSE) ||
- thd->make_lex_string(&alias, db.str, db.length, FALSE) ||
- check_db_name(&db))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
- break;
- }
- if (check_access(thd, CREATE_ACL, db.str , 0, 1, 0,
- is_schema_db(db.str, db.length)))
- break;
- general_log_print(thd, command, "%.*s", db.length, db.str);
- bzero(&create_info, sizeof(create_info));
- mysql_create_db(thd, (lower_case_table_names == 2 ? alias.str : db.str),
- &create_info, 0);
- break;
- }
- case COM_DROP_DB: // QQ: To be removed
- {
- status_var_increment(thd->status_var.com_stat[SQLCOM_DROP_DB]);
- LEX_STRING db;
-
- if (thd->make_lex_string(&db, packet, packet_length, FALSE) ||
- check_db_name(&db))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
- break;
- }
- if (check_access(thd, DROP_ACL, db.str, 0, 1, 0,
- is_schema_db(db.str, db.length)))
- break;
- if (thd->locked_tables || thd->active_transaction())
- {
- my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
- ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
- break;
- }
- general_log_write(thd, command, "%.*s", db.length, db.str);
- mysql_rm_db(thd, db.str, 0, 0);
- break;
- }
-#endif
#ifndef EMBEDDED_LIBRARY
case COM_BINLOG_DUMP:
{
@@ -1477,6 +1218,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
int not_used;
status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
ulong options= (ulong) (uchar) packet[0];
+ if (trans_commit_implicit(thd))
+ break;
+ thd->mdl_context.release_transactional_locks();
if (check_global_access(thd,RELOAD_ACL))
break;
general_log_print(thd, command, NullS);
@@ -1496,13 +1240,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
res= reload_acl_and_cache(NULL, options | REFRESH_FAST,
NULL, &not_used);
my_pthread_setspecific_ptr(THR_THD, thd);
- if (!res)
- my_ok(thd);
- break;
+ if (res)
+ break;
}
+ else
#endif
- if (!reload_acl_and_cache(thd, options, NULL, &not_used))
- my_ok(thd);
+ if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
+ break;
+ if (trans_commit_implicit(thd))
+ break;
+ close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks();
+ my_ok(thd);
break;
}
#ifndef EMBEDDED_LIBRARY
@@ -1532,7 +1281,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_PRINT("quit",("Got shutdown command for level %u", level));
general_log_print(thd, command, NullS);
my_eof(thd);
- close_thread_tables(thd); // Free before kill
kill_mysql();
error=TRUE;
break;
@@ -1567,23 +1315,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
cached_open_tables(),
(uint) (queries_per_second1000 / 1000),
(uint) (queries_per_second1000 % 1000));
-#ifdef SAFEMALLOC
- if (sf_malloc_cur_memory) // Using SAFEMALLOC
- {
- char *end= buff + length;
- length+= my_snprintf(end, buff_len - length - 1,
- end," Memory in use: %ldK Max memory used: %ldK",
- (sf_malloc_cur_memory+1023L)/1024L,
- (sf_malloc_max_memory+1023L)/1024L);
- }
-#endif
-#ifndef EMBEDDED_LIBRARY
- VOID(my_net_write(net, (uchar*) buff, length));
- VOID(net_flush(net));
- thd->main_da.disable_status();
-#else
+#ifdef EMBEDDED_LIBRARY
/* Store the buffer in permanent memory */
my_ok(thd, 0, 0, buff);
+#else
+ (void) my_net_write(net, (uchar*) buff, length);
+ (void) net_flush(net);
+ thd->stmt_da->disable_status();
#endif
break;
}
@@ -1645,44 +1383,41 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
+ DBUG_ASSERT(thd->derived_tables == NULL &&
+ (thd->open_tables == NULL ||
+ (thd->locked_tables_mode == LTM_LOCK_TABLES)));
- /* report error issued during command execution */
- if (thd->killed_errno())
- {
- if (! thd->main_da.is_set())
- thd->send_kill_message();
- }
- if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
- {
- thd->killed= THD::NOT_KILLED;
- thd->mysys_var->abort= 0;
- }
-
- /* If commit fails, we should be able to reset the OK status. */
- thd->main_da.can_overwrite_status= TRUE;
- ha_autocommit_or_rollback(thd, thd->is_error());
- thd->main_da.can_overwrite_status= FALSE;
-
- thd->transaction.stmt.reset();
-
- net_end_statement(thd);
+ /* Finalize server status flags after executing a command. */
+ thd->update_server_status();
+ thd->protocol->end_statement();
query_cache_end_of_result(thd);
- thd->proc_info= "closing tables";
- /* Free tables */
- close_thread_tables(thd);
+ if (!thd->is_error() && !thd->killed_errno())
+ mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0);
log_slow_statement(thd);
thd_proc_info(thd, "cleaning up");
- thd->set_query(NULL, 0);
+ thd->reset_query();
thd->command=COM_SLEEP;
- VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
- thread_running--;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ dec_thread_running();
thd_proc_info(thd, 0);
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+
+#if defined(ENABLED_PROFILING)
+ thd->profiling.finish_current_query();
+#endif
+ if (MYSQL_QUERY_DONE_ENABLED() || MYSQL_COMMAND_DONE_ENABLED())
+ {
+ int res __attribute__((unused));
+ res= (int) thd->is_error();
+ if (command == COM_QUERY)
+ {
+ MYSQL_QUERY_DONE(res);
+ }
+ MYSQL_COMMAND_DONE(res);
+ }
DBUG_RETURN(error);
}
@@ -1708,8 +1443,7 @@ void log_slow_statement(THD *thd)
ulonglong end_utime_of_query= thd->current_utime();
thd_proc_info(thd, "logging slow query");
- if (((end_utime_of_query - thd->utime_after_lock) >
- thd->variables.long_query_time ||
+ if (((thd->server_status & SERVER_QUERY_WAS_SLOW) ||
((thd->server_status &
(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
opt_log_queries_not_using_indexes &&
@@ -1813,7 +1547,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
/* 'parent_lex' is used in init_query() so it must be before it. */
schema_select_lex->parent_lex= lex;
schema_select_lex->init_query();
- if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
+ if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
+ MDL_SHARED_READ))
DBUG_RETURN(1);
lex->query_tables_last= query_tables_last;
break;
@@ -1824,7 +1559,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
Mark this current profiling record to be discarded. We don't
wish to have SHOW commands show up in profiling.
*/
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
thd->profiling.discard_current_query();
#endif
break;
@@ -2010,16 +1745,6 @@ bool sp_process_definer(THD *thd)
/**
Execute command saved in thd and lex->sql_command.
- Before every operation that can request a write lock for a table
- wait if a global read lock exists. However do not wait if this
- thread has locked tables already. No new locks can be requested
- until the other locks are released. The thread that requests the
- global read lock waits for write locked tables to become unlocked.
-
- Note that wait_if_global_read_lock() sets a protection against a new
- global read lock when it succeeds. This needs to be released by
- start_waiting_global_read_lock() after the operation.
-
@param thd Thread handle
@todo
@@ -2028,8 +1753,6 @@ bool sp_process_definer(THD *thd)
TODO: this is workaround. right way will be move invalidating in
the unlock procedure.
- TODO: use check_change_password()
- - JOIN is not supported yet. TODO
- - SUSPEND and FOR MIGRATE are not supported yet. TODO
@retval
FALSE OK
@@ -2041,7 +1764,6 @@ int
mysql_execute_command(THD *thd)
{
int res= FALSE;
- bool need_start_waiting= FALSE; // have protection against global read lock
int up_result= 0;
LEX *lex= thd->lex;
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
@@ -2056,12 +1778,12 @@ mysql_execute_command(THD *thd)
/* have table map for update for multi-update statement (BUG#37051) */
bool have_table_map_for_update= FALSE;
#endif
- /* Saved variable value */
DBUG_ENTER("mysql_execute_command");
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0;
#endif
+ DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt);
/*
In many cases first table of main SELECT_LEX have special meaning =>
check that it is first table in global list and relink it first in
@@ -2090,10 +1812,15 @@ mysql_execute_command(THD *thd)
A better approach would be to reset this for any commands
that is not a SHOW command or a select that only access local
variables, but for now this is probably good enough.
- Don't reset warnings when executing a stored routine.
*/
- if ((all_tables || !lex->is_single_level_stmt()) && !thd->spcont)
- mysql_reset_errors(thd, 0);
+ if ((sql_command_flags[lex->sql_command] & CF_DIAGNOSTIC_STMT) != 0)
+ thd->warning_info->set_read_only(TRUE);
+ else
+ {
+ thd->warning_info->set_read_only(FALSE);
+ if (all_tables)
+ thd->warning_info->opt_clear_warning_info(thd->query_id);
+ }
#ifdef HAVE_REPLICATION
if (unlikely(thd->slave_thread))
@@ -2220,10 +1947,33 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION
} /* endif unlikely slave */
#endif
+
status_var_increment(thd->status_var.com_stat[lex->sql_command]);
DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
-
+
+ /*
+ End a active transaction so that this command will have it's
+ own transaction and will also sync the binary log. If a DDL is
+ not run in it's own transaction it may simply never appear on
+ the slave in case the outside transaction rolls back.
+ */
+ if (stmt_causes_implicit_commit(thd, CF_IMPLICT_COMMIT_BEGIN))
+ {
+ /* Commit or rollback the statement transaction. */
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ /* Commit the normal transaction if one is active. */
+ if (trans_commit_implicit(thd))
+ goto error;
+ /* Release metadata locks acquired in this transaction. */
+ thd->mdl_context.release_transactional_locks();
+ }
+
+#ifndef DBUG_OFF
+ if (lex->sql_command != SQLCOM_SET_OPTION)
+ DEBUG_SYNC(thd,"before_execute_sql_command");
+#endif
+
switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS:
@@ -2233,14 +1983,17 @@ mysql_execute_command(THD *thd)
#endif
case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STATUS_FUNC:
- if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE)))
- res= execute_sqlcom_select(thd, all_tables);
+ if ((res= check_table_access(thd, SELECT_ACL, all_tables, FALSE,
+ UINT_MAX, FALSE)))
+ goto error;
+ res= execute_sqlcom_select(thd, all_tables);
break;
case SQLCOM_SHOW_STATUS:
{
system_status_var old_status_var= thd->status_var;
thd->initial_status_var= &old_status_var;
- if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE)))
+ if (!(res= check_table_access(thd, SELECT_ACL, all_tables, FALSE,
+ UINT_MAX, FALSE)))
res= execute_sqlcom_select(thd, all_tables);
/* Don't log SHOW STATUS commands to slow query log */
thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED |
@@ -2249,11 +2002,11 @@ mysql_execute_command(THD *thd)
restore status variables, as we don't want 'show status' to cause
changes
*/
- pthread_mutex_lock(&LOCK_status);
+ mysql_mutex_lock(&LOCK_status);
add_diff_to_status(&global_status_var, &thd->status_var,
&old_status_var);
thd->status_var= old_status_var;
- pthread_mutex_unlock(&LOCK_status);
+ mysql_mutex_unlock(&LOCK_status);
break;
}
case SQLCOM_SHOW_DATABASES:
@@ -2270,29 +2023,30 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_PROFILE:
case SQLCOM_SELECT:
+ {
thd->status_var.last_query_cost= 0.0;
+
+ /*
+ lex->exchange != NULL implies SELECT .. INTO OUTFILE and this
+ requires FILE_ACL access.
+ */
+ ulong privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL :
+ SELECT_ACL;
+
if (all_tables)
- {
res= check_table_access(thd,
- lex->exchange ? SELECT_ACL | FILE_ACL :
- SELECT_ACL,
- all_tables, UINT_MAX, FALSE);
- }
+ privileges_requested,
+ all_tables, FALSE, UINT_MAX, FALSE);
else
- res= check_access(thd,
- lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
- any_db, 0, 0, 0, 0);
+ res= check_access(thd, privileges_requested, any_db, NULL, NULL, 0, 0);
if (res)
break;
- if (!thd->locked_tables && lex->protect_against_global_read_lock &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- break;
-
res= execute_sqlcom_select(thd, all_tables);
break;
- case SQLCOM_PREPARE:
+ }
+case SQLCOM_PREPARE:
{
mysql_sql_stmt_prepare(thd);
break;
@@ -2308,8 +2062,8 @@ mysql_execute_command(THD *thd)
break;
}
case SQLCOM_DO:
- if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
- open_and_lock_tables(thd, all_tables))
+ if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)
+ || open_and_lock_tables(thd, all_tables, TRUE, 0))
goto error;
res= mysql_do(thd, *lex->insert_list);
@@ -2373,7 +2127,7 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_SHOW_PROFILES:
{
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
thd->profiling.discard_current_query();
res= thd->profiling.show_profiles();
if (res)
@@ -2406,6 +2160,7 @@ mysql_execute_command(THD *thd)
res = show_slave_hosts(thd);
break;
}
+ case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */
case SQLCOM_SHOW_BINLOG_EVENTS:
{
if (check_global_access(thd, REPL_SLAVE_ACL))
@@ -2415,36 +2170,13 @@ mysql_execute_command(THD *thd)
}
#endif
- case SQLCOM_BACKUP_TABLE:
- {
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
- check_global_access(thd, FILE_ACL))
- goto error; /* purecov: inspected */
- thd->enable_slow_log= opt_log_slow_admin_statements;
- res = mysql_backup_table(thd, first_table);
- select_lex->table_list.first= first_table;
- lex->query_tables=all_tables;
- break;
- }
- case SQLCOM_RESTORE_TABLE:
- {
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_table_access(thd, INSERT_ACL, all_tables, UINT_MAX, FALSE) ||
- check_global_access(thd, FILE_ACL))
- goto error; /* purecov: inspected */
- thd->enable_slow_log= opt_log_slow_admin_statements;
- res = mysql_restore_table(thd, first_table);
- select_lex->table_list.first= first_table;
- lex->query_tables=all_tables;
- break;
- }
case SQLCOM_ASSIGN_TO_KEYCACHE:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_access(thd, INDEX_ACL, first_table->db,
- &first_table->grant.privilege, 0, 0,
- test(first_table->schema_table)))
+ &first_table->grant.privilege,
+ &first_table->grant.m_internal,
+ 0, 0))
goto error;
res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
break;
@@ -2453,8 +2185,9 @@ mysql_execute_command(THD *thd)
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_access(thd, INDEX_ACL, first_table->db,
- &first_table->grant.privilege, 0, 0,
- test(first_table->schema_table)))
+ &first_table->grant.privilege,
+ &first_table->grant.m_internal,
+ 0, 0))
goto error;
res = mysql_preload_keys(thd, first_table);
break;
@@ -2464,9 +2197,9 @@ mysql_execute_command(THD *thd)
{
if (check_global_access(thd, SUPER_ACL))
goto error;
- pthread_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_active_mi);
res = change_master(thd,active_mi);
- pthread_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_unlock(&LOCK_active_mi);
break;
}
case SQLCOM_SHOW_SLAVE_STAT:
@@ -2474,7 +2207,7 @@ mysql_execute_command(THD *thd)
/* Accept one of two privileges */
if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
goto error;
- pthread_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_active_mi);
if (active_mi != NULL)
{
res = show_master_info(thd, active_mi);
@@ -2485,7 +2218,7 @@ mysql_execute_command(THD *thd)
WARN_NO_MASTER_INFO, ER(WARN_NO_MASTER_INFO));
my_ok(thd);
}
- pthread_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_unlock(&LOCK_active_mi);
break;
}
case SQLCOM_SHOW_MASTER_STAT:
@@ -2497,13 +2230,6 @@ mysql_execute_command(THD *thd)
break;
}
- case SQLCOM_LOAD_MASTER_DATA: // sync with master
- if (check_global_access(thd, SUPER_ACL))
- goto error;
- if (end_active_trans(thd))
- goto error;
- res = load_master_data(thd);
- break;
#endif /* HAVE_REPLICATION */
case SQLCOM_SHOW_ENGINE_STATUS:
{
@@ -2519,51 +2245,13 @@ mysql_execute_command(THD *thd)
res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
break;
}
-#ifdef HAVE_REPLICATION
- case SQLCOM_LOAD_MASTER_TABLE:
- {
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- DBUG_ASSERT(first_table->db); /* Must be set in the parser */
-
- if (check_access(thd, CREATE_ACL, first_table->db,
- &first_table->grant.privilege, 0, 0,
- test(first_table->schema_table)))
- goto error; /* purecov: inspected */
- /* Check that the first table has CREATE privilege */
- if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
- goto error;
-
- pthread_mutex_lock(&LOCK_active_mi);
- /*
- fetch_master_table will send the error to the client on failure.
- Give error if the table already exists.
- */
- if (!fetch_master_table(thd, first_table->db, first_table->table_name,
- active_mi, 0, 0))
- {
- my_ok(thd);
- }
- pthread_mutex_unlock(&LOCK_active_mi);
- break;
- }
-#endif /* HAVE_REPLICATION */
-
case SQLCOM_CREATE_TABLE:
{
- /* If CREATE TABLE of non-temporary table, do implicit commit */
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
- {
- if (end_active_trans(thd))
- {
- res= -1;
- break;
- }
- }
DBUG_ASSERT(first_table == all_tables && first_table != 0);
bool link_to_local;
- // Skip first table, which is the table we are creating
- TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
- TABLE_LIST *select_tables= lex->query_tables;
+ TABLE_LIST *create_table= first_table;
+ TABLE_LIST *select_tables= lex->create_last_non_select_table->next_global;
+
/*
Code below (especially in mysql_create_table() and select_create
methods) may modify HA_CREATE_INFO structure in LEX, so we have to
@@ -2613,25 +2301,7 @@ mysql_execute_command(THD *thd)
create_info.default_table_charset= create_info.table_charset;
create_info.table_charset= 0;
}
- /*
- The create-select command will open and read-lock the select table
- and then create, open and write-lock the new table. If a global
- read lock steps in, we get a deadlock. The write lock waits for
- the global read lock, while the global read lock waits for the
- select table to be closed. So we wait until the global readlock is
- gone before starting both steps. Note that
- wait_if_global_read_lock() sets a protection against a new global
- read lock when it succeeds. This needs to be released by
- start_waiting_global_read_lock(). We protect the normal CREATE
- TABLE in the same way. That way we avoid that a new table is
- created during a gobal read lock.
- */
- if (!thd->locked_tables &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- {
- res= 1;
- goto end_with_restore_list;
- }
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
{
partition_info *part_info= thd->lex->part_info;
@@ -2643,6 +2313,10 @@ mysql_execute_command(THD *thd)
thd->work_part_info= part_info;
}
#endif
+
+ /* Close any open handlers for the table. */
+ mysql_ha_rm_tables(thd, create_table);
+
if (select_lex->item_list.elements) // With select
{
select_result *result;
@@ -2700,71 +2374,37 @@ mysql_execute_command(THD *thd)
goto end_with_restore_list;
}
- if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
- {
- lex->link_first_table_back(create_table, link_to_local);
- create_table->create= TRUE;
- /* Base table and temporary table are not in the same name space. */
- create_table->skip_temporary= 1;
- }
-
- if (!(res= open_and_lock_tables(thd, lex->query_tables)))
+ if (!(res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0)))
{
- /*
- Is table which we are changing used somewhere in other parts
- of query
- */
- if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ /* The table already exists */
+ if (create_table->table)
{
- TABLE_LIST *duplicate;
- create_table= lex->unlink_first_table(&link_to_local);
-
- if (create_table->view)
+ if (create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
{
- if (create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_TABLE_EXISTS_ERROR,
- ER(ER_TABLE_EXISTS_ERROR),
- create_info.alias);
- my_ok(thd);
- }
- else
- {
- my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_info.alias);
- res= 1;
- }
- goto end_with_restore_list;
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_TABLE_EXISTS_ERROR,
+ ER(ER_TABLE_EXISTS_ERROR),
+ create_info.alias);
+ my_ok(thd);
}
-
- if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
+ else
{
- update_non_unique_table_error(create_table, "CREATE", duplicate);
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_info.alias);
res= 1;
- goto end_with_restore_list;
- }
- }
- /* If we create merge table, we have to test tables in merge, too */
- if (create_info.used_fields & HA_CREATE_USED_UNION)
- {
- TABLE_LIST *tab;
- for (tab= create_info.merge_list.first;
- tab;
- tab= tab->next_local)
- {
- TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, tab, select_tables, 0)))
- {
- update_non_unique_table_error(tab, "CREATE", duplicate);
- res= 1;
- goto end_with_restore_list;
- }
}
+ goto end_with_restore_list;
}
+ /*
+ Remove target table from main select and name resolution
+ context. This can't be done earlier as it will break view merging in
+ statements like "CREATE TABLE IF NOT EXISTS existing_view SELECT".
+ */
+ lex->unlink_first_table(&link_to_local);
+
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
- thd->options|= OPTION_KEEP_LOG;
+ thd->variables.option_bits|= OPTION_KEEP_LOG;
/*
select_create is currently not re-execution friendly and
@@ -2785,33 +2425,33 @@ mysql_execute_command(THD *thd)
res= handle_select(thd, lex, result, 0);
delete result;
}
- }
- else if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
- create_table= lex->unlink_first_table(&link_to_local);
+ lex->link_first_table_back(create_table, link_to_local);
+ }
}
else
{
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
- thd->options|= OPTION_KEEP_LOG;
+ thd->variables.option_bits|= OPTION_KEEP_LOG;
/* regular create */
if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
+ {
+ /* CREATE TABLE ... LIKE ... */
res= mysql_create_like_table(thd, create_table, select_tables,
&create_info);
+ }
else
{
- res= mysql_create_table(thd, create_table->db,
- create_table->table_name, &create_info,
- &alter_info, 0, 0);
+ /* Regular CREATE TABLE */
+ res= mysql_create_table(thd, create_table,
+ &create_info, &alter_info);
}
if (!res)
- my_ok(thd);
+ my_ok(thd);
}
- /* put tables back for PS rexecuting */
end_with_restore_list:
- lex->link_first_table_back(create_table, link_to_local);
break;
}
case SQLCOM_CREATE_INDEX:
@@ -2836,8 +2476,6 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
- if (end_active_trans(thd))
- goto error;
/*
Currently CREATE INDEX or DROP INDEX cause a full table rebuild
and thus classify as slow administrative statements just like
@@ -2858,9 +2496,9 @@ end_with_restore_list:
#ifdef HAVE_REPLICATION
case SQLCOM_SLAVE_START:
{
- pthread_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_active_mi);
start_slave(thd,active_mi,1 /* net report*/);
- pthread_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_unlock(&LOCK_active_mi);
break;
}
case SQLCOM_SLAVE_STOP:
@@ -2877,98 +2515,21 @@ end_with_restore_list:
To prevent that, refuse SLAVE STOP if the
client thread has locked tables
*/
- if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
+ if (thd->locked_tables_mode ||
+ thd->in_active_multi_stmt_transaction() || thd->global_read_lock.is_acquired())
{
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
{
- pthread_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_active_mi);
stop_slave(thd,active_mi,1/* net report*/);
- pthread_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_unlock(&LOCK_active_mi);
break;
}
#endif /* HAVE_REPLICATION */
- case SQLCOM_ALTER_TABLE:
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- {
- ulong priv=0;
- ulong priv_needed= ALTER_ACL;
- /*
- Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
- so we have to use a copy of this structure to make execution
- prepared statement- safe. A shallow copy is enough as no memory
- referenced from this structure will be modified.
- */
- HA_CREATE_INFO create_info(lex->create_info);
- Alter_info alter_info(lex->alter_info, thd->mem_root);
-
- if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
- goto error;
- /*
- We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
- as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
- */
- if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
- priv_needed|= DROP_ACL;
-
- /* Must be set in the parser */
- DBUG_ASSERT(select_lex->db);
- if (check_access(thd, priv_needed, first_table->db,
- &first_table->grant.privilege, 0, 0,
- test(first_table->schema_table)) ||
- check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0,
- is_schema_db(select_lex->db))||
- check_merge_table_access(thd, first_table->db,
- create_info.merge_list.first))
- goto error; /* purecov: inspected */
- if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0))
- goto error;
- if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
- { // Rename of table
- TABLE_LIST tmp_table;
- bzero((char*) &tmp_table,sizeof(tmp_table));
- tmp_table.table_name= lex->name.str;
- tmp_table.db=select_lex->db;
- tmp_table.grant.privilege=priv;
- if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
- UINT_MAX, 0))
- goto error;
- }
-
- /* Don't yet allow changing of symlinks with ALTER TABLE */
- if (create_info.data_file_name)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
- "DATA DIRECTORY");
- if (create_info.index_file_name)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
- "INDEX DIRECTORY");
- create_info.data_file_name= create_info.index_file_name= NULL;
- /* ALTER TABLE ends previous transaction */
- if (end_active_trans(thd))
- goto error;
-
- if (!thd->locked_tables &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- {
- res= 1;
- break;
- }
-
- thd->enable_slow_log= opt_log_slow_admin_statements;
- res= mysql_alter_table(thd, select_lex->db, lex->name.str,
- &create_info,
- first_table,
- &alter_info,
- select_lex->order_list.elements,
- (ORDER *) select_lex->order_list.first,
- lex->ignore);
- break;
- }
case SQLCOM_RENAME_TABLE:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
@@ -2976,10 +2537,13 @@ end_with_restore_list:
for (table= first_table; table; table= table->next_local->next_local)
{
if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
- &table->grant.privilege,0,0, test(table->schema_table)) ||
- check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
- &table->next_local->grant.privilege, 0, 0,
- test(table->next_local->schema_table)))
+ &table->grant.privilege,
+ &table->grant.m_internal,
+ 0, 0) ||
+ check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
+ &table->next_local->grant.privilege,
+ &table->next_local->grant.m_internal,
+ 0, 0))
goto error;
TABLE_LIST old_list, new_list;
/*
@@ -2988,14 +2552,15 @@ end_with_restore_list:
*/
old_list= table[0];
new_list= table->next_local[0];
- if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, 0, 1, 0) ||
+ if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, FALSE, 1, FALSE) ||
(!test_all_bits(table->next_local->grant.privilege,
INSERT_ACL | CREATE_ACL) &&
- check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
+ check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, FALSE, 1,
+ FALSE)))
goto error;
}
- if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
+ if (mysql_rename_tables(thd, first_table, 0))
goto error;
break;
}
@@ -3022,11 +2587,54 @@ end_with_restore_list:
goto error;
#else
{
- /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
+ /*
+ Access check:
+ SHOW CREATE TABLE require any privileges on the table level (ie
+ effecting all columns in the table).
+ SHOW CREATE VIEW require the SHOW_VIEW and SELECT ACLs on the table
+ level.
+ NOTE: SHOW_VIEW ACL is checked when the view is created.
+ */
+
+ DBUG_PRINT("debug", ("lex->only_view: %d, table: %s.%s",
+ lex->only_view,
+ first_table->db, first_table->table_name));
if (lex->only_view)
- first_table->skip_temporary= 1;
- if (check_show_create_table_access(thd, first_table))
- goto error;
+ {
+ if (check_table_access(thd, SELECT_ACL, first_table, FALSE, 1, FALSE))
+ {
+ DBUG_PRINT("debug", ("check_table_access failed"));
+ my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
+ "SHOW", thd->security_ctx->priv_user,
+ thd->security_ctx->host_or_ip, first_table->alias);
+ goto error;
+ }
+ DBUG_PRINT("debug", ("check_table_access succeeded"));
+
+ /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
+ first_table->open_type= OT_BASE_ONLY;
+
+ }
+ else
+ {
+ /*
+ The fact that check_some_access() returned FALSE does not mean that
+ access is granted. We need to check if first_table->grant.privilege
+ contains any table-specific privilege.
+ */
+ DBUG_PRINT("debug", ("first_table->grant.privilege: %lx",
+ first_table->grant.privilege));
+ if (check_some_access(thd, SHOW_CREATE_TABLE_ACLS, first_table) ||
+ (first_table->grant.privilege & SHOW_CREATE_TABLE_ACLS) == 0)
+ {
+ my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
+ "SHOW", thd->security_ctx->priv_user,
+ thd->security_ctx->host_or_ip, first_table->alias);
+ goto error;
+ }
+ }
+
+ /* Access is granted. Execute the command. */
res= mysqld_show_create(thd, first_table);
break;
}
@@ -3034,96 +2642,22 @@ end_with_restore_list:
case SQLCOM_CHECKSUM:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables,
- UINT_MAX, FALSE))
+ if (check_table_access(thd, SELECT_ACL, all_tables,
+ FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
- res = mysql_checksum_table(thd, first_table, &lex->check_opt);
- break;
- }
- case SQLCOM_REPAIR:
- {
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
- UINT_MAX, FALSE))
- goto error; /* purecov: inspected */
- thd->enable_slow_log= opt_log_slow_admin_statements;
- res= mysql_repair_table(thd, first_table, &lex->check_opt);
- /* ! we write after unlocking the table */
- if (!res && !lex->no_write_to_binlog)
- {
- /*
- Presumably, REPAIR and binlog writing doesn't require synchronization
- */
- res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- }
- select_lex->table_list.first= first_table;
- lex->query_tables=all_tables;
- break;
- }
- case SQLCOM_CHECK:
- {
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables,
- UINT_MAX, FALSE))
- goto error; /* purecov: inspected */
- thd->enable_slow_log= opt_log_slow_admin_statements;
- res = mysql_check_table(thd, first_table, &lex->check_opt);
- select_lex->table_list.first= first_table;
- lex->query_tables=all_tables;
- break;
- }
- case SQLCOM_ANALYZE:
- {
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
- UINT_MAX, FALSE))
- goto error; /* purecov: inspected */
- thd->enable_slow_log= opt_log_slow_admin_statements;
- res= mysql_analyze_table(thd, first_table, &lex->check_opt);
- /* ! we write after unlocking the table */
- if (!res && !lex->no_write_to_binlog)
- {
- /*
- Presumably, ANALYZE and binlog writing doesn't require synchronization
- */
- res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- }
- select_lex->table_list.first= first_table;
- lex->query_tables=all_tables;
- break;
- }
- case SQLCOM_OPTIMIZE:
- {
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
- UINT_MAX, FALSE))
- goto error; /* purecov: inspected */
- thd->enable_slow_log= opt_log_slow_admin_statements;
- res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
- mysql_recreate_table(thd, first_table) :
- mysql_optimize_table(thd, first_table, &lex->check_opt);
- /* ! we write after unlocking the table */
- if (!res && !lex->no_write_to_binlog)
- {
- /*
- Presumably, OPTIMIZE and binlog writing doesn't require synchronization
- */
- res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- }
- select_lex->table_list.first= first_table;
- lex->query_tables=all_tables;
+ res = mysql_checksum_table(thd, first_table, &lex->check_opt);
break;
}
case SQLCOM_UPDATE:
+ {
+ ha_rows found= 0, updated= 0;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (update_precheck(thd, all_tables))
break;
- if (!thd->locked_tables &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- goto error;
DBUG_ASSERT(select_lex->offset_limit == 0);
unit->set_limit(select_lex);
+ MYSQL_UPDATE_START(thd->query());
res= (up_result= mysql_update(thd, all_tables,
select_lex->item_list,
lex->value_list,
@@ -3131,11 +2665,14 @@ end_with_restore_list:
select_lex->order_list.elements,
select_lex->order_list.first,
unit->select_limit_cnt,
- lex->duplicates, lex->ignore));
+ lex->duplicates, lex->ignore,
+ &found, &updated));
+ MYSQL_UPDATE_DONE(res, found, updated);
/* mysql_update return 2 if we need to switch to multi-update */
if (up_result != 2)
break;
/* Fall through */
+ }
case SQLCOM_UPDATE_MULTI:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
@@ -3148,15 +2685,6 @@ end_with_restore_list:
else
res= 0;
- /*
- Protection might have already been risen if its a fall through
- from the SQLCOM_UPDATE case above.
- */
- if (!thd->locked_tables &&
- lex->sql_command == SQLCOM_UPDATE_MULTI &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- goto error;
-
res= mysql_multi_update_prepare(thd);
#ifdef HAVE_REPLICATION
@@ -3192,13 +2720,31 @@ end_with_restore_list:
#ifdef HAVE_REPLICATION
} /* unlikely */
#endif
-
- res= mysql_multi_update(thd, all_tables,
- &select_lex->item_list,
- &lex->value_list,
- select_lex->where,
- select_lex->options,
- lex->duplicates, lex->ignore, unit, select_lex);
+ {
+ multi_update *result_obj;
+ MYSQL_MULTI_UPDATE_START(thd->query());
+ res= mysql_multi_update(thd, all_tables,
+ &select_lex->item_list,
+ &lex->value_list,
+ select_lex->where,
+ select_lex->options,
+ lex->duplicates,
+ lex->ignore,
+ unit,
+ select_lex,
+ &result_obj);
+ if (result_obj)
+ {
+ MYSQL_MULTI_UPDATE_DONE(res, result_obj->num_found(),
+ result_obj->num_updated());
+ res= FALSE; /* Ignore errors here */
+ delete result_obj;
+ }
+ else
+ {
+ MYSQL_MULTI_UPDATE_DONE(1, 0, 0);
+ }
+ }
break;
}
case SQLCOM_REPLACE:
@@ -3242,17 +2788,11 @@ end_with_restore_list:
if ((res= insert_precheck(thd, all_tables)))
break;
- if (!thd->locked_tables &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- {
- res= 1;
- break;
- }
-
+ MYSQL_INSERT_START(thd->query());
res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
lex->update_list, lex->value_list,
lex->duplicates, lex->ignore);
-
+ MYSQL_INSERT_DONE(res, (ulong) thd->get_row_count_func());
/*
If we have inserted into a VIEW, and the base table has
AUTO_INCREMENT column, but this column is not accessible through
@@ -3291,15 +2831,9 @@ end_with_restore_list:
unit->set_limit(select_lex);
- if (! thd->locked_tables &&
- ! (need_start_waiting= ! wait_if_global_read_lock(thd, 0, 1)))
- {
- res= 1;
- break;
- }
-
- if (!(res= open_and_lock_tables(thd, all_tables)))
+ if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0)))
{
+ MYSQL_INSERT_SELECT_START(thd->query());
/* Skip first table, which is the table we are inserting in */
TABLE_LIST *second_table= first_table->next_local;
select_lex->table_list.first= second_table;
@@ -3333,9 +2867,9 @@ end_with_restore_list:
delete sel_result;
}
/* revert changes for SP */
+ MYSQL_INSERT_SELECT_DONE(res, (ulong) thd->get_row_count_func());
select_lex->table_list.first= first_table;
}
-
/*
If we have inserted into a VIEW, and the base table has
AUTO_INCREMENT column, but this column is not accessible through
@@ -3348,29 +2882,6 @@ end_with_restore_list:
break;
}
- case SQLCOM_TRUNCATE:
- if (end_active_trans(thd))
- {
- res= -1;
- break;
- }
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_one_table_access(thd, DROP_ACL, all_tables))
- goto error;
- /*
- Don't allow this within a transaction because we want to use
- re-generate table
- */
- if (thd->locked_tables || thd->active_transaction())
- {
- my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
- ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
- goto error;
- }
- if (!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- goto error;
- res= mysql_truncate(thd, first_table, 0);
- break;
case SQLCOM_DELETE:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
@@ -3379,17 +2890,11 @@ end_with_restore_list:
DBUG_ASSERT(select_lex->offset_limit == 0);
unit->set_limit(select_lex);
- if (!thd->locked_tables &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- {
- res= 1;
- break;
- }
-
+ MYSQL_DELETE_START(thd->query());
res = mysql_delete(thd, all_tables, select_lex->where,
&select_lex->order_list,
- unit->select_limit_cnt, select_lex->options,
- FALSE);
+ unit->select_limit_cnt, select_lex->options);
+ MYSQL_DELETE_DONE(res, (ulong) thd->get_row_count_func());
break;
}
case SQLCOM_DELETE_MULTI:
@@ -3398,13 +2903,6 @@ end_with_restore_list:
TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
multi_delete *del_result;
- if (!thd->locked_tables &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- {
- res= 1;
- break;
- }
-
if ((res= multi_delete_precheck(thd, all_tables)))
break;
@@ -3415,11 +2913,15 @@ end_with_restore_list:
goto error;
thd_proc_info(thd, "init");
- if ((res= open_and_lock_tables(thd, all_tables)))
+ if ((res= open_and_lock_tables(thd, all_tables, TRUE, 0)))
break;
+ MYSQL_MULTI_DELETE_START(thd->query());
if ((res= mysql_multi_delete_prepare(thd)))
+ {
+ MYSQL_MULTI_DELETE_DONE(1, 0);
goto error;
+ }
if (!thd->is_fatal_error &&
(del_result= new multi_delete(aux_tables, lex->table_count)))
@@ -3431,17 +2933,21 @@ end_with_restore_list:
select_lex->where,
0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
(ORDER *)NULL,
- (select_lex->options | thd->options |
+ (select_lex->options | thd->variables.option_bits |
SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT,
del_result, unit, select_lex);
res|= thd->is_error();
+ MYSQL_MULTI_DELETE_DONE(res, del_result->num_deleted());
if (res)
- del_result->abort();
+ del_result->abort_result_set();
delete del_result;
}
else
+ {
res= TRUE; // Error
+ MYSQL_MULTI_DELETE_DONE(1, 0);
+ }
break;
}
case SQLCOM_DROP_TABLE:
@@ -3449,17 +2955,15 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (!lex->drop_temporary)
{
- if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE))
+ if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
- if (end_active_trans(thd))
- goto error;
}
else
{
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
- thd->options|= OPTION_KEEP_LOG;
+ thd->variables.option_bits|= OPTION_KEEP_LOG;
}
- /* DDL and binlog write order protected by LOCK_open */
+ /* DDL and binlog write order are protected by metadata locks. */
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
lex->drop_temporary);
}
@@ -3483,9 +2987,6 @@ end_with_restore_list:
case SQLCOM_SHOW_PRIVILEGES:
res= mysqld_show_privileges(thd);
break;
- case SQLCOM_SHOW_COLUMN_TYPES:
- res= mysqld_show_column_types(thd);
- break;
case SQLCOM_SHOW_ENGINE_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
@@ -3493,7 +2994,7 @@ end_with_restore_list:
goto error;
#else
{
- if (check_access(thd, FILE_ACL, any_db,0,0,0,0))
+ if (check_access(thd, FILE_ACL, any_db, NULL, NULL, 0, 0))
goto error;
res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS);
break;
@@ -3529,10 +3030,6 @@ end_with_restore_list:
if (check_one_table_access(thd, privilege, all_tables))
goto error;
- if (!thd->locked_tables &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- goto error;
-
res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
lex->update_list, lex->value_list, lex->duplicates,
lex->ignore, (bool) lex->local_file);
@@ -3543,17 +3040,9 @@ end_with_restore_list:
{
List<set_var_base> *lex_var_list= &lex->var_list;
- if (lex->autocommit && end_active_trans(thd))
- goto error;
-
- if ((check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
- open_and_lock_tables(thd, all_tables)))
- goto error;
- if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
- {
- my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
+ if ((check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)
+ || open_and_lock_tables(thd, all_tables, TRUE, 0)))
goto error;
- }
if (!(res= sql_set_variables(thd, lex_var_list)))
{
/*
@@ -3585,52 +3074,67 @@ end_with_restore_list:
done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes
false, mysqldump will not work.
*/
- unlock_locked_tables(thd);
- if (thd->options & OPTION_TABLE_LOCK)
+ if (thd->variables.option_bits & OPTION_TABLE_LOCK)
{
- end_active_trans(thd);
- thd->options&= ~(OPTION_TABLE_LOCK);
+ res= trans_commit_implicit(thd);
+ thd->locked_tables_list.unlock_locked_tables(thd);
+ thd->mdl_context.release_transactional_locks();
+ thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
}
- if (thd->global_read_lock)
- unlock_global_read_lock(thd);
+ if (thd->global_read_lock.is_acquired())
+ thd->global_read_lock.unlock_global_read_lock(thd);
+ if (res)
+ goto error;
my_ok(thd);
break;
case SQLCOM_LOCK_TABLES:
- unlock_locked_tables(thd);
- /* we must end the trasaction first, regardless of anything */
- if (end_active_trans(thd))
+ /* We must end the transaction first, regardless of anything */
+ res= trans_commit_implicit(thd);
+ thd->locked_tables_list.unlock_locked_tables(thd);
+ /* Release transactional metadata locks. */
+ thd->mdl_context.release_transactional_locks();
+ if (res)
goto error;
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
- UINT_MAX, FALSE))
- goto error;
- if (lex->protect_against_global_read_lock &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ FALSE, UINT_MAX, FALSE))
goto error;
+
+ thd->variables.option_bits|= OPTION_TABLE_LOCK;
thd->in_lock_tables=1;
- thd->options|= OPTION_TABLE_LOCK;
- if (!(res= simple_open_n_lock_tables(thd, all_tables)))
{
-#ifdef HAVE_QUERY_CACHE
- if (thd->variables.query_cache_wlock_invalidate)
- query_cache.invalidate_locked_for_write(first_table);
-#endif /*HAVE_QUERY_CACHE*/
- thd->locked_tables=thd->lock;
- thd->lock=0;
- my_ok(thd);
+ Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
+
+ res= (open_and_lock_tables(thd, all_tables, FALSE, 0,
+ &lock_tables_prelocking_strategy) ||
+ thd->locked_tables_list.init_locked_tables(thd));
}
- else
+
+ thd->in_lock_tables= 0;
+
+ if (res)
{
- /*
+ trans_rollback_stmt(thd);
+ /*
Need to end the current transaction, so the storage engine (InnoDB)
can free its locks if LOCK TABLES locked some tables before finding
that it can't lock a table in its list
*/
- ha_autocommit_or_rollback(thd, 1);
- end_active_trans(thd);
- thd->options&= ~(OPTION_TABLE_LOCK);
+ trans_commit_implicit(thd);
+ /* Close tables and release metadata locks. */
+ close_thread_tables(thd);
+ DBUG_ASSERT(!thd->locked_tables_mode);
+ thd->mdl_context.release_transactional_locks();
+ thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
+ }
+ else
+ {
+#ifdef HAVE_QUERY_CACHE
+ if (thd->variables.query_cache_wlock_invalidate)
+ query_cache.invalidate_locked_for_write(first_table);
+#endif /*HAVE_QUERY_CACHE*/
+ my_ok(thd);
}
- thd->in_lock_tables=0;
break;
case SQLCOM_CREATE_DB:
{
@@ -3640,11 +3144,6 @@ end_with_restore_list:
prepared statement- safe.
*/
HA_CREATE_INFO create_info(lex->create_info);
- if (end_active_trans(thd))
- {
- res= -1;
- break;
- }
char *alias;
if (!(alias=thd->strmake(lex->name.str, lex->name.length)) ||
check_db_name(&lex->name))
@@ -3668,8 +3167,7 @@ end_with_restore_list:
break;
}
#endif
- if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
- is_schema_db(lex->name.str, lex->name.length)))
+ if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0))
break;
res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
lex->name.str), &create_info, 0);
@@ -3677,11 +3175,6 @@ end_with_restore_list:
}
case SQLCOM_DROP_DB:
{
- if (end_active_trans(thd))
- {
- res= -1;
- break;
- }
if (check_db_name(&lex->name))
{
my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
@@ -3703,26 +3196,14 @@ end_with_restore_list:
break;
}
#endif
- if (check_access(thd,DROP_ACL,lex->name.str,0,1,0,
- is_schema_db(lex->name.str, lex->name.length)))
+ if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0))
break;
- if (thd->locked_tables || thd->active_transaction())
- {
- my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
- ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
- goto error;
- }
res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
break;
}
case SQLCOM_ALTER_DB_UPGRADE:
{
LEX_STRING *db= & lex->name;
- if (end_active_trans(thd))
- {
- res= 1;
- break;
- }
#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
(!rpl_filter->db_ok(db->str) ||
@@ -3738,24 +3219,13 @@ end_with_restore_list:
my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
break;
}
- if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0,
- is_schema_db(db->str, db->length)) ||
- check_access(thd, DROP_ACL, db->str, 0, 1, 0,
- is_schema_db(db->str, db->length)) ||
- check_access(thd, CREATE_ACL, db->str, 0, 1, 0,
- is_schema_db(db->str, db->length)))
+ if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0) ||
+ check_access(thd, DROP_ACL, db->str, NULL, NULL, 1, 0) ||
+ check_access(thd, CREATE_ACL, db->str, NULL, NULL, 1, 0))
{
res= 1;
break;
}
- if (thd->locked_tables || thd->active_transaction())
- {
- res= 1;
- my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
- ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
- goto error;
- }
-
res= mysql_upgrade_db(thd, db);
if (!res)
my_ok(thd);
@@ -3786,15 +3256,8 @@ end_with_restore_list:
break;
}
#endif
- if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0,
- is_schema_db(db->str, db->length)))
+ if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0))
break;
- if (thd->locked_tables || thd->active_transaction())
- {
- my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
- ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
- goto error;
- }
res= mysql_alter_db(thd, db->str, &create_info);
break;
}
@@ -3872,7 +3335,7 @@ end_with_restore_list:
#endif
case SQLCOM_CREATE_FUNCTION: // UDF function
{
- if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
+ if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 0))
break;
#ifdef HAVE_DLOPEN
if (!(res = mysql_create_function(thd, &lex->udf)))
@@ -3886,11 +3349,9 @@ end_with_restore_list:
#ifndef NO_EMBEDDED_ACCESS_CHECKS
case SQLCOM_CREATE_USER:
{
- if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
+ if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
- if (end_active_trans(thd))
- goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_create_user(thd, lex->users_list)))
my_ok(thd);
@@ -3898,11 +3359,9 @@ end_with_restore_list:
}
case SQLCOM_DROP_USER:
{
- if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
+ if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
- if (end_active_trans(thd))
- goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_drop_user(thd, lex->users_list)))
my_ok(thd);
@@ -3910,11 +3369,9 @@ end_with_restore_list:
}
case SQLCOM_RENAME_USER:
{
- if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
+ if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
- if (end_active_trans(thd))
- goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_rename_user(thd, lex->users_list)))
my_ok(thd);
@@ -3922,9 +3379,7 @@ end_with_restore_list:
}
case SQLCOM_REVOKE_ALL:
{
- if (end_active_trans(thd))
- goto error;
- if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
+ if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
@@ -3939,16 +3394,12 @@ end_with_restore_list:
case SQLCOM_REVOKE:
case SQLCOM_GRANT:
{
- if (end_active_trans(thd))
- goto error;
-
- if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
- first_table ? first_table->db : select_lex->db,
- first_table ? &first_table->grant.privilege : 0,
- first_table ? 0 : 1, 0,
- first_table ? (bool) first_table->schema_table :
- select_lex->db ?
- is_schema_db(select_lex->db) : 0))
+ if (lex->type != TYPE_ENUM_PROXY &&
+ check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
+ first_table ? first_table->db : select_lex->db,
+ first_table ? &first_table->grant.privilege : NULL,
+ first_table ? &first_table->grant.m_internal : NULL,
+ first_table ? 0 : 1, 0))
goto error;
/* Replicate current user as grantor */
@@ -3957,6 +3408,7 @@ end_with_restore_list:
if (thd->security_ctx->user) // If not replication
{
LEX_USER *user, *tmp_user;
+ bool first_user= TRUE;
List_iterator <LEX_USER> user_list(lex->users_list);
while ((tmp_user= user_list++))
@@ -3971,20 +3423,23 @@ end_with_restore_list:
user->host.str);
// Are we trying to change a password of another user
DBUG_ASSERT(user->host.str != 0);
- if (strcmp(thd->security_ctx->user, user->user.str) ||
- my_strcasecmp(system_charset_info,
- user->host.str, thd->security_ctx->host_or_ip))
+
+ /*
+ GRANT/REVOKE PROXY has the target user as a first entry in the list.
+ */
+ if (lex->type == TYPE_ENUM_PROXY && first_user)
{
- // TODO: use check_change_password()
- if (is_acl_user(user->host.str, user->user.str) &&
- user->password.str &&
- check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
- {
- my_message(ER_PASSWORD_NOT_ALLOWED,
- ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
+ first_user= FALSE;
+ if (acl_check_proxy_grant_access (thd, user->host.str, user->user.str,
+ lex->grant & GRANT_ACL))
goto error;
- }
- }
+ }
+ else if (is_acl_user(user->host.str, user->user.str) &&
+ user->password.str &&
+ check_change_password (thd, user->host.str, user->user.str,
+ user->password.str,
+ user->password.length))
+ goto error;
}
}
if (first_table)
@@ -4009,7 +3464,7 @@ end_with_restore_list:
else
{
if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL),
- all_tables, 0, UINT_MAX, 0))
+ all_tables, FALSE, UINT_MAX, FALSE))
goto error;
/* Conditionally writes to binlog */
res= mysql_table_grant(thd, all_tables, lex->users_list,
@@ -4019,16 +3474,19 @@ end_with_restore_list:
}
else
{
- if (lex->columns.elements || lex->type)
+ if (lex->columns.elements || (lex->type && lex->type != TYPE_ENUM_PROXY))
{
my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
MYF(0));
goto error;
}
else
- /* Conditionally writes to binlog */
- res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
- lex->sql_command == SQLCOM_REVOKE);
+ {
+ /* Conditionally writes to binlog */
+ res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
+ lex->sql_command == SQLCOM_REVOKE,
+ lex->type == TYPE_ENUM_PROXY);
+ }
if (!res)
{
if (lex->sql_command == SQLCOM_GRANT)
@@ -4059,6 +3517,18 @@ end_with_restore_list:
if (check_global_access(thd,RELOAD_ACL))
goto error;
+ if (first_table && lex->type & REFRESH_READ_LOCK)
+ {
+ /* Check table-level privileges. */
+ if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
+ FALSE, UINT_MAX, FALSE))
+ goto error;
+ if (flush_tables_with_read_lock(thd, all_tables))
+ goto error;
+ my_ok(thd);
+ break;
+ }
+
/*
reload_acl_and_cache() will tell us if we are allowed to write to the
binlog or not.
@@ -4120,7 +3590,7 @@ end_with_restore_list:
goto error;
if ((thd->security_ctx->priv_user &&
!strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
- !check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
+ !check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 0))
{
res = mysql_show_grants(thd, grant_user);
}
@@ -4129,7 +3599,7 @@ end_with_restore_list:
#endif
case SQLCOM_HA_OPEN:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE))
+ if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE))
goto error;
res= mysql_ha_open(thd, first_table, 0);
break;
@@ -4151,128 +3621,84 @@ end_with_restore_list:
break;
case SQLCOM_BEGIN:
- if (thd->transaction.xid_state.xa_state != XA_NOTR)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- if (begin_trans(thd))
+ if (trans_begin(thd, lex->start_transaction_opt))
goto error;
- if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
- {
- if (ha_start_consistent_snapshot(thd))
- goto error;
- }
my_ok(thd);
break;
case SQLCOM_COMMIT:
- if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
- lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
- goto error;
- my_ok(thd);
- break;
- case SQLCOM_ROLLBACK:
- if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
- lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
- goto error;
- my_ok(thd);
- break;
- case SQLCOM_RELEASE_SAVEPOINT:
{
- SAVEPOINT *sv;
- for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
+ DBUG_ASSERT(thd->lock == NULL ||
+ thd->locked_tables_mode == LTM_LOCK_TABLES);
+ bool tx_chain= (lex->tx_chain == TVL_YES ||
+ (thd->variables.completion_type == 1 &&
+ lex->tx_chain != TVL_NO));
+ bool tx_release= (lex->tx_release == TVL_YES ||
+ (thd->variables.completion_type == 2 &&
+ lex->tx_release != TVL_NO));
+ if (trans_commit(thd))
+ goto error;
+ thd->mdl_context.release_transactional_locks();
+ /* Begin transaction with the same isolation level. */
+ if (tx_chain)
{
- if (my_strnncoll(system_charset_info,
- (uchar *)lex->ident.str, lex->ident.length,
- (uchar *)sv->name, sv->length) == 0)
- break;
+ if (trans_begin(thd))
+ goto error;
}
- if (sv)
+ else
{
- if (ha_release_savepoint(thd, sv))
- res= TRUE; // cannot happen
- else
- my_ok(thd);
- thd->transaction.savepoints=sv->prev;
+ /* Reset the isolation level if no chaining transaction. */
+ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
}
- else
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
+ /* Disconnect the current client connection. */
+ if (tx_release)
+ thd->killed= THD::KILL_CONNECTION;
+ my_ok(thd);
break;
}
- case SQLCOM_ROLLBACK_TO_SAVEPOINT:
+ case SQLCOM_ROLLBACK:
{
- SAVEPOINT *sv;
- for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
+ DBUG_ASSERT(thd->lock == NULL ||
+ thd->locked_tables_mode == LTM_LOCK_TABLES);
+ bool tx_chain= (lex->tx_chain == TVL_YES ||
+ (thd->variables.completion_type == 1 &&
+ lex->tx_chain != TVL_NO));
+ bool tx_release= (lex->tx_release == TVL_YES ||
+ (thd->variables.completion_type == 2 &&
+ lex->tx_release != TVL_NO));
+ if (trans_rollback(thd))
+ goto error;
+ thd->mdl_context.release_transactional_locks();
+ /* Begin transaction with the same isolation level. */
+ if (tx_chain)
{
- if (my_strnncoll(system_charset_info,
- (uchar *)lex->ident.str, lex->ident.length,
- (uchar *)sv->name, sv->length) == 0)
- break;
+ if (trans_begin(thd))
+ goto error;
}
- if (sv)
+ else
{
- if (ha_rollback_to_savepoint(thd, sv))
- res= TRUE; // cannot happen
- else
- {
- if (((thd->options & OPTION_KEEP_LOG) ||
- thd->transaction.all.modified_non_trans_table) &&
- !thd->slave_thread)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARNING_NOT_COMPLETE_ROLLBACK,
- ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
- my_ok(thd);
- }
- thd->transaction.savepoints=sv;
+ /* Reset the isolation level if no chaining transaction. */
+ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
}
- else
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
+ /* Disconnect the current client connection. */
+ if (tx_release)
+ thd->killed= THD::KILL_CONNECTION;
+ my_ok(thd);
break;
}
+ case SQLCOM_RELEASE_SAVEPOINT:
+ if (trans_release_savepoint(thd, lex->ident))
+ goto error;
+ my_ok(thd);
+ break;
+ case SQLCOM_ROLLBACK_TO_SAVEPOINT:
+ if (trans_rollback_to_savepoint(thd, lex->ident))
+ goto error;
+ my_ok(thd);
+ break;
case SQLCOM_SAVEPOINT:
- if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
- thd->in_sub_stmt) || !opt_using_transactions)
- my_ok(thd);
- else
- {
- SAVEPOINT **sv, *newsv;
- for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
- {
- if (my_strnncoll(system_charset_info,
- (uchar *)lex->ident.str, lex->ident.length,
- (uchar *)(*sv)->name, (*sv)->length) == 0)
- break;
- }
- if (*sv) /* old savepoint of the same name exists */
- {
- newsv=*sv;
- ha_release_savepoint(thd, *sv); // it cannot fail
- *sv=(*sv)->prev;
- }
- else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
- savepoint_alloc_size)) == 0)
- {
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- break;
- }
- newsv->name=strmake_root(&thd->transaction.mem_root,
- lex->ident.str, lex->ident.length);
- newsv->length=lex->ident.length;
- /*
- if we'll get an error here, don't add new savepoint to the list.
- we'll lose a little bit of memory in transaction mem_root, but it'll
- be free'd when transaction ends anyway
- */
- if (ha_savepoint(thd, newsv))
- res= TRUE;
- else
- {
- newsv->prev=thd->transaction.savepoints;
- thd->transaction.savepoints=newsv;
- my_ok(thd);
- }
- }
+ if (trans_savepoint(thd, lex->ident))
+ goto error;
+ my_ok(thd);
break;
case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_CREATE_SPFUNCTION:
@@ -4304,12 +3730,8 @@ end_with_restore_list:
goto create_sp_error;
}
- if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
- is_schema_db(lex->sphead->m_db.str,
- lex->sphead->m_db.length)))
- goto create_sp_error;
-
- if (end_active_trans(thd))
+ if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str,
+ NULL, NULL, 0, 0))
goto create_sp_error;
name= lex->sphead->name(&namelen);
@@ -4329,7 +3751,7 @@ end_with_restore_list:
if (sp_process_definer(thd))
goto create_sp_error;
- res= (sp_result= lex->sphead->create(thd));
+ res= (sp_result= sp_create_routine(thd, lex->sphead->m_type, lex->sphead));
switch (sp_result) {
case SP_OK: {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -4340,6 +3762,23 @@ end_with_restore_list:
Security_context *backup= NULL;
LEX_USER *definer= thd->lex->definer;
/*
+ We're going to issue an implicit GRANT statement so we close all
+ open tables. We have to keep metadata locks as this ensures that
+ this statement is atomic against concurent FLUSH TABLES WITH READ
+ LOCK. Deadlocks which can arise due to fact that this implicit
+ statement takes metadata locks should be detected by a deadlock
+ detector in MDL subsystem and reported as errors.
+
+ No need to commit/rollback statement transaction, it's not started.
+
+ TODO: Long-term we should either ensure that implicit GRANT statement
+ is written into binary log as a separate statement or make both
+ creation of routine and implicit GRANT parts of one fully atomic
+ statement.
+ */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ close_thread_tables(thd);
+ /*
Check if the definer exists on slave,
then use definer privilege to insert routine privileges to mysql.procs_priv.
@@ -4365,8 +3804,8 @@ end_with_restore_list:
if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
lex->sql_command == SQLCOM_CREATE_PROCEDURE))
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_PROC_AUTO_GRANT_FAIL,
- ER(ER_PROC_AUTO_GRANT_FAIL));
+ ER_PROC_AUTO_GRANT_FAIL, ER(ER_PROC_AUTO_GRANT_FAIL));
+ thd->clear_error();
}
/*
@@ -4411,13 +3850,13 @@ create_sp_error:
case SQLCOM_CALL:
{
sp_head *sp;
-
/*
This will cache all SP and SF and open and lock all tables
required for execution.
*/
- if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
- open_and_lock_tables(thd, all_tables))
+ if (check_table_access(thd, SELECT_ACL, all_tables, FALSE,
+ UINT_MAX, FALSE) ||
+ open_and_lock_tables(thd, all_tables, TRUE, 0))
goto error;
/*
@@ -4486,20 +3925,15 @@ create_sp_error:
So just execute the statement.
*/
res= sp->execute_procedure(thd, &lex->value_list);
- /*
- If warnings have been cleared, we have to clear total_warn_count
- too, otherwise the clients get confused.
- */
- if (thd->warn_list.is_empty())
- thd->total_warn_count= 0;
thd->variables.select_limit= select_limit;
thd->server_status&= ~bits_to_be_cleared;
if (!res)
- my_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
- thd->row_count_func));
+ {
+ my_ok(thd, (thd->get_row_count_func() < 0) ? 0 : thd->get_row_count_func());
+ }
else
{
DBUG_ASSERT(thd->is_error() || thd->killed);
@@ -4512,67 +3946,22 @@ create_sp_error:
case SQLCOM_ALTER_FUNCTION:
{
int sp_result;
- sp_head *sp;
- st_sp_chistics chistics;
-
- memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
- if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
- sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
- &thd->sp_proc_cache, FALSE);
- else
- sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
- &thd->sp_func_cache, FALSE);
- mysql_reset_errors(thd, 0);
- if (! sp)
- {
- if (lex->spname->m_db.str)
- sp_result= SP_KEY_NOT_FOUND;
- else
- {
- my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
- goto error;
- }
- }
- else
- {
- if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str,
- sp->m_name.str,
- lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
- goto error;
-
- if (end_active_trans(thd))
- goto error;
- memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
- if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
- !trust_function_creators && mysql_bin_log.is_open() &&
- !sp->m_chistics->detistic &&
- (chistics.daccess == SP_CONTAINS_SQL ||
- chistics.daccess == SP_MODIFIES_SQL_DATA))
- {
- my_message(ER_BINLOG_UNSAFE_ROUTINE,
- ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
- sp_result= SP_INTERNAL_ERROR;
- }
- else
- {
- /*
- Note that if you implement the capability of ALTER FUNCTION to
- alter the body of the function, this command should be made to
- follow the restrictions that log-bin-trust-function-creators=0
- already puts on CREATE FUNCTION.
- */
- /* Conditionally writes to binlog */
+ int type= (lex->sql_command == SQLCOM_ALTER_PROCEDURE ?
+ TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
- int type= lex->sql_command == SQLCOM_ALTER_PROCEDURE ?
- TYPE_ENUM_PROCEDURE :
- TYPE_ENUM_FUNCTION;
+ if (check_routine_access(thd, ALTER_PROC_ACL, lex->spname->m_db.str,
+ lex->spname->m_name.str,
+ lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
+ goto error;
- sp_result= sp_update_routine(thd,
- type,
- lex->spname,
- &lex->sp_chistics);
- }
- }
+ /*
+ Note that if you implement the capability of ALTER FUNCTION to
+ alter the body of the function, this command should be made to
+ follow the restrictions that log-bin-trust-function-creators=0
+ already puts on CREATE FUNCTION.
+ */
+ /* Conditionally writes to binlog */
+ sp_result= sp_update_routine(thd, type, lex->spname, &lex->sp_chistics);
switch (sp_result)
{
case SP_OK:
@@ -4592,69 +3981,92 @@ create_sp_error:
case SQLCOM_DROP_PROCEDURE:
case SQLCOM_DROP_FUNCTION:
{
- int sp_result;
- int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
- TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
-
- sp_result= sp_routine_exists_in_table(thd, type, lex->spname);
- mysql_reset_errors(thd, 0);
- if (sp_result == SP_OK)
+#ifdef HAVE_DLOPEN
+ if (lex->sql_command == SQLCOM_DROP_FUNCTION &&
+ ! lex->spname->m_explicit_name)
{
- char *db= lex->spname->m_db.str;
- char *name= lex->spname->m_name.str;
+ /* DROP FUNCTION <non qualified name> */
+ udf_func *udf = find_udf(lex->spname->m_name.str,
+ lex->spname->m_name.length);
+ if (udf)
+ {
+ if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 0))
+ goto error;
- if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
- lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
+ if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
+ {
+ my_ok(thd);
+ break;
+ }
+ my_error(ER_SP_DROP_FAILED, MYF(0),
+ "FUNCTION (UDF)", lex->spname->m_name.str);
goto error;
+ }
- if (end_active_trans(thd))
+ if (lex->spname->m_db.str == NULL)
+ {
+ if (lex->drop_if_exists)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
+ "FUNCTION (UDF)", lex->spname->m_name.str);
+ res= FALSE;
+ my_ok(thd);
+ break;
+ }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ "FUNCTION (UDF)", lex->spname->m_name.str);
goto error;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (sp_automatic_privileges && !opt_noacl &&
- sp_revoke_privileges(thd, db, name,
- lex->sql_command == SQLCOM_DROP_PROCEDURE))
- {
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_PROC_AUTO_REVOKE_FAIL,
- ER(ER_PROC_AUTO_REVOKE_FAIL));
- }
+ }
+ /* Fall thought to test for a stored function */
+ }
#endif
- /* Conditionally writes to binlog */
- int type= lex->sql_command == SQLCOM_DROP_PROCEDURE ?
- TYPE_ENUM_PROCEDURE :
- TYPE_ENUM_FUNCTION;
+ int sp_result;
+ int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
+ TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
+ char *db= lex->spname->m_db.str;
+ char *name= lex->spname->m_name.str;
- sp_result= sp_drop_routine(thd, type, lex->spname);
- }
- else
+ if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
+ lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
+ goto error;
+
+ /* Conditionally writes to binlog */
+ sp_result= sp_drop_routine(thd, type, lex->spname);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ We're going to issue an implicit REVOKE statement so we close all
+ open tables. We have to keep metadata locks as this ensures that
+ this statement is atomic against concurent FLUSH TABLES WITH READ
+ LOCK. Deadlocks which can arise due to fact that this implicit
+ statement takes metadata locks should be detected by a deadlock
+ detector in MDL subsystem and reported as errors.
+
+ No need to commit/rollback statement transaction, it's not started.
+
+ TODO: Long-term we should either ensure that implicit REVOKE statement
+ is written into binary log as a separate statement or make both
+ dropping of routine and implicit REVOKE parts of one fully atomic
+ statement.
+ */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ close_thread_tables(thd);
+
+ if (sp_result != SP_KEY_NOT_FOUND &&
+ sp_automatic_privileges && !opt_noacl &&
+ sp_revoke_privileges(thd, db, name,
+ lex->sql_command == SQLCOM_DROP_PROCEDURE))
{
-#ifdef HAVE_DLOPEN
- if (lex->sql_command == SQLCOM_DROP_FUNCTION)
- {
- udf_func *udf = find_udf(lex->spname->m_name.str,
- lex->spname->m_name.length);
- if (udf)
- {
- if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
- goto error;
-
- if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
- {
- my_ok(thd);
- break;
- }
- }
- }
-#endif
- if (lex->spname->m_db.str)
- sp_result= SP_KEY_NOT_FOUND;
- else
- {
- my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
- goto error;
- }
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_PROC_AUTO_REVOKE_FAIL,
+ ER(ER_PROC_AUTO_REVOKE_FAIL));
+ /* If this happens, an error should have been reported. */
+ goto error;
}
+#endif
+
res= sp_result;
switch (sp_result) {
case SP_OK:
@@ -4666,7 +4078,7 @@ create_sp_error:
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
- SP_COM_STRING(lex), lex->spname->m_name.str);
+ SP_COM_STRING(lex), lex->spname->m_qname.str);
if (!res)
my_ok(thd);
break;
@@ -4684,35 +4096,25 @@ create_sp_error:
case SQLCOM_SHOW_CREATE_PROC:
{
if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
- {
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
- SP_COM_STRING(lex), lex->spname->m_name.str);
- goto error;
- }
+ goto error;
break;
}
case SQLCOM_SHOW_CREATE_FUNC:
{
if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
- {
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
- SP_COM_STRING(lex), lex->spname->m_name.str);
goto error;
- }
break;
}
-#ifndef DBUG_OFF
case SQLCOM_SHOW_PROC_CODE:
case SQLCOM_SHOW_FUNC_CODE:
{
+#ifndef DBUG_OFF
sp_head *sp;
+ int type= (lex->sql_command == SQLCOM_SHOW_PROC_CODE ?
+ TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
- if (lex->sql_command == SQLCOM_SHOW_PROC_CODE)
- sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
- &thd->sp_proc_cache, FALSE);
- else
- sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
- &thd->sp_func_cache, FALSE);
+ if (sp_cache_routine(thd, type, lex->spname, FALSE, &sp))
+ goto error;
if (!sp || sp->show_routine_code(thd))
{
/* We don't distinguish between errors for now */
@@ -4721,8 +4123,12 @@ create_sp_error:
goto error;
}
break;
- }
+#else
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ "SHOW PROCEDURE|FUNCTION CODE", "--with-debug");
+ goto error;
#endif // ifndef DBUG_OFF
+ }
case SQLCOM_SHOW_CREATE_TRIGGER:
{
if (lex->spname->m_name.length > NAME_LEN)
@@ -4742,16 +4148,12 @@ create_sp_error:
Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands
as specified through the thd->lex->create_view_mode flag.
*/
- if (end_active_trans(thd))
- goto error;
-
res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
break;
}
case SQLCOM_DROP_VIEW:
{
- if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE) ||
- end_active_trans(thd))
+ if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE))
goto error;
/* Conditionally writes to binlog. */
res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
@@ -4759,9 +4161,6 @@ create_sp_error:
}
case SQLCOM_CREATE_TRIGGER:
{
- if (end_active_trans(thd))
- goto error;
-
/* Conditionally writes to binlog. */
res= mysql_create_or_drop_trigger(thd, all_tables, 1);
@@ -4769,210 +4168,52 @@ create_sp_error:
}
case SQLCOM_DROP_TRIGGER:
{
- if (end_active_trans(thd))
- goto error;
-
/* Conditionally writes to binlog. */
res= mysql_create_or_drop_trigger(thd, all_tables, 0);
break;
}
case SQLCOM_XA_START:
- if (thd->transaction.xid_state.xa_state == XA_IDLE &&
- thd->lex->xa_opt == XA_RESUME)
- {
- if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
- {
- my_error(ER_XAER_NOTA, MYF(0));
- break;
- }
- thd->transaction.xid_state.xa_state= XA_ACTIVE;
- my_ok(thd);
- break;
- }
- if (thd->lex->xa_opt != XA_NONE)
- { // JOIN is not supported yet. TODO
- my_error(ER_XAER_INVAL, MYF(0));
- break;
- }
- if (thd->transaction.xid_state.xa_state != XA_NOTR)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- if (thd->active_transaction() || thd->locked_tables)
- {
- my_error(ER_XAER_OUTSIDE, MYF(0));
- break;
- }
- DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
- thd->transaction.xid_state.xa_state= XA_ACTIVE;
- thd->transaction.xid_state.rm_error= 0;
- thd->transaction.xid_state.xid.set(thd->lex->xid);
- if (xid_cache_insert(&thd->transaction.xid_state))
- {
- thd->transaction.xid_state.xa_state= XA_NOTR;
- thd->transaction.xid_state.xid.null();
- break;
- }
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
- thd->server_status|= SERVER_STATUS_IN_TRANS;
+ if (trans_xa_start(thd))
+ goto error;
my_ok(thd);
break;
case SQLCOM_XA_END:
- /* fake it */
- if (thd->lex->xa_opt != XA_NONE)
- { // SUSPEND and FOR MIGRATE are not supported yet. TODO
- my_error(ER_XAER_INVAL, MYF(0));
- break;
- }
- if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
- {
- my_error(ER_XAER_NOTA, MYF(0));
- break;
- }
- if (xa_trans_rolled_back(&thd->transaction.xid_state))
- break;
- thd->transaction.xid_state.xa_state=XA_IDLE;
+ if (trans_xa_end(thd))
+ goto error;
my_ok(thd);
break;
case SQLCOM_XA_PREPARE:
- if (thd->transaction.xid_state.xa_state != XA_IDLE)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
- {
- my_error(ER_XAER_NOTA, MYF(0));
- break;
- }
- if (ha_prepare(thd))
- {
- my_error(ER_XA_RBROLLBACK, MYF(0));
- xid_cache_delete(&thd->transaction.xid_state);
- thd->transaction.xid_state.xa_state=XA_NOTR;
- break;
- }
- thd->transaction.xid_state.xa_state=XA_PREPARED;
+ if (trans_xa_prepare(thd))
+ goto error;
my_ok(thd);
break;
case SQLCOM_XA_COMMIT:
- if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
- {
- /*
- xid_state.in_thd is always true beside of xa recovery
- procedure. Note, that there is no race condition here
- between xid_cache_search and xid_cache_delete, since we're always
- deleting our own XID (thd->lex->xid == thd->transaction.xid_state.xid).
- The only case when thd->lex->xid != thd->transaction.xid_state.xid
- and xid_state->in_thd == 0 is in ha_recover() functionality,
- which is called before starting client connections, and thus is
- always single-threaded.
- */
- XID_STATE *xs=xid_cache_search(thd->lex->xid);
- if (!xs || xs->in_thd)
- my_error(ER_XAER_NOTA, MYF(0));
- else if (xa_trans_rolled_back(xs))
- {
- ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
- xid_cache_delete(xs);
- break;
- }
- else
- {
- ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
- xid_cache_delete(xs);
- my_ok(thd);
- }
- break;
- }
- if (xa_trans_rolled_back(&thd->transaction.xid_state))
- {
- xa_trans_rollback(thd);
- break;
- }
- if (thd->transaction.xid_state.xa_state == XA_IDLE &&
- thd->lex->xa_opt == XA_ONE_PHASE)
- {
- int r;
- if ((r= ha_commit(thd)))
- my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
- else
- my_ok(thd);
- }
- else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
- thd->lex->xa_opt == XA_NONE)
- {
- if (wait_if_global_read_lock(thd, 0, 0))
- {
- ha_rollback(thd);
- my_error(ER_XAER_RMERR, MYF(0));
- }
- else
- {
- if (ha_commit_one_phase(thd, 1))
- my_error(ER_XAER_RMERR, MYF(0));
- else
- my_ok(thd);
- start_waiting_global_read_lock(thd);
- }
- }
- else
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- xid_cache_delete(&thd->transaction.xid_state);
- thd->transaction.xid_state.xa_state=XA_NOTR;
+ if (trans_xa_commit(thd))
+ goto error;
+ thd->mdl_context.release_transactional_locks();
+ /*
+ We've just done a commit, reset transaction
+ isolation level to the session default.
+ */
+ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+ my_ok(thd);
break;
case SQLCOM_XA_ROLLBACK:
- if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
- {
- XID_STATE *xs=xid_cache_search(thd->lex->xid);
- if (!xs || xs->in_thd)
- my_error(ER_XAER_NOTA, MYF(0));
- else
- {
- bool ok= !xa_trans_rolled_back(xs);
- ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
- xid_cache_delete(xs);
- if (ok)
- my_ok(thd);
- }
- break;
- }
- if (thd->transaction.xid_state.xa_state != XA_IDLE &&
- thd->transaction.xid_state.xa_state != XA_PREPARED &&
- thd->transaction.xid_state.xa_state != XA_ROLLBACK_ONLY)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- if (xa_trans_rollback(thd))
- my_error(ER_XAER_RMERR, MYF(0));
- else
- my_ok(thd);
+ if (trans_xa_rollback(thd))
+ goto error;
+ thd->mdl_context.release_transactional_locks();
+ /*
+ We've just done a rollback, reset transaction
+ isolation level to the session default.
+ */
+ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+ my_ok(thd);
break;
case SQLCOM_XA_RECOVER:
res= mysql_xa_recover(thd);
break;
case SQLCOM_ALTER_TABLESPACE:
- if (check_access(thd, ALTER_ACL, thd->db, 0, 1, 0,
- thd->db ? is_schema_db(thd->db, thd->db_length) : 0))
+ if (check_global_access(thd, CREATE_TABLESPACE_ACL))
break;
if (!(res= mysql_alter_tablespace(thd, lex->alter_tablespace_info)))
my_ok(thd);
@@ -5059,6 +4300,19 @@ create_sp_error:
my_ok(thd, 1);
break;
}
+ case SQLCOM_ANALYZE:
+ case SQLCOM_CHECK:
+ case SQLCOM_OPTIMIZE:
+ case SQLCOM_REPAIR:
+ case SQLCOM_TRUNCATE:
+ case SQLCOM_ALTER_TABLE:
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ /* fall through */
+ case SQLCOM_SIGNAL:
+ case SQLCOM_RESIGNAL:
+ DBUG_ASSERT(lex->m_stmt != NULL);
+ res= lex->m_stmt->execute(thd);
+ break;
default:
#ifndef EMBEDDED_LIBRARY
DBUG_ASSERT(0); /* Impossible */
@@ -5081,29 +4335,82 @@ create_sp_error:
if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION)
reset_one_shot_variables(thd);
- /*
- The return value for ROW_COUNT() is "implementation dependent" if the
- statement is not DELETE, INSERT or UPDATE, but -1 is what JDBC and ODBC
- wants. We also keep the last value in case of SQLCOM_CALL or
- SQLCOM_EXECUTE.
- */
- if (!(sql_command_flags[lex->sql_command] & CF_HAS_ROW_COUNT))
- thd->row_count_func= -1;
-
goto finish;
error:
res= TRUE;
finish:
- if (need_start_waiting)
+
+ DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() ||
+ thd->in_multi_stmt_transaction_mode());
+
+
+ if (! thd->in_sub_stmt)
+ {
+ /* report error issued during command execution */
+ if (thd->killed_errno())
+ {
+ if (! thd->stmt_da->is_set())
+ thd->send_kill_message();
+ }
+ if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
+ {
+ thd->killed= THD::NOT_KILLED;
+ thd->mysys_var->abort= 0;
+ }
+ if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR))
+ trans_rollback_stmt(thd);
+ else
+ {
+ /* If commit fails, we should be able to reset the OK status. */
+ thd->stmt_da->can_overwrite_status= TRUE;
+ trans_commit_stmt(thd);
+ thd->stmt_da->can_overwrite_status= FALSE;
+ }
+ }
+
+ lex->unit.cleanup();
+ /* Free tables */
+ thd_proc_info(thd, "closing tables");
+ close_thread_tables(thd);
+ thd_proc_info(thd, 0);
+
+#ifndef DBUG_OFF
+ if (lex->sql_command != SQLCOM_SET_OPTION && ! thd->in_sub_stmt)
+ DEBUG_SYNC(thd, "execute_command_after_close_tables");
+#endif
+
+ if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END))
+ {
+ /* No transaction control allowed in sub-statements. */
+ DBUG_ASSERT(! thd->in_sub_stmt);
+ /* If commit fails, we should be able to reset the OK status. */
+ thd->stmt_da->can_overwrite_status= TRUE;
+ /* Commit the normal transaction if one is active. */
+ trans_commit_implicit(thd);
+ thd->stmt_da->can_overwrite_status= FALSE;
+ thd->mdl_context.release_transactional_locks();
+ }
+ else if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
{
/*
- Release the protection against the global read lock and wake
- everyone, who might want to set a global read lock.
+ - 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.
*/
- start_waiting_global_read_lock(thd);
+ thd->mdl_context.release_transactional_locks();
}
+ else if (! thd->in_sub_stmt)
+ {
+ thd->mdl_context.release_statement_locks();
+ }
+
DBUG_RETURN(res || thd->is_error());
}
@@ -5120,7 +4427,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
param->select_limit=
new Item_int((ulonglong) thd->variables.select_limit);
}
- if (!(res= open_and_lock_tables(thd, all_tables)))
+ if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0)))
{
if (lex->describe)
{
@@ -5145,7 +4452,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
ER_YES, str.ptr());
}
if (res)
- result->abort();
+ result->abort_result_set();
else
result->send_eof();
delete result;
@@ -5197,14 +4504,15 @@ bool check_single_table_access(THD *thd, ulong privilege,
db_name= all_tables->db;
if (check_access(thd, privilege, db_name,
- &all_tables->grant.privilege, 0, no_errors,
- test(all_tables->schema_table)))
+ &all_tables->grant.privilege,
+ &all_tables->grant.m_internal,
+ 0, no_errors))
goto deny;
/* Show only 1 table for check_grant */
if (!(all_tables->belong_to_view &&
(thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
- check_grant(thd, privilege, all_tables, 0, 1, no_errors))
+ check_grant(thd, privilege, all_tables, FALSE, 1, no_errors))
goto deny;
thd->security_ctx= backup_ctx;
@@ -5249,7 +4557,8 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
subselects_tables= subselects_tables->next_global;
}
if (subselects_tables &&
- (check_table_access(thd, SELECT_ACL, subselects_tables, UINT_MAX, FALSE)))
+ (check_table_access(thd, SELECT_ACL, subselects_tables, FALSE,
+ UINT_MAX, FALSE)))
return 1;
}
return 0;
@@ -5257,50 +4566,62 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
/**
- Get the user (global) and database privileges for all used tables.
-
- @param save_priv In this we store global and db level grants for the
- table. Note that we don't store db level grants if the
- global grants is enough to satisfy the request and the
- global grants contains a SELECT grant.
-
- @note
- The idea of EXTRA_ACL is that one will be granted access to the table if
- one has the asked privilege on any column combination of the table; For
- example to be able to check a table one needs to have SELECT privilege on
- any column of the table.
-
- @retval
- 0 ok
- @retval
- 1 If we can't get the privileges and we don't use table/column
- grants.
+ @brief Compare requested privileges with the privileges acquired from the
+ User- and Db-tables.
+ @param thd Thread handler
+ @param want_access The requested access privileges.
+ @param db A pointer to the Db name.
+ @param[out] save_priv A pointer to the granted privileges will be stored.
+ @param grant_internal_info A pointer to the internal grant cache.
+ @param dont_check_global_grants True if no global grants are checked.
+ @param no_error True if no errors should be sent to the client.
+
+ 'save_priv' is used to save the User-table (global) and Db-table grants for
+ the supplied db name. Note that we don't store db level grants if the global
+ grants is enough to satisfy the request AND the global grants contains a
+ SELECT grant.
+
+ For internal databases (INFORMATION_SCHEMA, PERFORMANCE_SCHEMA),
+ additional rules apply, see ACL_internal_schema_access.
+
+ @see check_grant
+
+ @return Status of denial of access by exclusive ACLs.
+ @retval FALSE Access can't exclusively be denied by Db- and User-table
+ access unless Column- and Table-grants are checked too.
+ @retval TRUE Access denied.
*/
+
bool
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
- bool dont_check_global_grants, bool no_errors, bool schema_db)
+ GRANT_INTERNAL_INFO *grant_internal_info,
+ bool dont_check_global_grants, bool no_errors)
{
Security_context *sctx= thd->security_ctx;
ulong db_access;
+
/*
GRANT command:
In case of database level grant the database name may be a pattern,
in case of table|column level grant the database name can not be a pattern.
We use 'dont_check_global_grants' as a flag to determine
- if it's database level grant command
+ if it's database level grant command
(see SQLCOM_GRANT case, mysql_execute_command() function) and
set db_is_pattern according to 'dont_check_global_grants' value.
*/
- bool db_is_pattern= (test(want_access & GRANT_ACL) &&
- dont_check_global_grants);
+ bool db_is_pattern= ((want_access & GRANT_ACL) && dont_check_global_grants);
ulong dummy;
DBUG_ENTER("check_access");
DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
db ? db : "", want_access, sctx->master_access));
+
if (save_priv)
*save_priv=0;
else
+ {
save_priv= &dummy;
+ dummy= 0;
+ }
thd_proc_info(thd, "checking permissions");
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
@@ -5312,88 +4633,166 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
DBUG_RETURN(TRUE); /* purecov: tested */
}
- if (schema_db)
+ if ((db != NULL) && (db != any_db))
{
- if ((!(sctx->master_access & FILE_ACL) && (want_access & FILE_ACL)) ||
- (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
+ const ACL_internal_schema_access *access;
+ access= get_cached_schema_access(grant_internal_info, db);
+ if (access)
{
- if (!no_errors)
+ switch (access->check(want_access, save_priv))
{
- const char *db_name= db ? db : thd->db;
- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- sctx->priv_user, sctx->priv_host, db_name);
+ case ACL_INTERNAL_ACCESS_GRANTED:
+ /*
+ All the privileges requested have been granted internally.
+ [out] *save_privileges= Internal privileges.
+ */
+ DBUG_RETURN(FALSE);
+ case ACL_INTERNAL_ACCESS_DENIED:
+ if (! no_errors)
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ sctx->priv_user, sctx->priv_host, db);
+ }
+ DBUG_RETURN(TRUE);
+ case ACL_INTERNAL_ACCESS_CHECK_GRANT:
+ /*
+ Only some of the privilege requested have been granted internally,
+ proceed with the remaining bits of the request (want_access).
+ */
+ want_access&= ~(*save_priv);
+ break;
}
- DBUG_RETURN(TRUE);
- }
- else
- {
- *save_priv= SELECT_ACL;
- DBUG_RETURN(FALSE);
}
}
if ((sctx->master_access & want_access) == want_access)
{
/*
- If we don't have a global SELECT privilege, we have to get the database
- specific access rights to be able to handle queries of type
+ 1. If we don't have a global SELECT privilege, we have to get the
+ database specific access rights to be able to handle queries of type
UPDATE t1 SET a=1 WHERE b > 0
+ 2. Change db access if it isn't current db which is being addressed
*/
- db_access= sctx->db_access;
- if (!(sctx->master_access & SELECT_ACL) &&
- (db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
- db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
- db_is_pattern);
- *save_priv=sctx->master_access | db_access;
+ if (!(sctx->master_access & SELECT_ACL))
+ {
+ if (db && (!thd->db || db_is_pattern || strcmp(db, thd->db)))
+ db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
+ db_is_pattern);
+ else
+ {
+ /* get access for current db */
+ db_access= sctx->db_access;
+ }
+ /*
+ The effective privileges are the union of the global privileges
+ and the intersection of db- and host-privileges,
+ plus the internal privileges.
+ */
+ *save_priv|= sctx->master_access | db_access;
+ }
+ else
+ *save_priv|= sctx->master_access;
DBUG_RETURN(FALSE);
}
- if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
+ if (((want_access & ~sctx->master_access) & ~DB_ACLS) ||
(! db && dont_check_global_grants))
{ // We can never grant this
DBUG_PRINT("error",("No possible access"));
if (!no_errors)
- my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
- sctx->priv_user,
- sctx->priv_host,
- (thd->password ?
- ER(ER_YES) :
- ER(ER_NO))); /* purecov: tested */
+ {
+ if (thd->password == 2)
+ my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
+ sctx->priv_user,
+ sctx->priv_host);
+ else
+ my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
+ sctx->priv_user,
+ sctx->priv_host,
+ (thd->password ?
+ ER(ER_YES) :
+ ER(ER_NO))); /* purecov: tested */
+ }
DBUG_RETURN(TRUE); /* purecov: tested */
}
if (db == any_db)
- DBUG_RETURN(FALSE); // Allow select on anything
+ {
+ /*
+ Access granted; Allow select on *any* db.
+ [out] *save_privileges= 0
+ */
+ DBUG_RETURN(FALSE);
+ }
if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
db_is_pattern);
else
db_access= sctx->db_access;
- DBUG_PRINT("info",("db_access: %lu", db_access));
- /* Remove SHOW attribute and access rights we already have */
- want_access &= ~(sctx->master_access | EXTRA_ACL);
DBUG_PRINT("info",("db_access: %lu want_access: %lu",
db_access, want_access));
- db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
- if (db_access == want_access ||
+ /*
+ Save the union of User-table and the intersection between Db-table and
+ Host-table privileges, with the already saved internal privileges.
+ */
+ db_access= (db_access | sctx->master_access);
+ *save_priv|= db_access;
+
+ /*
+ We need to investigate column- and table access if all requested privileges
+ belongs to the bit set of .
+ */
+ bool need_table_or_column_check=
+ (want_access & (TABLE_ACLS | PROC_ACLS | db_access)) == want_access;
+
+ /*
+ Grant access if the requested access is in the intersection of
+ host- and db-privileges (as retrieved from the acl cache),
+ also grant access if all the requested privileges are in the union of
+ TABLES_ACLS and PROC_ACLS; see check_grant.
+ */
+ if ( (db_access & want_access) == want_access ||
(!dont_check_global_grants &&
- !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
- DBUG_RETURN(FALSE); /* Ok */
+ need_table_or_column_check))
+ {
+ /*
+ Ok; but need to check table- and column privileges.
+ [out] *save_privileges is (User-priv | (Db-priv & Host-priv) | Internal-priv)
+ */
+ DBUG_RETURN(FALSE);
+ }
+ /*
+ Access is denied;
+ [out] *save_privileges is (User-priv | (Db-priv & Host-priv) | Internal-priv)
+ */
DBUG_PRINT("error",("Access denied"));
if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
sctx->priv_user, sctx->priv_host,
(db ? db : (thd->db ?
thd->db :
- "unknown"))); /* purecov: tested */
- DBUG_RETURN(TRUE); /* purecov: tested */
+ "unknown")));
+ DBUG_RETURN(TRUE);
+
}
static bool check_show_access(THD *thd, TABLE_LIST *table)
{
+ /*
+ This is a SHOW command using an INFORMATION_SCHEMA table.
+ check_access() has not been called for 'table',
+ and SELECT is currently always granted on the I_S, so we automatically
+ grant SELECT on table here, to bypass a call to check_access().
+ Note that not calling check_access(table) is an optimization,
+ which needs to be revisited if the INFORMATION_SCHEMA does
+ not always automatically grant SELECT but use the grant tables.
+ See Bug#38837 need a way to disable information_schema for security
+ */
+ table->grant.privilege= SELECT_ACL;
+
switch (get_schema_table_idx(table->schema_table)) {
case SCH_SCHEMATA:
return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
@@ -5410,8 +4809,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
DBUG_ASSERT(dst_db_name);
if (check_access(thd, SELECT_ACL, dst_db_name,
- &thd->col_access, FALSE, FALSE,
- is_schema_db(dst_db_name)))
+ &thd->col_access, NULL, FALSE, FALSE))
return TRUE;
if (!thd->col_access && check_grant_db(thd, dst_db_name))
@@ -5434,14 +4832,21 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
DBUG_ASSERT(dst_table);
- if (check_access(thd, SELECT_ACL | EXTRA_ACL,
- dst_table->db,
+ if (check_access(thd, SELECT_ACL, dst_table->db,
&dst_table->grant.privilege,
- FALSE, FALSE,
- test(dst_table->schema_table)))
- return FALSE;
+ &dst_table->grant.m_internal,
+ FALSE, FALSE))
+ return TRUE; /* Access denied */
- return (check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE));
+ /*
+ Check_grant will grant access if there is any column privileges on
+ all of the tables thanks to the fourth parameter (bool show_table).
+ */
+ if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE))
+ return TRUE; /* Access denied */
+
+ /* Access granted */
+ return FALSE;
}
default:
break;
@@ -5451,30 +4856,46 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
}
-/**
- Check the privilege for all used tables.
- @param thd Thread context
- @param want_access Privileges requested
- @param tables List of tables to be checked
- @param number Check at most this number of tables.
- @param no_errors FALSE/TRUE - report/don't report error to
- the client (using my_error() call).
+/**
+ @brief Check if the requested privileges exists in either User-, Host- or
+ Db-tables.
+ @param thd Thread context
+ @param want_access Privileges requested
+ @param tables List of tables to be compared against
+ @param no_errors Don't report error to the client (using my_error() call).
+ @param any_combination_of_privileges_will_do TRUE if any privileges on any
+ column combination is enough.
+ @param number Only the first 'number' tables in the linked list are
+ relevant.
+
+ The suppled table list contains cached privileges. This functions calls the
+ help functions check_access and check_grant to verify the first three steps
+ in the privileges check queue:
+ 1. Global privileges
+ 2. OR (db privileges AND host privileges)
+ 3. OR table privileges
+ 4. OR column privileges (not checked by this function!)
+ 5. OR routine privileges (not checked by this function!)
+
+ @see check_access
+ @see check_grant
+
+ @note This functions assumes that table list used and
+ thd->lex->query_tables_own_last value correspond to each other
+ (the latter should be either 0 or point to next_global member
+ of one of elements of this table list).
- @note
- Table privileges are cached in the table list for GRANT checking.
- This functions assumes that table list used and
- thd->lex->query_tables_own_last value correspond to each other
- (the latter should be either 0 or point to next_global member
- of one of elements of this table list).
-
- @retval FALSE OK
- @retval TRUE Access denied
+ @return
+ @retval FALSE OK
+ @retval TRUE Access denied; But column or routine privileges might need to
+ be checked also.
*/
bool
-check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
- uint number, bool no_errors)
+check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
+ bool any_combination_of_privileges_will_do,
+ uint number, bool no_errors)
{
TABLE_LIST *org_tables= tables;
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
@@ -5485,23 +4906,15 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
the given table list refers to the list for prelocking (contains tables
of other queries). For simple queries first_not_own_table is 0.
*/
- for (; i < number && tables != first_not_own_table;
+ for (; i < number && tables != first_not_own_table && tables;
tables= tables->next_global, i++)
{
+ ulong want_access= requirements;
if (tables->security_ctx)
sctx= tables->security_ctx;
else
sctx= backup_ctx;
- if (tables->schema_table &&
- (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
- {
- if (!no_errors)
- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- sctx->priv_user, sctx->priv_host,
- INFORMATION_SCHEMA_NAME.str);
- return TRUE;
- }
/*
Register access for view underlying table.
Remove SHOW_VIEW_ACL, because it will be checked during making view
@@ -5512,33 +4925,27 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
{
if (check_show_access(thd, tables))
goto deny;
-
continue;
}
+ DBUG_PRINT("info", ("derived: %d view: %d", tables->derived != 0,
+ tables->view != 0));
if (tables->is_anonymous_derived_table() ||
- (tables->table && (int)tables->table->s->tmp_table))
+ (tables->table && tables->table->s &&
+ (int)tables->table->s->tmp_table))
continue;
thd->security_ctx= sctx;
- if ((sctx->master_access & want_access) ==
- (want_access & ~EXTRA_ACL) &&
- thd->db)
- tables->grant.privilege= want_access;
- else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
- {
- if (check_access(thd, want_access, tables->get_db_name(),
- &tables->grant.privilege, 0, no_errors,
- test(tables->schema_table)))
- goto deny; // Access denied
- }
- else if (check_access(thd, want_access, tables->get_db_name(),
- &tables->grant.privilege, 0, no_errors,
- test(tables->schema_table)))
+
+ if (check_access(thd, want_access, tables->get_db_name(),
+ &tables->grant.privilege,
+ &tables->grant.m_internal,
+ 0, no_errors))
goto deny;
}
thd->security_ctx= backup_ctx;
- return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
- test(want_access & EXTRA_ACL), number, no_errors);
+ return check_grant(thd,requirements,org_tables,
+ any_combination_of_privileges_will_do,
+ number, no_errors);
deny:
thd->security_ctx= backup_ctx;
return TRUE;
@@ -5560,14 +4967,23 @@ check_routine_access(THD *thd, ulong want_access,char *db, char *name,
calculating db_access) under the assumption that it's common to
give persons global right to execute all stored SP (but not
necessary to create them).
+ Note that this effectively bypasses the ACL_internal_schema_access checks
+ that are implemented for the INFORMATION_SCHEMA and PERFORMANCE_SCHEMA,
+ which are located in check_access().
+ Since the I_S and P_S do not contain routines, this bypass is ok,
+ as long as this code path is not abused to create routines.
+ The assert enforce that.
*/
+ DBUG_ASSERT((want_access & CREATE_PROC_ACL) == 0);
if ((thd->security_ctx->master_access & want_access) == want_access)
tables->grant.privilege= want_access;
- else if (check_access(thd,want_access,db,&tables->grant.privilege,
- 0, no_errors, 0))
+ else if (check_access(thd, want_access, db,
+ &tables->grant.privilege,
+ &tables->grant.m_internal,
+ 0, no_errors))
return TRUE;
- return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
+ return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
}
@@ -5588,13 +5004,18 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name,
bool is_proc)
{
ulong save_priv;
- if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
- return FALSE;
/*
- There are no routines in information_schema db. So we can safely
- pass zero to last paramter of check_access function
+ The following test is just a shortcut for check_access() (to avoid
+ calculating db_access)
+ Note that this effectively bypasses the ACL_internal_schema_access checks
+ that are implemented for the INFORMATION_SCHEMA and PERFORMANCE_SCHEMA,
+ which are located in check_access().
+ Since the I_S and P_S do not contain routines, this bypass is ok,
+ as it only opens SHOW_PROC_ACLS.
*/
- if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1, 0) ||
+ if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
+ return FALSE;
+ if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, NULL, 0, 1) ||
(save_priv & SHOW_PROC_ACLS))
return FALSE;
return check_routine_level_acl(thd, db, name, is_proc);
@@ -5624,9 +5045,10 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
if (access & want_access)
{
if (!check_access(thd, access, table->db,
- &table->grant.privilege, 0, 1,
- test(table->schema_table)) &&
- !check_grant(thd, access, table, 0, 1, 1))
+ &table->grant.privilege,
+ &table->grant.m_internal,
+ 0, 1) &&
+ !check_grant(thd, access, table, FALSE, 1, TRUE))
DBUG_RETURN(0);
}
}
@@ -5673,7 +5095,6 @@ bool check_global_access(THD *thd, ulong want_access)
Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/
-#ifndef EMBEDDED_LIBRARY
#if STACK_DIRECTION < 0
#define used_stack(A,B) (long) (A - B)
@@ -5700,11 +5121,17 @@ bool check_stack_overrun(THD *thd, long margin,
if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
(long) (my_thread_stack_size - margin))
{
- char ebuff[MYSQL_ERRMSG_SIZE];
- my_snprintf(ebuff, sizeof(ebuff), ER(ER_STACK_OVERRUN_NEED_MORE),
- stack_used, my_thread_stack_size, margin);
- my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));
- thd->fatal_error();
+ /*
+ Do not use stack for the message buffer to ensure correct
+ behaviour in cases we have close to no stack left.
+ */
+ char* ebuff= new char[MYSQL_ERRMSG_SIZE];
+ if (ebuff) {
+ my_snprintf(ebuff, MYSQL_ERRMSG_SIZE, ER(ER_STACK_OVERRUN_NEED_MORE),
+ stack_used, my_thread_stack_size, margin);
+ my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));
+ delete [] ebuff;
+ }
return 1;
}
#ifndef DBUG_OFF
@@ -5712,7 +5139,7 @@ bool check_stack_overrun(THD *thd, long margin,
#endif
return 0;
}
-#endif /* EMBEDDED_LIBRARY */
+
#define MY_YACC_INIT 1000 // Start with big alloc
#define MY_YACC_MAX 32000 // Because of 'short'
@@ -5753,21 +5180,26 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
/**
- Reset THD part responsible for command processing state.
+ Reset the part of THD responsible for the state of command
+ processing.
- This needs to be called before execution of every statement
- (prepared or conventional).
- It is not called by substatements of routines.
+ This needs to be called before execution of every statement
+ (prepared or conventional). It is not called by substatements of
+ routines.
- @todo
- Make it a method of THD and align its name with the rest of
- reset/end/start/init methods.
- @todo
- Call it after we use THD for queries, not before.
-*/
+ @todo Remove mysql_reset_thd_for_next_command and only use the
+ member function.
+ @todo Call it after we use THD for queries, not before.
+*/
void mysql_reset_thd_for_next_command(THD *thd)
{
+ thd->reset_for_next_command();
+}
+
+void THD::reset_for_next_command()
+{
+ THD *thd= this;
DBUG_ENTER("mysql_reset_thd_for_next_command");
DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
DBUG_ASSERT(! thd->in_sub_stmt);
@@ -5792,9 +5224,9 @@ void mysql_reset_thd_for_next_command(THD *thd)
OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG to not get warnings
in ha_rollback_trans() about some tables couldn't be rolled back.
*/
- if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ if (!thd->in_multi_stmt_transaction_mode())
{
- thd->options&= ~OPTION_KEEP_LOG;
+ thd->variables.option_bits&= ~OPTION_KEEP_LOG;
thd->transaction.all.modified_non_trans_table= FALSE;
}
DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
@@ -5806,20 +5238,17 @@ void mysql_reset_thd_for_next_command(THD *thd)
thd->user_var_events_alloc= thd->mem_root;
}
thd->clear_error();
- thd->main_da.reset_diagnostics_area();
- thd->total_warn_count=0; // Warnings for this query
+ thd->stmt_da->reset_diagnostics_area();
+ thd->warning_info->reset_for_next_command();
thd->rand_used= 0;
thd->sent_row_count= thd->examined_row_count= 0;
- /*
- Because we come here only for start of top-statements, binlog format is
- constant inside a complex statement (using stored functions) etc.
- */
- thd->reset_current_stmt_binlog_row_based();
+ thd->reset_current_stmt_binlog_format_row();
+ thd->binlog_unsafe_warning_flags= 0;
DBUG_PRINT("debug",
- ("current_stmt_binlog_row_based: %d",
- thd->current_stmt_binlog_row_based));
+ ("is_current_stmt_binlog_format_row(): %d",
+ thd->is_current_stmt_binlog_format_row()));
DBUG_VOID_RETURN;
}
@@ -5981,7 +5410,6 @@ void mysql_init_multi_delete(LEX *lex)
lex->select_lex.select_limit= 0;
lex->unit.select_limit_cnt= HA_POS_ERROR;
lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
- lex->lock_option= TL_READ_DEFAULT;
lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
}
@@ -6003,8 +5431,9 @@ void mysql_init_multi_delete(LEX *lex)
*/
void mysql_parse(THD *thd, char *rawbuf, uint length,
- const char ** found_semicolon)
+ Parser_state *parser_state)
{
+ int error __attribute__((unused));
DBUG_ENTER("mysql_parse");
DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
@@ -6032,18 +5461,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
{
LEX *lex= thd->lex;
- sp_cache_flush_obsolete(&thd->sp_proc_cache);
- sp_cache_flush_obsolete(&thd->sp_func_cache);
-
- Parser_state parser_state;
- bool err;
- if (!(err= parser_state.init(thd, rawbuf, length)))
- {
- err= parse_sql(thd, & parser_state, NULL);
- *found_semicolon= parser_state.m_lip.found_semicolon;
- }
- else
- *found_semicolon= NULL;
+ bool err= parse_sql(thd, parser_state, NULL);
if (!err)
{
@@ -6058,6 +5476,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
{
if (! thd->is_error())
{
+ const char *found_semicolon= parser_state->m_lip.found_semicolon;
/*
Binlog logs a string starting from thd->query and having length
thd->query_length; so we set thd->query_length correctly (to not
@@ -6068,18 +5487,27 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
PROCESSLIST.
Note that we don't need LOCK_thread_count to modify query_length.
*/
- if (*found_semicolon && (ulong) (*found_semicolon - thd->query()))
+ if (found_semicolon && (ulong) (found_semicolon - thd->query()))
thd->set_query_inner(thd->query(),
- (uint32) (*found_semicolon -
- thd->query() - 1));
+ (uint32) (found_semicolon -
+ thd->query() - 1),
+ thd->charset());
/* Actually execute the query */
- if (*found_semicolon)
+ if (found_semicolon)
{
lex->safe_to_cache_query= 0;
thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
}
lex->set_trg_event_type_for_tables();
- mysql_execute_command(thd);
+ MYSQL_QUERY_EXEC_START(thd->query(),
+ thd->thread_id,
+ (char *) (thd->db ? thd->db : ""),
+ thd->security_ctx->priv_user,
+ (char *) thd->security_ctx->host_or_ip,
+ 0);
+
+ error= mysql_execute_command(thd);
+ MYSQL_QUERY_EXEC_DONE(error);
}
}
}
@@ -6089,24 +5517,13 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
thd->is_fatal_error));
- query_cache_abort(&thd->net);
+ query_cache_abort(&thd->query_cache_tls);
}
- if (thd->lex->sphead)
- {
- delete thd->lex->sphead;
- thd->lex->sphead= 0;
- }
- lex->unit.cleanup();
thd_proc_info(thd, "freeing items");
thd->end_statement();
thd->cleanup_after_query();
DBUG_ASSERT(thd->change_list.is_empty());
}
- else
- {
- /* There are no multi queries in the cache. */
- *found_semicolon= NULL;
- }
DBUG_VOID_RETURN;
}
@@ -6176,8 +5593,8 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
if (type_modifier & PRI_KEY_FLAG)
{
Key *key;
- lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
- key= new Key(Key::PRIMARY, NullS,
+ lex->col_list.push_back(new Key_part_spec(*field_name, 0));
+ key= new Key(Key::PRIMARY, null_lex_str,
&default_key_create_info,
0, lex->col_list);
lex->alter_info.key_list.push_back(key);
@@ -6186,8 +5603,8 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
{
Key *key;
- lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
- key= new Key(Key::UNIQUE, NullS,
+ lex->col_list.push_back(new Key_part_spec(*field_name, 0));
+ key= new Key(Key::UNIQUE, null_lex_str,
&default_key_create_info, 0,
lex->col_list);
lex->alter_info.key_list.push_back(key);
@@ -6233,17 +5650,6 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
DBUG_RETURN(1);
}
- if (type == MYSQL_TYPE_TIMESTAMP && length)
- {
- /* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1.
- In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4),
- and so on, the display width is ignored.
- */
- char buf[32];
- my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
- WARN_DEPRECATED(thd, "6.0", buf, "'TIMESTAMP'");
- }
-
if (!(new_field= new Create_field()) ||
new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
default_value, on_update_value, comment, change,
@@ -6260,7 +5666,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
void store_position_for_column(const char *name)
{
- current_thd->lex->last_field->after=my_const_cast(char*) (name);
+ current_thd->lex->last_field->after=(char*) (name);
}
bool
@@ -6311,6 +5717,7 @@ bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc)
- TL_OPTION_FORCE_INDEX : Force usage of index
- TL_OPTION_ALIAS : an alias in multi table DELETE
@param lock_type How table should be locked
+ @param mdl_type Type of metadata lock to acquire on the table.
@param use_index List of indexed used in USE INDEX
@param ignore_index List of indexed used in IGNORE INDEX
@@ -6325,6 +5732,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
LEX_STRING *alias,
ulong table_options,
thr_lock_type lock_type,
+ enum_mdl_type mdl_type,
List<Index_hint> *index_hints_arg,
LEX_STRING *option)
{
@@ -6367,13 +5775,17 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
DBUG_RETURN(0); /* purecov: inspected */
if (table->db.str)
{
+ ptr->is_fqtn= TRUE;
ptr->db= table->db.str;
ptr->db_length= table->db.length;
}
else if (lex->copy_db_to(&ptr->db, &ptr->db_length))
DBUG_RETURN(0);
+ else
+ ptr->is_fqtn= FALSE;
ptr->alias= alias_str;
+ ptr->is_alias= alias ? TRUE : FALSE;
if (lower_case_table_names && table->table.length)
table->table.length= my_casedn_str(files_charset_info, table->table.str);
ptr->table_name=table->table.str;
@@ -6384,9 +5796,21 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->derived= table->sel;
- if (!ptr->derived && is_schema_db(ptr->db, ptr->db_length))
+ if (!ptr->derived && is_infoschema_db(ptr->db, ptr->db_length))
{
- ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
+ ST_SCHEMA_TABLE *schema_table;
+ if (ptr->updating &&
+ /* Special cases which are processed by commands itself */
+ lex->sql_command != SQLCOM_CHECK &&
+ lex->sql_command != SQLCOM_CHECKSUM)
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->security_ctx->priv_user,
+ thd->security_ctx->priv_host,
+ INFORMATION_SCHEMA_NAME.str);
+ DBUG_RETURN(0);
+ }
+ schema_table= find_schema_table(thd, ptr->table_name);
if (!schema_table ||
(schema_table->hidden &&
((sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0 ||
@@ -6456,6 +5880,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->next_name_resolution_table= NULL;
/* Link table in global list (all used tables) */
lex->add_to_query_tables(ptr);
+ ptr->mdl_request.init(MDL_key::TABLE, ptr->db, ptr->table_name, mdl_type,
+ MDL_TRANSACTION);
DBUG_RETURN(ptr);
}
@@ -6691,6 +6117,8 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
{
tables->lock_type= lock_type;
tables->updating= for_update;
+ tables->mdl_request.set_type((lock_type >= TL_WRITE_ALLOW_WRITE) ?
+ MDL_SHARED_WRITE : MDL_SHARED_READ);
}
DBUG_VOID_RETURN;
}
@@ -6871,225 +6299,6 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
/**
- Reload/resets privileges and the different caches.
-
- @param thd Thread handler (can be NULL!)
- @param options What should be reset/reloaded (tables, privileges, slave...)
- @param tables Tables to flush (if any)
- @param write_to_binlog < 0 if there was an error while interacting with the binary log inside
- reload_acl_and_cache,
- 0 if we should not write to the binary log,
- > 0 if we can write to the binlog.
-
- @note Depending on 'options', it may be very bad to write the
- query to the binlog (e.g. FLUSH SLAVE); this is a
- pointer where reload_acl_and_cache() will put 0 if
- it thinks we really should not write to the binlog.
- Otherwise it will put 1.
-
- @return Error status code
- @retval 0 Ok
- @retval !=0 Error; thd->killed is set or thd->is_error() is true
-*/
-
-bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
- int *write_to_binlog)
-{
- bool result=0;
- select_errors=0; /* Write if more errors */
- int tmp_write_to_binlog= *write_to_binlog= 1;
-
- DBUG_ASSERT(!thd || !thd->in_sub_stmt);
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (options & REFRESH_GRANT)
- {
- THD *tmp_thd= 0;
- /*
- If reload_acl_and_cache() is called from SIGHUP handler we have to
- allocate temporary THD for execution of acl_reload()/grant_reload().
- */
- if (!thd && (thd= (tmp_thd= new THD)))
- {
- thd->thread_stack= (char*) &tmp_thd;
- thd->store_globals();
- lex_start(thd);
- }
-
- if (thd)
- {
- bool reload_acl_failed= acl_reload(thd);
- bool reload_grants_failed= grant_reload(thd);
- bool reload_servers_failed= servers_reload(thd);
-
- if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
- {
- result= 1;
- /*
- When an error is returned, my_message may have not been called and
- the client will hang waiting for a response.
- */
- my_error(ER_UNKNOWN_ERROR, MYF(0), "FLUSH PRIVILEGES failed");
- }
- }
-
- if (tmp_thd)
- {
- delete tmp_thd;
- /* Remember that we don't have a THD */
- my_pthread_setspecific_ptr(THR_THD, 0);
- thd= 0;
- }
- reset_mqh((LEX_USER *)NULL, TRUE);
- }
-#endif
- if (options & REFRESH_LOG)
- {
- /*
- Flush the normal query log, the update log, the binary log,
- the slow query log, the relay log (if it exists) and the log
- tables.
- */
-
- /*
- Writing this command to the binlog may result in infinite loops
- when doing mysqlbinlog|mysql, and anyway it does not really make
- sense to log it automatically (would cause more trouble to users
- than it would help them)
- */
- tmp_write_to_binlog= 0;
- if( mysql_bin_log.is_open() )
- {
- if (mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE))
- *write_to_binlog= -1;
- }
-#ifdef HAVE_REPLICATION
- int rotate_error= 0;
- pthread_mutex_lock(&LOCK_active_mi);
- rotate_error= rotate_relay_log(active_mi);
- pthread_mutex_unlock(&LOCK_active_mi);
- if (rotate_error)
- *write_to_binlog= -1;
-#endif
-
- /* flush slow and general logs */
- logger.flush_logs(thd);
-
- if (ha_flush_logs(NULL))
- result=1;
- if (flush_error_log())
- result=1;
- }
-#ifdef HAVE_QUERY_CACHE
- if (options & REFRESH_QUERY_CACHE_FREE)
- {
- query_cache.pack(); // FLUSH QUERY CACHE
- options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
- }
- if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
- {
- query_cache.flush(); // RESET QUERY CACHE
- }
-#endif /*HAVE_QUERY_CACHE*/
- /*
- Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
- (see sql_yacc.yy)
- */
- if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
- {
- if ((options & REFRESH_READ_LOCK) && thd)
- {
- /*
- We must not try to aspire a global read lock if we have a write
- locked table. This would lead to a deadlock when trying to
- reopen (and re-lock) the table after the flush.
- */
- if (thd->locked_tables)
- {
- THR_LOCK_DATA **lock_p= thd->locked_tables->locks;
- THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count;
-
- for (; lock_p < end_p; lock_p++)
- {
- if ((*lock_p)->type >= TL_WRITE_ALLOW_WRITE)
- {
- my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
- return 1;
- }
- }
- }
- /*
- Writing to the binlog could cause deadlocks, as we don't log
- UNLOCK TABLES
- */
- tmp_write_to_binlog= 0;
- if (lock_global_read_lock(thd))
- return 1; // Killed
- if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
- FALSE : TRUE, TRUE))
- result= 1;
-
- if (make_global_read_lock_block_commit(thd)) // Killed
- {
- /* Don't leave things in a half-locked state */
- unlock_global_read_lock(thd);
- return 1;
- }
- }
- else
- {
- if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
- FALSE : TRUE, FALSE))
- result= 1;
- }
- my_dbopt_cleanup();
- }
- if (options & REFRESH_HOSTS)
- hostname_cache_refresh();
- if (thd && (options & REFRESH_STATUS))
- refresh_status(thd);
- if (options & REFRESH_THREADS)
- flush_thread_cache();
-#ifdef HAVE_REPLICATION
- if (options & REFRESH_MASTER)
- {
- DBUG_ASSERT(thd);
- tmp_write_to_binlog= 0;
- if (reset_master(thd))
- {
- result=1;
- }
- }
-#endif
-#ifdef OPENSSL
- if (options & REFRESH_DES_KEY_FILE)
- {
- if (des_key_file && load_des_key_file(des_key_file))
- result= 1;
- }
-#endif
-#ifdef HAVE_REPLICATION
- if (options & REFRESH_SLAVE)
- {
- tmp_write_to_binlog= 0;
- pthread_mutex_lock(&LOCK_active_mi);
- if (reset_slave(thd, active_mi))
- result=1;
- pthread_mutex_unlock(&LOCK_active_mi);
- }
-#endif
- if (options & REFRESH_USER_RESOURCES)
- reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
- if (*write_to_binlog != -1)
- *write_to_binlog= tmp_write_to_binlog;
- /*
- If the query was killed then this function must fail.
- */
- return result || (thd ? thd->killed : 0);
-}
-
-
-/**
kill on thread.
@param thd Thread class
@@ -7106,7 +6315,7 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
uint error=ER_NO_SUCH_THREAD;
DBUG_ENTER("kill_one_thread");
DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
- VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
I_List_iterator<THD> it(threads);
while ((tmp=it++))
{
@@ -7114,11 +6323,11 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
continue;
if (tmp->thread_id == id)
{
- pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
+ mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
break;
}
}
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_mutex_unlock(&LOCK_thread_count);
if (tmp)
{
@@ -7147,7 +6356,7 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
}
else
error=ER_KILL_DENIED_ERROR;
- pthread_mutex_unlock(&tmp->LOCK_thd_data);
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
}
DBUG_PRINT("exit", ("%d", error));
DBUG_RETURN(error);
@@ -7164,11 +6373,15 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
only_kill_query Should it kill the query or the connection
*/
+static
void sql_kill(THD *thd, ulong id, bool only_kill_query)
{
uint error;
if (!(error= kill_one_thread(thd, id, only_kill_query)))
- my_ok(thd);
+ {
+ if (! thd->killed)
+ my_ok(thd);
+ }
else
my_error(error, MYF(0), id);
}
@@ -7328,13 +6541,15 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
if (table->derived)
table->grant.privilege= SELECT_ACL;
else if ((check_access(thd, UPDATE_ACL, table->db,
- &table->grant.privilege, 0, 1,
- test(table->schema_table)) ||
- check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
+ &table->grant.privilege,
+ &table->grant.m_internal,
+ 0, 1) ||
+ check_grant(thd, UPDATE_ACL, table, FALSE, 1, TRUE)) &&
(check_access(thd, SELECT_ACL, table->db,
- &table->grant.privilege, 0, 0,
- test(table->schema_table)) ||
- check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
+ &table->grant.privilege,
+ &table->grant.m_internal,
+ 0, 0) ||
+ check_grant(thd, SELECT_ACL, table, FALSE, 1, FALSE)))
DBUG_RETURN(TRUE);
table->table_in_first_from_clause= 1;
@@ -7350,9 +6565,10 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
if (!table->table_in_first_from_clause)
{
if (check_access(thd, SELECT_ACL, table->db,
- &table->grant.privilege, 0, 0,
- test(table->schema_table)) ||
- check_grant(thd, SELECT_ACL, table, 0, 1, 0))
+ &table->grant.privilege,
+ &table->grant.m_internal,
+ 0, 0) ||
+ check_grant(thd, SELECT_ACL, table, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
}
}
@@ -7391,7 +6607,7 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
/* sql_yacc guarantees that tables and aux_tables are not zero */
DBUG_ASSERT(aux_tables != 0);
- if (check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
+ if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE))
DBUG_RETURN(TRUE);
/*
@@ -7400,14 +6616,14 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
call check_table_access() safely.
*/
thd->lex->query_tables_own_last= 0;
- if (check_table_access(thd, DELETE_ACL, aux_tables, UINT_MAX, FALSE))
+ if (check_table_access(thd, DELETE_ACL, aux_tables, FALSE, UINT_MAX, FALSE))
{
thd->lex->query_tables_own_last= save_query_tables_own_last;
DBUG_RETURN(TRUE);
}
thd->lex->query_tables_own_last= save_query_tables_own_last;
- if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
+ if ((thd->variables.option_bits & OPTION_SAFE_UPDATES) && !select_lex->where)
{
my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
@@ -7417,6 +6633,63 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
}
+/*
+ Given a table in the source list, find a correspondent table in the
+ table references list.
+
+ @param lex Pointer to LEX representing multi-delete.
+ @param src Source table to match.
+ @param ref Table references list.
+
+ @remark The source table list (tables listed before the FROM clause
+ or tables listed in the FROM clause before the USING clause) may
+ contain table names or aliases that must match unambiguously one,
+ and only one, table in the target table list (table references list,
+ after FROM/USING clause).
+
+ @return Matching table, NULL otherwise.
+*/
+
+static TABLE_LIST *multi_delete_table_match(LEX *lex, TABLE_LIST *tbl,
+ TABLE_LIST *tables)
+{
+ TABLE_LIST *match= NULL;
+ DBUG_ENTER("multi_delete_table_match");
+
+ for (TABLE_LIST *elem= tables; elem; elem= elem->next_local)
+ {
+ int cmp;
+
+ if (tbl->is_fqtn && elem->is_alias)
+ continue; /* no match */
+ if (tbl->is_fqtn && elem->is_fqtn)
+ cmp= my_strcasecmp(table_alias_charset, tbl->table_name, elem->table_name) ||
+ strcmp(tbl->db, elem->db);
+ else if (elem->is_alias)
+ cmp= my_strcasecmp(table_alias_charset, tbl->alias, elem->alias);
+ else
+ cmp= my_strcasecmp(table_alias_charset, tbl->table_name, elem->table_name) ||
+ strcmp(tbl->db, elem->db);
+
+ if (cmp)
+ continue;
+
+ if (match)
+ {
+ my_error(ER_NONUNIQ_TABLE, MYF(0), elem->alias);
+ DBUG_RETURN(NULL);
+ }
+
+ match= elem;
+ }
+
+ if (!match)
+ my_error(ER_UNKNOWN_TABLE, MYF(0), tbl->table_name, "MULTI DELETE");
+
+ DBUG_RETURN(match);
+}
+
+
/**
Link tables in auxilary table list of multi-delete with corresponding
elements in main table list, and set proper locks for them.
@@ -7442,20 +6715,9 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
{
lex->table_count++;
/* All tables in aux_tables must be found in FROM PART */
- TABLE_LIST *walk;
- for (walk= tables; walk; walk= walk->next_local)
- {
- if (!my_strcasecmp(table_alias_charset,
- target_tbl->alias, walk->alias) &&
- !strcmp(walk->db, target_tbl->db))
- break;
- }
+ TABLE_LIST *walk= multi_delete_table_match(lex, target_tbl, tables);
if (!walk)
- {
- my_error(ER_UNKNOWN_TABLE, MYF(0),
- target_tbl->table_name, "MULTI DELETE");
DBUG_RETURN(TRUE);
- }
if (!walk->derived)
{
target_tbl->table_name= walk->table_name;
@@ -7463,6 +6725,9 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
}
walk->updating= target_tbl->updating;
walk->lock_type= target_tbl->lock_type;
+ /* We can assume that tables to be deleted from are locked for write. */
+ DBUG_ASSERT(walk->lock_type >= TL_WRITE_ALLOW_WRITE);
+ walk->mdl_request.set_type(MDL_SHARED_WRITE);
target_tbl->correspondent_table= walk; // Remember corresponding table
}
DBUG_RETURN(FALSE);
@@ -7554,21 +6819,30 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables)
/**
- @brief Check privileges for SHOW CREATE TABLE statement.
-
- @param thd Thread context
- @param table Target table
-
- @retval TRUE Failure
- @retval FALSE Success
+ Set proper open mode and table type for element representing target table
+ of CREATE TABLE statement, also adjust statement table list if necessary.
*/
-static bool check_show_create_table_access(THD *thd, TABLE_LIST *table)
+void create_table_set_open_action_and_adjust_tables(LEX *lex)
{
- return check_access(thd, SELECT_ACL | EXTRA_ACL, table->db,
- &table->grant.privilege, 0, 0,
- test(table->schema_table)) ||
- check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0);
+ TABLE_LIST *create_table= lex->query_tables;
+
+ if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ create_table->open_type= OT_TEMPORARY_ONLY;
+ else
+ create_table->open_type= OT_BASE_ONLY;
+
+ if (!lex->select_lex.item_list.elements)
+ {
+ /*
+ Avoid opening and locking target table for ordinary CREATE TABLE
+ or CREATE TABLE LIKE for write (unlike in CREATE ... SELECT we
+ won't do any insertions in it anyway). Not doing this causes
+ problems when running CREATE TABLE IF NOT EXISTS for already
+ existing log table.
+ */
+ create_table->lock_type= TL_READ;
+ }
}
@@ -7604,46 +6878,32 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
(select_lex->item_list.elements ? INSERT_ACL : 0);
if (check_access(thd, want_priv, create_table->db,
- &create_table->grant.privilege, 0, 0,
- test(create_table->schema_table)) ||
- check_merge_table_access(thd, create_table->db,
- lex->create_info.merge_list.first))
+ &create_table->grant.privilege,
+ &create_table->grant.m_internal,
+ 0, 0))
goto err;
+
+ /* If it is a merge table, check privileges for merge children. */
+ if (lex->create_info.merge_list.first &&
+ check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
+ lex->create_info.merge_list.first,
+ FALSE, UINT_MAX, FALSE))
+ goto err;
+
if (want_priv != CREATE_TMP_ACL &&
- check_grant(thd, want_priv, create_table, 0, 1, 0))
+ check_grant(thd, want_priv, create_table, FALSE, 1, FALSE))
goto err;
if (select_lex->item_list.elements)
{
/* Check permissions for used tables in CREATE TABLE ... SELECT */
-
-#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
- /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
- /*
- Only do the check for PS, because we on execute we have to check that
- against the opened tables to ensure we don't use a table that is part
- of the view (which can only be done after the table has been opened).
- */
- if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
- {
- /*
- For temporary tables we don't have to check if the created table exists
- */
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- find_table_in_global_list(tables, create_table->db,
- create_table->table_name))
- {
- error= FALSE;
- goto err;
- }
- }
-#endif
- if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
+ if (tables && check_table_access(thd, SELECT_ACL, tables, FALSE,
+ UINT_MAX, FALSE))
goto err;
}
else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
{
- if (check_show_create_table_access(thd, tables))
+ if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE))
goto err;
}
error= FALSE;
@@ -7704,8 +6964,9 @@ void get_default_definer(THD *thd, LEX_USER *definer)
definer->host.str= (char *) sctx->priv_host;
definer->host.length= strlen(definer->host.str);
- definer->password.str= NULL;
- definer->password.length= 0;
+ definer->password= null_lex_str;
+ definer->plugin= empty_lex_str;
+ definer->auth= empty_lex_str;
}
@@ -7841,7 +7102,10 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg,
return FALSE;
if (!no_error)
- my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_char_length);
+ {
+ ErrConvString err(str->str, str->length, cs);
+ my_error(ER_WRONG_STRING_LENGTH, MYF(0), err.ptr(), err_msg, max_char_length);
+ }
return TRUE;
}
@@ -7949,12 +7213,18 @@ bool parse_sql(THD *thd,
Parser_state *parser_state,
Object_creation_ctx *creation_ctx)
{
+ bool ret_value;
DBUG_ASSERT(thd->m_parser_state == NULL);
+ DBUG_ASSERT(thd->lex->m_stmt == NULL);
+ MYSQL_QUERY_PARSE_START(thd->query());
/* Backup creation context. */
Object_creation_ctx *backup_ctx= NULL;
+ if (check_stack_overrun(thd, 2 * STACK_MIN_SIZE, (uchar*)&backup_ctx))
+ return TRUE;
+
if (creation_ctx)
backup_ctx= creation_ctx->set_n_backup(thd);
@@ -7982,9 +7252,45 @@ bool parse_sql(THD *thd,
/* That's it. */
- return mysql_parse_status || thd->is_fatal_error;
+ ret_value= mysql_parse_status || thd->is_fatal_error;
+ MYSQL_QUERY_PARSE_DONE(ret_value);
+ return ret_value;
}
/**
@} (end of group Runtime_Environment)
*/
+
+
+
+/**
+ Check and merge "CHARACTER SET cs [ COLLATE cl ]" clause
+
+ @param cs character set pointer.
+ @param cl collation pointer.
+
+ Check if collation "cl" is applicable to character set "cs".
+
+ If "cl" is NULL (e.g. when COLLATE clause is not specified),
+ then simply "cs" is returned.
+
+ @return Error status.
+ @retval NULL, if "cl" is not applicable to "cs".
+ @retval pointer to merged CHARSET_INFO on success.
+*/
+
+
+CHARSET_INFO*
+merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl)
+{
+ if (cl)
+ {
+ if (!my_charset_same(cs, cl))
+ {
+ my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), cl->name, cs->csname);
+ return NULL;
+ }
+ return cl;
+ }
+ return cs;
+}
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
new file mode 100644
index 00000000000..c9b0f981d19
--- /dev/null
+++ b/sql/sql_parse.h
@@ -0,0 +1,200 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_PARSE_INCLUDED
+#define SQL_PARSE_INCLUDED
+
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_acl.h" /* GLOBAL_ACLS */
+
+class Comp_creator;
+class Item;
+class Object_creation_ctx;
+class Parser_state;
+struct TABLE_LIST;
+class THD;
+class Table_ident;
+struct LEX;
+
+enum enum_mysql_completiontype {
+ ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
+ COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6
+};
+
+extern "C" int test_if_data_home_dir(const char *dir);
+
+bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
+bool multi_delete_precheck(THD *thd, TABLE_LIST *tables);
+int mysql_multi_update_prepare(THD *thd);
+int mysql_multi_delete_prepare(THD *thd);
+bool mysql_insert_select_prepare(THD *thd);
+bool update_precheck(THD *thd, TABLE_LIST *tables);
+bool delete_precheck(THD *thd, TABLE_LIST *tables);
+bool insert_precheck(THD *thd, TABLE_LIST *tables);
+bool create_table_precheck(THD *thd, TABLE_LIST *tables,
+ TABLE_LIST *create_table);
+
+bool parse_sql(THD *thd,
+ Parser_state *parser_state,
+ Object_creation_ctx *creation_ctx);
+
+uint kill_one_thread(THD *thd, ulong id, bool only_kill_query);
+
+void free_items(Item *item);
+void cleanup_items(Item *item);
+
+Comp_creator *comp_eq_creator(bool invert);
+Comp_creator *comp_ge_creator(bool invert);
+Comp_creator *comp_gt_creator(bool invert);
+Comp_creator *comp_le_creator(bool invert);
+Comp_creator *comp_lt_creator(bool invert);
+Comp_creator *comp_ne_creator(bool invert);
+
+int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
+ enum enum_schema_tables schema_table_idx);
+void get_default_definer(THD *thd, LEX_USER *definer);
+LEX_USER *create_default_definer(THD *thd);
+LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
+LEX_USER *get_current_user(THD *thd, LEX_USER *user);
+bool check_string_byte_length(LEX_STRING *str, const char *err_msg,
+ uint max_byte_length);
+bool check_string_char_length(LEX_STRING *str, const char *err_msg,
+ uint max_char_length, CHARSET_INFO *cs,
+ bool no_error);
+CHARSET_INFO* merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl);
+bool check_host_name(LEX_STRING *str);
+bool check_identifier_name(LEX_STRING *str, uint max_char_length,
+ uint err_code, const char *param_for_err_msg);
+bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
+bool sqlcom_can_generate_row_events(const THD *thd);
+bool is_update_query(enum enum_sql_command command);
+bool is_log_table_write_query(enum enum_sql_command command);
+bool alloc_query(THD *thd, const char *packet, uint packet_length);
+void mysql_init_select(LEX *lex);
+void mysql_parse(THD *thd, char *rawbuf, uint length,
+ Parser_state *parser_state);
+void mysql_reset_thd_for_next_command(THD *thd);
+bool mysql_new_select(LEX *lex, bool move_down);
+void create_select_for_variable(const char *var_name);
+void create_table_set_open_action_and_adjust_tables(LEX *lex);
+void mysql_init_multi_delete(LEX *lex);
+bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
+void create_table_set_open_action_and_adjust_tables(LEX *lex);
+pthread_handler_t handle_bootstrap(void *arg);
+int mysql_execute_command(THD *thd);
+bool do_command(THD *thd);
+void do_handle_bootstrap(THD *thd);
+bool dispatch_command(enum enum_server_command command, THD *thd,
+ char* packet, uint packet_length);
+void log_slow_statement(THD *thd);
+bool append_file_to_dir(THD *thd, const char **filename_ptr,
+ const char *table_name);
+bool append_file_to_dir(THD *thd, const char **filename_ptr,
+ const char *table_name);
+void execute_init_command(THD *thd, LEX_STRING *init_command,
+ mysql_rwlock_t *var_lock);
+bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum enum_field_types type,
+ char *length, char *decimal,
+ uint type_modifier,
+ Item *default_value, Item *on_update_value,
+ LEX_STRING *comment,
+ char *change, List<String> *interval_list,
+ CHARSET_INFO *cs,
+ uint uint_geom_type);
+bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *group, bool asc);
+void add_join_on(TABLE_LIST *b,Item *expr);
+void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields,
+ SELECT_LEX *lex);
+bool add_proc_to_list(THD *thd, Item *item);
+bool push_new_name_resolution_context(THD *thd,
+ TABLE_LIST *left_op,
+ TABLE_LIST *right_op);
+void store_position_for_column(const char *name);
+void init_update_queries(void);
+bool check_simple_select();
+Item *negate_expression(THD *thd, Item *expr);
+bool check_stack_overrun(THD *thd, long margin, uchar *dummy);
+
+/* Variables */
+
+extern const char* any_db;
+extern uint sql_command_flags[];
+extern uint server_command_flags[];
+extern const LEX_STRING command_name[];
+extern uint server_command_flags[];
+
+/* Inline functions */
+inline bool check_identifier_name(LEX_STRING *str, uint err_code)
+{
+ return check_identifier_name(str, NAME_CHAR_LEN, err_code, "");
+}
+
+inline bool check_identifier_name(LEX_STRING *str)
+{
+ return check_identifier_name(str, NAME_CHAR_LEN, 0, "");
+}
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables);
+bool check_single_table_access(THD *thd, ulong privilege,
+ TABLE_LIST *tables, bool no_errors);
+bool check_routine_access(THD *thd,ulong want_access,char *db,char *name,
+ bool is_proc, bool no_errors);
+bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
+bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc);
+bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
+ GRANT_INTERNAL_INFO *grant_internal_info,
+ bool dont_check_global_grants, bool no_errors);
+bool check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
+ bool any_combination_of_privileges_will_do,
+ uint number,
+ bool no_errors);
+#else
+inline bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables)
+{ return false; }
+inline bool check_single_table_access(THD *thd, ulong privilege,
+ TABLE_LIST *tables, bool no_errors)
+{ return false; }
+inline bool check_routine_access(THD *thd,ulong want_access,char *db,
+ char *name, bool is_proc, bool no_errors)
+{ return false; }
+inline bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
+{
+ table->grant.privilege= want_access;
+ return false;
+}
+inline bool check_some_routine_access(THD *thd, const char *db,
+ const char *name, bool is_proc)
+{ return false; }
+inline bool check_access(THD *, ulong, const char *, ulong *save_priv,
+ GRANT_INTERNAL_INFO *, bool, bool)
+{
+ if (save_priv)
+ *save_priv= GLOBAL_ACLS;
+ return false;
+}
+inline bool
+check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
+ bool any_combination_of_privileges_will_do,
+ uint number,
+ bool no_errors)
+{ return false; }
+#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
+
+/* These were under the INNODB_COMPATIBILITY_HOOKS */
+
+bool check_global_access(THD *thd, ulong want_access);
+
+#endif /* SQL_PARSE_INCLUDED */
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 44ed9e759c6..cec047d11fc 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -1,4 +1,4 @@
-/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -18,28 +18,64 @@
to partitioning introduced in MySQL version 5.1. It contains functionality
used by all handlers that support partitioning, such as
the partitioning handler itself and the NDB handler.
+ (Much of the code in this file has been split into partition_info.cc and
+ the header files partition_info.h + partition_element.h + sql_partition.h)
- The first version was written by Mikael Ronstrom.
+ The first version was written by Mikael Ronstrom 2004-2006.
+ Various parts of the optimizer code was written by Sergey Petrunia.
+ Code have been maintained by Mattias Jonsson.
+ The second version was written by Mikael Ronstrom 2006-2007 with some
+ final fixes for partition pruning in 2008-2009 with assistance from Sergey
+ Petrunia and Mattias Jonsson.
- This version supports RANGE partitioning, LIST partitioning, HASH
+ The first version supports RANGE partitioning, LIST partitioning, HASH
partitioning and composite partitioning (hereafter called subpartitioning)
where each RANGE/LIST partitioning is HASH partitioned. The hash function
can either be supplied by the user or by only a list of fields (also
called KEY partitioning), where the MySQL server will use an internal
hash function.
There are quite a few defaults that can be used as well.
+
+ The second version introduces a new variant of RANGE and LIST partitioning
+ which is often referred to as column lists in the code variables. This
+ enables a user to specify a set of columns and their concatenated value
+ as the partition value. By comparing the concatenation of these values
+ the proper partition can be choosen.
*/
/* Some general useful functions */
#define MYSQL_LEX 1
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_partition.h"
+#include "key.h" // key_restore
+#include "sql_parse.h" // parse_sql
+#include "sql_cache.h" // query_cache_invalidate3
+#include "lock.h" // mysql_lock_remove
+#include "sql_show.h" // append_identifier
#include <errno.h>
#include <m_ctype.h>
#include "my_md5.h"
+#include "transaction.h"
+
+#include "sql_base.h" // close_all_tables_for_name
+#include "sql_table.h" // build_table_filename,
+ // build_table_shadow_filename,
+ // table_to_filename
+ // mysql_*_alter_copy_data
+#include "opt_range.h" // store_key_image_to_rec
+#include "sql_analyse.h" // append_escaped
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
+
+/* TODO: Change abort() to DBUG_SUICIDE() when bug#52002 is pushed */
+#define ERROR_INJECT_CRASH(code) \
+ DBUG_EVALUATE_IF(code, (abort(), 0), 0)
+#define ERROR_INJECT_ERROR(code) \
+ DBUG_EVALUATE_IF(code, (my_error(ER_UNKNOWN_ERROR, MYF(0)), TRUE), 0)
+
/*
Partition related functions declarations and some static constants;
*/
@@ -50,7 +86,8 @@ const LEX_STRING partition_keywords[]=
{ C_STRING_WITH_LEN("LIST") },
{ C_STRING_WITH_LEN("KEY") },
{ C_STRING_WITH_LEN("MAXVALUE") },
- { C_STRING_WITH_LEN("LINEAR ") }
+ { C_STRING_WITH_LEN("LINEAR ") },
+ { C_STRING_WITH_LEN(" COLUMNS") }
};
static const char *part_str= "PARTITION";
static const char *sub_str= "SUB";
@@ -61,26 +98,23 @@ static const char *end_paren_str= ")";
static const char *begin_paren_str= "(";
static const char *comma_str= ",";
-static int get_part_id_charset_func_all(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-static int get_part_id_charset_func_part(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-static int get_part_id_charset_func_subpart(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-static int get_part_part_id_charset_func(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-static int get_subpart_id_charset_func(partition_info *part_info,
- uint32 *part_id);
+int get_partition_id_list_col(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value);
int get_partition_id_list(partition_info *part_info,
uint32 *part_id,
longlong *func_value);
+int get_partition_id_range_col(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value);
int get_partition_id_range(partition_info *part_info,
uint32 *part_id,
longlong *func_value);
+static int get_part_id_charset_func_part(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value);
+static int get_part_id_charset_func_subpart(partition_info *part_info,
+ uint32 *part_id);
int get_partition_id_hash_nosub(partition_info *part_info,
uint32 *part_id,
longlong *func_value);
@@ -93,30 +127,9 @@ int get_partition_id_linear_hash_nosub(partition_info *part_info,
int get_partition_id_linear_key_nosub(partition_info *part_info,
uint32 *part_id,
longlong *func_value);
-int get_partition_id_range_sub_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_range_sub_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_range_sub_linear_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_range_sub_linear_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_list_sub_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_list_sub_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_list_sub_linear_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
-int get_partition_id_list_sub_linear_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value);
+int get_partition_id_with_sub(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value);
int get_partition_id_hash_sub(partition_info *part_info,
uint32 *part_id);
int get_partition_id_key_sub(partition_info *part_info,
@@ -134,16 +147,64 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter);
uint32 get_next_partition_id_list(PARTITION_ITERATOR* part_iter);
int get_part_iter_for_interval_via_mapping(partition_info *part_info,
bool is_subpart,
+ uint32 *store_length_array,
uchar *min_value, uchar *max_value,
+ uint min_len, uint max_len,
uint flags,
PARTITION_ITERATOR *part_iter);
+int get_part_iter_for_interval_cols_via_map(partition_info *part_info,
+ bool is_subpart,
+ uint32 *store_length_array,
+ uchar *min_value, uchar *max_value,
+ uint min_len, uint max_len,
+ uint flags,
+ PARTITION_ITERATOR *part_iter);
int get_part_iter_for_interval_via_walking(partition_info *part_info,
bool is_subpart,
+ uint32 *store_length_array,
uchar *min_value, uchar *max_value,
+ uint min_len, uint max_len,
uint flags,
PARTITION_ITERATOR *part_iter);
#ifdef WITH_PARTITION_STORAGE_ENGINE
+static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec);
+static int cmp_rec_and_tuple_prune(part_column_list_val *val,
+ uint32 n_vals_in_rec,
+ bool tail_is_min);
+
+/*
+ Convert constants in VALUES definition to the character set the
+ corresponding field uses.
+
+ SYNOPSIS
+ convert_charset_partition_constant()
+ item Item to convert
+ cs Character set to convert to
+
+ RETURN VALUE
+ NULL Error
+ item New converted item
+*/
+
+Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs)
+{
+ THD *thd= current_thd;
+ Name_resolution_context *context= &thd->lex->current_select->context;
+ TABLE_LIST *save_list= context->table_list;
+ const char *save_where= thd->where;
+
+ item= item->safe_charset_converter(cs);
+ context->table_list= NULL;
+ thd->where= "convert character set partition constant";
+ if (!item || item->fix_fields(thd, (Item**)NULL))
+ item= NULL;
+ thd->where= save_where;
+ context->table_list= save_list;
+ return item;
+}
+
+
/*
A support function to check if a name is in a list of strings
@@ -161,7 +222,7 @@ bool is_name_in_list(char *name,
List<char> list_names)
{
List_iterator<char> names_it(list_names);
- uint no_names= list_names.elements;
+ uint num_names= list_names.elements;
uint i= 0;
do
@@ -169,7 +230,7 @@ bool is_name_in_list(char *name,
char *list_name= names_it++;
if (!(my_strcasecmp(system_charset_info, name, list_name)))
return TRUE;
- } while (++i < no_names);
+ } while (++i < num_names);
return FALSE;
}
@@ -198,24 +259,24 @@ bool partition_default_handling(TABLE *table, partition_info *part_info,
if (!is_create_table_ind)
{
- if (part_info->use_default_no_partitions)
+ if (part_info->use_default_num_partitions)
{
- if (table->file->get_no_parts(normalized_path, &part_info->no_parts))
+ if (table->file->get_no_parts(normalized_path, &part_info->num_parts))
{
DBUG_RETURN(TRUE);
}
}
else if (part_info->is_sub_partitioned() &&
- part_info->use_default_no_subpartitions)
+ part_info->use_default_num_subpartitions)
{
- uint no_parts;
- if (table->file->get_no_parts(normalized_path, &no_parts))
+ uint num_parts;
+ if (table->file->get_no_parts(normalized_path, &num_parts))
{
DBUG_RETURN(TRUE);
}
- DBUG_ASSERT(part_info->no_parts > 0);
- DBUG_ASSERT((no_parts % part_info->no_parts) == 0);
- part_info->no_subparts= no_parts / part_info->no_parts;
+ DBUG_ASSERT(part_info->num_parts > 0);
+ DBUG_ASSERT((num_parts % part_info->num_parts) == 0);
+ part_info->num_subparts= num_parts / part_info->num_parts;
}
}
part_info->set_up_defaults_for_partitioning(table->file,
@@ -249,8 +310,8 @@ bool check_reorganise_list(partition_info *new_part_info,
List<char> list_part_names)
{
uint new_count, old_count;
- uint no_new_parts= new_part_info->partitions.elements;
- uint no_old_parts= old_part_info->partitions.elements;
+ uint num_new_parts= new_part_info->partitions.elements;
+ uint num_old_parts= old_part_info->partitions.elements;
List_iterator<partition_element> new_parts_it(new_part_info->partitions);
bool same_part_info= (new_part_info == old_part_info);
DBUG_ENTER("check_reorganise_list");
@@ -273,8 +334,8 @@ bool check_reorganise_list(partition_info *new_part_info,
if (!is_name_in_list(old_name, list_part_names))
DBUG_RETURN(TRUE);
}
- } while (old_count < no_old_parts);
- } while (new_count < no_new_parts);
+ } while (old_count < num_old_parts);
+ } while (new_count < num_new_parts);
DBUG_RETURN(FALSE);
}
@@ -449,9 +510,10 @@ static bool set_up_field_array(TABLE *table,
bool is_sub_part)
{
Field **ptr, *field, **field_array;
- uint no_fields= 0;
+ uint num_fields= 0;
uint size_field_array;
uint i= 0;
+ uint inx;
partition_info *part_info= table->part_info;
int result= FALSE;
DBUG_ENTER("set_up_field_array");
@@ -460,9 +522,19 @@ static bool set_up_field_array(TABLE *table,
while ((field= *(ptr++)))
{
if (field->flags & GET_FIXED_FIELDS_FLAG)
- no_fields++;
+ num_fields++;
}
- if (no_fields == 0)
+ if (num_fields > MAX_REF_PARTS)
+ {
+ char *ptr;
+ if (is_sub_part)
+ ptr= (char*)"subpartition function";
+ else
+ ptr= (char*)"partition function";
+ my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), ptr);
+ DBUG_RETURN(TRUE);
+ }
+ if (num_fields == 0)
{
/*
We are using hidden key as partitioning field
@@ -470,8 +542,8 @@ static bool set_up_field_array(TABLE *table,
DBUG_ASSERT(!is_sub_part);
DBUG_RETURN(result);
}
- size_field_array= (no_fields+1)*sizeof(Field*);
- field_array= (Field**)sql_alloc(size_field_array);
+ size_field_array= (num_fields+1)*sizeof(Field*);
+ field_array= (Field**)sql_calloc(size_field_array);
if (unlikely(!field_array))
{
mem_alloc_error(size_field_array);
@@ -486,7 +558,32 @@ static bool set_up_field_array(TABLE *table,
field->flags|= FIELD_IN_PART_FUNC_FLAG;
if (likely(!result))
{
- field_array[i++]= field;
+ if (!is_sub_part && part_info->column_list)
+ {
+ List_iterator<char> it(part_info->part_field_list);
+ char *field_name;
+
+ DBUG_ASSERT(num_fields == part_info->part_field_list.elements);
+ inx= 0;
+ do
+ {
+ field_name= it++;
+ if (!my_strcasecmp(system_charset_info,
+ field_name,
+ field->field_name))
+ break;
+ } while (++inx < num_fields);
+ if (inx == num_fields)
+ {
+ mem_alloc_error(1);
+ result= TRUE;
+ continue;
+ }
+ }
+ else
+ inx= i;
+ field_array[inx]= field;
+ i++;
/*
We check that the fields are proper. It is required for each
@@ -504,16 +601,16 @@ static bool set_up_field_array(TABLE *table,
}
}
}
- field_array[no_fields]= 0;
+ field_array[num_fields]= 0;
if (!is_sub_part)
{
part_info->part_field_array= field_array;
- part_info->no_part_fields= no_fields;
+ part_info->num_part_fields= num_fields;
}
else
{
part_info->subpart_field_array= field_array;
- part_info->no_subpart_fields= no_fields;
+ part_info->num_subpart_fields= num_fields;
}
DBUG_RETURN(result);
}
@@ -552,36 +649,36 @@ static bool create_full_part_field_array(THD *thd, TABLE *table,
if (!part_info->is_sub_partitioned())
{
part_info->full_part_field_array= part_info->part_field_array;
- part_info->no_full_part_fields= part_info->no_part_fields;
+ part_info->num_full_part_fields= part_info->num_part_fields;
}
else
{
Field *field, **field_array;
- uint no_part_fields=0, size_field_array;
+ uint num_part_fields=0, size_field_array;
ptr= table->field;
while ((field= *(ptr++)))
{
if (field->flags & FIELD_IN_PART_FUNC_FLAG)
- no_part_fields++;
+ num_part_fields++;
}
- size_field_array= (no_part_fields+1)*sizeof(Field*);
- field_array= (Field**)sql_alloc(size_field_array);
+ size_field_array= (num_part_fields+1)*sizeof(Field*);
+ field_array= (Field**)sql_calloc(size_field_array);
if (unlikely(!field_array))
{
mem_alloc_error(size_field_array);
result= TRUE;
goto end;
}
- no_part_fields= 0;
+ num_part_fields= 0;
ptr= table->field;
while ((field= *(ptr++)))
{
if (field->flags & FIELD_IN_PART_FUNC_FLAG)
- field_array[no_part_fields++]= field;
+ field_array[num_part_fields++]= field;
}
- field_array[no_part_fields]=0;
+ field_array[num_part_fields]=0;
part_info->full_part_field_array= field_array;
- part_info->no_full_part_fields= no_part_fields;
+ part_info->num_full_part_fields= num_part_fields;
}
/*
@@ -777,16 +874,16 @@ static bool handle_list_of_fields(List_iterator<char> it,
goto end;
}
}
- if (is_list_empty)
+ if (is_list_empty && part_info->part_type == HASH_PARTITION)
{
uint primary_key= table->s->primary_key;
if (primary_key != MAX_KEY)
{
- uint no_key_parts= table->key_info[primary_key].key_parts, i;
+ uint num_key_parts= table->key_info[primary_key].key_parts, i;
/*
In the case of an empty list we use primary key as partition key.
*/
- for (i= 0; i < no_key_parts; i++)
+ for (i= 0; i < num_key_parts; i++)
{
Field *field= table->key_info[primary_key].key_part[i].field;
field->flags|= GET_FIXED_FIELDS_FLAG;
@@ -850,11 +947,90 @@ int check_signed_flag(partition_info *part_info)
error= ER_PARTITION_CONST_DOMAIN_ERROR;
break;
}
- } while (++i < part_info->no_parts);
+ } while (++i < part_info->num_parts);
}
return error;
}
+/**
+ Initialize lex object for use in fix_fields and parsing.
+
+ SYNOPSIS
+ init_lex_with_single_table()
+ @param thd The thread object
+ @param table The table object
+ @return Operation status
+ @retval TRUE An error occurred, memory allocation error
+ @retval FALSE Ok
+
+ DESCRIPTION
+ This function is used to initialize a lex object on the
+ stack for use by fix_fields and for parsing. In order to
+ work properly it also needs to initialize the
+ Name_resolution_context object of the lexer.
+ Finally it needs to set a couple of variables to ensure
+ proper functioning of fix_fields.
+*/
+
+static int
+init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex)
+{
+ TABLE_LIST *table_list;
+ Table_ident *table_ident;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ Name_resolution_context *context= &select_lex->context;
+ /*
+ We will call the parser to create a part_info struct based on the
+ partition string stored in the frm file.
+ We will use a local lex object for this purpose. However we also
+ need to set the Name_resolution_object for this lex object. We
+ do this by using add_table_to_list where we add the table that
+ we're working with to the Name_resolution_context.
+ */
+ thd->lex= lex;
+ lex_start(thd);
+ context->init();
+ if ((!(table_ident= new Table_ident(thd,
+ table->s->table_name,
+ table->s->db, TRUE))) ||
+ (!(table_list= select_lex->add_table_to_list(thd,
+ table_ident,
+ NULL,
+ 0))))
+ return TRUE;
+ context->resolve_in_table_list_only(table_list);
+ lex->use_only_table_context= TRUE;
+ select_lex->cur_pos_in_select_list= UNDEF_POS;
+ table->map= 1; //To ensure correct calculation of const item
+ table->get_fields_in_item_tree= TRUE;
+ table_list->table= table;
+ return FALSE;
+}
+
+/**
+ End use of local lex with single table
+
+ SYNOPSIS
+ end_lex_with_single_table()
+ @param thd The thread object
+ @param table The table object
+ @param old_lex The real lex object connected to THD
+
+ DESCRIPTION
+ This function restores the real lex object after calling
+ init_lex_with_single_table and also restores some table
+ variables temporarily set.
+*/
+
+static void
+end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex)
+{
+ LEX *lex= thd->lex;
+ table->map= 0;
+ table->get_fields_in_item_tree= FALSE;
+ lex_end(lex);
+ thd->lex= old_lex;
+}
/*
The function uses a new feature in fix_fields where the flag
@@ -869,7 +1045,6 @@ int check_signed_flag(partition_info *part_info)
table The table object
part_info Reference to partitioning data structure
is_sub_part Is the table subpartitioned as well
- is_field_to_be_setup Flag if we are to set-up field arrays
is_create_table_ind Indicator of whether openfrm was called as part of
CREATE or ALTER TABLE
@@ -895,69 +1070,22 @@ int check_signed_flag(partition_info *part_info)
*/
static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
- bool is_sub_part, bool is_field_to_be_setup,
- bool is_create_table_ind)
+ bool is_sub_part, bool is_create_table_ind)
{
partition_info *part_info= table->part_info;
- uint dir_length, home_dir_length;
bool result= TRUE;
- TABLE_LIST tables;
- TABLE_LIST *save_table_list, *save_first_table, *save_last_table;
int error;
- Name_resolution_context *context;
- const char *save_where;
- char* db_name;
- char db_name_string[FN_REFLEN];
- bool save_use_only_table_context;
+ LEX *old_lex= thd->lex;
+ LEX lex;
uint8 saved_full_group_by_flag;
nesting_map saved_allow_sum_func;
DBUG_ENTER("fix_fields_part_func");
- if (part_info->fixed)
- {
- if (!(is_sub_part || (error= check_signed_flag(part_info))))
- result= FALSE;
+ if (init_lex_with_single_table(thd, table, &lex))
goto end;
- }
- /*
- Set-up the TABLE_LIST object to be a list with a single table
- Set the object to zero to create NULL pointers and set alias
- and real name to table name and get database name from file name.
- TODO: Consider generalizing or refactoring Lex::add_table_to_list() so
- it can be used in all places where we create TABLE_LIST objects.
- Also consider creating appropriate constructors for TABLE_LIST.
- */
-
- bzero((void*)&tables, sizeof(TABLE_LIST));
- tables.alias= tables.table_name= (char*) table->s->table_name.str;
- tables.table= table;
- tables.next_local= 0;
- tables.next_name_resolution_table= 0;
- /*
- Cache the table in Item_fields. All the tables can be cached except
- the trigger pseudo table.
- */
- tables.cacheable_table= TRUE;
- context= thd->lex->current_context();
- tables.select_lex= context->select_lex;
- strmov(db_name_string, table->s->normalized_path.str);
- dir_length= dirname_length(db_name_string);
- db_name_string[dir_length - 1]= 0;
- home_dir_length= dirname_length(db_name_string);
- db_name= &db_name_string[home_dir_length];
- tables.db= db_name;
-
- table->map= 1; //To ensure correct calculation of const item
- table->get_fields_in_item_tree= TRUE;
- save_table_list= context->table_list;
- save_first_table= context->first_name_resolution_table;
- save_last_table= context->last_name_resolution_table;
- context->table_list= &tables;
- context->first_name_resolution_table= &tables;
- context->last_name_resolution_table= NULL;
- func_expr->walk(&Item::change_context_processor, 0, (uchar*) context);
- save_where= thd->where;
+ func_expr->walk(&Item::change_context_processor, 0,
+ (uchar*) &lex.select_lex.context);
thd->where= "partition function";
/*
In execution we must avoid the use of thd->change_item_tree since
@@ -971,19 +1099,14 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
that does this during val_int must be disallowed as partition
function.
SEE Bug #21658
- */
- /*
+
This is a tricky call to prepare for since it can have a large number
of interesting side effects, both desirable and undesirable.
*/
-
- save_use_only_table_context= thd->lex->use_only_table_context;
- thd->lex->use_only_table_context= TRUE;
- thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
saved_full_group_by_flag= thd->lex->current_select->full_group_by_flag;
saved_allow_sum_func= thd->lex->allow_sum_func;
thd->lex->allow_sum_func= 0;
-
+
error= func_expr->fix_fields(thd, (Item**)&func_expr);
/*
@@ -993,19 +1116,12 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
thd->lex->current_select->full_group_by_flag= saved_full_group_by_flag;
thd->lex->allow_sum_func= saved_allow_sum_func;
- thd->lex->use_only_table_context= save_use_only_table_context;
-
- context->table_list= save_table_list;
- context->first_name_resolution_table= save_first_table;
- context->last_name_resolution_table= save_last_table;
if (unlikely(error))
{
DBUG_PRINT("info", ("Field in partition function not part of table"));
- if (is_field_to_be_setup)
- clear_field_flag(table);
+ clear_field_flag(table);
goto end;
}
- thd->where= save_where;
if (unlikely(func_expr->const_item()))
{
my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
@@ -1035,14 +1151,13 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
if ((!is_sub_part) && (error= check_signed_flag(part_info)))
goto end;
- result= FALSE;
- if (is_field_to_be_setup)
- result= set_up_field_array(table, is_sub_part);
- if (!is_sub_part)
- part_info->fixed= TRUE;
+ result= set_up_field_array(table, is_sub_part);
end:
- table->get_fields_in_item_tree= FALSE;
- table->map= 0; //Restore old value
+ end_lex_with_single_table(thd, table, old_lex);
+#if !defined(DBUG_OFF)
+ func_expr->walk(&Item::change_context_processor, 0,
+ (uchar*) 0);
+#endif
DBUG_RETURN(result);
}
@@ -1218,9 +1333,9 @@ void check_range_capable_PF(TABLE *table)
static bool set_up_partition_bitmap(THD *thd, partition_info *part_info)
{
uint32 *bitmap_buf;
- uint bitmap_bits= part_info->no_subparts?
- (part_info->no_subparts* part_info->no_parts):
- part_info->no_parts;
+ uint bitmap_bits= part_info->num_subparts?
+ (part_info->num_subparts* part_info->num_parts):
+ part_info->num_parts;
uint bitmap_bytes= bitmap_buffer_size(bitmap_bits);
DBUG_ENTER("set_up_partition_bitmap");
@@ -1320,64 +1435,47 @@ static void set_up_partition_func_pointers(partition_info *part_info)
if (part_info->is_sub_partitioned())
{
+ part_info->get_partition_id= get_partition_id_with_sub;
if (part_info->part_type == RANGE_PARTITION)
{
- part_info->get_part_partition_id= get_partition_id_range;
+ if (part_info->column_list)
+ part_info->get_part_partition_id= get_partition_id_range_col;
+ else
+ part_info->get_part_partition_id= get_partition_id_range;
if (part_info->list_of_subpart_fields)
{
if (part_info->linear_hash_ind)
- {
- part_info->get_partition_id= get_partition_id_range_sub_linear_key;
part_info->get_subpartition_id= get_partition_id_linear_key_sub;
- }
else
- {
- part_info->get_partition_id= get_partition_id_range_sub_key;
part_info->get_subpartition_id= get_partition_id_key_sub;
- }
}
else
{
if (part_info->linear_hash_ind)
- {
- part_info->get_partition_id= get_partition_id_range_sub_linear_hash;
part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
- }
else
- {
- part_info->get_partition_id= get_partition_id_range_sub_hash;
part_info->get_subpartition_id= get_partition_id_hash_sub;
- }
}
}
else /* LIST Partitioning */
{
- part_info->get_part_partition_id= get_partition_id_list;
+ if (part_info->column_list)
+ part_info->get_part_partition_id= get_partition_id_list_col;
+ else
+ part_info->get_part_partition_id= get_partition_id_list;
if (part_info->list_of_subpart_fields)
{
if (part_info->linear_hash_ind)
- {
- part_info->get_partition_id= get_partition_id_list_sub_linear_key;
part_info->get_subpartition_id= get_partition_id_linear_key_sub;
- }
else
- {
- part_info->get_partition_id= get_partition_id_list_sub_key;
part_info->get_subpartition_id= get_partition_id_key_sub;
- }
}
else
{
if (part_info->linear_hash_ind)
- {
- part_info->get_partition_id= get_partition_id_list_sub_linear_hash;
part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
- }
else
- {
- part_info->get_partition_id= get_partition_id_list_sub_hash;
part_info->get_subpartition_id= get_partition_id_hash_sub;
- }
}
}
}
@@ -1386,9 +1484,19 @@ static void set_up_partition_func_pointers(partition_info *part_info)
part_info->get_part_partition_id= NULL;
part_info->get_subpartition_id= NULL;
if (part_info->part_type == RANGE_PARTITION)
- part_info->get_partition_id= get_partition_id_range;
+ {
+ if (part_info->column_list)
+ part_info->get_partition_id= get_partition_id_range_col;
+ else
+ part_info->get_partition_id= get_partition_id_range;
+ }
else if (part_info->part_type == LIST_PARTITION)
- part_info->get_partition_id= get_partition_id_list;
+ {
+ if (part_info->column_list)
+ part_info->get_partition_id= get_partition_id_list_col;
+ else
+ part_info->get_partition_id= get_partition_id_list;
+ }
else /* HASH partitioning */
{
if (part_info->list_of_part_fields)
@@ -1407,32 +1515,43 @@ static void set_up_partition_func_pointers(partition_info *part_info)
}
}
}
- if (part_info->full_part_charset_field_array)
- {
- DBUG_ASSERT(part_info->get_partition_id);
- part_info->get_partition_id_charset= part_info->get_partition_id;
- if (part_info->part_charset_field_array &&
- part_info->subpart_charset_field_array)
- part_info->get_partition_id= get_part_id_charset_func_all;
- else if (part_info->part_charset_field_array)
- part_info->get_partition_id= get_part_id_charset_func_part;
- else
- part_info->get_partition_id= get_part_id_charset_func_subpart;
- }
- if (part_info->part_charset_field_array &&
- part_info->is_sub_partitioned())
+ /*
+ We need special functions to handle character sets since they require copy
+ of field pointers and restore afterwards. For subpartitioned tables we do
+ the copy and restore individually on the part and subpart parts. For non-
+ subpartitioned tables we use the same functions as used for the parts part
+ of subpartioning.
+ Thus for subpartitioned tables the get_partition_id is always
+ get_partition_id_with_sub, even when character sets exists.
+ */
+ if (part_info->part_charset_field_array)
{
- DBUG_ASSERT(part_info->get_part_partition_id);
- part_info->get_part_partition_id_charset=
+ if (part_info->is_sub_partitioned())
+ {
+ DBUG_ASSERT(part_info->get_part_partition_id);
+ if (!part_info->column_list)
+ {
+ part_info->get_part_partition_id_charset=
part_info->get_part_partition_id;
- part_info->get_part_partition_id= get_part_part_id_charset_func;
+ part_info->get_part_partition_id= get_part_id_charset_func_part;
+ }
+ }
+ else
+ {
+ DBUG_ASSERT(part_info->get_partition_id);
+ if (!part_info->column_list)
+ {
+ part_info->get_part_partition_id_charset= part_info->get_partition_id;
+ part_info->get_part_partition_id= get_part_id_charset_func_part;
+ }
+ }
}
if (part_info->subpart_charset_field_array)
{
DBUG_ASSERT(part_info->get_subpartition_id);
part_info->get_subpartition_id_charset=
part_info->get_subpartition_id;
- part_info->get_subpartition_id= get_subpart_id_charset_func;
+ part_info->get_subpartition_id= get_part_id_charset_func_subpart;
}
DBUG_VOID_RETURN;
}
@@ -1440,22 +1559,22 @@ static void set_up_partition_func_pointers(partition_info *part_info)
/*
For linear hashing we need a mask which is on the form 2**n - 1 where
- 2**n >= no_parts. Thus if no_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7.
+ 2**n >= num_parts. Thus if num_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7.
SYNOPSIS
set_linear_hash_mask()
part_info Reference to partitioning data structure
- no_parts Number of parts in linear hash partitioning
+ num_parts Number of parts in linear hash partitioning
RETURN VALUE
NONE
*/
-void set_linear_hash_mask(partition_info *part_info, uint no_parts)
+void set_linear_hash_mask(partition_info *part_info, uint num_parts)
{
uint mask;
- for (mask= 1; mask < no_parts; mask<<=1)
+ for (mask= 1; mask < num_parts; mask<<=1)
;
part_info->linear_hash_mask= mask - 1;
}
@@ -1469,7 +1588,7 @@ void set_linear_hash_mask(partition_info *part_info, uint no_parts)
get_part_id_from_linear_hash()
hash_value Hash value calculated by HASH function or KEY function
mask Mask calculated previously by set_linear_hash_mask
- no_parts Number of partitions in HASH partitioned part
+ num_parts Number of partitions in HASH partitioned part
RETURN VALUE
part_id The calculated partition identity (starting at 0)
@@ -1482,11 +1601,11 @@ void set_linear_hash_mask(partition_info *part_info, uint no_parts)
*/
static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask,
- uint no_parts)
+ uint num_parts)
{
uint32 part_id= (uint32)(hash_value & mask);
- if (part_id >= no_parts)
+ if (part_id >= num_parts)
{
uint new_mask= ((mask + 1) >> 1) - 1;
part_id= (uint32)(hash_value & new_mask);
@@ -1630,7 +1749,7 @@ bool fix_partition_func(THD *thd, TABLE *table,
function is correct.
*/
if (part_info->linear_hash_ind)
- set_linear_hash_mask(part_info, part_info->no_subparts);
+ set_linear_hash_mask(part_info, part_info->num_subparts);
if (part_info->list_of_subpart_fields)
{
List_iterator<char> it(part_info->subpart_field_list);
@@ -1640,13 +1759,11 @@ bool fix_partition_func(THD *thd, TABLE *table,
else
{
if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr,
- table, TRUE, TRUE,
- is_create_table_ind)))
+ table, TRUE, is_create_table_ind)))
goto end;
if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT))
{
- my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0),
- "SUBPARTITION");
+ part_info->report_part_expr_error(TRUE);
goto end;
}
}
@@ -1659,7 +1776,7 @@ bool fix_partition_func(THD *thd, TABLE *table,
if (part_info->part_type == HASH_PARTITION)
{
if (part_info->linear_hash_ind)
- set_linear_hash_mask(part_info, part_info->no_parts);
+ set_linear_hash_mask(part_info, part_info->num_parts);
if (part_info->list_of_part_fields)
{
List_iterator<char> it(part_info->part_field_list);
@@ -1669,34 +1786,42 @@ bool fix_partition_func(THD *thd, TABLE *table,
else
{
if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
- table, FALSE, TRUE,
- is_create_table_ind)))
+ table, FALSE, is_create_table_ind)))
goto end;
if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
{
- my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str);
+ part_info->report_part_expr_error(FALSE);
goto end;
}
- part_info->part_result_type= INT_RESULT;
}
+ part_info->fixed= TRUE;
}
else
{
const char *error_str;
- if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
- table, FALSE, TRUE,
- is_create_table_ind)))
- goto end;
+ if (part_info->column_list)
+ {
+ List_iterator<char> it(part_info->part_field_list);
+ if (unlikely(handle_list_of_fields(it, table, part_info, FALSE)))
+ goto end;
+ }
+ else
+ {
+ if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
+ table, FALSE, is_create_table_ind)))
+ goto end;
+ }
+ part_info->fixed= TRUE;
if (part_info->part_type == RANGE_PARTITION)
{
error_str= partition_keywords[PKW_RANGE].str;
- if (unlikely(part_info->check_range_constants()))
+ if (unlikely(part_info->check_range_constants(thd)))
goto end;
}
else if (part_info->part_type == LIST_PARTITION)
{
error_str= partition_keywords[PKW_LIST].str;
- if (unlikely(part_info->check_list_constants()))
+ if (unlikely(part_info->check_list_constants(thd)))
goto end;
}
else
@@ -1705,24 +1830,30 @@ bool fix_partition_func(THD *thd, TABLE *table,
my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR, MYF(0));
goto end;
}
- if (unlikely(part_info->no_parts < 1))
+ if (unlikely(part_info->num_parts < 1))
{
my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str);
goto end;
}
- if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
+ if (unlikely(!part_info->column_list &&
+ part_info->part_expr->result_type() != INT_RESULT))
{
- my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str);
+ part_info->report_part_expr_error(FALSE);
goto end;
}
}
if (((part_info->part_type != HASH_PARTITION ||
- part_info->list_of_part_fields == FALSE) &&
- check_part_func_fields(part_info->part_field_array, TRUE)) ||
+ part_info->list_of_part_fields == FALSE) &&
+ !part_info->column_list &&
+ check_part_func_fields(part_info->part_field_array, TRUE)) ||
(part_info->list_of_subpart_fields == FALSE &&
part_info->is_sub_partitioned() &&
check_part_func_fields(part_info->subpart_field_array, TRUE)))
{
+ /*
+ Range/List/HASH (but not KEY) and not COLUMNS or HASH subpartitioning
+ with columns in the partitioning expression using unallowed charset.
+ */
my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
goto end;
}
@@ -1741,6 +1872,11 @@ bool fix_partition_func(THD *thd, TABLE *table,
my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
goto end;
}
+ if (unlikely(part_info->check_partition_field_length()))
+ {
+ my_error(ER_PARTITION_FIELDS_TOO_LONG, MYF(0));
+ goto end;
+ }
check_range_capable_PF(table);
set_up_partition_key_maps(table, part_info);
set_up_partition_func_pointers(part_info);
@@ -1763,9 +1899,9 @@ end:
static int add_write(File fptr, const char *buf, uint len)
{
- uint len_written= my_write(fptr, (const uchar*)buf, len, MYF(0));
+ uint ret_code= mysql_file_write(fptr, (const uchar*)buf, len, MYF(MY_FNABP));
- if (likely(len == len_written))
+ if (likely(ret_code == 0))
return 0;
else
return 1;
@@ -1814,14 +1950,8 @@ static int add_begin_parenthesis(File fptr)
static int add_part_key_word(File fptr, const char *key_string)
{
int err= add_string(fptr, key_string);
-
err+= add_space(fptr);
- return err + add_begin_parenthesis(fptr);
-}
-
-static int add_hash(File fptr)
-{
- return add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
+ return err;
}
static int add_partition(File fptr)
@@ -1852,30 +1982,31 @@ static int add_subpartition_by(File fptr)
return err + add_partition_by(fptr);
}
-static int add_key_partition(File fptr, List<char> field_list)
+static int add_part_field_list(File fptr, List<char> field_list)
{
- uint i, no_fields;
- int err;
+ uint i, num_fields;
+ int err= 0;
List_iterator<char> part_it(field_list);
- err= add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
- no_fields= field_list.elements;
+ num_fields= field_list.elements;
i= 0;
- while (i < no_fields)
+ err+= add_begin_parenthesis(fptr);
+ while (i < num_fields)
{
const char *field_str= part_it++;
String field_string("", 0, system_charset_info);
THD *thd= current_thd;
- ulonglong save_options= thd->options;
- thd->options= 0;
+ ulonglong save_options= thd->variables.option_bits;
+ thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE;
append_identifier(thd, &field_string, field_str,
strlen(field_str));
- thd->options= save_options;
+ thd->variables.option_bits= save_options;
err+= add_string_object(fptr, &field_string);
- if (i != (no_fields-1))
+ if (i != (num_fields-1))
err+= add_comma(fptr);
i++;
}
+ err+= add_end_parenthesis(fptr);
return err;
}
@@ -1884,12 +2015,11 @@ static int add_name_string(File fptr, const char *name)
int err;
String name_string("", 0, system_charset_info);
THD *thd= current_thd;
- ulonglong save_options= thd->options;
-
- thd->options= 0;
+ ulonglong save_options= thd->variables.option_bits;
+ thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE;
append_identifier(thd, &name_string, name,
strlen(name));
- thd->options= save_options;
+ thd->variables.option_bits= save_options;
err= add_string_object(fptr, &name_string);
return err;
}
@@ -1985,37 +2115,269 @@ static int add_partition_options(File fptr, partition_element *p_elem)
return err + add_engine(fptr,p_elem->engine_type);
}
-static int add_partition_values(File fptr, partition_info *part_info, partition_element *p_elem)
+
+/*
+ Check partition fields for result type and if they need
+ to check the character set.
+
+ SYNOPSIS
+ check_part_field()
+ sql_type Type provided by user
+ field_name Name of field, used for error handling
+ result_type Out value: Result type of field
+ need_cs_check Out value: Do we need character set check
+
+ RETURN VALUES
+ TRUE Error
+ FALSE Ok
+*/
+
+static int check_part_field(enum_field_types sql_type,
+ const char *field_name,
+ Item_result *result_type,
+ bool *need_cs_check)
+{
+ if (sql_type >= MYSQL_TYPE_TINY_BLOB &&
+ sql_type <= MYSQL_TYPE_BLOB)
+ {
+ my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
+ return TRUE;
+ }
+ switch (sql_type)
+ {
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ *result_type= INT_RESULT;
+ *need_cs_check= FALSE;
+ return FALSE;
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ *result_type= STRING_RESULT;
+ *need_cs_check= TRUE;
+ return FALSE;
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ *result_type= STRING_RESULT;
+ *need_cs_check= TRUE;
+ return FALSE;
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_GEOMETRY:
+ goto error;
+ default:
+ goto error;
+ }
+error:
+ my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
+ field_name);
+ return TRUE;
+}
+
+
+/*
+ Find the given field's Create_field object using name of field
+
+ SYNOPSIS
+ get_sql_field()
+ field_name Field name
+ alter_info Info from ALTER TABLE/CREATE TABLE
+
+ RETURN VALUE
+ sql_field Object filled in by parser about field
+ NULL No field found
+*/
+
+static Create_field* get_sql_field(char *field_name,
+ Alter_info *alter_info)
+{
+ List_iterator<Create_field> it(alter_info->create_list);
+ Create_field *sql_field;
+ DBUG_ENTER("get_sql_field");
+
+ while ((sql_field= it++))
+ {
+ if (!(my_strcasecmp(system_charset_info,
+ sql_field->field_name,
+ field_name)))
+ {
+ DBUG_RETURN(sql_field);
+ }
+ }
+ DBUG_RETURN(NULL);
+}
+
+
+static int add_column_list_values(File fptr, partition_info *part_info,
+ part_elem_value *list_value,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info)
+{
+ int err= 0;
+ uint i;
+ List_iterator<char> it(part_info->part_field_list);
+ uint num_elements= part_info->part_field_list.elements;
+ bool use_parenthesis= (part_info->part_type == LIST_PARTITION &&
+ part_info->num_columns > 1U);
+
+ if (use_parenthesis)
+ err+= add_begin_parenthesis(fptr);
+ for (i= 0; i < num_elements; i++)
+ {
+ part_column_list_val *col_val= &list_value->col_val_array[i];
+ char *field_name= it++;
+ if (col_val->max_value)
+ err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
+ else if (col_val->null_value)
+ err+= add_string(fptr, "NULL");
+ else
+ {
+ char buffer[MAX_KEY_LENGTH];
+ String str(buffer, sizeof(buffer), &my_charset_bin);
+ Item *item_expr= col_val->item_expression;
+ if (item_expr->null_value)
+ err+= add_string(fptr, "NULL");
+ else
+ {
+ String *res;
+ CHARSET_INFO *field_cs;
+ bool need_cs_check= FALSE;
+ Item_result result_type= STRING_RESULT;
+
+ /*
+ This function is called at a very early stage, even before
+ we have prepared the sql_field objects. Thus we have to
+ find the proper sql_field object and get the character set
+ from that object.
+ */
+ if (create_info)
+ {
+ Create_field *sql_field;
+
+ if (!(sql_field= get_sql_field(field_name,
+ alter_info)))
+ {
+ my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
+ return 1;
+ }
+ if (check_part_field(sql_field->sql_type,
+ sql_field->field_name,
+ &result_type,
+ &need_cs_check))
+ return 1;
+ if (need_cs_check)
+ field_cs= get_sql_field_charset(sql_field, create_info);
+ else
+ field_cs= NULL;
+ }
+ else
+ {
+ Field *field= part_info->part_field_array[i];
+ result_type= field->result_type();
+ if (check_part_field(field->real_type(),
+ field->field_name,
+ &result_type,
+ &need_cs_check))
+ return 1;
+ DBUG_ASSERT(result_type == field->result_type());
+ if (need_cs_check)
+ field_cs= field->charset();
+ else
+ field_cs= NULL;
+ }
+ if (result_type != item_expr->result_type())
+ {
+ my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
+ return 1;
+ }
+ if (field_cs && field_cs != item_expr->collation.collation)
+ {
+ if (!(item_expr= convert_charset_partition_constant(item_expr,
+ field_cs)))
+ {
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+ return 1;
+ }
+ }
+ {
+ String val_conv;
+ val_conv.set_charset(system_charset_info);
+ res= item_expr->val_str(&str);
+ if (get_cs_converted_part_value_from_string(current_thd,
+ item_expr, res,
+ &val_conv, field_cs,
+ (bool)(alter_info != NULL)))
+ return 1;
+ err+= add_string_object(fptr, &val_conv);
+ }
+ }
+ }
+ if (i != (num_elements - 1))
+ err+= add_string(fptr, comma_str);
+ }
+ if (use_parenthesis)
+ err+= add_end_parenthesis(fptr);
+ return err;
+}
+
+static int add_partition_values(File fptr, partition_info *part_info,
+ partition_element *p_elem,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info)
{
int err= 0;
if (part_info->part_type == RANGE_PARTITION)
{
err+= add_string(fptr, " VALUES LESS THAN ");
- if (!p_elem->max_value)
+ if (part_info->column_list)
{
+ List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
+ part_elem_value *list_value= list_val_it++;
err+= add_begin_parenthesis(fptr);
- if (p_elem->signed_flag)
- err+= add_int(fptr, p_elem->range_value);
- else
- err+= add_uint(fptr, p_elem->range_value);
+ err+= add_column_list_values(fptr, part_info, list_value,
+ create_info, alter_info);
err+= add_end_parenthesis(fptr);
}
else
- err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
+ {
+ if (!p_elem->max_value)
+ {
+ err+= add_begin_parenthesis(fptr);
+ if (p_elem->signed_flag)
+ err+= add_int(fptr, p_elem->range_value);
+ else
+ err+= add_uint(fptr, p_elem->range_value);
+ err+= add_end_parenthesis(fptr);
+ }
+ else
+ err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
+ }
}
else if (part_info->part_type == LIST_PARTITION)
{
uint i;
List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
err+= add_string(fptr, " VALUES IN ");
- uint no_items= p_elem->list_val_list.elements;
+ uint num_items= p_elem->list_val_list.elements;
err+= add_begin_parenthesis(fptr);
if (p_elem->has_null_value)
{
err+= add_string(fptr, "NULL");
- if (no_items == 0)
+ if (num_items == 0)
{
err+= add_end_parenthesis(fptr);
goto end;
@@ -2027,13 +2389,19 @@ static int add_partition_values(File fptr, partition_info *part_info, partition_
{
part_elem_value *list_value= list_val_it++;
- if (!list_value->unsigned_flag)
- err+= add_int(fptr, list_value->value);
+ if (part_info->column_list)
+ err+= add_column_list_values(fptr, part_info, list_value,
+ create_info, alter_info);
else
- err+= add_uint(fptr, list_value->value);
- if (i != (no_items-1))
+ {
+ if (!list_value->unsigned_flag)
+ err+= add_int(fptr, list_value->value);
+ else
+ err+= add_uint(fptr, list_value->value);
+ }
+ if (i != (num_items-1))
err+= add_comma(fptr);
- } while (++i < no_items);
+ } while (++i < num_items);
err+= add_end_parenthesis(fptr);
}
end:
@@ -2052,6 +2420,8 @@ end:
use_sql_alloc Allocate buffer from sql_alloc if true
otherwise use my_malloc
show_partition_options Should we display partition options
+ create_info Info generated by parser
+ alter_info Info generated by parser
RETURN VALUES
NULL error
@@ -2080,9 +2450,11 @@ end:
char *generate_partition_syntax(partition_info *part_info,
uint *buf_length,
bool use_sql_alloc,
- bool show_partition_options)
+ bool show_partition_options,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info)
{
- uint i,j, tot_no_parts, no_subparts;
+ uint i,j, tot_num_parts, num_subparts;
partition_element *part_elem;
ulonglong buffer_length;
char path[FN_REFLEN];
@@ -2113,27 +2485,37 @@ char *generate_partition_syntax(partition_info *part_info,
if (part_info->linear_hash_ind)
err+= add_string(fptr, partition_keywords[PKW_LINEAR].str);
if (part_info->list_of_part_fields)
- err+= add_key_partition(fptr, part_info->part_field_list);
+ {
+ err+= add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
+ err+= add_part_field_list(fptr, part_info->part_field_list);
+ }
else
- err+= add_hash(fptr);
+ err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
break;
default:
DBUG_ASSERT(0);
/* We really shouldn't get here, no use in continuing from here */
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- current_thd->fatal_error();
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
DBUG_RETURN(NULL);
}
if (part_info->part_expr)
+ {
+ err+= add_begin_parenthesis(fptr);
err+= add_string_len(fptr, part_info->part_func_string,
part_info->part_func_len);
- err+= add_end_parenthesis(fptr);
- if ((!part_info->use_default_no_partitions) &&
+ err+= add_end_parenthesis(fptr);
+ }
+ else if (part_info->column_list)
+ {
+ err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str);
+ err+= add_part_field_list(fptr, part_info->part_field_list);
+ }
+ if ((!part_info->use_default_num_partitions) &&
part_info->use_default_partitions)
{
err+= add_string(fptr, "\n");
err+= add_string(fptr, "PARTITIONS ");
- err+= add_int(fptr, part_info->no_parts);
+ err+= add_int(fptr, part_info->num_parts);
}
if (part_info->is_sub_partitioned())
{
@@ -2143,23 +2525,29 @@ char *generate_partition_syntax(partition_info *part_info,
if (part_info->linear_hash_ind)
err+= add_string(fptr, partition_keywords[PKW_LINEAR].str);
if (part_info->list_of_subpart_fields)
- err+= add_key_partition(fptr, part_info->subpart_field_list);
+ {
+ add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
+ add_part_field_list(fptr, part_info->subpart_field_list);
+ }
else
- err+= add_hash(fptr);
+ err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
if (part_info->subpart_expr)
+ {
+ err+= add_begin_parenthesis(fptr);
err+= add_string_len(fptr, part_info->subpart_func_string,
part_info->subpart_func_len);
- err+= add_end_parenthesis(fptr);
- if ((!part_info->use_default_no_subpartitions) &&
+ err+= add_end_parenthesis(fptr);
+ }
+ if ((!part_info->use_default_num_subpartitions) &&
part_info->use_default_subpartitions)
{
err+= add_string(fptr, "\n");
err+= add_string(fptr, "SUBPARTITIONS ");
- err+= add_int(fptr, part_info->no_subparts);
+ err+= add_int(fptr, part_info->num_subparts);
}
}
- tot_no_parts= part_info->partitions.elements;
- no_subparts= part_info->no_subparts;
+ tot_num_parts= part_info->partitions.elements;
+ num_subparts= part_info->num_subparts;
if (!part_info->use_default_partitions)
{
@@ -2182,7 +2570,8 @@ char *generate_partition_syntax(partition_info *part_info,
first= FALSE;
err+= add_partition(fptr);
err+= add_name_string(fptr, part_elem->partition_name);
- err+= add_partition_values(fptr, part_info, part_elem);
+ err+= add_partition_values(fptr, part_info, part_elem,
+ create_info, alter_info);
if (!part_info->is_sub_partitioned() ||
part_info->use_default_subpartitions)
{
@@ -2203,7 +2592,7 @@ char *generate_partition_syntax(partition_info *part_info,
err+= add_name_string(fptr, part_elem->partition_name);
if (show_partition_options)
err+= add_partition_options(fptr, part_elem);
- if (j != (no_subparts-1))
+ if (j != (num_subparts-1))
{
err+= add_comma(fptr);
err+= add_string(fptr, "\n");
@@ -2212,19 +2601,20 @@ char *generate_partition_syntax(partition_info *part_info,
}
else
err+= add_end_parenthesis(fptr);
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
}
- if (i == (tot_no_parts-1))
+ if (i == (tot_num_parts-1))
err+= add_end_parenthesis(fptr);
- } while (++i < tot_no_parts);
+ } while (++i < tot_num_parts);
}
if (err)
goto close_file;
- buffer_length= my_seek(fptr, 0L,MY_SEEK_END,MYF(0));
+ buffer_length= mysql_file_seek(fptr, 0L, MY_SEEK_END, MYF(0));
if (unlikely(buffer_length == MY_FILEPOS_ERROR))
goto close_file;
- if (unlikely(my_seek(fptr, 0L, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR))
+ if (unlikely(mysql_file_seek(fptr, 0L, MY_SEEK_SET, MYF(0))
+ == MY_FILEPOS_ERROR))
goto close_file;
*buf_length= (uint)buffer_length;
if (use_sql_alloc)
@@ -2234,10 +2624,10 @@ char *generate_partition_syntax(partition_info *part_info,
if (!buf)
goto close_file;
- if (unlikely(my_read(fptr, (uchar*)buf, *buf_length, MYF(MY_FNABP))))
+ if (unlikely(mysql_file_read(fptr, (uchar*)buf, *buf_length, MYF(MY_FNABP))))
{
if (!use_sql_alloc)
- my_free(buf, MYF(0));
+ my_free(buf);
else
buf= NULL;
}
@@ -2245,7 +2635,7 @@ char *generate_partition_syntax(partition_info *part_info,
buf[*buf_length]= 0;
close_file:
- my_close(fptr, MYF(0));
+ mysql_file_close(fptr, MYF(0));
DBUG_RETURN(buf);
}
@@ -2364,14 +2754,14 @@ static uint32 calculate_key_value(Field **field_array)
get_part_id_for_sub()
loc_part_id Local partition id
sub_part_id Subpartition id
- no_subparts Number of subparts
+ num_subparts Number of subparts
*/
inline
static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
- uint no_subparts)
+ uint num_subparts)
{
- return (uint32)((loc_part_id * no_subparts) + sub_part_id);
+ return (uint32)((loc_part_id * num_subparts) + sub_part_id);
}
@@ -2380,7 +2770,7 @@ static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
SYNOPSIS
get_part_id_hash()
- no_parts Number of hash partitions
+ num_parts Number of hash partitions
part_expr Item tree of hash function
out:part_id The returned partition id
out:func_value Value of hash function
@@ -2390,7 +2780,7 @@ static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
FALSE Success
*/
-static int get_part_id_hash(uint no_parts,
+static int get_part_id_hash(uint num_parts,
Item *part_expr,
uint32 *part_id,
longlong *func_value)
@@ -2401,7 +2791,7 @@ static int get_part_id_hash(uint no_parts,
if (part_val_int(part_expr, func_value))
DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
- int_hash_id= *func_value % no_parts;
+ int_hash_id= *func_value % num_parts;
*part_id= int_hash_id < 0 ? (uint32) -int_hash_id : (uint32) int_hash_id;
DBUG_RETURN(FALSE);
@@ -2415,7 +2805,7 @@ static int get_part_id_hash(uint no_parts,
get_part_id_linear_hash()
part_info A reference to the partition_info struct where all the
desired information is given
- no_parts Number of hash partitions
+ num_parts Number of hash partitions
part_expr Item tree of hash function
out:part_id The returned partition id
out:func_value Value of hash function
@@ -2426,7 +2816,7 @@ static int get_part_id_hash(uint no_parts,
*/
static int get_part_id_linear_hash(partition_info *part_info,
- uint no_parts,
+ uint num_parts,
Item *part_expr,
uint32 *part_id,
longlong *func_value)
@@ -2438,7 +2828,7 @@ static int get_part_id_linear_hash(partition_info *part_info,
*part_id= get_part_id_from_linear_hash(*func_value,
part_info->linear_hash_mask,
- no_parts);
+ num_parts);
DBUG_RETURN(FALSE);
}
@@ -2449,7 +2839,7 @@ static int get_part_id_linear_hash(partition_info *part_info,
SYNOPSIS
get_part_id_key()
field_array Array of fields for PARTTION KEY
- no_parts Number of KEY partitions
+ num_parts Number of KEY partitions
RETURN VALUE
Calculated partition id
@@ -2457,12 +2847,12 @@ static int get_part_id_linear_hash(partition_info *part_info,
inline
static uint32 get_part_id_key(Field **field_array,
- uint no_parts,
+ uint num_parts,
longlong *func_value)
{
DBUG_ENTER("get_part_id_key");
*func_value= calculate_key_value(field_array);
- DBUG_RETURN((uint32) (*func_value % no_parts));
+ DBUG_RETURN((uint32) (*func_value % num_parts));
}
@@ -2474,7 +2864,7 @@ static uint32 get_part_id_key(Field **field_array,
part_info A reference to the partition_info struct where all the
desired information is given
field_array Array of fields for PARTTION KEY
- no_parts Number of KEY partitions
+ num_parts Number of KEY partitions
RETURN VALUE
Calculated partition id
@@ -2483,15 +2873,15 @@ static uint32 get_part_id_key(Field **field_array,
inline
static uint32 get_part_id_linear_key(partition_info *part_info,
Field **field_array,
- uint no_parts,
+ uint num_parts,
longlong *func_value)
{
- DBUG_ENTER("get_partition_id_linear_key");
+ DBUG_ENTER("get_part_id_linear_key");
*func_value= calculate_key_value(field_array);
DBUG_RETURN(get_part_id_from_linear_hash(*func_value,
part_info->linear_hash_mask,
- no_parts));
+ num_parts));
}
/*
@@ -2525,7 +2915,8 @@ static void copy_to_part_field_buffers(Field **ptr,
if (!field->maybe_null() || !field->is_null())
{
CHARSET_INFO *cs= ((Field_str*)field)->charset();
- uint len= field->pack_length();
+ uint max_len= field->pack_length();
+ uint data_len= field->data_length();
uchar *field_buf= *field_bufs;
/*
We only use the field buffer for VARCHAR and CHAR strings
@@ -2537,17 +2928,17 @@ static void copy_to_part_field_buffers(Field **ptr,
if (field->type() == MYSQL_TYPE_VARCHAR)
{
uint len_bytes= ((Field_varstring*)field)->length_bytes;
- my_strnxfrm(cs, field_buf + len_bytes, (len - len_bytes),
- field->ptr + len_bytes, field->field_length);
+ my_strnxfrm(cs, field_buf + len_bytes, max_len,
+ field->ptr + len_bytes, data_len);
if (len_bytes == 1)
- *field_buf= (uchar) field->field_length;
+ *field_buf= (uchar) data_len;
else
- int2store(field_buf, field->field_length);
+ int2store(field_buf, data_len);
}
else
{
- my_strnxfrm(cs, field_buf, len,
- field->ptr, field->field_length);
+ my_strnxfrm(cs, field_buf, max_len,
+ field->ptr, max_len);
}
field->ptr= field_buf;
}
@@ -2577,6 +2968,44 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr)
return;
}
+/*
+ This function is used to calculate the partition id where all partition
+ fields have been prepared to point to a record where the partition field
+ values are bound.
+
+ SYNOPSIS
+ get_partition_id()
+ part_info A reference to the partition_info struct where all the
+ desired information is given
+ out:part_id The partition id is returned through this pointer
+ out:func_value Value of partition function (longlong)
+
+ RETURN VALUE
+ part_id Partition id of partition that would contain
+ row with given values of PF-fields
+ HA_ERR_NO_PARTITION_FOUND The fields of the partition function didn't
+ fit into any partition and thus the values of
+ the PF-fields are not allowed.
+
+ DESCRIPTION
+ A routine used from write_row, update_row and delete_row from any
+ handler supporting partitioning. It is also a support routine for
+ get_partition_set used to find the set of partitions needed to scan
+ for a certain index scan or full table scan.
+
+ It is actually 9 different variants of this function which are called
+ through a function pointer.
+
+ get_partition_id_list
+ get_partition_id_list_col
+ get_partition_id_range
+ get_partition_id_range_col
+ get_partition_id_hash_nosub
+ get_partition_id_key_nosub
+ get_partition_id_linear_hash_nosub
+ get_partition_id_linear_key_nosub
+ get_partition_id_with_sub
+*/
/*
This function is used to calculate the main partition to use in the case of
@@ -2598,67 +3027,26 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr)
DESCRIPTION
- It is actually 6 different variants of this function which are called
+ It is actually 8 different variants of this function which are called
through a function pointer.
get_partition_id_list
+ get_partition_id_list_col
get_partition_id_range
+ get_partition_id_range_col
get_partition_id_hash_nosub
get_partition_id_key_nosub
get_partition_id_linear_hash_nosub
get_partition_id_linear_key_nosub
*/
-static int get_part_id_charset_func_subpart(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- int res;
- copy_to_part_field_buffers(part_info->subpart_charset_field_array,
- part_info->subpart_field_buffers,
- part_info->restore_subpart_field_ptrs);
- res= part_info->get_partition_id_charset(part_info, part_id, func_value);
- restore_part_field_pointers(part_info->subpart_charset_field_array,
- part_info->restore_subpart_field_ptrs);
- return res;
-}
-
-
static int get_part_id_charset_func_part(partition_info *part_info,
uint32 *part_id,
longlong *func_value)
{
int res;
- copy_to_part_field_buffers(part_info->part_charset_field_array,
- part_info->part_field_buffers,
- part_info->restore_part_field_ptrs);
- res= part_info->get_partition_id_charset(part_info, part_id, func_value);
- restore_part_field_pointers(part_info->part_charset_field_array,
- part_info->restore_part_field_ptrs);
- return res;
-}
-
-
-static int get_part_id_charset_func_all(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- int res;
- copy_to_part_field_buffers(part_info->full_part_field_array,
- part_info->full_part_field_buffers,
- part_info->restore_full_part_field_ptrs);
- res= part_info->get_partition_id_charset(part_info, part_id, func_value);
- restore_part_field_pointers(part_info->full_part_field_array,
- part_info->restore_full_part_field_ptrs);
- return res;
-}
-
+ DBUG_ENTER("get_part_id_charset_func_part");
-static int get_part_part_id_charset_func(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- int res;
copy_to_part_field_buffers(part_info->part_charset_field_array,
part_info->part_field_buffers,
part_info->restore_part_field_ptrs);
@@ -2666,21 +3054,58 @@ static int get_part_part_id_charset_func(partition_info *part_info,
part_id, func_value);
restore_part_field_pointers(part_info->part_charset_field_array,
part_info->restore_part_field_ptrs);
- return res;
+ DBUG_RETURN(res);
}
-static int get_subpart_id_charset_func(partition_info *part_info,
- uint32 *part_id)
+static int get_part_id_charset_func_subpart(partition_info *part_info,
+ uint32 *part_id)
{
int res;
+ DBUG_ENTER("get_part_id_charset_func_subpart");
+
copy_to_part_field_buffers(part_info->subpart_charset_field_array,
part_info->subpart_field_buffers,
part_info->restore_subpart_field_ptrs);
res= part_info->get_subpartition_id_charset(part_info, part_id);
restore_part_field_pointers(part_info->subpart_charset_field_array,
part_info->restore_subpart_field_ptrs);
- return res;
+ DBUG_RETURN(res);
+}
+
+int get_partition_id_list_col(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value)
+{
+ part_column_list_val *list_col_array= part_info->list_col_array;
+ uint num_columns= part_info->part_field_list.elements;
+ int list_index, cmp;
+ int min_list_index= 0;
+ int max_list_index= part_info->num_list_values - 1;
+ DBUG_ENTER("get_partition_id_list_col");
+
+ while (max_list_index >= min_list_index)
+ {
+ list_index= (max_list_index + min_list_index) >> 1;
+ cmp= cmp_rec_and_tuple(list_col_array + list_index*num_columns,
+ num_columns);
+ if (cmp > 0)
+ min_list_index= list_index + 1;
+ else if (cmp < 0)
+ {
+ if (!list_index)
+ goto notfound;
+ max_list_index= list_index - 1;
+ }
+ else
+ {
+ *part_id= (uint32)list_col_array[list_index*num_columns].partition_id;
+ DBUG_RETURN(0);
+ }
+ }
+notfound:
+ *part_id= 0;
+ DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
}
@@ -2691,7 +3116,7 @@ int get_partition_id_list(partition_info *part_info,
LIST_PART_ENTRY *list_array= part_info->list_array;
int list_index;
int min_list_index= 0;
- int max_list_index= part_info->no_list_values - 1;
+ int max_list_index= part_info->num_list_values - 1;
longlong part_func_value;
int error= part_val_int(part_info->part_expr, &part_func_value);
longlong list_value;
@@ -2761,7 +3186,7 @@ notfound:
index idx.
The function returns first number idx, such that
list_array[idx].list_value is NOT contained within the passed interval.
- If all array elements are contained, part_info->no_list_values is
+ If all array elements are contained, part_info->num_list_values is
returned.
NOTE
@@ -2775,6 +3200,44 @@ notfound:
The edge of corresponding sub-array of part_info->list_array
*/
+uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info,
+ bool left_endpoint,
+ bool include_endpoint,
+ uint32 nparts)
+{
+ part_column_list_val *list_col_array= part_info->list_col_array;
+ uint num_columns= part_info->part_field_list.elements;
+ int list_index, cmp;
+ uint min_list_index= 0;
+ uint max_list_index= part_info->num_list_values - 1;
+ bool tailf= !(left_endpoint ^ include_endpoint);
+ DBUG_ENTER("get_partition_id_cols_list_for_endpoint");
+
+ do
+ {
+ list_index= (max_list_index + min_list_index) >> 1;
+ cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*num_columns,
+ nparts, tailf);
+ if (cmp > 0)
+ min_list_index= list_index + 1;
+ else if (cmp < 0)
+ {
+ if (!list_index)
+ goto notfound;
+ max_list_index= list_index - 1;
+ }
+ else
+ {
+ DBUG_RETURN(list_index + test(!tailf));
+ }
+ } while (max_list_index >= min_list_index);
+ if (cmp > 0)
+ list_index++;
+notfound:
+ DBUG_RETURN(list_index);
+}
+
+
uint32 get_list_array_idx_for_endpoint_charset(partition_info *part_info,
bool left_endpoint,
bool include_endpoint)
@@ -2796,7 +3259,7 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
{
LIST_PART_ENTRY *list_array= part_info->list_array;
uint list_index;
- uint min_list_index= 0, max_list_index= part_info->no_list_values - 1;
+ uint min_list_index= 0, max_list_index= part_info->num_list_values - 1;
longlong list_value;
/* Get the partitioning function value for the endpoint */
longlong part_func_value=
@@ -2826,7 +3289,7 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
if (unsigned_flag)
part_func_value-= 0x8000000000000000ULL;
- DBUG_ASSERT(part_info->no_list_values);
+ DBUG_ASSERT(part_info->num_list_values);
do
{
list_index= (max_list_index + min_list_index) >> 1;
@@ -2851,12 +3314,49 @@ notfound:
}
+int get_partition_id_range_col(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value)
+{
+ part_column_list_val *range_col_array= part_info->range_col_array;
+ uint num_columns= part_info->part_field_list.elements;
+ uint max_partition= part_info->num_parts - 1;
+ uint min_part_id= 0;
+ uint max_part_id= max_partition;
+ uint loc_part_id;
+ DBUG_ENTER("get_partition_id_range_col");
+
+ while (max_part_id > min_part_id)
+ {
+ loc_part_id= (max_part_id + min_part_id + 1) >> 1;
+ if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
+ num_columns) >= 0)
+ min_part_id= loc_part_id + 1;
+ else
+ max_part_id= loc_part_id - 1;
+ }
+ loc_part_id= max_part_id;
+ if (loc_part_id != max_partition)
+ if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
+ num_columns) >= 0)
+ loc_part_id++;
+ *part_id= (uint32)loc_part_id;
+ if (loc_part_id == max_partition &&
+ (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
+ num_columns) >= 0))
+ DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
+
+ DBUG_PRINT("exit",("partition: %d", *part_id));
+ DBUG_RETURN(0);
+}
+
+
int get_partition_id_range(partition_info *part_info,
uint32 *part_id,
longlong *func_value)
{
longlong *range_array= part_info->range_int_array;
- uint max_partition= part_info->no_parts - 1;
+ uint max_partition= part_info->num_parts - 1;
uint min_part_id= 0;
uint max_part_id= max_partition;
uint loc_part_id;
@@ -2931,7 +3431,7 @@ int get_partition_id_range(partition_info *part_info,
represented by range_int_array[idx] has EMPTY intersection with the
passed interval.
If the interval represented by the last array element has non-empty
- intersection with the passed interval, part_info->no_parts is
+ intersection with the passed interval, part_info->num_parts is
returned.
RETURN
@@ -2960,7 +3460,7 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
{
longlong *range_array= part_info->range_int_array;
longlong part_end_val;
- uint max_partition= part_info->no_parts - 1;
+ uint max_partition= part_info->num_parts - 1;
uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
/* Get the partitioning function value for the endpoint */
longlong part_func_value=
@@ -3048,7 +3548,7 @@ int get_partition_id_hash_nosub(partition_info *part_info,
uint32 *part_id,
longlong *func_value)
{
- return get_part_id_hash(part_info->no_parts, part_info->part_expr,
+ return get_part_id_hash(part_info->num_parts, part_info->part_expr,
part_id, func_value);
}
@@ -3057,7 +3557,7 @@ int get_partition_id_linear_hash_nosub(partition_info *part_info,
uint32 *part_id,
longlong *func_value)
{
- return get_part_id_linear_hash(part_info, part_info->no_parts,
+ return get_part_id_linear_hash(part_info, part_info->num_parts,
part_info->part_expr, part_id, func_value);
}
@@ -3067,232 +3567,44 @@ int get_partition_id_key_nosub(partition_info *part_info,
longlong *func_value)
{
*part_id= get_part_id_key(part_info->part_field_array,
- part_info->no_parts, func_value);
+ part_info->num_parts, func_value);
return 0;
}
int get_partition_id_linear_key_nosub(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
+ uint32 *part_id,
+ longlong *func_value)
{
*part_id= get_part_id_linear_key(part_info,
part_info->part_field_array,
- part_info->no_parts, func_value);
+ part_info->num_parts, func_value);
return 0;
}
-int get_partition_id_range_sub_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_range_sub_hash");
- LINT_INIT(loc_part_id);
- LINT_INIT(sub_part_id);
-
- if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr,
- &sub_part_id, &local_func_value))))
- {
- DBUG_RETURN(error);
- }
-
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_range_sub_linear_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_range_sub_linear_hash");
- LINT_INIT(loc_part_id);
- LINT_INIT(sub_part_id);
-
- if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts,
- part_info->subpart_expr,
- &sub_part_id,
- &local_func_value))))
- {
- DBUG_RETURN(error);
- }
-
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_range_sub_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_range_sub_key");
- LINT_INIT(loc_part_id);
-
- if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- sub_part_id= get_part_id_key(part_info->subpart_field_array,
- no_subparts, &local_func_value);
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_range_sub_linear_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_range_sub_linear_key");
- LINT_INIT(loc_part_id);
-
- if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- sub_part_id= get_part_id_linear_key(part_info,
- part_info->subpart_field_array,
- no_subparts, &local_func_value);
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_list_sub_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_list_sub_hash");
- LINT_INIT(sub_part_id);
-
- if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr,
- &sub_part_id, &local_func_value))))
- {
- DBUG_RETURN(error);
- }
-
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_list_sub_linear_hash(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_list_sub_linear_hash");
- LINT_INIT(sub_part_id);
-
- if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
- func_value))))
- {
- DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts,
- part_info->subpart_expr,
- &sub_part_id,
- &local_func_value))))
- {
- DBUG_RETURN(error);
- }
-
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_list_sub_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
+int get_partition_id_with_sub(partition_info *part_info,
+ uint32 *part_id,
+ longlong *func_value)
{
uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
+ uint num_subparts;
int error;
- DBUG_ENTER("get_partition_id_range_sub_key");
+ DBUG_ENTER("get_partition_id_with_sub");
- if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
- func_value))))
+ if (unlikely((error= part_info->get_part_partition_id(part_info,
+ &loc_part_id,
+ func_value))))
{
DBUG_RETURN(error);
}
- no_subparts= part_info->no_subparts;
- sub_part_id= get_part_id_key(part_info->subpart_field_array,
- no_subparts, &local_func_value);
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
- DBUG_RETURN(0);
-}
-
-
-int get_partition_id_list_sub_linear_key(partition_info *part_info,
- uint32 *part_id,
- longlong *func_value)
-{
- uint32 loc_part_id, sub_part_id;
- uint no_subparts;
- longlong local_func_value;
- int error;
- DBUG_ENTER("get_partition_id_list_sub_linear_key");
-
- if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
- func_value))))
+ num_subparts= part_info->num_subparts;
+ if (unlikely((error= part_info->get_subpartition_id(part_info,
+ &sub_part_id))))
{
DBUG_RETURN(error);
- }
- no_subparts= part_info->no_subparts;
- sub_part_id= get_part_id_linear_key(part_info,
- part_info->subpart_field_array,
- no_subparts, &local_func_value);
- *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
+ }
+ *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, num_subparts);
DBUG_RETURN(0);
}
@@ -3325,7 +3637,7 @@ int get_partition_id_hash_sub(partition_info *part_info,
uint32 *part_id)
{
longlong func_value;
- return get_part_id_hash(part_info->no_subparts, part_info->subpart_expr,
+ return get_part_id_hash(part_info->num_subparts, part_info->subpart_expr,
part_id, &func_value);
}
@@ -3334,7 +3646,7 @@ int get_partition_id_linear_hash_sub(partition_info *part_info,
uint32 *part_id)
{
longlong func_value;
- return get_part_id_linear_hash(part_info, part_info->no_subparts,
+ return get_part_id_linear_hash(part_info, part_info->num_subparts,
part_info->subpart_expr, part_id,
&func_value);
}
@@ -3345,7 +3657,7 @@ int get_partition_id_key_sub(partition_info *part_info,
{
longlong func_value;
*part_id= get_part_id_key(part_info->subpart_field_array,
- part_info->no_subparts, &func_value);
+ part_info->num_subparts, &func_value);
return FALSE;
}
@@ -3356,7 +3668,7 @@ int get_partition_id_linear_key_sub(partition_info *part_info,
longlong func_value;
*part_id= get_part_id_linear_key(part_info,
part_info->subpart_field_array,
- part_info->no_subparts, &func_value);
+ part_info->num_subparts, &func_value);
return FALSE;
}
@@ -3655,16 +3967,16 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
const key_range *key_spec, part_id_range *part_spec)
{
partition_info *part_info= table->part_info;
- uint no_parts= part_info->get_tot_partitions();
+ uint num_parts= part_info->get_tot_partitions();
uint i, part_id;
- uint sub_part= no_parts;
- uint32 part_part= no_parts;
+ uint sub_part= num_parts;
+ uint32 part_part= num_parts;
KEY *key_info= NULL;
bool found_part_field= FALSE;
DBUG_ENTER("get_partition_set");
part_spec->start_part= 0;
- part_spec->end_part= no_parts - 1;
+ part_spec->end_part= num_parts - 1;
if ((index < MAX_KEY) &&
key_spec->flag == (uint)HA_READ_KEY_EXACT &&
part_info->some_fields_in_PF.is_set(index))
@@ -3701,7 +4013,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
{
if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
{
- part_spec->start_part= no_parts;
+ part_spec->start_part= num_parts;
DBUG_VOID_RETURN;
}
}
@@ -3715,7 +4027,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
allowed values. Thus it is certain that the result of this
scan will be empty.
*/
- part_spec->start_part= no_parts;
+ part_spec->start_part= num_parts;
DBUG_VOID_RETURN;
}
}
@@ -3753,7 +4065,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
{
if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
{
- part_spec->start_part= no_parts;
+ part_spec->start_part= num_parts;
clear_indicator_in_key_fields(key_info);
DBUG_VOID_RETURN;
}
@@ -3762,7 +4074,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
{
if (get_part_id_from_key(table,buf,key_info,key_spec,&part_part))
{
- part_spec->start_part= no_parts;
+ part_spec->start_part= num_parts;
clear_indicator_in_key_fields(key_info);
DBUG_VOID_RETURN;
}
@@ -3783,29 +4095,29 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
nothing or we have discovered a range of partitions with possible holes
in it. We need a bitvector to further the work here.
*/
- if (!(part_part == no_parts && sub_part == no_parts))
+ if (!(part_part == num_parts && sub_part == num_parts))
{
/*
We can only arrive here if we are using subpartitioning.
*/
- if (part_part != no_parts)
+ if (part_part != num_parts)
{
/*
We know the top partition and need to scan all underlying
subpartitions. This is a range without holes.
*/
- DBUG_ASSERT(sub_part == no_parts);
- part_spec->start_part= part_part * part_info->no_subparts;
- part_spec->end_part= part_spec->start_part+part_info->no_subparts - 1;
+ DBUG_ASSERT(sub_part == num_parts);
+ part_spec->start_part= part_part * part_info->num_subparts;
+ part_spec->end_part= part_spec->start_part+part_info->num_subparts - 1;
}
else
{
- DBUG_ASSERT(sub_part != no_parts);
+ DBUG_ASSERT(sub_part != num_parts);
part_spec->start_part= sub_part;
part_spec->end_part=sub_part+
- (part_info->no_subparts*(part_info->no_parts-1));
- for (i= 0, part_id= sub_part; i < part_info->no_parts;
- i++, part_id+= part_info->no_subparts)
+ (part_info->num_subparts*(part_info->num_parts-1));
+ for (i= 0, part_id= sub_part; i < part_info->num_parts;
+ i++, part_id+= part_info->num_subparts)
; //Set bit part_id in bit array
}
}
@@ -3877,7 +4189,6 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
bool mysql_unpack_partition(THD *thd,
char *part_buf, uint part_info_len,
- const char *part_state, uint part_state_len,
TABLE* table, bool is_create_table_ind,
handlerton *default_db_type,
bool *work_part_info_used)
@@ -3889,28 +4200,15 @@ bool mysql_unpack_partition(THD *thd,
LEX lex;
DBUG_ENTER("mysql_unpack_partition");
- thd->lex= &lex;
thd->variables.character_set_client= system_charset_info;
Parser_state parser_state;
if (parser_state.init(thd, part_buf, part_info_len))
goto end;
- lex_start(thd);
- *work_part_info_used= false;
- /*
- We need to use the current SELECT_LEX since I need to keep the
- Name_resolution_context object which is referenced from the
- Item_field objects.
- This is not a nice solution since if the parser uses current_select
- for anything else it will corrupt the current LEX object.
- Also, we need to make sure there even is a select -- if the statement
- was a "USE ...", current_select will be NULL, but we may still end up
- here if we try to log to a partitioned table. This is currently
- unsupported, but should still fail rather than crash!
- */
- if (!(thd->lex->current_select= old_lex->current_select))
+ if (init_lex_with_single_table(thd, table, &lex))
goto end;
+
/*
All Items created is put into a free list on the THD object. This list
is used to free all Item objects after completing a query. We don't
@@ -3920,16 +4218,17 @@ bool mysql_unpack_partition(THD *thd,
Thus we move away the current list temporarily and start a new list that
we then save in the partition info structure.
*/
+ *work_part_info_used= FALSE;
lex.part_info= new partition_info();/* Indicates MYSQLparse from this place */
if (!lex.part_info)
{
mem_alloc_error(sizeof(partition_info));
goto end;
}
- lex.part_info->part_state= part_state;
- lex.part_info->part_state_len= part_state_len;
+ part_info= lex.part_info;
DBUG_PRINT("info", ("Parse: %s", part_buf));
- if (parse_sql(thd, & parser_state, NULL))
+ if (parse_sql(thd, & parser_state, NULL) ||
+ part_info->fix_parser_data(thd))
{
thd->free_items();
goto end;
@@ -3950,45 +4249,27 @@ bool mysql_unpack_partition(THD *thd,
*/
DBUG_PRINT("info", ("Successful parse"));
- part_info= lex.part_info;
DBUG_PRINT("info", ("default engine = %s, default_db_type = %s",
ha_resolve_storage_engine_name(part_info->default_engine_type),
ha_resolve_storage_engine_name(default_db_type)));
if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE)
{
- if (old_lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
- {
- /*
- This code is executed when we create table in CREATE TABLE t1 LIKE t2.
- old_lex->query_tables contains table list element for t2 and the table
- we are opening has name t1.
- */
- if (partition_default_handling(table, part_info, FALSE,
- old_lex->query_tables->table->s->path.str))
- {
- result= TRUE;
- goto end;
- }
- }
- else
- {
- /*
- When we come here we are doing a create table. In this case we
- have already done some preparatory work on the old part_info
- object. We don't really need this new partition_info object.
- Thus we go back to the old partition info object.
- We need to free any memory objects allocated on item_free_list
- by the parser since we are keeping the old info from the first
- parser call in CREATE TABLE.
- We'll ensure that this object isn't put into table cache also
- just to ensure we don't get into strange situations with the
- item objects.
- */
- thd->free_items();
- part_info= thd->work_part_info;
- table->s->version= 0UL;
- *work_part_info_used= true;
- }
+ /*
+ When we come here we are doing a create table. In this case we
+ have already done some preparatory work on the old part_info
+ object. We don't really need this new partition_info object.
+ Thus we go back to the old partition info object.
+ We need to free any memory objects allocated on item_free_list
+ by the parser since we are keeping the old info from the first
+ parser call in CREATE TABLE.
+
+ This table object can not be used any more. However, since
+ this is CREATE TABLE, we know that it will be destroyed by the
+ caller, and rely on that.
+ */
+ thd->free_items();
+ part_info= thd->work_part_info;
+ *work_part_info_used= true;
}
table->part_info= part_info;
table->file->set_part_info(part_info);
@@ -4032,8 +4313,7 @@ bool mysql_unpack_partition(THD *thd,
result= FALSE;
end:
- lex_end(thd->lex);
- thd->lex= old_lex;
+ end_lex_with_single_table(thd, table, old_lex);
thd->variables.character_set_client= old_character_set_client;
DBUG_RETURN(result);
}
@@ -4071,60 +4351,35 @@ set_engine_all_partitions(partition_info *part_info,
partition_element *sub_elem= sub_it++;
sub_elem->engine_type= engine_type;
- } while (++j < part_info->no_subparts);
+ } while (++j < part_info->num_subparts);
}
- } while (++i < part_info->no_parts);
+ } while (++i < part_info->num_parts);
}
-/*
- SYNOPSIS
- fast_end_partition()
- thd Thread object
- out:copied Number of records copied
- out:deleted Number of records deleted
- table_list Table list with the one table in it
- empty Has nothing been done
- lpt Struct to be used by error handler
- RETURN VALUES
- FALSE Success
- TRUE Failure
- DESCRIPTION
- Support routine to handle the successful cases for partition
- management.
+/**
+ Support routine to handle the successful cases for partition management.
+
+ @param thd Thread object
+ @param copied Number of records copied
+ @param deleted Number of records deleted
+ @param table_list Table list with the one table in it
+
+ @return Operation status
+ @retval FALSE Success
+ @retval TRUE Failure
*/
static int fast_end_partition(THD *thd, ulonglong copied,
ulonglong deleted,
- TABLE *table,
- TABLE_LIST *table_list, bool is_empty,
- ALTER_PARTITION_PARAM_TYPE *lpt,
- bool written_bin_log)
+ TABLE_LIST *table_list)
{
- int error;
char tmp_name[80];
DBUG_ENTER("fast_end_partition");
thd->proc_info="end";
- if (!is_empty)
- query_cache_invalidate3(thd, table_list, 0);
-
- error= ha_autocommit_or_rollback(thd, 0);
- if (end_active_trans(thd))
- error= 1;
-
- if (error)
- {
- /* If error during commit, no need to rollback, it's done. */
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(TRUE);
- }
-
- if ((!is_empty) && (!written_bin_log) &&
- (!thd->lex->no_write_to_binlog) &&
- write_bin_log(thd, FALSE, thd->query(), thd->query_length()))
- DBUG_RETURN(TRUE);
+ query_cache_invalidate3(thd, table_list, 0);
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
(ulong) (copied + deleted),
@@ -4219,7 +4474,7 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
enum partition_state part_state)
{
uint part_count= 0;
- uint no_parts_found= 0;
+ uint num_parts_found= 0;
List_iterator<partition_element> part_it(tab_part_info->partitions);
do
@@ -4232,41 +4487,39 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
/*
Mark the partition.
I.e mark the partition as a partition to be "changed" by
- analyzing/optimizing/rebuilding/checking/repairing
+ analyzing/optimizing/rebuilding/checking/repairing/...
*/
- no_parts_found++;
+ num_parts_found++;
part_elem->part_state= part_state;
DBUG_PRINT("info", ("Setting part_state to %u for partition %s",
part_state, part_elem->partition_name));
}
- } while (++part_count < tab_part_info->no_parts);
- return no_parts_found;
+ else
+ part_elem->part_state= PART_NORMAL;
+ } while (++part_count < tab_part_info->num_parts);
+ return num_parts_found;
}
-/*
+/**
Prepare for ALTER TABLE of partition structure
- SYNOPSIS
- prep_alter_part_table()
- thd Thread object
- table Table object
- inout:alter_info Alter information
- inout:create_info Create info for CREATE TABLE
- old_db_type Old engine type
- out:partition_changed Boolean indicating whether partition changed
- out:fast_alter_partition Boolean indicating whether fast partition
- change is requested
+ @param[in] thd Thread object
+ @param[in] table Table object
+ @param[in,out] alter_info Alter information
+ @param[in,out] create_info Create info for CREATE TABLE
+ @param[in] old_db_type Old engine type
+ @param[out] partition_changed Boolean indicating whether partition changed
+ @param[out] fast_alter_table Internal temporary table allowing fast
+ partition change or NULL if not possible
- RETURN VALUES
- TRUE Error
- FALSE Success
- partition_changed
- fast_alter_partition
+ @return Operation status
+ @retval TRUE Error
+ @retval FALSE Success
- DESCRIPTION
+ @note
This method handles all preparations for ALTER TABLE for partitioned
- tables
+ tables.
We need to handle both partition management command such as Add Partition
and others here as well as an ALTER TABLE that completely changes the
partitioning and yet others that don't change anything at all. We start
@@ -4278,8 +4531,12 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
HA_CREATE_INFO *create_info,
handlerton *old_db_type,
bool *partition_changed,
- uint *fast_alter_partition)
+ char *db,
+ const char *table_name,
+ const char *path,
+ TABLE **fast_alter_table)
{
+ TABLE *new_table= NULL;
DBUG_ENTER("prep_alter_part_table");
/* Foreign keys on partitioned tables are not supported, waits for WL#148 */
@@ -4288,16 +4545,9 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0));
DBUG_RETURN(TRUE);
}
- /*
- We are going to manipulate the partition info on the table object
- so we need to ensure that the data structure of the table object
- is freed by setting version to 0. table->s->version= 0 forces a
- flush of the table object in close_thread_tables().
- */
- if (table->part_info)
- table->s->version= 0L;
thd->work_part_info= thd->lex->part_info;
+
if (thd->work_part_info &&
!(thd->work_part_info= thd->lex->part_info->get_clone()))
DBUG_RETURN(TRUE);
@@ -4310,25 +4560,51 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
ALTER_COALESCE_PARTITION | ALTER_REORGANIZE_PARTITION |
ALTER_TABLE_REORG | ALTER_REBUILD_PARTITION))
{
- partition_info *tab_part_info= table->part_info;
+ partition_info *tab_part_info;
partition_info *alt_part_info= thd->work_part_info;
uint flags= 0;
- if (!tab_part_info)
+ bool is_last_partition_reorged= FALSE;
+ part_elem_value *tab_max_elem_val= NULL;
+ part_elem_value *alt_max_elem_val= NULL;
+ longlong tab_max_range= 0, alt_max_range= 0;
+
+ if (!table->part_info)
{
my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
DBUG_RETURN(TRUE);
}
+
+ /*
+ Open our intermediate table, we will operate on a temporary instance
+ of the original table, to be able to skip copying all partitions.
+ Open it as a copy of the original table, and modify its partition_info
+ object to allow fast_alter_partition_table to perform the changes.
+ */
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
+ MDL_INTENTION_EXCLUSIVE));
+ new_table= open_table_uncached(thd, path, db, table_name, 0);
+ if (!new_table)
+ DBUG_RETURN(TRUE);
+
+ /*
+ This table may be used for copy rows between partitions
+ and also read/write columns when fixing the partition_info struct.
+ */
+ new_table->use_all_columns();
+
+ tab_part_info= new_table->part_info;
+
if (alter_info->flags & ALTER_TABLE_REORG)
{
uint new_part_no, curr_part_no;
if (tab_part_info->part_type != HASH_PARTITION ||
- tab_part_info->use_default_no_partitions)
+ tab_part_info->use_default_num_partitions)
{
my_error(ER_REORG_NO_PARAM_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
- new_part_no= table->file->get_default_no_partitions(create_info);
- curr_part_no= tab_part_info->no_parts;
+ new_part_no= new_table->file->get_default_no_partitions(create_info);
+ curr_part_no= tab_part_info->num_parts;
if (new_part_no == curr_part_no)
{
/*
@@ -4336,7 +4612,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
after the change as before. Thus we can reply ok immediately
without any changes at all.
*/
- *fast_alter_partition= TRUE;
+ *fast_alter_table= new_table;
+ thd->work_part_info= tab_part_info;
DBUG_RETURN(FALSE);
}
else if (new_part_no > curr_part_no)
@@ -4346,7 +4623,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
setting the flag for no default number of partitions
*/
alter_info->flags|= ALTER_ADD_PARTITION;
- thd->work_part_info->no_parts= new_part_no - curr_part_no;
+ thd->work_part_info->num_parts= new_part_no - curr_part_no;
}
else
{
@@ -4355,46 +4632,85 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
without setting the flag for no default number of partitions
*/
alter_info->flags|= ALTER_COALESCE_PARTITION;
- alter_info->no_parts= curr_part_no - new_part_no;
+ alter_info->num_parts= curr_part_no - new_part_no;
}
}
- if (!(flags= table->file->alter_table_flags(alter_info->flags)))
+ if (!(flags= new_table->file->alter_table_flags(alter_info->flags)))
{
my_error(ER_PARTITION_FUNCTION_FAILURE, MYF(0));
- DBUG_RETURN(1);
+ goto err;
}
- *fast_alter_partition=
- ((flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE)) != 0);
- DBUG_PRINT("info", ("*fast_alter_partition: %d flags: 0x%x",
- *fast_alter_partition, flags));
- if (((alter_info->flags & ALTER_ADD_PARTITION) ||
- (alter_info->flags & ALTER_REORGANIZE_PARTITION)) &&
- (thd->work_part_info->part_type != tab_part_info->part_type) &&
- (thd->work_part_info->part_type != NOT_A_PARTITION))
+ if ((flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE)) != 0)
+ *fast_alter_table= new_table;
+ DBUG_PRINT("info", ("*fast_alter_table: %p flags: 0x%x",
+ *fast_alter_table, flags));
+ if ((alter_info->flags & ALTER_ADD_PARTITION) ||
+ (alter_info->flags & ALTER_REORGANIZE_PARTITION))
{
- if (thd->work_part_info->part_type == RANGE_PARTITION)
+ if (thd->work_part_info->part_type != tab_part_info->part_type)
{
- my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
- "RANGE", "LESS THAN");
- }
- else if (thd->work_part_info->part_type == LIST_PARTITION)
- {
- DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION);
- my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
- "LIST", "IN");
+ if (thd->work_part_info->part_type == NOT_A_PARTITION)
+ {
+ if (tab_part_info->part_type == RANGE_PARTITION)
+ {
+ my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "RANGE");
+ goto err;
+ }
+ else if (tab_part_info->part_type == LIST_PARTITION)
+ {
+ my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "LIST");
+ goto err;
+ }
+ /*
+ Hash partitions can be altered without parser finds out about
+ that it is HASH partitioned. So no error here.
+ */
+ }
+ else
+ {
+ if (thd->work_part_info->part_type == RANGE_PARTITION)
+ {
+ my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
+ "RANGE", "LESS THAN");
+ }
+ else if (thd->work_part_info->part_type == LIST_PARTITION)
+ {
+ DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION);
+ my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
+ "LIST", "IN");
+ }
+ else if (tab_part_info->part_type == RANGE_PARTITION)
+ {
+ my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
+ "RANGE", "LESS THAN");
+ }
+ else
+ {
+ DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION);
+ my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
+ "LIST", "IN");
+ }
+ goto err;
+ }
}
- else if (tab_part_info->part_type == RANGE_PARTITION)
+ if ((tab_part_info->column_list &&
+ alt_part_info->num_columns != tab_part_info->num_columns) ||
+ (!tab_part_info->column_list &&
+ (tab_part_info->part_type == RANGE_PARTITION ||
+ tab_part_info->part_type == LIST_PARTITION) &&
+ alt_part_info->num_columns != 1U) ||
+ (!tab_part_info->column_list &&
+ tab_part_info->part_type == HASH_PARTITION &&
+ alt_part_info->num_columns != 0))
{
- my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
- "RANGE", "LESS THAN");
+ my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
+ goto err;
}
- else
+ alt_part_info->column_list= tab_part_info->column_list;
+ if (alt_part_info->fix_parser_data(thd))
{
- DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION);
- my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
- "LIST", "IN");
+ goto err;
}
- DBUG_RETURN(TRUE);
}
if (alter_info->flags & ALTER_ADD_PARTITION)
{
@@ -4404,9 +4720,9 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
partitioning scheme as currently set-up.
Partitions are always added at the end in ADD PARTITION.
*/
- uint no_new_partitions= alt_part_info->no_parts;
- uint no_orig_partitions= tab_part_info->no_parts;
- uint check_total_partitions= no_new_partitions + no_orig_partitions;
+ uint num_new_partitions= alt_part_info->num_parts;
+ uint num_orig_partitions= tab_part_info->num_parts;
+ uint check_total_partitions= num_new_partitions + num_orig_partitions;
uint new_total_partitions= check_total_partitions;
/*
We allow quite a lot of values to be supplied by defaults, however we
@@ -4416,42 +4732,42 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
tab_part_info->part_type != HASH_PARTITION)
{
my_error(ER_NO_BINLOG_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
if (tab_part_info->defined_max_value)
{
my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
- if (no_new_partitions == 0)
+ if (num_new_partitions == 0)
{
my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
if (tab_part_info->is_sub_partitioned())
{
- if (alt_part_info->no_subparts == 0)
- alt_part_info->no_subparts= tab_part_info->no_subparts;
- else if (alt_part_info->no_subparts != tab_part_info->no_subparts)
+ if (alt_part_info->num_subparts == 0)
+ alt_part_info->num_subparts= tab_part_info->num_subparts;
+ else if (alt_part_info->num_subparts != tab_part_info->num_subparts)
{
my_error(ER_ADD_PARTITION_SUBPART_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
check_total_partitions= new_total_partitions*
- alt_part_info->no_subparts;
+ alt_part_info->num_subparts;
}
if (check_total_partitions > MAX_PARTITIONS)
{
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
alt_part_info->part_type= tab_part_info->part_type;
alt_part_info->subpart_type= tab_part_info->subpart_type;
- if (alt_part_info->set_up_defaults_for_partitioning(table->file,
- ULL(0),
- tab_part_info->no_parts))
+ if (alt_part_info->set_up_defaults_for_partitioning(new_table->file,
+ ULL(0),
+ tab_part_info->num_parts))
{
- DBUG_RETURN(TRUE);
+ goto err;
}
/*
Handling of on-line cases:
@@ -4515,7 +4831,7 @@ adding and copying partitions, the second after completing the adding
and copying and finally the third line after also dropping the partitions
that are reorganised.
*/
- if (*fast_alter_partition &&
+ if (*fast_alter_table &&
tab_part_info->part_type == HASH_PARTITION)
{
uint part_no= 0, start_part= 1, start_sec_part= 1;
@@ -4524,7 +4840,7 @@ that are reorganised.
uint lower_2n= upper_2n >> 1;
bool all_parts= TRUE;
if (tab_part_info->linear_hash_ind &&
- no_new_partitions < upper_2n)
+ num_new_partitions < upper_2n)
{
/*
An analysis of which parts needs reorganisation shows that it is
@@ -4533,7 +4849,7 @@ that are reorganised.
onwards it starts again from partition 0 and goes on until
it reaches p(upper_2n - 1). If the last new partition reaches
beyond upper_2n - 1 then the first interval will end with
- p(lower_2n - 1) and start with p(no_orig_partitions - lower_2n).
+ p(lower_2n - 1) and start with p(num_orig_partitions - lower_2n).
If lower_2n partitions are added then p0 to p(lower_2n - 1) will
be reorganised which means that the two interval becomes one
interval at this point. Thus only when adding less than
@@ -4561,7 +4877,7 @@ that are reorganised.
to TRUE. In this case we don't get into this if-part at all.
*/
all_parts= FALSE;
- if (no_new_partitions >= lower_2n)
+ if (num_new_partitions >= lower_2n)
{
/*
In this case there is only one interval since the two intervals
@@ -4577,8 +4893,8 @@ that are reorganised.
Also in this case there is only one interval since we are not
going over a 2**n boundary
*/
- start_part= no_orig_partitions - lower_2n;
- end_part= start_part + (no_new_partitions - 1);
+ start_part= num_orig_partitions - lower_2n;
+ end_part= start_part + (num_new_partitions - 1);
}
else
{
@@ -4587,7 +4903,7 @@ that are reorganised.
new parts that would ensure that the intervals become
overlapping.
*/
- start_part= no_orig_partitions - lower_2n;
+ start_part= num_orig_partitions - lower_2n;
end_part= upper_2n - 1;
start_sec_part= 0;
end_sec_part= new_total_partitions - (upper_2n + 1);
@@ -4604,7 +4920,7 @@ that are reorganised.
{
p_elem->part_state= PART_CHANGED;
}
- } while (++part_no < no_orig_partitions);
+ } while (++part_no < num_orig_partitions);
}
/*
Need to concatenate the lists here to make it possible to check the
@@ -4620,15 +4936,15 @@ that are reorganised.
do
{
partition_element *part_elem= alt_it++;
- if (*fast_alter_partition)
+ if (*fast_alter_table)
part_elem->part_state= PART_TO_BE_ADDED;
if (tab_part_info->partitions.push_back(part_elem))
{
mem_alloc_error(1);
- DBUG_RETURN(TRUE);
+ goto err;
}
- } while (++part_count < no_new_partitions);
- tab_part_info->no_parts+= no_new_partitions;
+ } while (++part_count < num_new_partitions);
+ tab_part_info->num_parts+= num_new_partitions;
}
/*
If we specify partitions explicitly we don't use defaults anymore.
@@ -4643,7 +4959,7 @@ that are reorganised.
DBUG_PRINT("info", ("part_info: 0x%lx", (long) tab_part_info));
tab_part_info->use_default_partitions= FALSE;
}
- tab_part_info->use_default_no_partitions= FALSE;
+ tab_part_info->use_default_num_partitions= FALSE;
tab_part_info->is_auto_partitioned= FALSE;
}
}
@@ -4657,8 +4973,8 @@ that are reorganised.
command to drop the partition failed in the middle.
*/
uint part_count= 0;
- uint no_parts_dropped= alter_info->partition_names.elements;
- uint no_parts_found= 0;
+ uint num_parts_dropped= alter_info->partition_names.elements;
+ uint num_parts_found= 0;
List_iterator<partition_element> part_it(tab_part_info->partitions);
tab_part_info->is_auto_partitioned= FALSE;
@@ -4666,12 +4982,12 @@ that are reorganised.
tab_part_info->part_type == LIST_PARTITION))
{
my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
- DBUG_RETURN(TRUE);
+ goto err;
}
- if (no_parts_dropped >= tab_part_info->no_parts)
+ if (num_parts_dropped >= tab_part_info->num_parts)
{
my_error(ER_DROP_LAST_PARTITION, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
do
{
@@ -4682,58 +4998,58 @@ that are reorganised.
/*
Set state to indicate that the partition is to be dropped.
*/
- no_parts_found++;
+ num_parts_found++;
part_elem->part_state= PART_TO_BE_DROPPED;
}
- } while (++part_count < tab_part_info->no_parts);
- if (no_parts_found != no_parts_dropped)
+ } while (++part_count < tab_part_info->num_parts);
+ if (num_parts_found != num_parts_dropped)
{
my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "DROP");
- DBUG_RETURN(TRUE);
+ goto err;
}
- if (table->file->is_fk_defined_on_table_or_index(MAX_KEY))
+ if (new_table->file->is_fk_defined_on_table_or_index(MAX_KEY))
{
my_error(ER_ROW_IS_REFERENCED, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
- tab_part_info->no_parts-= no_parts_dropped;
+ tab_part_info->num_parts-= num_parts_dropped;
}
else if (alter_info->flags & ALTER_REBUILD_PARTITION)
{
- uint no_parts_found;
- uint no_parts_opt= alter_info->partition_names.elements;
- no_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED);
- if (no_parts_found != no_parts_opt &&
+ uint num_parts_found;
+ uint num_parts_opt= alter_info->partition_names.elements;
+ num_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED);
+ if (num_parts_found != num_parts_opt &&
(!(alter_info->flags & ALTER_ALL_PARTITION)))
{
my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD");
- DBUG_RETURN(TRUE);
+ goto err;
}
- if (!(*fast_alter_partition))
+ if (!(*fast_alter_table))
{
- table->file->print_error(HA_ERR_WRONG_COMMAND, MYF(0));
- DBUG_RETURN(TRUE);
+ new_table->file->print_error(HA_ERR_WRONG_COMMAND, MYF(0));
+ goto err;
}
}
else if (alter_info->flags & ALTER_COALESCE_PARTITION)
{
- uint no_parts_coalesced= alter_info->no_parts;
- uint no_parts_remain= tab_part_info->no_parts - no_parts_coalesced;
+ uint num_parts_coalesced= alter_info->num_parts;
+ uint num_parts_remain= tab_part_info->num_parts - num_parts_coalesced;
List_iterator<partition_element> part_it(tab_part_info->partitions);
if (tab_part_info->part_type != HASH_PARTITION)
{
my_error(ER_COALESCE_ONLY_ON_HASH_PARTITION, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
- if (no_parts_coalesced == 0)
+ if (num_parts_coalesced == 0)
{
my_error(ER_COALESCE_PARTITION_NO_PARTITION, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
- if (no_parts_coalesced >= tab_part_info->no_parts)
+ if (num_parts_coalesced >= tab_part_info->num_parts)
{
my_error(ER_DROP_LAST_PARTITION, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
/*
Online handling:
@@ -4772,50 +5088,50 @@ state of p1.
uint part_count= 0, start_part= 1, start_sec_part= 1;
uint end_part= 0, end_sec_part= 0;
bool all_parts= TRUE;
- if (*fast_alter_partition &&
+ if (*fast_alter_table &&
tab_part_info->linear_hash_ind)
{
uint upper_2n= tab_part_info->linear_hash_mask + 1;
uint lower_2n= upper_2n >> 1;
all_parts= FALSE;
- if (no_parts_coalesced >= lower_2n)
+ if (num_parts_coalesced >= lower_2n)
{
all_parts= TRUE;
}
- else if (no_parts_remain >= lower_2n)
+ else if (num_parts_remain >= lower_2n)
{
- end_part= tab_part_info->no_parts - (lower_2n + 1);
- start_part= no_parts_remain - lower_2n;
+ end_part= tab_part_info->num_parts - (lower_2n + 1);
+ start_part= num_parts_remain - lower_2n;
}
else
{
start_part= 0;
- end_part= tab_part_info->no_parts - (lower_2n + 1);
+ end_part= tab_part_info->num_parts - (lower_2n + 1);
end_sec_part= (lower_2n >> 1) - 1;
- start_sec_part= end_sec_part - (lower_2n - (no_parts_remain + 1));
+ start_sec_part= end_sec_part - (lower_2n - (num_parts_remain + 1));
}
}
do
{
partition_element *p_elem= part_it++;
- if (*fast_alter_partition &&
+ if (*fast_alter_table &&
(all_parts ||
(part_count >= start_part && part_count <= end_part) ||
(part_count >= start_sec_part && part_count <= end_sec_part)))
p_elem->part_state= PART_CHANGED;
- if (++part_count > no_parts_remain)
+ if (++part_count > num_parts_remain)
{
- if (*fast_alter_partition)
+ if (*fast_alter_table)
p_elem->part_state= PART_REORGED_DROPPED;
else
part_it.remove();
}
- } while (part_count < tab_part_info->no_parts);
- tab_part_info->no_parts= no_parts_remain;
+ } while (part_count < tab_part_info->num_parts);
+ tab_part_info->num_parts= num_parts_remain;
}
if (!(alter_info->flags & ALTER_TABLE_REORG))
{
- tab_part_info->use_default_no_partitions= FALSE;
+ tab_part_info->use_default_num_partitions= FALSE;
tab_part_info->is_auto_partitioned= FALSE;
}
}
@@ -4832,47 +5148,46 @@ state of p1.
range as those changed from.
This command can be used on RANGE and LIST partitions.
*/
- uint no_parts_reorged= alter_info->partition_names.elements;
- uint no_parts_new= thd->work_part_info->partitions.elements;
- partition_info *alt_part_info= thd->work_part_info;
+ uint num_parts_reorged= alter_info->partition_names.elements;
+ uint num_parts_new= thd->work_part_info->partitions.elements;
uint check_total_partitions;
tab_part_info->is_auto_partitioned= FALSE;
- if (no_parts_reorged > tab_part_info->no_parts)
+ if (num_parts_reorged > tab_part_info->num_parts)
{
my_error(ER_REORG_PARTITION_NOT_EXIST, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
if (!(tab_part_info->part_type == RANGE_PARTITION ||
tab_part_info->part_type == LIST_PARTITION) &&
- (no_parts_new != no_parts_reorged))
+ (num_parts_new != num_parts_reorged))
{
my_error(ER_REORG_HASH_ONLY_ON_SAME_NO, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
if (tab_part_info->is_sub_partitioned() &&
- alt_part_info->no_subparts &&
- alt_part_info->no_subparts != tab_part_info->no_subparts)
+ alt_part_info->num_subparts &&
+ alt_part_info->num_subparts != tab_part_info->num_subparts)
{
my_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
- check_total_partitions= tab_part_info->no_parts + no_parts_new;
- check_total_partitions-= no_parts_reorged;
+ check_total_partitions= tab_part_info->num_parts + num_parts_new;
+ check_total_partitions-= num_parts_reorged;
if (check_total_partitions > MAX_PARTITIONS)
{
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
alt_part_info->part_type= tab_part_info->part_type;
alt_part_info->subpart_type= tab_part_info->subpart_type;
- alt_part_info->no_subparts= tab_part_info->no_subparts;
+ alt_part_info->num_subparts= tab_part_info->num_subparts;
DBUG_ASSERT(!alt_part_info->use_default_partitions);
- if (alt_part_info->set_up_defaults_for_partitioning(table->file,
+ if (alt_part_info->set_up_defaults_for_partitioning(new_table->file,
ULL(0),
0))
{
- DBUG_RETURN(TRUE);
+ goto err;
}
/*
Online handling:
@@ -4914,9 +5229,7 @@ the generated partition syntax in a correct manner.
uint part_count= 0;
bool found_first= FALSE;
bool found_last= FALSE;
- bool is_last_partition_reorged;
uint drop_count= 0;
- longlong tab_max_range= 0, alt_max_range= 0;
do
{
partition_element *part_elem= tab_it++;
@@ -4926,37 +5239,51 @@ the generated partition syntax in a correct manner.
{
is_last_partition_reorged= TRUE;
drop_count++;
- tab_max_range= part_elem->range_value;
- if (*fast_alter_partition &&
+ if (tab_part_info->column_list)
+ {
+ List_iterator<part_elem_value> p(part_elem->list_val_list);
+ tab_max_elem_val= p++;
+ }
+ else
+ tab_max_range= part_elem->range_value;
+ if (*fast_alter_table &&
tab_part_info->temp_partitions.push_back(part_elem))
{
mem_alloc_error(1);
- DBUG_RETURN(TRUE);
+ goto err;
}
- if (*fast_alter_partition)
+ if (*fast_alter_table)
part_elem->part_state= PART_TO_BE_REORGED;
if (!found_first)
{
uint alt_part_count= 0;
- found_first= TRUE;
+ partition_element *alt_part_elem;
List_iterator<partition_element>
alt_it(alt_part_info->partitions);
+ found_first= TRUE;
do
{
- partition_element *alt_part_elem= alt_it++;
- alt_max_range= alt_part_elem->range_value;
- if (*fast_alter_partition)
+ alt_part_elem= alt_it++;
+ if (tab_part_info->column_list)
+ {
+ List_iterator<part_elem_value> p(alt_part_elem->list_val_list);
+ alt_max_elem_val= p++;
+ }
+ else
+ alt_max_range= alt_part_elem->range_value;
+
+ if (*fast_alter_table)
alt_part_elem->part_state= PART_TO_BE_ADDED;
if (alt_part_count == 0)
tab_it.replace(alt_part_elem);
else
tab_it.after(alt_part_elem);
- } while (++alt_part_count < no_parts_new);
+ } while (++alt_part_count < num_parts_new);
}
else if (found_last)
{
my_error(ER_CONSECUTIVE_REORG_PARTITIONS, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
else
tab_it.remove();
@@ -4966,32 +5293,13 @@ the generated partition syntax in a correct manner.
if (found_first)
found_last= TRUE;
}
- } while (++part_count < tab_part_info->no_parts);
- if (drop_count != no_parts_reorged)
+ } while (++part_count < tab_part_info->num_parts);
+ if (drop_count != num_parts_reorged)
{
my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE");
- DBUG_RETURN(TRUE);
- }
- if (tab_part_info->part_type == RANGE_PARTITION &&
- ((is_last_partition_reorged &&
- alt_max_range < tab_max_range) ||
- (!is_last_partition_reorged &&
- alt_max_range != tab_max_range)))
- {
- /*
- For range partitioning the total resulting range before and
- after the change must be the same except in one case. This is
- when the last partition is reorganised, in this case it is
- acceptable to increase the total range.
- The reason is that it is not allowed to have "holes" in the
- middle of the ranges and thus we should not allow to reorganise
- to create "holes". Also we should not allow using REORGANIZE
- to drop data.
- */
- my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
- tab_part_info->no_parts= check_total_partitions;
+ tab_part_info->num_parts= check_total_partitions;
}
}
else
@@ -5007,12 +5315,44 @@ the generated partition syntax in a correct manner.
!alt_part_info->use_default_subpartitions)
{
tab_part_info->use_default_subpartitions= FALSE;
- tab_part_info->use_default_no_subpartitions= FALSE;
+ tab_part_info->use_default_num_subpartitions= FALSE;
}
if (tab_part_info->check_partition_info(thd, (handlerton**)NULL,
- table->file, ULL(0), FALSE))
+ new_table->file, ULL(0), TRUE))
{
- DBUG_RETURN(TRUE);
+ goto err;
+ }
+ /*
+ The check below needs to be performed after check_partition_info
+ since this function "fixes" the item trees of the new partitions
+ to reorganize into
+ */
+ if (alter_info->flags == ALTER_REORGANIZE_PARTITION &&
+ tab_part_info->part_type == RANGE_PARTITION &&
+ ((is_last_partition_reorged &&
+ (tab_part_info->column_list ?
+ (tab_part_info->compare_column_values(
+ alt_max_elem_val->col_val_array,
+ tab_max_elem_val->col_val_array) < 0) :
+ alt_max_range < tab_max_range)) ||
+ (!is_last_partition_reorged &&
+ (tab_part_info->column_list ?
+ (tab_part_info->compare_column_values(
+ alt_max_elem_val->col_val_array,
+ tab_max_elem_val->col_val_array) != 0) :
+ alt_max_range != tab_max_range))))
+ {
+ /*
+ For range partitioning the total resulting range before and
+ after the change must be the same except in one case. This is
+ when the last partition is reorganised, in this case it is
+ acceptable to increase the total range.
+ The reason is that it is not allowed to have "holes" in the
+ middle of the ranges and thus we should not allow to reorganise
+ to create "holes".
+ */
+ my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
+ goto err;
}
}
}
@@ -5127,6 +5467,10 @@ the generated partition syntax in a correct manner.
{
DBUG_PRINT("info", ("partition changed"));
*partition_changed= TRUE;
+ if (thd->work_part_info->fix_parser_data(thd))
+ {
+ goto err;
+ }
}
/*
Set up partition default_engine_type either from the create_info
@@ -5146,7 +5490,7 @@ the generated partition syntax in a correct manner.
if (check_native_partitioned(create_info, &is_native_partitioned,
part_info, thd))
{
- DBUG_RETURN(TRUE);
+ goto err;
}
if (!is_native_partitioned)
{
@@ -5156,6 +5500,17 @@ the generated partition syntax in a correct manner.
}
}
DBUG_RETURN(FALSE);
+err:
+ if (new_table)
+ {
+ /*
+ Only remove the intermediate table object and its share object,
+ do not remove the .frm file, since it is the original one.
+ */
+ close_temporary(new_table, 1, 0);
+ }
+ *fast_alter_table= NULL;
+ DBUG_RETURN(TRUE);
}
@@ -5190,20 +5545,33 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
char path[FN_REFLEN+1];
int error;
handler *file= lpt->table->file;
+ THD *thd= lpt->thd;
DBUG_ENTER("mysql_change_partitions");
build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0);
+
+ if(mysql_trans_prepare_alter_copy_data(thd))
+ DBUG_RETURN(TRUE);
+
+ if (file->ha_external_lock(thd, F_WRLCK))
+ DBUG_RETURN(TRUE);
+
+ /* TODO: test if bulk_insert would increase the performance */
+
if ((error= file->ha_change_partitions(lpt->create_info, path, &lpt->copied,
&lpt->deleted, lpt->pack_frm_data,
lpt->pack_frm_len)))
{
- if (error != ER_OUTOFMEMORY)
- file->print_error(error, MYF(0));
- else
- lpt->thd->fatal_error();
- DBUG_RETURN(TRUE);
+ file->print_error(error, MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATALERROR));
}
- DBUG_RETURN(FALSE);
+
+ if (mysql_trans_commit_alter_copy_data(thd))
+ error= 1; /* The error has been reported */
+
+ if (file->ha_external_lock(thd, F_UNLCK))
+ error= 1;
+
+ DBUG_RETURN(test(error));
}
@@ -5287,8 +5655,8 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
part_it.remove();
remove_count++;
}
- } while (++i < part_info->no_parts);
- part_info->no_parts-= remove_count;
+ } while (++i < part_info->num_parts);
+ part_info->num_parts-= remove_count;
DBUG_RETURN(FALSE);
}
@@ -5410,7 +5778,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
char normal_path[FN_REFLEN];
List_iterator<partition_element> part_it(part_info->partitions);
uint temp_partitions= part_info->temp_partitions.elements;
- uint no_elements= part_info->partitions.elements;
+ uint num_elements= part_info->partitions.elements;
uint i= 0;
DBUG_ENTER("write_log_changed_partitions");
@@ -5423,7 +5791,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
if (part_info->is_sub_partitioned())
{
List_iterator<partition_element> sub_it(part_elem->subpartitions);
- uint no_subparts= part_info->no_subparts;
+ uint num_subparts= part_info->num_subparts;
uint j= 0;
do
{
@@ -5452,7 +5820,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
*next_entry= log_entry->entry_pos;
sub_elem->log_entry= log_entry;
insert_part_info_log_entry_list(part_info, log_entry);
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
else
{
@@ -5480,7 +5848,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
insert_part_info_log_entry_list(part_info, log_entry);
}
}
- } while (++i < no_elements);
+ } while (++i < num_elements);
DBUG_RETURN(FALSE);
}
@@ -5506,14 +5874,14 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
char tmp_path[FN_LEN];
List_iterator<partition_element> part_it(part_info->partitions);
List_iterator<partition_element> temp_it(part_info->temp_partitions);
- uint no_temp_partitions= part_info->temp_partitions.elements;
- uint no_elements= part_info->partitions.elements;
+ uint num_temp_partitions= part_info->temp_partitions.elements;
+ uint num_elements= part_info->partitions.elements;
DBUG_ENTER("write_log_dropped_partitions");
ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
if (temp_list)
- no_elements= no_temp_partitions;
- while (no_elements--)
+ num_elements= num_temp_partitions;
+ while (num_elements--)
{
partition_element *part_elem;
if (temp_list)
@@ -5527,14 +5895,14 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
uint name_variant;
if (part_elem->part_state == PART_CHANGED ||
(part_elem->part_state == PART_TO_BE_ADDED &&
- no_temp_partitions))
+ num_temp_partitions))
name_variant= TEMP_PART_NAME;
else
name_variant= NORMAL_PART_NAME;
if (part_info->is_sub_partitioned())
{
List_iterator<partition_element> sub_it(part_elem->subpartitions);
- uint no_subparts= part_info->no_subparts;
+ uint num_subparts= part_info->num_subparts;
uint j= 0;
do
{
@@ -5554,7 +5922,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
*next_entry= log_entry->entry_pos;
sub_elem->log_entry= log_entry;
insert_part_info_log_entry_list(part_info, log_entry);
- } while (++j < no_subparts);
+ } while (++j < num_subparts);
}
else
{
@@ -5622,7 +5990,7 @@ static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
DBUG_ENTER("write_log_drop_shadow_frm");
build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
- pthread_mutex_lock(&LOCK_gdl);
+ mysql_mutex_lock(&LOCK_gdl);
if (write_log_replace_delete_frm(lpt, 0UL, NULL,
(const char*)shadow_path, FALSE))
goto error;
@@ -5630,13 +5998,13 @@ static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
if (write_execute_ddl_log_entry(log_entry->entry_pos,
FALSE, &exec_log_entry))
goto error;
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
set_part_info_exec_log_entry(part_info, exec_log_entry);
DBUG_RETURN(FALSE);
error:
release_part_info_log_entries(part_info->first_log_entry);
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
part_info->first_log_entry= NULL;
my_error(ER_DDL_LOG_ERROR, MYF(0));
DBUG_RETURN(TRUE);
@@ -5670,7 +6038,7 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
- pthread_mutex_lock(&LOCK_gdl);
+ mysql_mutex_lock(&LOCK_gdl);
if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE))
goto error;
log_entry= part_info->first_log_entry;
@@ -5679,12 +6047,12 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
FALSE, &exec_log_entry))
goto error;
release_part_info_log_entries(old_first_log_entry);
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(FALSE);
error:
release_part_info_log_entries(part_info->first_log_entry);
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
part_info->first_log_entry= old_first_log_entry;
part_info->frm_log_entry= NULL;
my_error(ER_DDL_LOG_ERROR, MYF(0));
@@ -5722,7 +6090,7 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
- pthread_mutex_lock(&LOCK_gdl);
+ mysql_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
FALSE))
goto error;
@@ -5735,12 +6103,12 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
FALSE, &exec_log_entry))
goto error;
release_part_info_log_entries(old_first_log_entry);
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(FALSE);
error:
release_part_info_log_entries(part_info->first_log_entry);
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
part_info->first_log_entry= old_first_log_entry;
part_info->frm_log_entry= NULL;
my_error(ER_DDL_LOG_ERROR, MYF(0));
@@ -5769,34 +6137,41 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
{
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
- DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL;
+ DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
char tmp_path[FN_REFLEN + 1];
char path[FN_REFLEN + 1];
uint next_entry= 0;
+ DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
+ /* write_log_drop_shadow_frm(lpt) must have been run first */
+ DBUG_ASSERT(old_first_log_entry);
DBUG_ENTER("write_log_add_change_partition");
build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
- pthread_mutex_lock(&LOCK_gdl);
+ mysql_mutex_lock(&LOCK_gdl);
+
+ /* Relink the previous drop shadow frm entry */
+ if (old_first_log_entry)
+ next_entry= old_first_log_entry->entry_pos;
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
FALSE))
goto error;
- if (write_log_replace_delete_frm(lpt, next_entry, NULL, tmp_path,
- FALSE))
- goto error;
log_entry= part_info->first_log_entry;
+
if (write_execute_ddl_log_entry(log_entry->entry_pos,
- FALSE, &exec_log_entry))
+ FALSE,
+ /* Reuse the old execute ddl_log_entry */
+ &exec_log_entry))
goto error;
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
set_part_info_exec_log_entry(part_info, exec_log_entry);
DBUG_RETURN(FALSE);
error:
release_part_info_log_entries(part_info->first_log_entry);
- pthread_mutex_unlock(&LOCK_gdl);
- part_info->first_log_entry= NULL;
+ mysql_mutex_unlock(&LOCK_gdl);
+ part_info->first_log_entry= old_first_log_entry;
my_error(ER_DDL_LOG_ERROR, MYF(0));
DBUG_RETURN(TRUE);
}
@@ -5813,9 +6188,15 @@ error:
TRUE Error
FALSE Success
DESCRIPTION
- We will write log entries that specify to remove all partitions reorganised,
- to rename others to reflect the new naming scheme and to install the shadow
- frm file.
+ We will write log entries that specify to
+ 1) Install the shadow frm file.
+ 2) Remove all partitions reorganized. (To be able to reorganize a partition
+ to the same name. Like in REORGANIZE p0 INTO (p0, p1),
+ so that the later rename from the new p0-temporary name to p0 don't
+ fail because the partition already exists.
+ 3) Rename others to reflect the new naming scheme.
+
+ Note that it is written in the ddl log in reverse.
*/
static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
@@ -5829,30 +6210,35 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
uint next_entry= 0;
DBUG_ENTER("write_log_final_change_partition");
+ /*
+ Do not link any previous log entry.
+ Replace the revert operations with forced retry operations.
+ */
part_info->first_log_entry= NULL;
build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
- pthread_mutex_lock(&LOCK_gdl);
+ mysql_mutex_lock(&LOCK_gdl);
+ if (write_log_changed_partitions(lpt, &next_entry, (const char*)path))
+ goto error;
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
lpt->alter_info->flags & ALTER_REORGANIZE_PARTITION))
goto error;
- if (write_log_changed_partitions(lpt, &next_entry, (const char*)path))
- goto error;
- if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE))
+ if (write_log_replace_delete_frm(lpt, next_entry, shadow_path, path, TRUE))
goto error;
log_entry= part_info->first_log_entry;
part_info->frm_log_entry= log_entry;
+ /* Overwrite the revert execute log entry with this retry execute entry */
if (write_execute_ddl_log_entry(log_entry->entry_pos,
FALSE, &exec_log_entry))
goto error;
release_part_info_log_entries(old_first_log_entry);
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(FALSE);
error:
release_part_info_log_entries(part_info->first_log_entry);
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
part_info->first_log_entry= old_first_log_entry;
part_info->frm_log_entry= NULL;
my_error(ER_DDL_LOG_ERROR, MYF(0));
@@ -5879,7 +6265,7 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
DBUG_ENTER("write_log_completed");
DBUG_ASSERT(log_entry);
- pthread_mutex_lock(&LOCK_gdl);
+ mysql_mutex_lock(&LOCK_gdl);
if (write_execute_ddl_log_entry(0UL, TRUE, &log_entry))
{
/*
@@ -5893,7 +6279,7 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
}
release_part_info_log_entries(part_info->first_log_entry);
release_part_info_log_entries(part_info->exec_log_entry);
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
part_info->exec_log_entry= NULL;
part_info->first_log_entry= NULL;
DBUG_VOID_RETURN;
@@ -5911,10 +6297,10 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
static void release_log_entries(partition_info *part_info)
{
- pthread_mutex_lock(&LOCK_gdl);
+ mysql_mutex_lock(&LOCK_gdl);
release_part_info_log_entries(part_info->first_log_entry);
release_part_info_log_entries(part_info->exec_log_entry);
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
part_info->first_log_entry= NULL;
part_info->exec_log_entry= NULL;
}
@@ -5931,53 +6317,86 @@ static void release_log_entries(partition_info *part_info)
*/
static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
{
- int err;
- if (lpt->thd->locked_tables)
+ THD *thd= lpt->thd;
+
+ if (lpt->old_table)
+ close_all_tables_for_name(thd, lpt->old_table->s, FALSE);
+ if (lpt->table)
{
/*
- When we have the table locked, it is necessary to reopen the table
- since all table objects were closed and removed as part of the
- ALTER TABLE of partitioning structure.
+ Only remove the intermediate table object and its share object,
+ do not remove the .frm file, since it is the original one.
*/
- pthread_mutex_lock(&LOCK_open);
- lpt->thd->in_lock_tables= 1;
- err= reopen_tables(lpt->thd, 1, 1);
- lpt->thd->in_lock_tables= 0;
- if (err)
- {
- /*
- Issue a warning since we weren't able to regain the lock again.
- We also need to unlink table from thread's open list and from
- table_cache
- */
- unlink_open_table(lpt->thd, lpt->table, FALSE);
- sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE");
- }
- pthread_mutex_unlock(&LOCK_open);
+ close_temporary(lpt->table, 1, 0);
}
+ lpt->table= 0;
+ lpt->old_table= 0;
+ lpt->table_list->table= 0;
+ if (thd->locked_tables_list.reopen_tables(thd))
+ sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE");
}
/*
- Handle errors for ALTER TABLE for partitioning
+ Unlock and close table before renaming and dropping partitions
SYNOPSIS
- handle_alter_part_error()
+ alter_close_tables()
lpt Struct carrying parameters
- not_completed Was request in complete phase when error occurred
+ close_old Close original table too
RETURN VALUES
- NONE
+ 0
+*/
+
+static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt, bool close_old)
+{
+ DBUG_ENTER("alter_close_tables");
+ if (lpt->table->db_stat)
+ {
+ lpt->table->file->close();
+ lpt->table->db_stat= 0; // Mark file closed
+ }
+ if (close_old && lpt->old_table)
+ {
+ close_all_tables_for_name(lpt->thd, lpt->old_table->s, FALSE);
+ lpt->old_table= 0;
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**
+ Handle errors for ALTER TABLE for partitioning.
+
+ @param lpt Struct carrying parameters
+ @param action_completed The action must be completed, NOT reverted
+ @param drop_partition Partitions has not been dropped yet
+ @param frm_install The shadow frm-file has not yet been installed
+ @param close_table Table is still open, close it before reverting
*/
void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
- bool not_completed,
+ bool action_completed,
bool drop_partition,
- bool frm_install)
+ bool frm_install,
+ bool close_table)
{
partition_info *part_info= lpt->part_info;
DBUG_ENTER("handle_alter_part_error");
+ if (close_table)
+ {
+ /*
+ Since the error handling (ddl_log) needs to drop newly created
+ partitions they must be closed first to not issue errors.
+ But we still need some information from the part_info object,
+ so we clone it first to have a copy.
+ */
+ part_info= lpt->part_info->get_clone();
+ alter_close_tables(lpt, action_completed);
+ }
+
if (part_info->first_log_entry &&
- execute_ddl_log_entry(current_thd,
+ execute_ddl_log_entry(lpt->thd,
part_info->first_log_entry->entry_pos))
{
/*
@@ -5986,7 +6405,7 @@ void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
*/
write_log_completed(lpt, FALSE);
release_log_entries(part_info);
- if (not_completed)
+ if (!action_completed)
{
if (drop_partition)
{
@@ -6051,7 +6470,7 @@ void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
else
{
release_log_entries(part_info);
- if (not_completed)
+ if (!action_completed)
{
/*
We hit an error before things were completed but managed
@@ -6078,25 +6497,40 @@ void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
}
-/*
+/**
+ Downgrade an exclusive MDL lock if under LOCK TABLE.
+
+ If we don't downgrade the lock, it will not be downgraded or released
+ until the table is unlocked, resulting in blocking other threads using
+ the table.
+*/
+
+static void downgrade_mdl_if_lock_tables_mode(THD *thd, MDL_ticket *ticket,
+ enum_mdl_type type)
+{
+ if (thd->locked_tables_mode)
+ ticket->downgrade_exclusive_lock(type);
+}
+
+
+/**
Actually perform the change requested by ALTER TABLE of partitions
previously prepared.
- SYNOPSIS
- fast_alter_partition_table()
- thd Thread object
- table Table object
- alter_info ALTER TABLE info
- create_info Create info for CREATE TABLE
- table_list List of the table involved
- db Database name of new table
- table_name Table name of new table
+ @param thd Thread object
+ @param table Original table object
+ @param alter_info ALTER TABLE info
+ @param create_info Create info for CREATE TABLE
+ @param table_list List of the table involved
+ @param db Database name of new table
+ @param table_name Table name of new table
+ @param fast_alter_table Prepared table object
- RETURN VALUES
- TRUE Error
- FALSE Success
+ @return Operation status
+ @retval TRUE Error
+ @retval FALSE Success
- DESCRIPTION
+ @note
Perform all ALTER TABLE operations for partitioned tables that can be
performed fast without a full copy of the original table.
*/
@@ -6107,25 +6541,30 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
TABLE_LIST *table_list,
char *db,
const char *table_name,
- uint fast_alter_partition)
+ TABLE *fast_alter_table)
{
/* Set-up struct used to write frm files */
- partition_info *part_info= table->part_info;
+ partition_info *part_info;
ALTER_PARTITION_PARAM_TYPE lpt_obj;
ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj;
- bool written_bin_log= TRUE;
- bool not_completed= TRUE;
+ bool action_completed= FALSE;
+ bool close_table_on_failure= FALSE;
bool frm_install= FALSE;
+ MDL_ticket *mdl_ticket= table->mdl_ticket;
+ DBUG_ASSERT(fast_alter_table);
DBUG_ENTER("fast_alter_partition_table");
+ part_info= fast_alter_table->part_info;
lpt->thd= thd;
+ lpt->table_list= table_list;
lpt->part_info= part_info;
lpt->alter_info= alter_info;
lpt->create_info= create_info;
lpt->db_options= create_info->table_options;
if (create_info->row_type == ROW_TYPE_DYNAMIC)
lpt->db_options|= HA_OPTION_PACK_RECORD;
- lpt->table= table;
+ lpt->table= fast_alter_table;
+ lpt->old_table= table;
lpt->key_info_buffer= 0;
lpt->key_count= 0;
lpt->db= db;
@@ -6134,12 +6573,12 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
lpt->deleted= 0;
lpt->pack_frm_data= NULL;
lpt->pack_frm_len= 0;
- thd->work_part_info= part_info;
/* Never update timestamp columns when alter */
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+ lpt->table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
- if (fast_alter_partition & HA_PARTITION_ONE_PHASE)
+ if (table->file->alter_table_flags(alter_info->flags) &
+ HA_PARTITION_ONE_PHASE)
{
/*
In the case where the engine supports one phase online partition
@@ -6213,20 +6652,18 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
0) Write an entry that removes the shadow frm file if crash occurs
1) Write the new frm file as a shadow frm
- 2) Write the ddl log to ensure that the operation is completed
- even in the presence of a MySQL Server crash
- 3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to
- the table have completed. This ensures that other threads can not
- execute on the table in parallel.
- 4) Get a name lock on the table. This ensures that we can release all
- locks on the table and since no one can open the table, there can
- be no new threads accessing the table. They will be hanging on the
- name lock.
- 5) Close all tables that have already been opened but didn't stumble on
+ 2) Get an exclusive metadata lock on the table (waits for all active
+ transactions using this table). This ensures that we
+ can release all other locks on the table and since no one can open
+ the table, there can be no new threads accessing the table. They
+ will be hanging on this exclusive lock.
+ 3) Write the ddl log to ensure that the operation is completed
+ even in the presence of a MySQL Server crash (the log is executed
+ before any other threads are started, so there are no locking issues).
+ 4) Close all tables that have already been opened but didn't stumble on
the abort locked previously. This is done as part of the
- close_data_files_and_morph_locks call.
- 6) We are now ready to release all locks we got in this thread.
- 7) Write the bin log
+ alter_close_tables call.
+ 5) Write the bin log
Unfortunately the writing of the binlog is not synchronised with
other logging activities. So no matter in which order the binlog
is written compared to other activities there will always be cases
@@ -6237,40 +6674,54 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
require writing the statement first in the ddl log and then
when recovering from the crash read the binlog and insert it into
the binlog if not written already.
- 8) Install the previously written shadow frm file
- 9) Prepare handlers for drop of partitions
- 10) Drop the partitions
- 11) Remove entries from ddl log
- 12) Reopen table if under lock tables
- 13) Complete query
+ 6) Install the previously written shadow frm file
+ 7) Prepare handlers for drop of partitions
+ 8) Drop the partitions
+ 9) Remove entries from ddl log
+ 10) Reopen table if under lock tables
+ 11) Complete query
We insert Error injections at all places where it could be interesting
to test if recovery is properly done.
*/
if (write_log_drop_shadow_frm(lpt) ||
ERROR_INJECT_CRASH("crash_drop_partition_1") ||
+ ERROR_INJECT_ERROR("fail_drop_partition_1") ||
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
ERROR_INJECT_CRASH("crash_drop_partition_2") ||
- write_log_drop_partition(lpt) ||
+ ERROR_INJECT_ERROR("fail_drop_partition_2") ||
+ wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN) ||
ERROR_INJECT_CRASH("crash_drop_partition_3") ||
- (not_completed= FALSE) ||
- abort_and_upgrade_lock_and_close_table(lpt) ||
+ ERROR_INJECT_ERROR("fail_drop_partition_3") ||
+ (close_table_on_failure= TRUE, FALSE) ||
+ write_log_drop_partition(lpt) ||
+ (action_completed= TRUE, FALSE) ||
+ ERROR_INJECT_CRASH("crash_drop_partition_4") ||
+ ERROR_INJECT_ERROR("fail_drop_partition_4") ||
+ alter_close_tables(lpt, action_completed) ||
+ (close_table_on_failure= FALSE, FALSE) ||
ERROR_INJECT_CRASH("crash_drop_partition_5") ||
+ ERROR_INJECT_ERROR("fail_drop_partition_5") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query(), thd->query_length()), FALSE)) ||
ERROR_INJECT_CRASH("crash_drop_partition_6") ||
- ((frm_install= TRUE), FALSE) ||
+ ERROR_INJECT_ERROR("fail_drop_partition_6") ||
+ (frm_install= TRUE, FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
- ((frm_install= FALSE), FALSE) ||
+ (frm_install= FALSE, FALSE) ||
ERROR_INJECT_CRASH("crash_drop_partition_7") ||
+ ERROR_INJECT_ERROR("fail_drop_partition_7") ||
mysql_drop_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_drop_partition_8") ||
+ ERROR_INJECT_ERROR("fail_drop_partition_8") ||
(write_log_completed(lpt, FALSE), FALSE) ||
ERROR_INJECT_CRASH("crash_drop_partition_9") ||
+ ERROR_INJECT_ERROR("fail_drop_partition_9") ||
(alter_partition_lock_handling(lpt), FALSE))
{
- handle_alter_part_error(lpt, not_completed, TRUE, frm_install);
+ handle_alter_part_error(lpt, action_completed, TRUE, frm_install,
+ close_table_on_failure);
goto err;
}
}
@@ -6289,53 +6740,65 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
0) Write an entry that removes the shadow frm file if crash occurs
1) Write the new frm file as a shadow frm file
- 2) Log the changes to happen in ddl log
- 2) Add the new partitions
- 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users
- are still using the old partitioning scheme. Wait until all
- ongoing users have completed before progressing.
- 4) Get a name lock on the table. This ensures that we can release all
- locks on the table and since no one can open the table, there can
- be no new threads accessing the table. They will be hanging on the
- name lock.
- 5) Close all tables that have already been opened but didn't stumble on
- the abort locked previously. This is done as part of the
- close_data_files_and_morph_locks call.
- 6) Close all table handlers and unlock all handlers but retain name lock
- 7) Write binlog
- 8) Now the change is completed except for the installation of the
+ 2) Get an exclusive metadata lock on the table (waits for all active
+ transactions using this table). This ensures that we
+ can release all other locks on the table and since no one can open
+ the table, there can be no new threads accessing the table. They
+ will be hanging on this exclusive lock.
+ 3) Write an entry to remove the new parttions if crash occurs
+ 4) Add the new partitions.
+ 5) Close all instances of the table and remove them from the table cache.
+ 6) Write binlog
+ 7) Now the change is completed except for the installation of the
new frm file. We thus write an action in the log to change to
the shadow frm file
- 9) Install the new frm file of the table where the partitions are
+ 8) Install the new frm file of the table where the partitions are
added to the table.
- 10)Wait until all accesses using the old frm file has completed
- 11)Remove entries from ddl log
- 12)Reopen tables if under lock tables
- 13)Complete query
+ 9) Remove entries from ddl log
+ 10)Reopen tables if under lock tables
+ 11)Complete query
*/
- if (write_log_add_change_partition(lpt) ||
+ if (write_log_drop_shadow_frm(lpt) ||
ERROR_INJECT_CRASH("crash_add_partition_1") ||
+ ERROR_INJECT_ERROR("fail_add_partition_1") ||
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
ERROR_INJECT_CRASH("crash_add_partition_2") ||
- mysql_change_partitions(lpt) ||
+ ERROR_INJECT_ERROR("fail_add_partition_2") ||
+ wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN) ||
ERROR_INJECT_CRASH("crash_add_partition_3") ||
- abort_and_upgrade_lock_and_close_table(lpt) ||
+ ERROR_INJECT_ERROR("fail_add_partition_3") ||
+ (close_table_on_failure= TRUE, FALSE) ||
+ write_log_add_change_partition(lpt) ||
+ ERROR_INJECT_CRASH("crash_add_partition_4") ||
+ ERROR_INJECT_ERROR("fail_add_partition_4") ||
+ mysql_change_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_add_partition_5") ||
+ ERROR_INJECT_ERROR("fail_add_partition_5") ||
+ (close_table_on_failure= FALSE, FALSE) ||
+ alter_close_tables(lpt, action_completed) ||
+ ERROR_INJECT_CRASH("crash_add_partition_6") ||
+ ERROR_INJECT_ERROR("fail_add_partition_6") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query(), thd->query_length()), FALSE)) ||
- ERROR_INJECT_CRASH("crash_add_partition_6") ||
- write_log_rename_frm(lpt) ||
- (not_completed= FALSE) ||
ERROR_INJECT_CRASH("crash_add_partition_7") ||
- ((frm_install= TRUE), FALSE) ||
- mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
+ ERROR_INJECT_ERROR("fail_add_partition_7") ||
+ write_log_rename_frm(lpt) ||
+ (action_completed= TRUE, FALSE) ||
ERROR_INJECT_CRASH("crash_add_partition_8") ||
- (write_log_completed(lpt, FALSE), FALSE) ||
+ ERROR_INJECT_ERROR("fail_add_partition_8") ||
+ (frm_install= TRUE, FALSE) ||
+ mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
+ (frm_install= FALSE, FALSE) ||
ERROR_INJECT_CRASH("crash_add_partition_9") ||
- (alter_partition_lock_handling(lpt), FALSE))
+ ERROR_INJECT_ERROR("fail_add_partition_9") ||
+ (write_log_completed(lpt, FALSE), FALSE) ||
+ ERROR_INJECT_CRASH("crash_add_partition_10") ||
+ ERROR_INJECT_ERROR("fail_add_partition_10") ||
+ (alter_partition_lock_handling(lpt), FALSE))
{
- handle_alter_part_error(lpt, not_completed, FALSE, frm_install);
+ handle_alter_part_error(lpt, action_completed, FALSE, frm_install,
+ close_table_on_failure);
goto err;
}
}
@@ -6378,65 +6841,96 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
removed in a crash situation
3) Add the new partitions
Copy from the reorganised partitions to the new partitions
- 4) Log that operation is completed and log all complete actions
+ 4) Get an exclusive metadata lock on the table (waits for all active
+ transactions using this table). This ensures that we
+ can release all other locks on the table and since no one can open
+ the table, there can be no new threads accessing the table. They
+ will be hanging on this exclusive lock.
+ 5) Log that operation is completed and log all complete actions
needed to complete operation from here
- 5) Lock all partitions in TL_WRITE_ONLY to ensure that no users
- are still using the old partitioning scheme. Wait until all
- ongoing users have completed before progressing.
- 6) Get a name lock of the table
- 7) Close all tables opened but not yet locked, after this call we are
- certain that no other thread is in the lock wait queue or has
- opened the table. The name lock will ensure that they are blocked
- on the open call.
- This is achieved also by close_data_files_and_morph_locks call.
- 8) Close all partitions opened by this thread, but retain name lock.
- 9) Write bin log
- 10) Prepare handlers for rename and delete of partitions
- 11) Rename and drop the reorged partitions such that they are no
- longer used and rename those added to their real new names.
- 12) Install the shadow frm file
- 13) Reopen the table if under lock tables
- 14) Complete query
+ 6) Write bin log
+ 7) Close all instances of the table and remove them from the table cache.
+ 8) Prepare handlers for rename and delete of partitions
+ 9) Rename and drop the reorged partitions such that they are no
+ longer used and rename those added to their real new names.
+ 10) Install the shadow frm file
+ 11) Reopen the table if under lock tables
+ 12) Complete query
*/
- if (write_log_add_change_partition(lpt) ||
+ if (write_log_drop_shadow_frm(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_1") ||
+ ERROR_INJECT_ERROR("fail_change_partition_1") ||
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
ERROR_INJECT_CRASH("crash_change_partition_2") ||
- mysql_change_partitions(lpt) ||
+ ERROR_INJECT_ERROR("fail_change_partition_2") ||
+ (close_table_on_failure= TRUE, FALSE) ||
+ write_log_add_change_partition(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_3") ||
- write_log_final_change_partition(lpt) ||
+ ERROR_INJECT_ERROR("fail_change_partition_3") ||
+ mysql_change_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_4") ||
- (not_completed= FALSE) ||
- abort_and_upgrade_lock_and_close_table(lpt) ||
+ ERROR_INJECT_ERROR("fail_change_partition_4") ||
+ wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN) ||
+ ERROR_INJECT_CRASH("crash_change_partition_5") ||
+ ERROR_INJECT_ERROR("fail_change_partition_5") ||
+ write_log_final_change_partition(lpt) ||
+ (action_completed= TRUE, FALSE) ||
ERROR_INJECT_CRASH("crash_change_partition_6") ||
+ ERROR_INJECT_ERROR("fail_change_partition_6") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query(), thd->query_length()), FALSE)) ||
ERROR_INJECT_CRASH("crash_change_partition_7") ||
+ ERROR_INJECT_ERROR("fail_change_partition_7") ||
+ ((frm_install= TRUE), FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
+ (frm_install= FALSE, FALSE) ||
ERROR_INJECT_CRASH("crash_change_partition_8") ||
- mysql_drop_partitions(lpt) ||
+ ERROR_INJECT_ERROR("fail_change_partition_8") ||
+ alter_close_tables(lpt, action_completed) ||
+ (close_table_on_failure= FALSE, FALSE) ||
ERROR_INJECT_CRASH("crash_change_partition_9") ||
- mysql_rename_partitions(lpt) ||
- ((frm_install= TRUE), FALSE) ||
+ ERROR_INJECT_ERROR("fail_change_partition_9") ||
+ mysql_drop_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_10") ||
- (write_log_completed(lpt, FALSE), FALSE) ||
+ ERROR_INJECT_ERROR("fail_change_partition_10") ||
+ mysql_rename_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_11") ||
+ ERROR_INJECT_ERROR("fail_change_partition_11") ||
+ (write_log_completed(lpt, FALSE), FALSE) ||
+ ERROR_INJECT_CRASH("crash_change_partition_12") ||
+ ERROR_INJECT_ERROR("fail_change_partition_12") ||
(alter_partition_lock_handling(lpt), FALSE))
{
- handle_alter_part_error(lpt, not_completed, FALSE, frm_install);
+ handle_alter_part_error(lpt, action_completed, FALSE, frm_install,
+ close_table_on_failure);
goto err;
}
}
+ downgrade_mdl_if_lock_tables_mode(thd, mdl_ticket, MDL_SHARED_NO_READ_WRITE);
/*
A final step is to write the query to the binlog and send ok to the
user
*/
- DBUG_RETURN(fast_end_partition(thd, lpt->copied, lpt->deleted,
- table, table_list, FALSE, NULL,
- written_bin_log));
+ DBUG_RETURN(fast_end_partition(thd, lpt->copied, lpt->deleted, table_list));
err:
- close_thread_tables(thd);
+ if (action_completed)
+ {
+ /*
+ Although error occurred, the action was forced to retry for completion.
+ Therefore we must close+reopen all instances of the table.
+ */
+ (void) alter_partition_lock_handling(lpt);
+ }
+ else
+ {
+ /*
+ The failed action was reverted, leave the original table as is and
+ close/destroy the intermediate table object and its share.
+ */
+ close_temporary(lpt->table, 1, 0);
+ }
+ downgrade_mdl_if_lock_tables_mode(thd, mdl_ticket, MDL_SHARED_NO_READ_WRITE);
DBUG_RETURN(TRUE);
}
#endif
@@ -6618,16 +7112,19 @@ void make_used_partitions_str(partition_info *part_info, String *parts_str)
IMPLEMENTATION
There are two available interval analyzer functions:
(1) get_part_iter_for_interval_via_mapping
- (2) get_part_iter_for_interval_via_walking
+ (2) get_part_iter_for_interval_cols_via_map
+ (3) get_part_iter_for_interval_via_walking
They both have limited applicability:
(1) is applicable for "PARTITION BY <RANGE|LIST>(func(t.field))", where
func is a monotonic function.
-
- (2) is applicable for
+
+ (2) is applicable for "PARTITION BY <RANGE|LIST> COLUMNS (field_list)
+
+ (3) is applicable for
"[SUB]PARTITION BY <any-partitioning-type>(any_func(t.integer_field))"
- If both are applicable, (1) is preferred over (2).
+ If both (1) and (3) are applicable, (1) is preferred over (3).
This function sets part_info::get_part_iter_for_interval according to
this criteria, and also sets some auxilary fields that the function
@@ -6647,10 +7144,19 @@ static void set_up_range_analysis_info(partition_info *part_info)
switch (part_info->part_type) {
case RANGE_PARTITION:
case LIST_PARTITION:
- if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC)
+ if (!part_info->column_list)
+ {
+ if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC)
+ {
+ part_info->get_part_iter_for_interval=
+ get_part_iter_for_interval_via_mapping;
+ goto setup_subparts;
+ }
+ }
+ else
{
part_info->get_part_iter_for_interval=
- get_part_iter_for_interval_via_mapping;
+ get_part_iter_for_interval_cols_via_map;
goto setup_subparts;
}
default:
@@ -6661,7 +7167,7 @@ static void set_up_range_analysis_info(partition_info *part_info)
Check if get_part_iter_for_interval_via_walking() can be used for
partitioning
*/
- if (part_info->no_part_fields == 1)
+ if (part_info->num_part_fields == 1)
{
Field *field= part_info->part_field_array[0];
switch (field->type()) {
@@ -6683,7 +7189,7 @@ setup_subparts:
Check if get_part_iter_for_interval_via_walking() can be used for
subpartitioning
*/
- if (part_info->no_subpart_fields == 1)
+ if (part_info->num_subpart_fields == 1)
{
Field *field= part_info->subpart_field_array[0];
switch (field->type()) {
@@ -6701,9 +7207,118 @@ setup_subparts:
}
+/*
+ This function takes a memory of packed fields in opt-range format
+ and stores it in record format. To avoid having to worry about how
+ the length of fields are calculated in opt-range format we send
+ an array of lengths used for each field in store_length_array.
+
+ SYNOPSIS
+ store_tuple_to_record()
+ pfield Field array
+ store_length_array Array of field lengths
+ value Memory where fields are stored
+ value_end End of memory
+
+ RETURN VALUE
+ nparts Number of fields assigned
+*/
+uint32 store_tuple_to_record(Field **pfield,
+ uint32 *store_length_array,
+ uchar *value,
+ uchar *value_end)
+{
+ /* This function is inspired by store_key_image_rec. */
+ uint32 nparts= 0;
+ uchar *loc_value;
+ while (value < value_end)
+ {
+ loc_value= value;
+ if ((*pfield)->real_maybe_null())
+ {
+ if (*loc_value)
+ (*pfield)->set_null();
+ else
+ (*pfield)->set_notnull();
+ loc_value++;
+ }
+ uint len= (*pfield)->pack_length();
+ (*pfield)->set_key_image(loc_value, len);
+ value+= *store_length_array;
+ store_length_array++;
+ nparts++;
+ pfield++;
+ }
+ return nparts;
+}
+
+/*
+ RANGE(columns) partitioning: compare value bound and probe tuple.
+
+ The value bound always is a full tuple (but may include the MAXVALUE
+ special value).
+
+ The probe tuple may be a prefix of partitioning tuple. The tail_is_min
+ parameter specifies whether the suffix components should be assumed to
+ hold MAXVALUE
+*/
+
+static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec)
+{
+ partition_info *part_info= val->part_info;
+ Field **field= part_info->part_field_array;
+ Field **fields_end= field + nvals_in_rec;
+ int res;
+
+ for (; field != fields_end; field++, val++)
+ {
+ if (val->max_value)
+ return -1;
+ if ((*field)->is_null())
+ {
+ if (val->null_value)
+ continue;
+ return -1;
+ }
+ if (val->null_value)
+ return +1;
+ res= (*field)->cmp((const uchar*)val->column_value);
+ if (res)
+ return res;
+ }
+ return 0;
+}
+
+
+static int cmp_rec_and_tuple_prune(part_column_list_val *val,
+ uint32 n_vals_in_rec,
+ bool tail_is_min)
+{
+ int cmp;
+ Field **field;
+ partition_info *part_info;
+ if ((cmp= cmp_rec_and_tuple(val, n_vals_in_rec)))
+ return cmp;
+ part_info= val->part_info;
+ field= part_info->part_field_array + n_vals_in_rec;
+ for (; *field; field++, val++)
+ {
+ if (tail_is_min)
+ return -1;
+ if (!tail_is_min && !val->max_value)
+ return +1;
+ }
+ return 0;
+}
+
+
typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
bool include_endpoint);
+typedef uint32 (*get_col_endpoint_func)(partition_info*, bool left_endpoint,
+ bool include_endpoint,
+ uint32 num_parts);
+
/*
Partitioning Interval Analysis: Initialize the iterator for "mapping" case
@@ -6739,18 +7354,145 @@ typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
-1 - All partitions would match (iterator not initialized)
*/
+uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info,
+ bool left_endpoint,
+ bool include_endpoint,
+ uint32 nparts)
+{
+ uint max_partition= part_info->num_parts - 1;
+ uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
+ part_column_list_val *range_col_array= part_info->range_col_array;
+ uint num_columns= part_info->part_field_list.elements;
+ bool tailf= !(left_endpoint ^ include_endpoint);
+ DBUG_ENTER("get_partition_id_cols_range_for_endpoint");
+
+ /* Get the partitioning function value for the endpoint */
+ while (max_part_id > min_part_id)
+ {
+ loc_part_id= (max_part_id + min_part_id + 1) >> 1;
+ if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns,
+ nparts, tailf) >= 0)
+ min_part_id= loc_part_id + 1;
+ else
+ max_part_id= loc_part_id - 1;
+ }
+ loc_part_id= max_part_id;
+ if (loc_part_id < max_partition &&
+ cmp_rec_and_tuple_prune(range_col_array + (loc_part_id+1)*num_columns,
+ nparts, tailf) >= 0
+ )
+ {
+ loc_part_id++;
+ }
+ if (left_endpoint)
+ {
+ if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns,
+ nparts, tailf) >= 0)
+ loc_part_id++;
+ }
+ else
+ {
+ if (loc_part_id < max_partition)
+ {
+ int res= cmp_rec_and_tuple_prune(range_col_array +
+ loc_part_id * num_columns,
+ nparts, tailf);
+ if (!res)
+ loc_part_id += test(include_endpoint);
+ else if (res > 0)
+ loc_part_id++;
+ }
+ loc_part_id++;
+ }
+ DBUG_RETURN(loc_part_id);
+}
+
+
+int get_part_iter_for_interval_cols_via_map(partition_info *part_info,
+ bool is_subpart,
+ uint32 *store_length_array,
+ uchar *min_value, uchar *max_value,
+ uint min_len, uint max_len,
+ uint flags,
+ PARTITION_ITERATOR *part_iter)
+{
+ uint32 nparts;
+ get_col_endpoint_func get_col_endpoint;
+ DBUG_ENTER("get_part_iter_for_interval_cols_via_map");
+
+ if (part_info->part_type == RANGE_PARTITION)
+ {
+ get_col_endpoint= get_partition_id_cols_range_for_endpoint;
+ part_iter->get_next= get_next_partition_id_range;
+ }
+ else if (part_info->part_type == LIST_PARTITION)
+ {
+ get_col_endpoint= get_partition_id_cols_list_for_endpoint;
+ part_iter->get_next= get_next_partition_id_list;
+ part_iter->part_info= part_info;
+ DBUG_ASSERT(part_info->num_list_values);
+ }
+ else
+ assert(0);
+
+ if (flags & NO_MIN_RANGE)
+ part_iter->part_nums.start= part_iter->part_nums.cur= 0;
+ else
+ {
+ // Copy from min_value to record
+ nparts= store_tuple_to_record(part_info->part_field_array,
+ store_length_array,
+ min_value,
+ min_value + min_len);
+ part_iter->part_nums.start= part_iter->part_nums.cur=
+ get_col_endpoint(part_info, TRUE, !(flags & NEAR_MIN),
+ nparts);
+ }
+ if (flags & NO_MAX_RANGE)
+ {
+ if (part_info->part_type == RANGE_PARTITION)
+ part_iter->part_nums.end= part_info->num_parts;
+ else /* LIST_PARTITION */
+ {
+ DBUG_ASSERT(part_info->part_type == LIST_PARTITION);
+ part_iter->part_nums.end= part_info->num_list_values;
+ }
+ }
+ else
+ {
+ // Copy from max_value to record
+ nparts= store_tuple_to_record(part_info->part_field_array,
+ store_length_array,
+ max_value,
+ max_value + max_len);
+ part_iter->part_nums.end= get_col_endpoint(part_info, FALSE,
+ !(flags & NEAR_MAX),
+ nparts);
+ }
+ if (part_iter->part_nums.start == part_iter->part_nums.end)
+ DBUG_RETURN(0);
+ DBUG_RETURN(1);
+}
+
+
int get_part_iter_for_interval_via_mapping(partition_info *part_info,
bool is_subpart,
+ uint32 *store_length_array, /* ignored */
uchar *min_value, uchar *max_value,
+ uint min_len, uint max_len, /* ignored */
uint flags,
PARTITION_ITERATOR *part_iter)
{
- DBUG_ASSERT(!is_subpart);
Field *field= part_info->part_field_array[0];
uint32 UNINIT_VAR(max_endpoint_val);
get_endpoint_func UNINIT_VAR(get_endpoint);
bool can_match_multiple_values; /* is not '=' */
uint field_len= field->pack_length_in_rec();
+ DBUG_ENTER("get_part_iter_for_interval_via_mapping");
+ DBUG_ASSERT(!is_subpart);
+ (void) store_length_array;
+ (void)min_len;
+ (void)max_len;
part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
if (part_info->part_type == RANGE_PARTITION)
@@ -6759,7 +7501,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
get_endpoint= get_partition_id_range_for_endpoint_charset;
else
get_endpoint= get_partition_id_range_for_endpoint;
- max_endpoint_val= part_info->no_parts;
+ max_endpoint_val= part_info->num_parts;
part_iter->get_next= get_next_partition_id_range;
}
else if (part_info->part_type == LIST_PARTITION)
@@ -6769,7 +7511,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
get_endpoint= get_list_array_idx_for_endpoint_charset;
else
get_endpoint= get_list_array_idx_for_endpoint;
- max_endpoint_val= part_info->no_list_values;
+ max_endpoint_val= part_info->num_list_values;
part_iter->get_next= get_next_partition_id_list;
part_iter->part_info= part_info;
if (max_endpoint_val == 0)
@@ -6782,7 +7524,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
part_iter->part_nums.start= part_iter->part_nums.end= 0;
part_iter->part_nums.cur= 0;
part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
- return -1;
+ DBUG_RETURN(-1);
}
}
else
@@ -6814,11 +7556,11 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
{
part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
part_iter->part_nums.start= part_iter->part_nums.cur= 0;
- if (*max_value && !(flags & NO_MAX_RANGE))
+ if (!(flags & NO_MAX_RANGE) && *max_value)
{
/* The right bound is X <= NULL, i.e. it is a "X IS NULL" interval */
part_iter->part_nums.end= 0;
- return 1;
+ DBUG_RETURN(1);
}
}
else
@@ -6842,11 +7584,11 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
part_iter->part_nums.cur= part_iter->part_nums.start= 0;
part_iter->part_nums.end= 0;
part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
- return 1;
+ DBUG_RETURN(1);
}
part_iter->part_nums.cur= part_iter->part_nums.start;
if (part_iter->part_nums.start == max_endpoint_val)
- return 0; /* No partitions */
+ DBUG_RETURN(0); /* No partitions */
}
}
@@ -6860,14 +7602,14 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp);
if (part_iter->part_nums.start >= part_iter->part_nums.end &&
!part_iter->ret_null_part)
- return 0; /* No partitions */
+ DBUG_RETURN(0); /* No partitions */
}
- return 1; /* Ok, iterator initialized */
+ DBUG_RETURN(1); /* Ok, iterator initialized */
}
/* See get_part_iter_for_interval_via_walking for definition of what this is */
-#define MAX_RANGE_TO_WALK 10
+#define MAX_RANGE_TO_WALK 32
/*
@@ -6903,16 +7645,6 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
Intervals with +inf/-inf, and [NULL, c1] interval can be processed but
that is more tricky and I don't have time to do it right now.
- Additionally we have these requirements:
- * number of values in the interval must be less then number of
- [sub]partitions, and
- * Number of values in the interval must be less then MAX_RANGE_TO_WALK.
-
- The rationale behind these requirements is that if they are not met
- we're likely to hit most of the partitions and traversing the interval
- will only add overhead. So it's better return "all partitions used" in
- that case.
-
RETURN
0 - No matching partitions, iterator not initialized
1 - Some partitions would match, iterator intialized for traversing them
@@ -6920,25 +7652,32 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
*/
int get_part_iter_for_interval_via_walking(partition_info *part_info,
- bool is_subpart,
- uchar *min_value, uchar *max_value,
- uint flags,
- PARTITION_ITERATOR *part_iter)
+ bool is_subpart,
+ uint32 *store_length_array, /* ignored */
+ uchar *min_value, uchar *max_value,
+ uint min_len, uint max_len, /* ignored */
+ uint flags,
+ PARTITION_ITERATOR *part_iter)
{
Field *field;
uint total_parts;
partition_iter_func get_next_func;
+ DBUG_ENTER("get_part_iter_for_interval_via_walking");
+ (void)store_length_array;
+ (void)min_len;
+ (void)max_len;
+
part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
if (is_subpart)
{
field= part_info->subpart_field_array[0];
- total_parts= part_info->no_subparts;
+ total_parts= part_info->num_subparts;
get_next_func= get_next_subpartition_via_walking;
}
else
{
field= part_info->part_field_array[0];
- total_parts= part_info->no_parts;
+ total_parts= part_info->num_parts;
get_next_func= get_next_partition_via_walking;
}
@@ -6958,7 +7697,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
if (!part_info->get_subpartition_id(part_info, &part_id))
{
init_single_partition_iterator(part_id, part_iter);
- return 1; /* Ok, iterator initialized */
+ DBUG_RETURN(1); /* Ok, iterator initialized */
}
}
else
@@ -6971,10 +7710,10 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
if (!res)
{
init_single_partition_iterator(part_id, part_iter);
- return 1; /* Ok, iterator initialized */
+ DBUG_RETURN(1); /* Ok, iterator initialized */
}
}
- return 0; /* No partitions match */
+ DBUG_RETURN(0); /* No partitions match */
}
if ((field->real_maybe_null() &&
@@ -6982,7 +7721,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
(!(flags & NO_MAX_RANGE) && *max_value))) || // X <? NULL
(flags & (NO_MIN_RANGE | NO_MAX_RANGE))) // -inf at any bound
{
- return -1; /* Can't handle this interval, have to use all partitions */
+ DBUG_RETURN(-1); /* Can't handle this interval, have to use all partitions */
}
/* Get integers for left and right interval bound */
@@ -7001,20 +7740,36 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
an empty interval by "wrapping around" a + 4G-1 + 1 = a.
*/
if ((ulonglong)b - (ulonglong)a == ~0ULL)
- return -1;
+ DBUG_RETURN(-1);
a += test(flags & NEAR_MIN);
b += test(!(flags & NEAR_MAX));
ulonglong n_values= b - a;
-
- if (n_values > total_parts || n_values > MAX_RANGE_TO_WALK)
- return -1;
+
+ /*
+ Will it pay off to enumerate all values in the [a..b] range and evaluate
+ the partitioning function for every value? It depends on
+ 1. whether we'll be able to infer that some partitions are not used
+ 2. if time savings from not scanning these partitions will be greater
+ than time spent in enumeration.
+ We will assume that the cost of accessing one extra partition is greater
+ than the cost of evaluating the partitioning function O(#partitions).
+ This means we should jump at any chance to eliminate a partition, which
+ gives us this logic:
+
+ Do the enumeration if
+ - the number of values to enumerate is comparable to the number of
+ partitions, or
+ - there are not many values to enumerate.
+ */
+ if ((n_values > 2*total_parts) && n_values > MAX_RANGE_TO_WALK)
+ DBUG_RETURN(-1);
part_iter->field_vals.start= part_iter->field_vals.cur= a;
part_iter->field_vals.end= b;
part_iter->part_info= part_info;
part_iter->get_next= get_next_func;
- return 1;
+ DBUG_RETURN(1);
}
@@ -7062,8 +7817,9 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter)
DESCRIPTION
This implementation of PARTITION_ITERATOR::get_next() is special for
- LIST partitioning: it enumerates partition ids in
- part_info->list_array[i] where i runs over [min_idx, max_idx] interval.
+ LIST partitioning: it enumerates partition ids in
+ part_info->list_array[i] (list_col_array[i*cols] for COLUMNS LIST
+ partitioning) where i runs over [min_idx, max_idx] interval.
The function conforms to partition_iter_func type.
RETURN
@@ -7085,8 +7841,16 @@ uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter)
return NOT_A_PARTITION_ID;
}
else
- return part_iter->part_info->list_array[part_iter->
- part_nums.cur++].partition_id;
+ {
+ partition_info *part_info= part_iter->part_info;
+ uint32 num_part= part_iter->part_nums.cur++;
+ if (part_info->column_list)
+ {
+ uint num_columns= part_info->part_field_list.elements;
+ return part_info->list_col_array[num_part*num_columns].partition_id;
+ }
+ return part_info->list_array[num_part].partition_id;
+ }
}
@@ -7227,5 +7991,17 @@ void create_subpartition_name(char *out, const char *in1,
strxmov(out, in1, "#P#", transl_part_name,
"#SP#", transl_subpart_name, "#REN#", NullS);
}
+
+uint get_partition_field_store_length(Field *field)
+{
+ uint store_length;
+
+ store_length= field->key_length();
+ if (field->real_maybe_null())
+ store_length+= HA_KEY_NULL_LENGTH;
+ if (field->real_type() == MYSQL_TYPE_VARCHAR)
+ store_length+= HA_KEY_BLOB_LENGTH;
+ return store_length;
+}
#endif
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index 02a5ead1117..9a9a0bd56fa 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -1,4 +1,7 @@
-/* Copyright (C) 2006 MySQL AB
+#ifndef SQL_PARTITION_INCLUDED
+#define SQL_PARTITION_INCLUDED
+
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -17,25 +20,51 @@
#pragma interface /* gcc class implementation */
#endif
+#include "sql_list.h" /* List */
+#include "table.h" /* TABLE_LIST */
+
+class Alter_info;
+class Field;
+class String;
+class handler;
+class partition_info;
+struct TABLE;
+struct TABLE_LIST;
+typedef struct st_bitmap MY_BITMAP;
+typedef struct st_ha_create_information HA_CREATE_INFO;
+typedef struct st_key KEY;
+typedef struct st_key_range key_range;
+
/* Flags for partition handlers */
#define HA_CAN_PARTITION (1 << 0) /* Partition support */
#define HA_CAN_UPDATE_PARTITION_KEY (1 << 1)
#define HA_CAN_PARTITION_UNIQUE (1 << 2)
#define HA_USE_AUTO_PARTITION (1 << 3)
-/*typedef struct {
- ulonglong data_file_length;
- ulonglong max_data_file_length;
- ulonglong index_file_length;
- ulonglong delete_length;
- ha_rows records;
- ulong mean_rec_length;
- time_t create_time;
- time_t check_time;
- time_t update_time;
- ulonglong check_sum;
-} PARTITION_INFO;
-*/
+#define NORMAL_PART_NAME 0
+#define TEMP_PART_NAME 1
+#define RENAMED_PART_NAME 2
+
+typedef struct st_lock_param_type
+{
+ TABLE_LIST *table_list;
+ ulonglong copied;
+ ulonglong deleted;
+ THD *thd;
+ HA_CREATE_INFO *create_info;
+ Alter_info *alter_info;
+ TABLE *table;
+ TABLE *old_table;
+ KEY *key_info_buffer;
+ const char *db;
+ const char *table_name;
+ uchar *pack_frm_data;
+ uint key_count;
+ uint db_options;
+ size_t pack_frm_len;
+ partition_info *part_info;
+} ALTER_PARTITION_PARAM_TYPE;
+
typedef struct {
longlong list_value;
uint32 partition_id;
@@ -65,22 +94,25 @@ int get_part_for_delete(const uchar *buf, const uchar *rec0,
void prune_partition_set(const TABLE *table, part_id_range *part_spec);
bool check_partition_info(partition_info *part_info,handlerton **eng_type,
TABLE *table, handler *file, HA_CREATE_INFO *info);
-void set_linear_hash_mask(partition_info *part_info, uint no_parts);
+void set_linear_hash_mask(partition_info *part_info, uint num_parts);
bool fix_partition_func(THD *thd, TABLE *table, bool create_table_ind);
-char *generate_partition_syntax(partition_info *part_info,
- uint *buf_length, bool use_sql_alloc,
- bool show_partition_options);
bool partition_key_modified(TABLE *table, const MY_BITMAP *fields);
void get_partition_set(const TABLE *table, uchar *buf, const uint index,
const key_range *key_spec,
part_id_range *part_spec);
+uint get_partition_field_store_length(Field *field);
+int get_cs_converted_part_value_from_string(THD *thd,
+ Item *item,
+ String *input_str,
+ String *output_str,
+ CHARSET_INFO *cs,
+ bool use_hex);
void get_full_part_id_from_key(const TABLE *table, uchar *buf,
KEY *key_info,
const key_range *key_spec,
part_id_range *part_spec);
bool mysql_unpack_partition(THD *thd, char *part_buf,
uint part_info_len,
- const char *part_state, uint part_state_len,
TABLE *table, bool is_create_table_ind,
handlerton *default_db_type,
bool *work_part_info_used);
@@ -93,6 +125,8 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
bool include_endpoint);
bool check_part_func_fields(Field **ptr, bool ok_with_charsets);
bool field_is_partition_charset(Field *field);
+Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs);
+void mem_alloc_error(size_t size);
/*
A "Get next" function for partition iterator.
@@ -169,13 +203,16 @@ typedef struct st_partition_iter
SYNOPSIS
get_partitions_in_range_iter()
- part_info Partitioning info
- is_subpart
- min_val Left edge, field value in opt_range_key format.
- max_val Right edge, field value in opt_range_key format.
- flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
- NO_MAX_RANGE.
- part_iter Iterator structure to be initialized
+ part_info Partitioning info
+ is_subpart
+ store_length_array Length of fields packed in opt_range_key format
+ min_val Left edge, field value in opt_range_key format
+ max_val Right edge, field value in opt_range_key format
+ min_len Length of minimum value
+ max_len Length of maximum value
+ flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
+ NO_MAX_RANGE
+ part_iter Iterator structure to be initialized
DESCRIPTION
Functions with this signature are used to perform "Partitioning Interval
@@ -188,8 +225,9 @@ typedef struct st_partition_iter
The set of partitions is returned by initializing an iterator in *part_iter
NOTES
- There are currently two functions of this type:
+ There are currently three functions of this type:
- get_part_iter_for_interval_via_walking
+ - get_part_iter_for_interval_cols_via_map
- get_part_iter_for_interval_via_mapping
RETURN
@@ -200,9 +238,50 @@ typedef struct st_partition_iter
typedef int (*get_partitions_in_range_iter)(partition_info *part_info,
bool is_subpart,
+ uint32 *store_length_array,
uchar *min_val, uchar *max_val,
+ uint min_len, uint max_len,
uint flags,
PARTITION_ITERATOR *part_iter);
#include "partition_info.h"
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+uint fast_alter_partition_table(THD *thd, TABLE *table,
+ Alter_info *alter_info,
+ HA_CREATE_INFO *create_info,
+ TABLE_LIST *table_list,
+ char *db,
+ const char *table_name,
+ TABLE *fast_alter_table);
+uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
+ enum partition_state part_state);
+uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
+ HA_CREATE_INFO *create_info,
+ handlerton *old_db_type,
+ bool *partition_changed,
+ char *db,
+ const char *table_name,
+ const char *path,
+ TABLE **fast_alter_table);
+char *generate_partition_syntax(partition_info *part_info,
+ uint *buf_length, bool use_sql_alloc,
+ bool show_partition_options,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info);
+#endif
+
+void create_partition_name(char *out, const char *in1,
+ const char *in2, uint name_variant,
+ bool translate);
+void create_subpartition_name(char *out, const char *in1,
+ const char *in2, const char *in3,
+ uint name_variant);
+
+void set_field_ptr(Field **ptr, const uchar *new_buf, const uchar *old_buf);
+void set_key_field_ptr(KEY *key_info, const uchar *new_buf,
+ const uchar *old_buf);
+
+extern const LEX_STRING partition_keywords[];
+
+#endif /* SQL_PARTITION_INCLUDED */
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
new file mode 100644
index 00000000000..cadfc587c1c
--- /dev/null
+++ b/sql/sql_partition_admin.cc
@@ -0,0 +1,193 @@
+/* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 */
+
+#include "sql_parse.h" // check_one_table_access
+#include "sql_table.h" // mysql_alter_table, etc.
+#include "sql_lex.h" // Sql_statement
+#include "sql_admin.h" // Analyze/Check/.._table_statement
+#include "sql_partition_admin.h" // Alter_table_*_partition
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+#include "ha_partition.h" // ha_partition
+#endif
+#include "sql_base.h" // open_and_lock_tables
+
+#ifndef WITH_PARTITION_STORAGE_ENGINE
+
+bool Partition_statement_unsupported::execute(THD *)
+{
+ DBUG_ENTER("Partition_statement_unsupported::execute");
+ /* error, partitioning support not compiled in... */
+ my_error(ER_FEATURE_DISABLED, MYF(0), "partitioning",
+ "--with-plugin-partition");
+ DBUG_RETURN(TRUE);
+}
+
+#else
+
+bool Alter_table_analyze_partition_statement::execute(THD *thd)
+{
+ bool res;
+ DBUG_ENTER("Alter_table_analyze_partition_statement::execute");
+
+ /*
+ Flag that it is an ALTER command which administrates partitions, used
+ by ha_partition
+ */
+ m_lex->alter_info.flags|= ALTER_ADMIN_PARTITION;
+
+ res= Analyze_table_statement::execute(thd);
+
+ DBUG_RETURN(res);
+}
+
+
+bool Alter_table_check_partition_statement::execute(THD *thd)
+{
+ bool res;
+ DBUG_ENTER("Alter_table_check_partition_statement::execute");
+
+ /*
+ Flag that it is an ALTER command which administrates partitions, used
+ by ha_partition
+ */
+ m_lex->alter_info.flags|= ALTER_ADMIN_PARTITION;
+
+ res= Check_table_statement::execute(thd);
+
+ DBUG_RETURN(res);
+}
+
+
+bool Alter_table_optimize_partition_statement::execute(THD *thd)
+{
+ bool res;
+ DBUG_ENTER("Alter_table_optimize_partition_statement::execute");
+
+ /*
+ Flag that it is an ALTER command which administrates partitions, used
+ by ha_partition
+ */
+ m_lex->alter_info.flags|= ALTER_ADMIN_PARTITION;
+
+ res= Optimize_table_statement::execute(thd);
+
+ DBUG_RETURN(res);
+}
+
+
+bool Alter_table_repair_partition_statement::execute(THD *thd)
+{
+ bool res;
+ DBUG_ENTER("Alter_table_repair_partition_statement::execute");
+
+ /*
+ Flag that it is an ALTER command which administrates partitions, used
+ by ha_partition
+ */
+ m_lex->alter_info.flags|= ALTER_ADMIN_PARTITION;
+
+ res= Repair_table_statement::execute(thd);
+
+ DBUG_RETURN(res);
+}
+
+
+bool Alter_table_truncate_partition_statement::execute(THD *thd)
+{
+ int error;
+ ha_partition *partition;
+ ulong timeout= thd->variables.lock_wait_timeout;
+ TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
+ bool binlog_stmt;
+ DBUG_ENTER("Alter_table_truncate_partition_statement::execute");
+
+ /*
+ Flag that it is an ALTER command which administrates partitions, used
+ by ha_partition.
+ */
+ m_lex->alter_info.flags|= ALTER_ADMIN_PARTITION |
+ ALTER_TRUNCATE_PARTITION;
+
+ /* Fix the lock types (not the same as ordinary ALTER TABLE). */
+ first_table->lock_type= TL_WRITE;
+ first_table->mdl_request.set_type(MDL_EXCLUSIVE);
+
+ /*
+ Check table permissions and open it with a exclusive lock.
+ Ensure it is a partitioned table and finally, upcast the
+ handler and invoke the partition truncate method. Lastly,
+ write the statement to the binary log if necessary.
+ */
+
+ if (check_one_table_access(thd, DROP_ACL, first_table))
+ DBUG_RETURN(TRUE);
+
+ if (open_and_lock_tables(thd, first_table, FALSE, 0))
+ DBUG_RETURN(TRUE);
+
+ /*
+ TODO: Add support for TRUNCATE PARTITION for NDB and other
+ engines supporting native partitioning.
+ */
+ if (first_table->table->s->db_type() != partition_hton)
+ {
+ my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Under locked table modes this might still not be an exclusive
+ lock. Hence, upgrade the lock since the handler truncate method
+ mandates an exclusive metadata lock.
+ */
+ MDL_ticket *ticket= first_table->table->mdl_ticket;
+ if (thd->mdl_context.upgrade_shared_lock_to_exclusive(ticket, timeout))
+ DBUG_RETURN(TRUE);
+
+ tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN, first_table->db,
+ first_table->table_name, FALSE);
+
+ partition= (ha_partition *) first_table->table->file;
+
+ /* Invoke the handler method responsible for truncating the partition. */
+ if ((error= partition->truncate_partition(&thd->lex->alter_info,
+ &binlog_stmt)))
+ first_table->table->file->print_error(error, MYF(0));
+
+ /*
+ All effects of a truncate operation are committed even if the
+ operation fails. Thus, the query must be written to the binary
+ log. The exception is a unimplemented truncate method or failure
+ before any call to handler::truncate() is done.
+ Also, it is logged in statement format, regardless of the binlog format.
+ */
+ if (error != HA_ERR_WRONG_COMMAND && binlog_stmt)
+ error|= write_bin_log(thd, !error, thd->query(), thd->query_length());
+
+ /*
+ A locked table ticket was upgraded to a exclusive lock. After the
+ the query has been written to the binary log, downgrade the lock
+ to a shared one.
+ */
+ if (thd->locked_tables_mode)
+ ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
+
+ if (! error)
+ my_ok(thd);
+
+ DBUG_RETURN(error);
+}
+
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
diff --git a/sql/sql_partition_admin.h b/sql/sql_partition_admin.h
new file mode 100644
index 00000000000..564b8676be8
--- /dev/null
+++ b/sql/sql_partition_admin.h
@@ -0,0 +1,236 @@
+/* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 SQL_PARTITION_ADMIN_H
+#define SQL_PARTITION_ADMIN_H
+
+#ifndef WITH_PARTITION_STORAGE_ENGINE
+
+/**
+ Stub class that returns a error if the partition storage engine is
+ not supported.
+*/
+class Partition_statement_unsupported : public Sql_statement
+{
+public:
+ Partition_statement_unsupported(LEX *lex)
+ : Sql_statement(lex)
+ {}
+
+ ~Partition_statement_unsupported()
+ {}
+
+ bool execute(THD *thd);
+};
+
+
+class Alter_table_analyze_partition_statement :
+ public Partition_statement_unsupported
+{
+public:
+ Alter_table_analyze_partition_statement(LEX *lex)
+ : Partition_statement_unsupported(lex)
+ {}
+
+ ~Alter_table_analyze_partition_statement()
+ {}
+};
+
+
+class Alter_table_check_partition_statement :
+ public Partition_statement_unsupported
+{
+public:
+ Alter_table_check_partition_statement(LEX *lex)
+ : Partition_statement_unsupported(lex)
+ {}
+
+ ~Alter_table_check_partition_statement()
+ {}
+};
+
+
+class Alter_table_optimize_partition_statement :
+ public Partition_statement_unsupported
+{
+public:
+ Alter_table_optimize_partition_statement(LEX *lex)
+ : Partition_statement_unsupported(lex)
+ {}
+
+ ~Alter_table_optimize_partition_statement()
+ {}
+};
+
+
+class Alter_table_repair_partition_statement :
+ public Partition_statement_unsupported
+{
+public:
+ Alter_table_repair_partition_statement(LEX *lex)
+ : Partition_statement_unsupported(lex)
+ {}
+
+ ~Alter_table_repair_partition_statement()
+ {}
+};
+
+
+class Alter_table_truncate_partition_statement :
+ public Partition_statement_unsupported
+{
+public:
+ Alter_table_truncate_partition_statement(LEX *lex)
+ : Partition_statement_unsupported(lex)
+ {}
+
+ ~Alter_table_truncate_partition_statement()
+ {}
+};
+
+
+#else
+
+/**
+ Class that represents the ALTER TABLE t1 ANALYZE PARTITION p statement.
+*/
+class Alter_table_analyze_partition_statement : public Analyze_table_statement
+{
+public:
+ /**
+ Constructor, used to represent a ALTER TABLE ANALYZE PARTITION statement.
+ @param lex the LEX structure for this statement.
+ */
+ Alter_table_analyze_partition_statement(LEX *lex)
+ : Analyze_table_statement(lex)
+ {}
+
+ ~Alter_table_analyze_partition_statement()
+ {}
+
+ /**
+ Execute a ALTER TABLE ANALYZE PARTITION statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+};
+
+
+/**
+ Class that represents the ALTER TABLE t1 CHECK PARTITION p statement.
+*/
+class Alter_table_check_partition_statement : public Check_table_statement
+{
+public:
+ /**
+ Constructor, used to represent a ALTER TABLE CHECK PARTITION statement.
+ @param lex the LEX structure for this statement.
+ */
+ Alter_table_check_partition_statement(LEX *lex)
+ : Check_table_statement(lex)
+ {}
+
+ ~Alter_table_check_partition_statement()
+ {}
+
+ /**
+ Execute a ALTER TABLE CHECK PARTITION statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+};
+
+
+/**
+ Class that represents the ALTER TABLE t1 OPTIMIZE PARTITION p statement.
+*/
+class Alter_table_optimize_partition_statement : public Optimize_table_statement
+{
+public:
+ /**
+ Constructor, used to represent a ALTER TABLE OPTIMIZE PARTITION statement.
+ @param lex the LEX structure for this statement.
+ */
+ Alter_table_optimize_partition_statement(LEX *lex)
+ : Optimize_table_statement(lex)
+ {}
+
+ ~Alter_table_optimize_partition_statement()
+ {}
+
+ /**
+ Execute a ALTER TABLE OPTIMIZE PARTITION statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+};
+
+
+/**
+ Class that represents the ALTER TABLE t1 REPAIR PARTITION p statement.
+*/
+class Alter_table_repair_partition_statement : public Repair_table_statement
+{
+public:
+ /**
+ Constructor, used to represent a ALTER TABLE REPAIR PARTITION statement.
+ @param lex the LEX structure for this statement.
+ */
+ Alter_table_repair_partition_statement(LEX *lex)
+ : Repair_table_statement(lex)
+ {}
+
+ ~Alter_table_repair_partition_statement()
+ {}
+
+ /**
+ Execute a ALTER TABLE REPAIR PARTITION statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+};
+
+
+/**
+ Class that represents the ALTER TABLE t1 TRUNCATE PARTITION p statement.
+*/
+class Alter_table_truncate_partition_statement : public Sql_statement
+{
+public:
+ /**
+ Constructor, used to represent a ALTER TABLE TRUNCATE PARTITION statement.
+ @param lex the LEX structure for this statement.
+ */
+ Alter_table_truncate_partition_statement(LEX *lex)
+ : Sql_statement(lex)
+ {}
+
+ virtual ~Alter_table_truncate_partition_statement()
+ {}
+
+ /**
+ Execute a ALTER TABLE TRUNCATE PARTITION statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+};
+
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
+#endif /* SQL_PARTITION_ADMIN_H */
diff --git a/sql/sql_plist.h b/sql/sql_plist.h
new file mode 100644
index 00000000000..db85266be15
--- /dev/null
+++ b/sql/sql_plist.h
@@ -0,0 +1,260 @@
+#ifndef SQL_PLIST_H
+#define SQL_PLIST_H
+/* Copyright (C) 2008 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <my_global.h>
+
+template <typename T, typename B, typename C, typename I>
+class I_P_List_iterator;
+class I_P_List_null_counter;
+template <typename T> class I_P_List_no_push_back;
+
+
+/**
+ Intrusive parameterized list.
+
+ Unlike I_List does not require its elements to be descendant of ilink
+ class and therefore allows them to participate in several such lists
+ simultaneously.
+
+ Unlike List is doubly-linked list and thus supports efficient deletion
+ of element without iterator.
+
+ @param T Type of elements which will belong to list.
+ @param B Class which via its methods specifies which members
+ of T should be used for participating in this list.
+ Here is typical layout of such class:
+
+ struct B
+ {
+ static inline T **next_ptr(T *el)
+ {
+ return &el->next;
+ }
+ static inline T ***prev_ptr(T *el)
+ {
+ return &el->prev;
+ }
+ };
+ @param C Policy class specifying how counting of elements in the list
+ should be done. Instance of this class is also used as a place
+ where information about number of list elements is stored.
+ @sa I_P_List_null_counter, I_P_List_counter
+ @param I Policy class specifying whether I_P_List should support
+ efficient push_back() operation. Instance of this class
+ is used as place where we store information to support
+ this operation.
+ @sa I_P_List_no_push_back, I_P_List_fast_push_back.
+*/
+
+template <typename T, typename B,
+ typename C = I_P_List_null_counter,
+ typename I = I_P_List_no_push_back<T> >
+class I_P_List : public C, public I
+{
+ T *m_first;
+
+ /*
+ Do not prohibit copying of I_P_List object to simplify their usage in
+ backup/restore scenarios. Note that performing any operations on such
+ is a bad idea.
+ */
+public:
+ I_P_List() : I(&m_first), m_first(NULL) {};
+ inline void empty() { m_first= NULL; C::reset(); I::set_last(&m_first); }
+ inline bool is_empty() const { return (m_first == NULL); }
+ inline void push_front(T* a)
+ {
+ *B::next_ptr(a)= m_first;
+ if (m_first)
+ *B::prev_ptr(m_first)= B::next_ptr(a);
+ else
+ I::set_last(B::next_ptr(a));
+ m_first= a;
+ *B::prev_ptr(a)= &m_first;
+ C::inc();
+ }
+ inline void push_back(T *a)
+ {
+ T **last= I::get_last();
+ *B::next_ptr(a)= *last;
+ *last= a;
+ *B::prev_ptr(a)= last;
+ I::set_last(B::next_ptr(a));
+ }
+ inline void insert_after(T *pos, T *a)
+ {
+ if (pos == NULL)
+ push_front(a);
+ else
+ {
+ *B::next_ptr(a)= *B::next_ptr(pos);
+ *B::prev_ptr(a)= B::next_ptr(pos);
+ *B::next_ptr(pos)= a;
+ if (*B::next_ptr(a))
+ {
+ T *old_next= *B::next_ptr(a);
+ *B::prev_ptr(old_next)= B::next_ptr(a);
+ }
+ else
+ I::set_last(B::next_ptr(a));
+ }
+ }
+ inline void remove(T *a)
+ {
+ T *next= *B::next_ptr(a);
+ if (next)
+ *B::prev_ptr(next)= *B::prev_ptr(a);
+ else
+ I::set_last(*B::prev_ptr(a));
+ **B::prev_ptr(a)= next;
+ C::dec();
+ }
+ inline T* front() { return m_first; }
+ inline const T *front() const { return m_first; }
+ void swap(I_P_List<T, B, C> &rhs)
+ {
+ swap_variables(T *, m_first, rhs.m_first);
+ I::swap(rhs);
+ if (m_first)
+ *B::prev_ptr(m_first)= &m_first;
+ else
+ I::set_last(&m_first);
+ if (rhs.m_first)
+ *B::prev_ptr(rhs.m_first)= &rhs.m_first;
+ else
+ I::set_last(&rhs.m_first);
+ C::swap(rhs);
+ }
+#ifndef _lint
+ friend class I_P_List_iterator<T, B, C, I>;
+#endif
+ typedef I_P_List_iterator<T, B, C, I> Iterator;
+};
+
+
+/**
+ Iterator for I_P_List.
+*/
+
+template <typename T, typename B,
+ typename C = I_P_List_null_counter,
+ typename I = I_P_List_no_push_back<T> >
+class I_P_List_iterator
+{
+ const I_P_List<T, B, C, I> *list;
+ T *current;
+public:
+ I_P_List_iterator(const I_P_List<T, B, C, I> &a)
+ : list(&a), current(a.m_first) {}
+ I_P_List_iterator(const I_P_List<T, B, C, I> &a, T* current_arg)
+ : list(&a), current(current_arg) {}
+ inline void init(const I_P_List<T, B, C, I> &a)
+ {
+ list= &a;
+ current= a.m_first;
+ }
+ inline T* operator++(int)
+ {
+ T *result= current;
+ if (result)
+ current= *B::next_ptr(current);
+ return result;
+ }
+ inline T* operator++()
+ {
+ current= *B::next_ptr(current);
+ return current;
+ }
+ inline void rewind()
+ {
+ current= list->m_first;
+ }
+};
+
+
+/**
+ Element counting policy class for I_P_List to be used in
+ cases when no element counting should be done.
+*/
+
+class I_P_List_null_counter
+{
+protected:
+ void reset() {}
+ void inc() {}
+ void dec() {}
+ void swap(I_P_List_null_counter &rhs) {}
+};
+
+
+/**
+ Element counting policy class for I_P_List which provides
+ basic element counting.
+*/
+
+class I_P_List_counter
+{
+ uint m_counter;
+protected:
+ I_P_List_counter() : m_counter (0) {}
+ void reset() {m_counter= 0;}
+ void inc() {m_counter++;}
+ void dec() {m_counter--;}
+ void swap(I_P_List_counter &rhs)
+ { swap_variables(uint, m_counter, rhs.m_counter); }
+public:
+ uint elements() const { return m_counter; }
+};
+
+
+/**
+ A null insertion policy class for I_P_List to be used
+ in cases when push_back() operation is not necessary.
+*/
+
+template <typename T> class I_P_List_no_push_back
+{
+protected:
+ I_P_List_no_push_back(T **a) {};
+ void set_last(T **a) {}
+ /*
+ T** get_last() const method is intentionally left unimplemented
+ in order to prohibit usage of push_back() method in lists which
+ use this policy.
+ */
+ void swap(I_P_List_no_push_back<T> &rhs) {}
+};
+
+
+/**
+ An insertion policy class for I_P_List which can
+ be used when fast push_back() operation is required.
+*/
+
+template <typename T> class I_P_List_fast_push_back
+{
+ T **m_last;
+protected:
+ I_P_List_fast_push_back(T **a) : m_last(a) { };
+ void set_last(T **a) { m_last= a; }
+ T** get_last() const { return m_last; }
+ void swap(I_P_List_fast_push_back<T> &rhs)
+ { swap_variables(T**, m_last, rhs.m_last); }
+};
+
+#endif
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 03a729258ca..dc5b7b5a37b 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 MySQL AB
+/* Copyright (C) 2005 MySQL AB, 2009 Sun Microsystems, Inc.
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
@@ -13,29 +13,37 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h" // SHOW_MY_BOOL
+#include "unireg.h"
+#include "my_global.h" // REQUIRED by m_string.h
+#include "sql_class.h" // set_var.h: THD
+#include "sys_vars_shared.h"
+#include "sql_locale.h"
+#include "sql_plugin.h"
+#include "sql_parse.h" // check_table_access
+#include "sql_base.h" // close_mysql_tables
+#include "key.h" // key_copy
+#include "sql_show.h" // remove_status_vars, add_status_vars
+#include "strfunc.h" // find_set
+#include "sql_acl.h" // *_ACL
+#include "records.h" // init_read_record, end_read_record
#include <my_pthread.h>
#include <my_getopt.h>
+#include "sql_audit.h"
+#include <mysql/plugin_auth.h>
+#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
#define REPORT_TO_LOG 1
#define REPORT_TO_USER 2
-#ifdef DBUG_OFF
-#define plugin_ref_to_int(A) A
-#define plugin_int_to_ref(A) A
-#else
-#define plugin_ref_to_int(A) (A ? A[0] : NULL)
-#define plugin_int_to_ref(A) &(A)
-#endif
-
-extern struct st_mysql_plugin *mysqld_builtins[];
+extern struct st_mysql_plugin *mysql_optional_plugins[];
+extern struct st_mysql_plugin *mysql_mandatory_plugins[];
/**
@note The order of the enumeration is critical.
@see construct_options
*/
-static const char *global_plugin_typelib_names[]=
- { "OFF", "ON", "FORCE", NULL };
-enum enum_plugin_load_policy {PLUGIN_OFF, PLUGIN_ON, PLUGIN_FORCE};
+const char *global_plugin_typelib_names[]=
+ { "OFF", "ON", "FORCE", "FORCE_PLUS_PERMANENT", NULL };
static TYPELIB global_plugin_typelib=
{ array_elements(global_plugin_typelib_names)-1,
"", global_plugin_typelib_names, NULL };
@@ -54,12 +62,18 @@ const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{ C_STRING_WITH_LEN("STORAGE ENGINE") },
{ C_STRING_WITH_LEN("FTPARSER") },
{ C_STRING_WITH_LEN("DAEMON") },
- { C_STRING_WITH_LEN("INFORMATION SCHEMA") }
+ { C_STRING_WITH_LEN("INFORMATION SCHEMA") },
+ { C_STRING_WITH_LEN("AUDIT") },
+ { C_STRING_WITH_LEN("REPLICATION") },
+ { C_STRING_WITH_LEN("AUTHENTICATION") }
};
extern int initialize_schema_table(st_plugin_int *plugin);
extern int finalize_schema_table(st_plugin_int *plugin);
+extern int initialize_audit_plugin(st_plugin_int *plugin);
+extern int finalize_audit_plugin(st_plugin_int *plugin);
+
/*
The number of elements in both plugin_type_initialize and
plugin_type_deinitialize should equal to the number of plugins
@@ -67,12 +81,14 @@ extern int finalize_schema_table(st_plugin_int *plugin);
*/
plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
- 0,ha_initialize_handlerton,0,0,initialize_schema_table
+ 0,ha_initialize_handlerton,0,0,initialize_schema_table,
+ initialize_audit_plugin,0,0
};
plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
- 0,ha_finalize_handlerton,0,0,finalize_schema_table
+ 0,ha_finalize_handlerton,0,0,finalize_schema_table,
+ finalize_audit_plugin,0,0
};
#ifdef HAVE_DLOPEN
@@ -93,7 +109,10 @@ static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION,
MYSQL_DAEMON_INTERFACE_VERSION,
- MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
+ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION,
+ MYSQL_AUDIT_INTERFACE_VERSION,
+ MYSQL_REPLICATION_INTERFACE_VERSION,
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION
};
static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
@@ -101,23 +120,30 @@ static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION,
MYSQL_DAEMON_INTERFACE_VERSION,
- MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
+ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION,
+ MYSQL_AUDIT_INTERFACE_VERSION,
+ MYSQL_REPLICATION_INTERFACE_VERSION,
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION
};
-static bool initialized= 0;
+/* support for Services */
+
+#include "sql_plugin_services.h"
/*
A mutex LOCK_plugin must be acquired before accessing the
following variables/structures.
We are always manipulating ref count, so a rwlock here is unneccessary.
*/
-pthread_mutex_t LOCK_plugin;
+mysql_mutex_t LOCK_plugin;
static DYNAMIC_ARRAY plugin_dl_array;
static DYNAMIC_ARRAY plugin_array;
static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
static bool reap_needed= false;
static int plugin_array_version=0;
+static bool initialized= 0;
+
/*
write-lock on LOCK_system_variables_hash is required before modifying
the following variables/structures
@@ -165,6 +191,8 @@ struct st_mysql_sys_var
MYSQL_PLUGIN_VAR_HEADER;
};
+static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var);
+
/*
sys_var class for access to all plugin variables visible to the user
@@ -174,28 +202,44 @@ class sys_var_pluginvar: public sys_var
public:
struct st_plugin_int *plugin;
struct st_mysql_sys_var *plugin_var;
+ /**
+ variable name from whatever is hard-coded in the plugin source
+ and doesn't have pluginname- prefix is replaced by an allocated name
+ with a plugin prefix. When plugin is uninstalled we need to restore the
+ pointer to point to the hard-coded value, because plugin may be
+ installed/uninstalled many times without reloading the shared object.
+ */
+ const char *orig_pluginvar_name;
static void *operator new(size_t size, MEM_ROOT *mem_root)
- { return (void*) alloc_root(mem_root, (uint) size); }
+ { return (void*) alloc_root(mem_root, size); }
static void operator delete(void *ptr_arg,size_t size)
{ TRASH(ptr_arg, size); }
- sys_var_pluginvar(const char *name_arg,
+ sys_var_pluginvar(sys_var_chain *chain, const char *name_arg,
struct st_mysql_sys_var *plugin_var_arg)
- :sys_var(name_arg), plugin_var(plugin_var_arg) {}
+ :sys_var(chain, name_arg, plugin_var_arg->comment,
+ (plugin_var_arg->flags & PLUGIN_VAR_THDLOCAL ? SESSION : GLOBAL) |
+ (plugin_var_arg->flags & PLUGIN_VAR_READONLY ? READONLY : 0),
+ 0, -1, NO_ARG, pluginvar_show_type(plugin_var_arg), 0, 0,
+ VARIABLE_NOT_IN_BINLOG, 0, 0, 0, 0, PARSE_NORMAL),
+ plugin_var(plugin_var_arg), orig_pluginvar_name(plugin_var_arg->name)
+ { plugin_var->name= name_arg; }
sys_var_pluginvar *cast_pluginvar() { return this; }
- bool is_readonly() const { return plugin_var->flags & PLUGIN_VAR_READONLY; }
- bool check_type(enum_var_type type)
- { return !(plugin_var->flags & PLUGIN_VAR_THDLOCAL) && type != OPT_GLOBAL; }
bool check_update_type(Item_result type);
SHOW_TYPE show_type();
uchar* real_value_ptr(THD *thd, enum_var_type type);
TYPELIB* plugin_var_typelib(void);
- uchar* value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- bool check(THD *thd, set_var *var);
- bool check_default(enum_var_type type) { return is_readonly(); }
- void set_default(THD *thd, enum_var_type type);
- bool update(THD *thd, set_var *var);
+ uchar* do_value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ uchar* session_value_ptr(THD *thd, LEX_STRING *base)
+ { return do_value_ptr(thd, OPT_SESSION, base); }
+ uchar* global_value_ptr(THD *thd, LEX_STRING *base)
+ { return do_value_ptr(thd, OPT_GLOBAL, base); }
+ bool do_check(THD *thd, set_var *var);
+ virtual void session_save_default(THD *thd, set_var *var) {}
+ virtual void global_save_default(THD *thd, set_var *var) {}
+ bool session_update(THD *thd, set_var *var);
+ bool global_update(THD *thd, set_var *var);
};
@@ -210,26 +254,31 @@ static bool register_builtin(struct st_mysql_plugin *, struct st_plugin_int *,
static void unlock_variables(THD *thd, struct system_variables *vars);
static void cleanup_variables(THD *thd, struct system_variables *vars);
static void plugin_vars_free_values(sys_var *vars);
-static void plugin_opt_set_limits(struct my_option *options,
- const struct st_mysql_sys_var *opt);
-#define my_intern_plugin_lock(A,B) intern_plugin_lock(A,B CALLER_INFO)
-#define my_intern_plugin_lock_ci(A,B) intern_plugin_lock(A,B ORIG_CALLER_INFO)
-static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin
- CALLER_INFO_PROTO);
+static void restore_pluginvar_names(sys_var *first);
+static void plugin_opt_set_limits(struct my_option *,
+ const struct st_mysql_sys_var *);
+#define my_intern_plugin_lock(A,B) intern_plugin_lock(A,B)
+#define my_intern_plugin_lock_ci(A,B) intern_plugin_lock(A,B)
+static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin);
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
static void reap_plugins(void);
-
-/* declared in set_var.cc */
-extern sys_var *intern_find_sys_var(const char *str, uint length, bool no_error);
-extern bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd,
- const char *name, longlong val);
-
-#ifdef EMBEDDED_LIBRARY
-/* declared in sql_base.cc */
-extern bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists);
-#endif /* EMBEDDED_LIBRARY */
-
+static void report_error(int where_to, uint error, ...)
+{
+ va_list args;
+ if (where_to & REPORT_TO_USER)
+ {
+ va_start(args, error);
+ my_printv_error(error, ER(error), MYF(0), args);
+ va_end(args);
+ }
+ if (where_to & REPORT_TO_LOG)
+ {
+ va_start(args, error);
+ error_log_print(ERROR_LEVEL, ER_DEFAULT(error), args);
+ va_end(args);
+ }
+}
/**
Check if the provided path is valid in the sense that it does cause
@@ -294,6 +343,11 @@ static int item_val_int(struct st_mysql_value *value, long long *buf)
return 0;
}
+static int item_is_unsigned(struct st_mysql_value *value)
+{
+ Item *item= ((st_item_value_holder*)value)->item;
+ return item->unsigned_flag;
+}
static int item_val_real(struct st_mysql_value *value, double *buf)
{
@@ -360,9 +414,9 @@ static inline void free_plugin_mem(struct st_plugin_dl *p)
if (p->handle)
dlclose(p->handle);
#endif
- my_free(p->dl.str, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(p->dl.str);
if (p->version != MYSQL_PLUGIN_INTERFACE_VERSION)
- my_free((uchar*)p->plugins, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(p->plugins);
}
@@ -370,7 +424,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
{
#ifdef HAVE_DLOPEN
char dlpath[FN_REFLEN];
- uint plugin_dir_len, dummy_errors, dlpathlen;
+ uint plugin_dir_len, dummy_errors, dlpathlen, i;
struct st_plugin_dl *tmp, plugin_dl;
void *sym;
DBUG_ENTER("plugin_dl_add");
@@ -387,10 +441,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
system_charset_info, 1) ||
plugin_dir_len + dl->length + 1 >= FN_REFLEN)
{
- if (report & REPORT_TO_USER)
- my_error(ER_UDF_NO_PATHS, MYF(0));
- if (report & REPORT_TO_LOG)
- sql_print_error("%s", ER(ER_UDF_NO_PATHS));
+ report_error(report, ER_UDF_NO_PATHS);
DBUG_RETURN(0);
}
/* If this dll is already loaded just increase ref_count. */
@@ -415,20 +466,14 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
if (*errmsg == ':') errmsg++;
if (*errmsg == ' ') errmsg++;
}
- if (report & REPORT_TO_USER)
- my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, errno, errmsg);
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, errno, errmsg);
+ report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, errno, errmsg);
DBUG_RETURN(0);
}
/* Determine interface version */
if (!(sym= dlsym(plugin_dl.handle, plugin_interface_version_sym)))
{
free_plugin_mem(&plugin_dl);
- if (report & REPORT_TO_USER)
- my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_interface_version_sym);
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_interface_version_sym);
+ report_error(report, ER_CANT_FIND_DL_ENTRY, plugin_interface_version_sym);
DBUG_RETURN(0);
}
plugin_dl.version= *(int *)sym;
@@ -437,28 +482,41 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
(plugin_dl.version >> 8) > (MYSQL_PLUGIN_INTERFACE_VERSION >> 8))
{
free_plugin_mem(&plugin_dl);
- if (report & REPORT_TO_USER)
- my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, 0,
- "plugin interface version mismatch");
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, 0,
- "plugin interface version mismatch");
+ report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, 0,
+ "plugin interface version mismatch");
DBUG_RETURN(0);
}
+
+ /* link the services in */
+ for (i= 0; i < array_elements(list_of_services); i++)
+ {
+ if ((sym= dlsym(plugin_dl.handle, list_of_services[i].name)))
+ {
+ uint ver= (uint)(intptr)*(void**)sym;
+ if (ver > list_of_services[i].version ||
+ (ver >> 8) < (list_of_services[i].version >> 8))
+ {
+ char buf[MYSQL_ERRMSG_SIZE];
+ my_snprintf(buf, sizeof(buf),
+ "service '%s' interface version mismatch",
+ list_of_services[i].name);
+ report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, 0, buf);
+ DBUG_RETURN(0);
+ }
+ *(void**)sym= list_of_services[i].service;
+ }
+ }
+
/* Find plugin declarations */
if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))
{
free_plugin_mem(&plugin_dl);
- if (report & REPORT_TO_USER)
- my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_declarations_sym);
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_declarations_sym);
+ report_error(report, ER_CANT_FIND_DL_ENTRY, plugin_declarations_sym);
DBUG_RETURN(0);
}
if (plugin_dl.version != MYSQL_PLUGIN_INTERFACE_VERSION)
{
- int i;
uint sizeof_st_plugin;
struct st_mysql_plugin *old, *cur;
char *ptr= (char *)sym;
@@ -468,11 +526,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
else
{
#ifdef ERROR_ON_NO_SIZEOF_PLUGIN_SYMBOL
- free_plugin_mem(&plugin_dl);
- if (report & REPORT_TO_USER)
- my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), sizeof_st_plugin_sym);
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), sizeof_st_plugin_sym);
+ report_error(report, ER_CANT_FIND_DL_ENTRY, sizeof_st_plugin_sym);
DBUG_RETURN(0);
#else
/*
@@ -490,14 +544,11 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
/* no op */;
cur= (struct st_mysql_plugin*)
- my_malloc(i*sizeof(struct st_mysql_plugin), MYF(MY_ZEROFILL|MY_WME));
+ my_malloc((i+1)*sizeof(struct st_mysql_plugin), MYF(MY_ZEROFILL|MY_WME));
if (!cur)
{
free_plugin_mem(&plugin_dl);
- if (report & REPORT_TO_USER)
- my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length);
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
+ report_error(report, ER_OUTOFMEMORY, plugin_dl.dl.length);
DBUG_RETURN(0);
}
/*
@@ -519,10 +570,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
{
free_plugin_mem(&plugin_dl);
- if (report & REPORT_TO_USER)
- my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length);
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
+ report_error(report, ER_OUTOFMEMORY, plugin_dl.dl.length);
DBUG_RETURN(0);
}
plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length,
@@ -533,19 +581,13 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl)))
{
free_plugin_mem(&plugin_dl);
- if (report & REPORT_TO_USER)
- my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_dl));
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_dl));
+ report_error(report, ER_OUTOFMEMORY, sizeof(struct st_plugin_dl));
DBUG_RETURN(0);
}
DBUG_RETURN(tmp);
#else
DBUG_ENTER("plugin_dl_add");
- if (report & REPORT_TO_USER)
- my_error(ER_FEATURE_DISABLED, MYF(0), "plugin", "HAVE_DLOPEN");
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_FEATURE_DISABLED), "plugin", "HAVE_DLOPEN");
+ report_error(report, ER_FEATURE_DISABLED, "plugin", "HAVE_DLOPEN");
DBUG_RETURN(0);
#endif
}
@@ -557,7 +599,7 @@ static void plugin_dl_del(const LEX_STRING *dl)
uint i;
DBUG_ENTER("plugin_dl_del");
- safe_mutex_assert_owner(&LOCK_plugin);
+ mysql_mutex_assert_owner(&LOCK_plugin);
for (i= 0; i < plugin_dl_array.elements; i++)
{
@@ -589,21 +631,22 @@ static struct st_plugin_int *plugin_find_internal(const LEX_STRING *name, int ty
if (! initialized)
DBUG_RETURN(0);
- safe_mutex_assert_owner(&LOCK_plugin);
+ mysql_mutex_assert_owner(&LOCK_plugin);
if (type == MYSQL_ANY_PLUGIN)
{
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
{
struct st_plugin_int *plugin= (st_plugin_int *)
- hash_search(&plugin_hash[i], (const uchar *)name->str, name->length);
+ my_hash_search(&plugin_hash[i], (const uchar *)name->str, name->length);
if (plugin)
DBUG_RETURN(plugin);
}
}
else
DBUG_RETURN((st_plugin_int *)
- hash_search(&plugin_hash[type], (const uchar *)name->str, name->length));
+ my_hash_search(&plugin_hash[type], (const uchar *)name->str,
+ name->length));
DBUG_RETURN(0);
}
@@ -613,14 +656,14 @@ static SHOW_COMP_OPTION plugin_status(const LEX_STRING *name, int type)
SHOW_COMP_OPTION rc= SHOW_OPTION_NO;
struct st_plugin_int *plugin;
DBUG_ENTER("plugin_is_ready");
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
if ((plugin= plugin_find_internal(name, type)))
{
rc= SHOW_OPTION_DISABLED;
if (plugin->state == PLUGIN_IS_READY)
rc= SHOW_OPTION_YES;
}
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(rc);
}
@@ -634,19 +677,19 @@ bool plugin_is_ready(const LEX_STRING *name, int type)
}
-SHOW_COMP_OPTION sys_var_have_plugin::get_option()
+SHOW_COMP_OPTION plugin_status(const char *name, int len, size_t type)
{
- LEX_STRING plugin_name= { (char *) plugin_name_str, plugin_name_len };
- return plugin_status(&plugin_name, plugin_type);
+ LEX_STRING plugin_name= { (char *) name, len };
+ return plugin_status(&plugin_name, type);
}
-static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc CALLER_INFO_PROTO)
+static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc)
{
st_plugin_int *pi= plugin_ref_to_int(rc);
DBUG_ENTER("intern_plugin_lock");
- safe_mutex_assert_owner(&LOCK_plugin);
+ mysql_mutex_assert_owner(&LOCK_plugin);
if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
{
@@ -661,9 +704,9 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc CALLER_INFO_PROTO)
/*
For debugging, we do an additional malloc which allows the
memory manager and/or valgrind to track locked references and
- double unlocks to aid resolving reference counting.problems.
+ double unlocks to aid resolving reference counting problems.
*/
- if (!(plugin= (plugin_ref) my_malloc_ci(sizeof(pi), MYF(MY_WME))))
+ if (!(plugin= (plugin_ref) my_malloc(sizeof(pi), MYF(MY_WME))))
DBUG_RETURN(NULL);
*plugin= pi;
@@ -680,29 +723,28 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc CALLER_INFO_PROTO)
}
-plugin_ref plugin_lock(THD *thd, plugin_ref *ptr CALLER_INFO_PROTO)
+plugin_ref plugin_lock(THD *thd, plugin_ref *ptr)
{
LEX *lex= thd ? thd->lex : 0;
plugin_ref rc;
DBUG_ENTER("plugin_lock");
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
rc= my_intern_plugin_lock_ci(lex, *ptr);
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(rc);
}
-plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name, int type
- CALLER_INFO_PROTO)
+plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name, int type)
{
LEX *lex= thd ? thd->lex : 0;
plugin_ref rc= NULL;
st_plugin_int *plugin;
DBUG_ENTER("plugin_lock_by_name");
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
if ((plugin= plugin_find_internal(name, type)))
rc= my_intern_plugin_lock_ci(lex, plugin_int_to_ref(plugin));
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(rc);
}
@@ -744,10 +786,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
DBUG_ENTER("plugin_add");
if (plugin_find_internal(name, MYSQL_ANY_PLUGIN))
{
- if (report & REPORT_TO_USER)
- my_error(ER_UDF_EXISTS, MYF(0), name->str);
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_UDF_EXISTS), name->str);
+ report_error(report, ER_UDF_EXISTS, name->str);
DBUG_RETURN(TRUE);
}
/* Clear the whole struct to catch future extensions. */
@@ -774,10 +813,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
strxnmov(buf, sizeof(buf) - 1, "API version for ",
plugin_type_names[plugin->type].str,
" plugin is too different", NullS);
- if (report & REPORT_TO_USER)
- my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dl->str, 0, buf);
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dl->str, 0, buf);
+ report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf);
goto err;
}
tmp.plugin= plugin;
@@ -785,6 +821,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
tmp.name.length= name_len;
tmp.ref_count= 0;
tmp.state= PLUGIN_IS_UNINITIALIZED;
+ tmp.load_option= PLUGIN_ON;
if (test_plugin_options(tmp_root, &tmp, argc, argv))
tmp.state= PLUGIN_IS_DISABLED;
@@ -799,6 +836,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
tmp_plugin_ptr->state= PLUGIN_IS_FREED;
}
mysql_del_sys_var_chain(tmp.system_vars);
+ restore_pluginvar_names(tmp.system_vars);
goto err;
/* plugin was disabled */
@@ -806,10 +844,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
DBUG_RETURN(FALSE);
}
}
- if (report & REPORT_TO_USER)
- my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), name->str);
- if (report & REPORT_TO_LOG)
- sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name->str);
+ report_error(report, ER_CANT_FIND_DL_ENTRY, name->str);
err:
plugin_dl_del(dl);
DBUG_RETURN(TRUE);
@@ -823,17 +858,17 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
deinitialization to deadlock if plugins have worker threads
with plugin locks
*/
- safe_mutex_assert_not_owner(&LOCK_plugin);
+ mysql_mutex_assert_not_owner(&LOCK_plugin);
if (plugin->plugin->status_vars)
{
#ifdef FIX_LATER
- /*
- We have a problem right now where we can not prepend without
- breaking backwards compatibility. We will fix this shortly so
- that engines have "use names" and we wil use those for
- CREATE TABLE, and use the plugin name then for adding automatic
- variable names.
+ /**
+ @todo
+ unfortunately, status variables were introduced without a
+ pluginname_ namespace, that is pluginname_ was not added automatically
+ to status variable names. It should be fixed together with the next
+ incompatible API change.
*/
SHOW_VAR array[2]= {
{plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
@@ -873,44 +908,31 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
plugin->name.str, plugin->ref_count);
}
-
static void plugin_del(struct st_plugin_int *plugin)
{
DBUG_ENTER("plugin_del(plugin)");
- safe_mutex_assert_owner(&LOCK_plugin);
+ mysql_mutex_assert_owner(&LOCK_plugin);
/* Free allocated strings before deleting the plugin. */
+ mysql_rwlock_wrlock(&LOCK_system_variables_hash);
+ mysql_del_sys_var_chain(plugin->system_vars);
+ mysql_rwlock_unlock(&LOCK_system_variables_hash);
+ restore_pluginvar_names(plugin->system_vars);
plugin_vars_free_values(plugin->system_vars);
- hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
+ my_hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
if (plugin->plugin_dl)
plugin_dl_del(&plugin->plugin_dl->dl);
plugin->state= PLUGIN_IS_FREED;
plugin_array_version++;
- rw_wrlock(&LOCK_system_variables_hash);
- mysql_del_sys_var_chain(plugin->system_vars);
- rw_unlock(&LOCK_system_variables_hash);
free_root(&plugin->mem_root, MYF(0));
DBUG_VOID_RETURN;
}
-#ifdef NOT_USED
-
-static void plugin_del(const LEX_STRING *name)
-{
- struct st_plugin_int *plugin;
- DBUG_ENTER("plugin_del(name)");
- if ((plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
- plugin_del(plugin);
- DBUG_VOID_RETURN;
-}
-
-#endif
-
static void reap_plugins(void)
{
uint count, idx;
struct st_plugin_int *plugin, **reap, **list;
- safe_mutex_assert_owner(&LOCK_plugin);
+ mysql_mutex_assert_owner(&LOCK_plugin);
if (!reap_needed)
return;
@@ -931,13 +953,13 @@ static void reap_plugins(void)
}
}
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
list= reap;
while ((plugin= *(--list)))
plugin_deinitialize(plugin, true);
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
while ((plugin= *(--reap)))
plugin_del(plugin);
@@ -951,7 +973,7 @@ static void intern_plugin_unlock(LEX *lex, plugin_ref plugin)
st_plugin_int *pi;
DBUG_ENTER("intern_plugin_unlock");
- safe_mutex_assert_owner(&LOCK_plugin);
+ mysql_mutex_assert_owner(&LOCK_plugin);
if (!plugin)
DBUG_VOID_RETURN;
@@ -962,7 +984,7 @@ static void intern_plugin_unlock(LEX *lex, plugin_ref plugin)
if (!pi->plugin_dl)
DBUG_VOID_RETURN;
#else
- my_free((uchar*) plugin, MYF(MY_WME));
+ my_free(plugin);
#endif
DBUG_PRINT("info",("unlocking plugin, name= %s, ref_count= %d",
@@ -1004,10 +1026,10 @@ void plugin_unlock(THD *thd, plugin_ref plugin)
if (!plugin_dlib(plugin))
DBUG_VOID_RETURN;
#endif
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
intern_plugin_unlock(lex, plugin);
reap_plugins();
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
DBUG_VOID_RETURN;
}
@@ -1017,11 +1039,11 @@ void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
LEX *lex= thd ? thd->lex : 0;
DBUG_ENTER("plugin_unlock_list");
DBUG_ASSERT(list);
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
while (count--)
intern_plugin_unlock(lex, *list++);
reap_plugins();
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
DBUG_VOID_RETURN;
}
@@ -1031,11 +1053,11 @@ static int plugin_initialize(struct st_plugin_int *plugin)
int ret= 1;
DBUG_ENTER("plugin_initialize");
- safe_mutex_assert_owner(&LOCK_plugin);
+ mysql_mutex_assert_owner(&LOCK_plugin);
uint state= plugin->state;
DBUG_ASSERT(state == PLUGIN_IS_UNINITIALIZED);
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
if (plugin_type_initialize[plugin->plugin->type])
{
if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
@@ -1097,8 +1119,14 @@ static int plugin_initialize(struct st_plugin_int *plugin)
ret= 0;
err:
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
plugin->state= state;
+
+ /* maintain the obsolete @@have_innodb variable */
+ if (!my_strcasecmp(&my_charset_latin1, plugin->name.str, "InnoDB"))
+ have_innodb= state & PLUGIN_IS_READY ? SHOW_OPTION_YES
+ : SHOW_OPTION_DISABLED;
+
DBUG_RETURN(ret);
}
@@ -1138,6 +1166,26 @@ static inline void convert_underscore_to_dash(char *str, int len)
*p= '-';
}
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_LOCK_plugin;
+
+static PSI_mutex_info all_plugin_mutexes[]=
+{
+ { &key_LOCK_plugin, "LOCK_plugin", PSI_FLAG_GLOBAL}
+};
+
+static void init_plugin_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_plugin_mutexes);
+ PSI_server->register_mutex(category, all_plugin_mutexes, count);
+}
+#endif /* HAVE_PSI_INTERFACE */
/*
The logic is that we first load and initialize all compiled in plugins.
@@ -1154,21 +1202,26 @@ int plugin_init(int *argc, char **argv, int flags)
struct st_mysql_plugin *plugin;
struct st_plugin_int tmp, *plugin_ptr, **reap;
MEM_ROOT tmp_root;
- bool reaped_mandatory_plugin= FALSE;
+ bool reaped_mandatory_plugin= false;
+ bool mandatory= true;
DBUG_ENTER("plugin_init");
if (initialized)
DBUG_RETURN(0);
+#ifdef HAVE_PSI_INTERFACE
+ init_plugin_psi_keys();
+#endif
+
init_alloc_root(&plugin_mem_root, 4096, 4096);
init_alloc_root(&tmp_root, 4096, 4096);
- if (hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
- get_bookmark_hash_key, NULL, HASH_UNIQUE))
+ if (my_hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
+ get_bookmark_hash_key, NULL, HASH_UNIQUE))
goto err;
- pthread_mutex_init(&LOCK_plugin, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_plugin, &LOCK_plugin, MY_MUTEX_INIT_FAST);
if (my_init_dynamic_array(&plugin_dl_array,
sizeof(struct st_plugin_dl *),16,16) ||
@@ -1178,20 +1231,27 @@ int plugin_init(int *argc, char **argv, int flags)
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
{
- if (hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
- get_plugin_hash_key, NULL, HASH_UNIQUE))
+ if (my_hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
+ get_plugin_hash_key, NULL, HASH_UNIQUE))
goto err;
}
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
initialized= 1;
/*
First we register builtin plugins
*/
- for (builtins= mysqld_builtins; *builtins; builtins++)
+ for (builtins= mysql_mandatory_plugins; *builtins || mandatory; builtins++)
{
+ if (!*builtins)
+ {
+ builtins= mysql_optional_plugins;
+ mandatory= false;
+ if (!*builtins)
+ break;
+ }
for (plugin= *builtins; plugin->info; plugin++)
{
if (opt_ignore_builtin_innodb &&
@@ -1203,6 +1263,27 @@ int plugin_init(int *argc, char **argv, int flags)
tmp.name.str= (char *)plugin->name;
tmp.name.length= strlen(plugin->name);
tmp.state= 0;
+ tmp.load_option= mandatory ? PLUGIN_FORCE : PLUGIN_ON;
+
+ /*
+ If the performance schema is compiled in,
+ treat the storage engine plugin as 'mandatory',
+ to suppress any plugin-level options such as '--performance-schema'.
+ This is specific to the performance schema, and is done on purpose:
+ the server-level option '--performance-schema' controls the overall
+ performance schema initialization, which consists of much more that
+ the underlying storage engine initialization.
+ See mysqld.cc, set_vars.cc.
+ Suppressing ways to interfere directly with the storage engine alone
+ prevents awkward situations where:
+ - the user wants the performance schema functionality, by using
+ '--enable-performance-schema' (the server option),
+ - yet disable explicitly a component needed for the functionality
+ to work, by using '--skip-performance-schema' (the plugin)
+ */
+ if (!my_strcasecmp(&my_charset_latin1, plugin->name, "PERFORMANCE_SCHEMA"))
+ tmp.load_option= PLUGIN_FORCE;
+
free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
if (test_plugin_options(&tmp_root, &tmp, argc, argv))
tmp.state= PLUGIN_IS_DISABLED;
@@ -1217,7 +1298,7 @@ int plugin_init(int *argc, char **argv, int flags)
my_strcasecmp(&my_charset_latin1, plugin->name, "CSV"))
continue;
- if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED &&
+ if (plugin_ptr->state != PLUGIN_IS_UNINITIALIZED ||
plugin_initialize(plugin_ptr))
goto err_unlock;
@@ -1238,7 +1319,7 @@ int plugin_init(int *argc, char **argv, int flags)
/* should now be set to MyISAM storage engine */
DBUG_ASSERT(global_system_variables.table_plugin);
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
/* Register all dynamic plugins */
if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
@@ -1256,7 +1337,7 @@ int plugin_init(int *argc, char **argv, int flags)
Now we initialize all remaining plugins
*/
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
reap= (st_plugin_int **) my_alloca((plugin_array.elements+1) * sizeof(void*));
*(reap++)= NULL;
@@ -1278,15 +1359,16 @@ int plugin_init(int *argc, char **argv, int flags)
*/
while ((plugin_ptr= *(--reap)))
{
- pthread_mutex_unlock(&LOCK_plugin);
- if (plugin_ptr->is_mandatory)
+ mysql_mutex_unlock(&LOCK_plugin);
+ if (plugin_ptr->load_option == PLUGIN_FORCE ||
+ plugin_ptr->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
reaped_mandatory_plugin= TRUE;
plugin_deinitialize(plugin_ptr, true);
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
plugin_del(plugin_ptr);
}
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
my_afree(reap);
if (reaped_mandatory_plugin)
goto err;
@@ -1297,7 +1379,7 @@ end:
DBUG_RETURN(0);
err_unlock:
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
err:
free_root(&tmp_root, MYF(0));
DBUG_RETURN(1);
@@ -1327,94 +1409,47 @@ static bool register_builtin(struct st_mysql_plugin *plugin,
}
-#ifdef NOT_USED_YET
-/*
- Register a plugin at run time. (note, this doesn't initialize a plugin)
- Will be useful for embedded applications.
-
- SYNOPSIS
- plugin_register_builtin()
- thd current thread (used to store scratch data in mem_root)
- plugin static plugin to install
-
- RETURN
- false - plugin registered successfully
-*/
-bool plugin_register_builtin(THD *thd, struct st_mysql_plugin *plugin)
-{
- struct st_plugin_int tmp, *ptr;
- bool result= true;
- int dummy_argc= 0;
- DBUG_ENTER("plugin_register_builtin");
-
- bzero(&tmp, sizeof(tmp));
- tmp.plugin= plugin;
- tmp.name.str= (char *)plugin->name;
- tmp.name.length= strlen(plugin->name);
-
- pthread_mutex_lock(&LOCK_plugin);
- rw_wrlock(&LOCK_system_variables_hash);
-
- if (test_plugin_options(thd->mem_root, &tmp, &dummy_argc, NULL))
- goto end;
- tmp.state= PLUGIN_IS_UNINITIALIZED;
- if ((result= register_builtin(plugin, &tmp, &ptr)))
- mysql_del_sys_var_chain(tmp.system_vars);
-
-end:
- rw_unlock(&LOCK_system_variables_hash);
- pthread_mutex_unlock(&LOCK_plugin);
-
- DBUG_RETURN(result);;
-}
-#endif /* NOT_USED_YET */
-
-
/*
called only by plugin_init()
*/
static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
{
+ THD thd;
TABLE_LIST tables;
TABLE *table;
READ_RECORD read_record_info;
int error;
- THD *new_thd;
+ THD *new_thd= &thd;
+ bool result;
#ifdef EMBEDDED_LIBRARY
- bool table_exists;
+ No_such_table_error_handler error_handler;
#endif /* EMBEDDED_LIBRARY */
DBUG_ENTER("plugin_load");
- if (!(new_thd= new THD))
- {
- sql_print_error("Can't allocate memory for plugin structures");
- delete new_thd;
- DBUG_VOID_RETURN;
- }
new_thd->thread_stack= (char*) &tables;
new_thd->store_globals();
- lex_start(new_thd);
new_thd->db= my_strdup("mysql", MYF(0));
new_thd->db_length= 5;
- bzero((uchar*)&tables, sizeof(tables));
- tables.alias= tables.table_name= (char*)"plugin";
- tables.lock_type= TL_READ;
- tables.db= new_thd->db;
+ bzero((char*) &thd.net, sizeof(thd.net));
+ tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_READ);
#ifdef EMBEDDED_LIBRARY
/*
When building an embedded library, if the mysql.plugin table
does not exist, we silently ignore the missing table
*/
- pthread_mutex_lock(&LOCK_open);
- if (check_if_table_exists(new_thd, &tables, &table_exists))
- table_exists= FALSE;
- pthread_mutex_unlock(&LOCK_open);
- if (!table_exists)
+ new_thd->push_internal_handler(&error_handler);
+#endif /* EMBEDDED_LIBRARY */
+
+ result= open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT);
+
+#ifdef EMBEDDED_LIBRARY
+ new_thd->pop_internal_handler();
+ if (error_handler.safely_trapped_errors())
goto end;
#endif /* EMBEDDED_LIBRARY */
- if (simple_open_n_lock_tables(new_thd, &tables))
+ if (result)
{
DBUG_PRINT("error",("Can't open plugin table"));
sql_print_error("Can't open the mysql.plugin table. Please "
@@ -1427,10 +1462,10 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
/*
there're no other threads running yet, so we don't need a mutex.
but plugin_add() before is designed to work in multi-threaded
- environment, and it uses safe_mutex_assert_owner(), so we lock
+ environment, and it uses mysql_mutex_assert_owner(), so we lock
the mutex here to satisfy the assert
*/
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
while (!(error= read_record_info.read_record(&read_record_info)))
{
DBUG_PRINT("info", ("init plugin record"));
@@ -1446,14 +1481,13 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
str_name.c_ptr(), str_dl.c_ptr());
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
}
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
if (error > 0)
sql_print_error(ER(ER_GET_ERRNO), my_errno);
end_read_record(&read_record_info);
- new_thd->version--; // Force close to free memory
+ table->m_needs_reopen= TRUE; // Force close to free memory
+ close_mysql_tables(new_thd);
end:
- close_thread_tables(new_thd);
- delete new_thd;
/* Remember that we don't have a THD */
my_pthread_setspecific_ptr(THR_THD, 0);
DBUG_VOID_RETURN;
@@ -1498,7 +1532,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
}
dl= name;
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG)))
{
for (plugin= plugin_dl->plugins; plugin->info; plugin++)
@@ -1516,11 +1550,11 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
else
{
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
goto error;
}
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
name.length= dl.length= 0;
dl.str= NULL; name.str= p= buffer;
str= &name;
@@ -1541,7 +1575,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
}
DBUG_RETURN(FALSE);
error:
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
sql_print_error("Couldn't load plugin named '%s' with soname '%s'.",
name.str, dl.str);
DBUG_RETURN(TRUE);
@@ -1557,7 +1591,7 @@ void plugin_shutdown(void)
if (initialized)
{
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
reap_needed= true;
@@ -1602,7 +1636,7 @@ void plugin_shutdown(void)
if (plugins[i]->state == PLUGIN_IS_DELETED)
plugins[i]->state= PLUGIN_IS_DYING;
}
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
/*
We loop through all plugins and call deinit() if they have one.
@@ -1623,9 +1657,9 @@ void plugin_shutdown(void)
/*
It's perfectly safe not to lock LOCK_plugin, as there're no
concurrent threads anymore. But some functions called from here
- use safe_mutex_assert_owner(), so we lock the mutex to satisfy it
+ use mysql_mutex_assert_owner(), so we lock the mutex to satisfy it
*/
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
/*
We defer checking ref_counts until after all plugins are deinitialized
@@ -1646,10 +1680,10 @@ void plugin_shutdown(void)
cleanup_variables(NULL, &global_system_variables);
cleanup_variables(NULL, &max_system_variables);
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
initialized= 0;
- pthread_mutex_destroy(&LOCK_plugin);
+ mysql_mutex_destroy(&LOCK_plugin);
my_afree(plugins);
}
@@ -1657,7 +1691,7 @@ void plugin_shutdown(void)
/* Dispose of the memory */
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
- hash_free(&plugin_hash[i]);
+ my_hash_free(&plugin_hash[i]);
delete_dynamic(&plugin_array);
count= plugin_dl_array.elements;
@@ -1669,7 +1703,7 @@ void plugin_shutdown(void)
my_afree(dl);
delete_dynamic(&plugin_dl_array);
- hash_free(&bookmark_hash);
+ my_hash_free(&bookmark_hash);
free_root(&plugin_mem_root, MYF(0));
global_variables_dynamic_size= 0;
@@ -1693,24 +1727,48 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl
DBUG_RETURN(TRUE);
}
- bzero(&tables, sizeof(tables));
- tables.db= (char *)"mysql";
- tables.table_name= tables.alias= (char *)"plugin";
- if (check_table_access(thd, INSERT_ACL, &tables, 1, FALSE))
+ tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE);
+ if (check_table_access(thd, INSERT_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
/* need to open before acquiring LOCK_plugin or it will deadlock */
- if (! (table = open_ltable(thd, &tables, TL_WRITE, 0)))
+ if (! (table = open_ltable(thd, &tables, TL_WRITE,
+ MYSQL_LOCK_IGNORE_TIMEOUT)))
DBUG_RETURN(TRUE);
- pthread_mutex_lock(&LOCK_plugin);
- rw_wrlock(&LOCK_system_variables_hash);
+ /*
+ Pre-acquire audit plugins for events that may potentially occur
+ during [UN]INSTALL PLUGIN.
- my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL);
+ When audit event is triggered, audit subsystem acquires interested
+ plugins by walking through plugin list. Evidently plugin list
+ iterator protects plugin list by acquiring LOCK_plugin, see
+ plugin_foreach_with_mask().
+
+ On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
+ rather for a long time.
+
+ When audit event is triggered during [UN]INSTALL PLUGIN, plugin
+ list iterator acquires the same lock (within the same thread)
+ second time.
+
+ This hack should be removed when LOCK_plugin is fixed so it
+ protects only what it supposed to protect.
+ */
+ mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS);
+
+ mysql_mutex_lock(&LOCK_plugin);
+ mysql_rwlock_wrlock(&LOCK_system_variables_hash);
+
+ if (my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL))
+ {
+ report_error(REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str);
+ goto err;
+ }
error= plugin_add(thd->mem_root, name, dl, &argc, argv, REPORT_TO_USER);
if (argv)
free_defaults(argv);
- rw_unlock(&LOCK_system_variables_hash);
+ mysql_rwlock_unlock(&LOCK_system_variables_hash);
if (error || !(tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
goto err;
@@ -1723,7 +1781,6 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl
}
else
{
- DBUG_ASSERT(tmp->state == PLUGIN_IS_UNINITIALIZED);
if (plugin_initialize(tmp))
{
my_error(ER_CANT_INITIALIZE_UDF, MYF(0), name->str,
@@ -1750,14 +1807,14 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl
goto deinit;
}
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(FALSE);
deinit:
tmp->state= PLUGIN_IS_DELETED;
reap_needed= true;
reap_plugins();
err:
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(TRUE);
}
@@ -1775,17 +1832,37 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
DBUG_RETURN(TRUE);
}
- bzero(&tables, sizeof(tables));
- tables.db= (char *)"mysql";
- tables.table_name= tables.alias= (char *)"plugin";
- if (check_table_access(thd, DELETE_ACL, &tables, 1, FALSE))
+ tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE);
+
+ if (check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
/* need to open before acquiring LOCK_plugin or it will deadlock */
- if (! (table= open_ltable(thd, &tables, TL_WRITE, 0)))
+ if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
DBUG_RETURN(TRUE);
- pthread_mutex_lock(&LOCK_plugin);
+ /*
+ Pre-acquire audit plugins for events that may potentially occur
+ during [UN]INSTALL PLUGIN.
+
+ When audit event is triggered, audit subsystem acquires interested
+ plugins by walking through plugin list. Evidently plugin list
+ iterator protects plugin list by acquiring LOCK_plugin, see
+ plugin_foreach_with_mask().
+
+ On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
+ rather for a long time.
+
+ When audit event is triggered during [UN]INSTALL PLUGIN, plugin
+ list iterator acquires the same lock (within the same thread)
+ second time.
+
+ This hack should be removed when LOCK_plugin is fixed so it
+ protects only what it supposed to protect.
+ */
+ mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS);
+
+ mysql_mutex_lock(&LOCK_plugin);
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
{
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
@@ -1798,6 +1875,11 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
goto err;
}
+ if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
+ {
+ my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str);
+ goto err;
+ }
plugin->state= PLUGIN_IS_DELETED;
if (plugin->ref_count)
@@ -1806,14 +1888,15 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
else
reap_needed= true;
reap_plugins();
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
+ uchar user_key[MAX_KEY_LENGTH];
table->use_all_columns();
table->field[0]->store(name->str, name->length, system_charset_info);
- if (! table->file->index_read_idx_map(table->record[0], 0,
- (uchar *)table->field[0]->ptr,
- HA_WHOLE_KEY,
- HA_READ_KEY_EXACT))
+ key_copy(user_key, table->record[0], table->key_info,
+ table->key_info->key_length);
+ if (! table->file->index_read_idx_map(table->record[0], 0, user_key,
+ HA_WHOLE_KEY, HA_READ_KEY_EXACT))
{
int error;
/*
@@ -1832,7 +1915,7 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
}
DBUG_RETURN(FALSE);
err:
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(TRUE);
}
@@ -1850,7 +1933,7 @@ bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
state_mask= ~state_mask; // do it only once
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
total= type == MYSQL_ANY_PLUGIN ? plugin_array.elements
: plugin_hash[type].records;
/*
@@ -1871,21 +1954,21 @@ bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
HASH *hash= plugin_hash + type;
for (idx= 0; idx < total; idx++)
{
- plugin= (struct st_plugin_int *) hash_element(hash, idx);
+ plugin= (struct st_plugin_int *) my_hash_element(hash, idx);
plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
}
}
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
for (idx= 0; idx < total; idx++)
{
if (unlikely(version != plugin_array_version))
{
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
for (uint i=idx; i < total; i++)
if (plugins[i] && plugins[i]->state & state_mask)
plugins[i]=0;
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
}
plugin= plugins[idx];
/* It will stop iterating on first engine error when "func" returns TRUE */
@@ -1944,7 +2027,7 @@ static int check_func_bool(THD *thd, struct st_mysql_sys_var *var,
void *save, st_mysql_value *value)
{
char buff[STRING_BUFFER_USUAL_SIZE];
- const char *strvalue= "NULL", *str;
+ const char *str;
int result, length;
long long tmp;
@@ -1953,28 +2036,19 @@ static int check_func_bool(THD *thd, struct st_mysql_sys_var *var,
length= sizeof(buff);
if (!(str= value->val_str(value, buff, &length)) ||
(result= find_type(&bool_typelib, str, length, 1)-1) < 0)
- {
- if (str)
- strvalue= str;
goto err;
- }
}
else
{
if (value->val_int(value, &tmp) < 0)
goto err;
if (tmp > 1)
- {
- llstr(tmp, buff);
- strvalue= buff;
goto err;
- }
result= (int) tmp;
}
*(my_bool *) save= -result;
return 0;
err:
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
return 1;
}
@@ -1982,60 +2056,87 @@ err:
static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
void *save, st_mysql_value *value)
{
- my_bool fixed;
- long long tmp;
+ my_bool fixed1, fixed2;
+ long long orig, val;
struct my_option options;
- value->val_int(value, &tmp);
+ value->val_int(value, &orig);
+ val= orig;
plugin_opt_set_limits(&options, var);
if (var->flags & PLUGIN_VAR_UNSIGNED)
- *(uint *)save= (uint) getopt_ull_limit_value((ulonglong) tmp, &options,
- &fixed);
+ {
+ if ((fixed1= (!value->is_unsigned(value) && val < 0)))
+ val=0;
+ *(uint *)save= (uint) getopt_ull_limit_value((ulonglong) val, &options,
+ &fixed2);
+ }
else
- *(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed);
+ {
+ if ((fixed1= (value->is_unsigned(value) && val < 0)))
+ val=LONGLONG_MAX;
+ *(int *)save= (int) getopt_ll_limit_value(val, &options, &fixed2);
+ }
- return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
- var->name, (longlong) tmp);
+ return throw_bounds_warning(thd, var->name, fixed1 || fixed2,
+ value->is_unsigned(value), (longlong) orig);
}
static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
void *save, st_mysql_value *value)
{
- my_bool fixed;
- long long tmp;
+ my_bool fixed1, fixed2;
+ long long orig, val;
struct my_option options;
- value->val_int(value, &tmp);
+ value->val_int(value, &orig);
+ val= orig;
plugin_opt_set_limits(&options, var);
if (var->flags & PLUGIN_VAR_UNSIGNED)
- *(ulong *)save= (ulong) getopt_ull_limit_value((ulonglong) tmp, &options,
- &fixed);
+ {
+ if ((fixed1= (!value->is_unsigned(value) && val < 0)))
+ val=0;
+ *(ulong *)save= (ulong) getopt_ull_limit_value((ulonglong) val, &options,
+ &fixed2);
+ }
else
- *(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed);
+ {
+ if ((fixed1= (value->is_unsigned(value) && val < 0)))
+ val=LONGLONG_MAX;
+ *(long *)save= (long) getopt_ll_limit_value(val, &options, &fixed2);
+ }
- return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
- var->name, (longlong) tmp);
+ return throw_bounds_warning(thd, var->name, fixed1 || fixed2,
+ value->is_unsigned(value), (longlong) orig);
}
static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var,
void *save, st_mysql_value *value)
{
- my_bool fixed;
- long long tmp;
+ my_bool fixed1, fixed2;
+ long long orig, val;
struct my_option options;
- value->val_int(value, &tmp);
+ value->val_int(value, &orig);
+ val= orig;
plugin_opt_set_limits(&options, var);
if (var->flags & PLUGIN_VAR_UNSIGNED)
- *(ulonglong *)save= getopt_ull_limit_value((ulonglong) tmp, &options,
- &fixed);
+ {
+ if ((fixed1= (!value->is_unsigned(value) && val < 0)))
+ val=0;
+ *(ulonglong *)save= getopt_ull_limit_value((ulonglong) val, &options,
+ &fixed2);
+ }
else
- *(longlong *)save= getopt_ll_limit_value(tmp, &options, &fixed);
+ {
+ if ((fixed1= (value->is_unsigned(value) && val < 0)))
+ val=LONGLONG_MAX;
+ *(longlong *)save= getopt_ll_limit_value(val, &options, &fixed2);
+ }
- return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
- var->name, (longlong) tmp);
+ return throw_bounds_warning(thd, var->name, fixed1 || fixed2,
+ value->is_unsigned(value), (longlong) orig);
}
static int check_func_str(THD *thd, struct st_mysql_sys_var *var,
@@ -2057,7 +2158,7 @@ static int check_func_enum(THD *thd, struct st_mysql_sys_var *var,
void *save, st_mysql_value *value)
{
char buff[STRING_BUFFER_USUAL_SIZE];
- const char *strvalue= "NULL", *str;
+ const char *str;
TYPELIB *typelib;
long long tmp;
long result;
@@ -2073,28 +2174,20 @@ static int check_func_enum(THD *thd, struct st_mysql_sys_var *var,
length= sizeof(buff);
if (!(str= value->val_str(value, buff, &length)))
goto err;
- if ((result= (long)find_type(typelib, str, length, 1)-1) < 0)
- {
- strvalue= str;
+ if ((result= (long)find_type(typelib, str, length, 0) - 1) < 0)
goto err;
- }
}
else
{
if (value->val_int(value, &tmp))
goto err;
- if (tmp >= typelib->count)
- {
- llstr(tmp, buff);
- strvalue= buff;
+ if (tmp < 0 || tmp >= typelib->count)
goto err;
- }
result= (long) tmp;
}
*(long*)save= result;
return 0;
err:
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
return 1;
}
@@ -2103,7 +2196,7 @@ static int check_func_set(THD *thd, struct st_mysql_sys_var *var,
void *save, st_mysql_value *value)
{
char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
- const char *strvalue= "NULL", *str;
+ const char *str;
TYPELIB *typelib;
ulonglong result;
uint error_len= 0; // init as only set on error
@@ -2123,28 +2216,19 @@ static int check_func_set(THD *thd, struct st_mysql_sys_var *var,
result= find_set(typelib, str, length, NULL,
&error, &error_len, &not_used);
if (error_len)
- {
- strmake(buff, error, min(sizeof(buff) - 1, error_len));
- strvalue= buff;
goto err;
- }
}
else
{
if (value->val_int(value, (long long *)&result))
goto err;
- if (unlikely((result >= (ULL(1) << typelib->count)) &&
+ if (unlikely((result >= (1ULL << typelib->count)) &&
(typelib->count < sizeof(long)*8)))
- {
- llstr(result, buff);
- strvalue= buff;
goto err;
- }
}
*(ulonglong*)save= result;
return 0;
err:
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
return 1;
}
@@ -2185,7 +2269,7 @@ static void update_func_str(THD *thd, struct st_mysql_sys_var *var,
if (var->flags & PLUGIN_VAR_MEMALLOC)
{
*(char **)tgt= my_strdup(*(char **) save, MYF(0));
- my_free(old, MYF(0));
+ my_free(old);
}
}
@@ -2202,12 +2286,12 @@ sys_var *find_sys_var(THD *thd, const char *str, uint length)
plugin_ref plugin;
DBUG_ENTER("find_sys_var");
- pthread_mutex_lock(&LOCK_plugin);
- rw_rdlock(&LOCK_system_variables_hash);
- if ((var= intern_find_sys_var(str, length, false)) &&
+ mysql_mutex_lock(&LOCK_plugin);
+ mysql_rwlock_rdlock(&LOCK_system_variables_hash);
+ if ((var= intern_find_sys_var(str, length)) &&
(pi= var->cast_pluginvar()))
{
- rw_unlock(&LOCK_system_variables_hash);
+ mysql_rwlock_unlock(&LOCK_system_variables_hash);
LEX *lex= thd ? thd->lex : 0;
if (!(plugin= my_intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
var= NULL; /* failed to lock it, it must be uninstalling */
@@ -2220,14 +2304,10 @@ sys_var *find_sys_var(THD *thd, const char *str, uint length)
}
}
else
- rw_unlock(&LOCK_system_variables_hash);
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_rwlock_unlock(&LOCK_system_variables_hash);
+ mysql_mutex_unlock(&LOCK_plugin);
- /*
- If the variable exists but the plugin it is associated with is not ready
- then the intern_plugin_lock did not raise an error, so we do it here.
- */
- if (pi && !var)
+ if (!var)
my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
DBUG_RETURN(var);
}
@@ -2266,8 +2346,8 @@ static st_bookmark *find_bookmark(const char *plugin, const char *name,
varname[0]= flags & PLUGIN_VAR_TYPEMASK;
- result= (st_bookmark*) hash_search(&bookmark_hash,
- (const uchar*) varname, length - 1);
+ result= (st_bookmark*) my_hash_search(&bookmark_hash,
+ (const uchar*) varname, length - 1);
my_afree(varname);
return result;
@@ -2377,6 +2457,15 @@ static st_bookmark *register_var(const char *plugin, const char *name,
return result;
}
+static void restore_pluginvar_names(sys_var *first)
+{
+ for (sys_var *var= first; var; var= var->next)
+ {
+ sys_var_pluginvar *pv= var->cast_pluginvar();
+ pv->plugin_var->name= pv->orig_pluginvar_name;
+ }
+}
+
/*
returns a pointer to the memory which holds the thd-local variable or
@@ -2400,7 +2489,7 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
{
uint idx;
- rw_rdlock(&LOCK_system_variables_hash);
+ mysql_rwlock_rdlock(&LOCK_system_variables_hash);
thd->variables.dynamic_variables_ptr= (char*)
my_realloc(thd->variables.dynamic_variables_ptr,
@@ -2408,9 +2497,9 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
if (global_lock)
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
- safe_mutex_assert_owner(&LOCK_global_system_variables);
+ mysql_mutex_assert_owner(&LOCK_global_system_variables);
memcpy(thd->variables.dynamic_variables_ptr +
thd->variables.dynamic_variables_size,
@@ -2427,10 +2516,10 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
{
sys_var_pluginvar *pi;
sys_var *var;
- st_bookmark *v= (st_bookmark*) hash_element(&bookmark_hash,idx);
+ st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx);
if (v->version <= thd->variables.dynamic_variables_version ||
- !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
+ !(var= intern_find_sys_var(v->key + 1, v->name_len)) ||
!(pi= var->cast_pluginvar()) ||
v->key[0] != (pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
continue;
@@ -2449,7 +2538,7 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
}
if (global_lock)
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
thd->variables.dynamic_variables_version=
global_system_variables.dynamic_variables_version;
@@ -2458,7 +2547,7 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
thd->variables.dynamic_variables_size=
global_system_variables.dynamic_variables_size;
- rw_unlock(&LOCK_system_variables_hash);
+ mysql_rwlock_unlock(&LOCK_system_variables_hash);
}
return (uchar*)thd->variables.dynamic_variables_ptr + offset;
}
@@ -2523,11 +2612,11 @@ void plugin_thdvar_init(THD *thd)
thd->variables.dynamic_variables_size= 0;
thd->variables.dynamic_variables_ptr= 0;
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
thd->variables.table_plugin=
my_intern_plugin_lock(NULL, global_system_variables.table_plugin);
intern_plugin_unlock(NULL, old_table_plugin);
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
DBUG_VOID_RETURN;
}
@@ -2556,12 +2645,12 @@ static void cleanup_variables(THD *thd, struct system_variables *vars)
int flags;
uint idx;
- rw_rdlock(&LOCK_system_variables_hash);
+ mysql_rwlock_rdlock(&LOCK_system_variables_hash);
for (idx= 0; idx < bookmark_hash.records; idx++)
{
- v= (st_bookmark*) hash_element(&bookmark_hash, idx);
+ v= (st_bookmark*) my_hash_element(&bookmark_hash, idx);
if (v->version > vars->dynamic_variables_version ||
- !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
+ !(var= intern_find_sys_var(v->key + 1, v->name_len)) ||
!(pivar= var->cast_pluginvar()) ||
v->key[0] != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
continue;
@@ -2572,15 +2661,15 @@ static void cleanup_variables(THD *thd, struct system_variables *vars)
flags & PLUGIN_VAR_THDLOCAL && flags & PLUGIN_VAR_MEMALLOC)
{
char **ptr= (char**) pivar->real_value_ptr(thd, OPT_SESSION);
- my_free(*ptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
+ my_free(*ptr);
*ptr= NULL;
}
}
- rw_unlock(&LOCK_system_variables_hash);
+ mysql_rwlock_unlock(&LOCK_system_variables_hash);
DBUG_ASSERT(vars->table_plugin == NULL);
- my_free(vars->dynamic_variables_ptr, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(vars->dynamic_variables_ptr);
vars->dynamic_variables_ptr= NULL;
vars->dynamic_variables_size= 0;
vars->dynamic_variables_version= 0;
@@ -2593,7 +2682,7 @@ void plugin_thdvar_cleanup(THD *thd)
plugin_ref *list;
DBUG_ENTER("plugin_thdvar_cleanup");
- pthread_mutex_lock(&LOCK_plugin);
+ mysql_mutex_lock(&LOCK_plugin);
unlock_variables(thd, &thd->variables);
cleanup_variables(thd, &thd->variables);
@@ -2607,7 +2696,7 @@ void plugin_thdvar_cleanup(THD *thd)
}
reap_plugins();
- pthread_mutex_unlock(&LOCK_plugin);
+ mysql_mutex_unlock(&LOCK_plugin);
reset_dynamic(&thd->lex->plugins);
@@ -2640,51 +2729,52 @@ static void plugin_vars_free_values(sys_var *vars)
/* Free the string from global_system_variables. */
char **valptr= (char**) piv->real_value_ptr(NULL, OPT_GLOBAL);
DBUG_PRINT("plugin", ("freeing value for: '%s' addr: 0x%lx",
- var->name, (long) valptr));
- my_free(*valptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
+ var->name.str, (long) valptr));
+ my_free(*valptr);
*valptr= NULL;
}
}
DBUG_VOID_RETURN;
}
-
-bool sys_var_pluginvar::check_update_type(Item_result type)
+static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var)
{
- if (is_readonly())
- return 1;
switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
+ case PLUGIN_VAR_BOOL:
+ return SHOW_MY_BOOL;
case PLUGIN_VAR_INT:
+ return SHOW_INT;
case PLUGIN_VAR_LONG:
+ return SHOW_LONG;
case PLUGIN_VAR_LONGLONG:
- return type != INT_RESULT;
+ return SHOW_LONGLONG;
case PLUGIN_VAR_STR:
- return type != STRING_RESULT;
+ return SHOW_CHAR_PTR;
+ case PLUGIN_VAR_ENUM:
+ case PLUGIN_VAR_SET:
+ return SHOW_CHAR;
default:
- return 0;
+ DBUG_ASSERT(0);
+ return SHOW_UNDEF;
}
}
-SHOW_TYPE sys_var_pluginvar::show_type()
+bool sys_var_pluginvar::check_update_type(Item_result type)
{
switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
- case PLUGIN_VAR_BOOL:
- return SHOW_MY_BOOL;
case PLUGIN_VAR_INT:
- return SHOW_INT;
case PLUGIN_VAR_LONG:
- return SHOW_LONG;
case PLUGIN_VAR_LONGLONG:
- return SHOW_LONGLONG;
+ return type != INT_RESULT;
case PLUGIN_VAR_STR:
- return SHOW_CHAR_PTR;
+ return type != STRING_RESULT;
case PLUGIN_VAR_ENUM:
+ case PLUGIN_VAR_BOOL:
case PLUGIN_VAR_SET:
- return SHOW_CHAR;
+ return type != STRING_RESULT && type != INT_RESULT;
default:
- DBUG_ASSERT(0);
- return SHOW_UNDEF;
+ return true;
}
}
@@ -2717,12 +2807,12 @@ TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
default:
return NULL;
}
- return NULL;
+ return NULL; /* Keep compiler happy */
}
-uchar* sys_var_pluginvar::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
+uchar* sys_var_pluginvar::do_value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
{
uchar* result;
@@ -2731,139 +2821,104 @@ uchar* sys_var_pluginvar::value_ptr(THD *thd, enum_var_type type,
if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_ENUM)
result= (uchar*) get_type(plugin_var_typelib(), *(ulong*)result);
else if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_SET)
- {
- char buffer[STRING_BUFFER_USUAL_SIZE];
- String str(buffer, sizeof(buffer), system_charset_info);
- TYPELIB *typelib= plugin_var_typelib();
- ulonglong mask= 1, value= *(ulonglong*) result;
- uint i;
-
- str.length(0);
- for (i= 0; i < typelib->count; i++, mask<<=1)
- {
- if (!(value & mask))
- continue;
- str.append(typelib->type_names[i], typelib->type_lengths
- ? typelib->type_lengths[i]
- : strlen(typelib->type_names[i]));
- str.append(',');
- }
-
- result= (uchar*) "";
- if (str.length())
- result= (uchar*) thd->strmake(str.ptr(), str.length()-1);
- }
+ result= (uchar*) set_to_string(thd, 0, *(ulonglong*) result,
+ plugin_var_typelib()->type_names);
return result;
}
-
-bool sys_var_pluginvar::check(THD *thd, set_var *var)
+bool sys_var_pluginvar::do_check(THD *thd, set_var *var)
{
st_item_value_holder value;
- DBUG_ASSERT(is_readonly() || plugin_var->check);
+ DBUG_ASSERT(!is_readonly());
+ DBUG_ASSERT(plugin_var->check);
value.value_type= item_value_type;
value.val_str= item_val_str;
value.val_int= item_val_int;
value.val_real= item_val_real;
+ value.is_unsigned= item_is_unsigned;
value.item= var->value;
- return is_readonly() ||
- plugin_var->check(thd, plugin_var, &var->save_result, &value);
+ return plugin_var->check(thd, plugin_var, &var->save_result, &value);
}
-
-void sys_var_pluginvar::set_default(THD *thd, enum_var_type type)
+bool sys_var_pluginvar::session_update(THD *thd, set_var *var)
{
- const void *src;
- void *tgt;
-
- DBUG_ASSERT(is_readonly() || plugin_var->update);
+ DBUG_ASSERT(!is_readonly());
+ DBUG_ASSERT(plugin_var->flags & PLUGIN_VAR_THDLOCAL);
+ DBUG_ASSERT(thd == current_thd);
- if (is_readonly())
- return;
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ void *tgt= real_value_ptr(thd, var->type);
+ const void *src= var->value ? (void*)&var->save_result
+ : (void*)real_value_ptr(thd, OPT_GLOBAL);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ plugin_var->update(thd, plugin_var, tgt, src);
- pthread_mutex_lock(&LOCK_global_system_variables);
- tgt= real_value_ptr(thd, type);
- src= ((void **) (plugin_var + 1) + 1);
-
- if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
- {
- if (type != OPT_GLOBAL)
- src= real_value_ptr(thd, OPT_GLOBAL);
- else
- switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
- case PLUGIN_VAR_INT:
- src= &((thdvar_uint_t*) plugin_var)->def_val;
- break;
- case PLUGIN_VAR_LONG:
- src= &((thdvar_ulong_t*) plugin_var)->def_val;
- break;
- case PLUGIN_VAR_LONGLONG:
- src= &((thdvar_ulonglong_t*) plugin_var)->def_val;
- break;
- case PLUGIN_VAR_ENUM:
- src= &((thdvar_enum_t*) plugin_var)->def_val;
- break;
- case PLUGIN_VAR_SET:
- src= &((thdvar_set_t*) plugin_var)->def_val;
- break;
- case PLUGIN_VAR_BOOL:
- src= &((thdvar_bool_t*) plugin_var)->def_val;
- break;
- case PLUGIN_VAR_STR:
- src= &((thdvar_str_t*) plugin_var)->def_val;
- break;
- default:
- DBUG_ASSERT(0);
- }
- }
-
- /* thd must equal current_thd if PLUGIN_VAR_THDLOCAL flag is set */
- DBUG_ASSERT(!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ||
- thd == current_thd);
-
- if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || type == OPT_GLOBAL)
- {
- plugin_var->update(thd, plugin_var, tgt, src);
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- {
- pthread_mutex_unlock(&LOCK_global_system_variables);
- plugin_var->update(thd, plugin_var, tgt, src);
- }
+ return false;
}
-
-bool sys_var_pluginvar::update(THD *thd, set_var *var)
+bool sys_var_pluginvar::global_update(THD *thd, set_var *var)
{
- void *tgt;
-
- DBUG_ASSERT(is_readonly() || plugin_var->update);
+ DBUG_ASSERT(!is_readonly());
+ mysql_mutex_assert_owner(&LOCK_global_system_variables);
- /* thd must equal current_thd if PLUGIN_VAR_THDLOCAL flag is set */
- DBUG_ASSERT(!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ||
- thd == current_thd);
+ void *tgt= real_value_ptr(thd, var->type);
+ const void *src= &var->save_result;
- if (is_readonly())
- return 1;
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- tgt= real_value_ptr(thd, var->type);
-
- if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || var->type == OPT_GLOBAL)
+ if (!var->value)
{
- /* variable we are updating has global scope, so we unlock after updating */
- plugin_var->update(thd, plugin_var, tgt, &var->save_result);
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- {
- pthread_mutex_unlock(&LOCK_global_system_variables);
- plugin_var->update(thd, plugin_var, tgt, &var->save_result);
+ switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) {
+ case PLUGIN_VAR_INT:
+ src= &((sysvar_uint_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_LONG:
+ src= &((sysvar_ulong_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_LONGLONG:
+ src= &((sysvar_ulonglong_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_ENUM:
+ src= &((sysvar_enum_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_SET:
+ src= &((sysvar_set_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_BOOL:
+ src= &((sysvar_bool_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_STR:
+ src= &((sysvar_str_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
+ src= &((thdvar_uint_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL:
+ src= &((thdvar_ulong_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL:
+ src= &((thdvar_ulonglong_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
+ src= &((thdvar_enum_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
+ src= &((thdvar_set_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL:
+ src= &((thdvar_bool_t*) plugin_var)->def_val;
+ break;
+ case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL:
+ src= &((thdvar_str_t*) plugin_var)->def_val;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
}
- return 0;
+
+ plugin_var->update(thd, plugin_var, tgt, src);
+
+ return false;
}
@@ -2913,7 +2968,7 @@ static void plugin_opt_set_limits(struct my_option *options,
options->typelib= ((sysvar_set_t*) opt)->typelib;
options->def_value= ((sysvar_set_t*) opt)->def_val;
options->min_value= options->block_size= 0;
- options->max_value= (ULL(1) << options->typelib->count) - 1;
+ options->max_value= (1ULL << options->typelib->count) - 1;
break;
case PLUGIN_VAR_BOOL:
options->var_type= GET_BOOL;
@@ -2955,7 +3010,7 @@ static void plugin_opt_set_limits(struct my_option *options,
options->typelib= ((thdvar_set_t*) opt)->typelib;
options->def_value= ((thdvar_set_t*) opt)->def_val;
options->min_value= options->block_size= 0;
- options->max_value= (ULL(1) << options->typelib->count) - 1;
+ options->max_value= (1ULL << options->typelib->count) - 1;
break;
case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL:
options->var_type= GET_BOOL;
@@ -3026,40 +3081,49 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
DBUG_ENTER("construct_options");
- options[0].name= plugin_name_ptr= (char*) alloc_root(mem_root,
- plugin_name_len + 1);
+ plugin_name_ptr= (char*) alloc_root(mem_root, plugin_name_len + 1);
strcpy(plugin_name_ptr, plugin_name);
my_casedn_str(&my_charset_latin1, plugin_name_ptr);
convert_underscore_to_dash(plugin_name_ptr, plugin_name_len);
- /* support --skip-plugin-foo syntax */
- options[1].name= plugin_name_with_prefix_ptr= (char*) alloc_root(mem_root,
- plugin_name_len +
- plugin_dash.length + 1);
- strxmov(plugin_name_with_prefix_ptr, plugin_dash.str, options[0].name, NullS);
-
- options[0].id= options[1].id= 256; /* must be >255. dup id ok */
- options[0].var_type= options[1].var_type= GET_ENUM;
- options[0].arg_type= options[1].arg_type= OPT_ARG;
- options[0].def_value= options[1].def_value= 1; /* ON */
- options[0].typelib= options[1].typelib= &global_plugin_typelib;
-
- strxnmov(comment, max_comment_len, "Enable or disable ", plugin_name,
- " plugin. Possible values are ON, OFF, FORCE (don't start "
- "if the plugin fails to load).", NullS);
- options[0].comment= comment;
+ plugin_name_with_prefix_ptr= (char*) alloc_root(mem_root,
+ plugin_name_len +
+ plugin_dash.length + 1);
+ strxmov(plugin_name_with_prefix_ptr, plugin_dash.str, plugin_name_ptr, NullS);
+
+ if (tmp->load_option != PLUGIN_FORCE &&
+ tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ {
+ /* support --skip-plugin-foo syntax */
+ options[0].name= plugin_name_ptr;
+ options[1].name= plugin_name_with_prefix_ptr;
+ options[0].id= options[1].id= 0;
+ options[0].var_type= options[1].var_type= GET_ENUM;
+ options[0].arg_type= options[1].arg_type= OPT_ARG;
+ options[0].def_value= options[1].def_value= 1; /* ON */
+ options[0].typelib= options[1].typelib= &global_plugin_typelib;
+
+ strxnmov(comment, max_comment_len, "Enable or disable ", plugin_name,
+ " plugin. Possible values are ON, OFF, FORCE (don't start "
+ "if the plugin fails to load).", NullS);
+ options[0].comment= comment;
+ /*
+ Allocate temporary space for the value of the tristate.
+ This option will have a limited lifetime and is not used beyond
+ server initialization.
+ GET_ENUM value is an unsigned long integer.
+ */
+ options[0].value= options[1].value=
+ (uchar **)alloc_root(mem_root, sizeof(ulong));
+ *((ulong*) options[0].value)= (ulong) options[0].def_value;
- /*
- Allocate temporary space for the value of the tristate.
- This option will have a limited lifetime and is not used beyond
- server initialization.
- GET_ENUM value is a unsigned long integer.
- */
- options[0].value= options[1].value= (uchar **)alloc_root(mem_root,
- sizeof(ulong));
- *((ulong*) options[0].value)= *((ulong*) options[1].value)=
- (ulong) options[0].def_value;
+ options+= 2;
+ }
- options+= 2;
+ if (!my_strcasecmp(&my_charset_latin1, plugin_name_ptr, "NDBCLUSTER"))
+ {
+ plugin_name_ptr= const_cast<char*>("ndb"); // Use legacy "ndb" prefix
+ plugin_name_len= 3;
+ }
/*
Two passes as the 2nd pass will take pointer addresses for use
@@ -3207,7 +3271,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
options->name= optname;
options->comment= opt->comment;
options->app_type= opt;
- options->id= (options-1)->id + 1;
+ options->id= 0;
plugin_opt_set_limits(options, opt);
@@ -3248,13 +3312,20 @@ static my_option *construct_help_options(MEM_ROOT *mem_root,
bzero(opts, sizeof(my_option) * count);
+ /**
+ some plugin variables (those that don't have PLUGIN_VAR_NOSYSVAR flag)
+ have their names prefixed with the plugin name. Restore the names here
+ to get the correct (not double-prefixed) help text.
+ We won't need @@sysvars anymore and don't care about their proper names.
+ */
+ restore_pluginvar_names(p->system_vars);
+
if (construct_options(mem_root, p, opts))
DBUG_RETURN(NULL);
DBUG_RETURN(opts);
}
-
/**
Create and register system variables supplied from the plugin and
assigns initial values from corresponding command line arguments.
@@ -3279,18 +3350,17 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
int *argc, char **argv)
{
struct sys_var_chain chain= { NULL, NULL };
- my_bool can_disable;
bool disable_plugin;
- enum_plugin_load_policy plugin_load_policy= PLUGIN_ON;
+ enum_plugin_load_option plugin_load_option= tmp->load_option;
MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ?
&tmp->mem_root : &plugin_mem_root;
st_mysql_sys_var **opt;
my_option *opts= NULL;
+ LEX_STRING plugin_name;
char *varname;
int error;
- st_mysql_sys_var *o;
- sys_var *v;
+ sys_var *v __attribute__((unused));
struct st_bookmark *var;
uint len, count= EXTRA_OPTIONS;
DBUG_ENTER("test_plugin_options");
@@ -3302,7 +3372,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
*/
if (!(my_strcasecmp(&my_charset_latin1, tmp->name.str, "federated") &&
my_strcasecmp(&my_charset_latin1, tmp->name.str, "ndbcluster")))
- plugin_load_policy= PLUGIN_OFF;
+ plugin_load_option= PLUGIN_OFF;
for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
@@ -3326,9 +3396,11 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
We adjust the default value to account for the hardcoded exceptions
we have set for the federated and ndbcluster storage engines.
*/
- opts[0].def_value= opts[1].def_value= (int)plugin_load_policy;
+ if (tmp->load_option != PLUGIN_FORCE &&
+ tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ opts[0].def_value= opts[1].def_value= plugin_load_option;
- error= handle_options(argc, &argv, opts, get_one_plugin_option);
+ error= handle_options(argc, &argv, opts, NULL);
(*argc)++; /* add back one for the program name */
if (error)
@@ -3341,24 +3413,13 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
Set plugin loading policy from option value. First element in the option
list is always the <plugin name> option value.
*/
- plugin_load_policy= (enum_plugin_load_policy)*(ulong*)opts[0].value;
+ if (tmp->load_option != PLUGIN_FORCE &&
+ tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ plugin_load_option= (enum_plugin_load_option) *(ulong*) opts[0].value;
}
- disable_plugin= (plugin_load_policy == PLUGIN_OFF);
- /*
- The 'MyISAM' and 'Memory' storage engines currently can't be disabled.
- */
- can_disable=
- my_strcasecmp(&my_charset_latin1, tmp->name.str, "MyISAM") &&
- my_strcasecmp(&my_charset_latin1, tmp->name.str, "MEMORY");
-
- tmp->is_mandatory= (plugin_load_policy == PLUGIN_FORCE) || !can_disable;
-
- if (disable_plugin && !can_disable)
- {
- sql_print_warning("Plugin '%s' cannot be disabled", tmp->name.str);
- disable_plugin= FALSE;
- }
+ disable_plugin= (plugin_load_option == PLUGIN_OFF);
+ tmp->load_option= plugin_load_option;
/*
If the plugin is disabled it should not be initialized.
@@ -3373,34 +3434,37 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
DBUG_RETURN(1);
}
+ if (!my_strcasecmp(&my_charset_latin1, tmp->name.str, "NDBCLUSTER"))
+ {
+ plugin_name.str= const_cast<char*>("ndb"); // Use legacy "ndb" prefix
+ plugin_name.length= 3;
+ }
+ else
+ plugin_name= tmp->name;
+
error= 1;
for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
{
+ st_mysql_sys_var *o;
if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
continue;
- if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
- v= new (mem_root) sys_var_pluginvar(var->key + 1, o);
+ if ((var= find_bookmark(plugin_name.str, o->name, o->flags)))
+ v= new (mem_root) sys_var_pluginvar(&chain, var->key + 1, o);
else
{
- len= tmp->name.length + strlen(o->name) + 2;
+ len= plugin_name.length + strlen(o->name) + 2;
varname= (char*) alloc_root(mem_root, len);
- strxmov(varname, tmp->name.str, "-", o->name, NullS);
+ strxmov(varname, plugin_name.str, "-", o->name, NullS);
my_casedn_str(&my_charset_latin1, varname);
convert_dash_to_underscore(varname, len-1);
- v= new (mem_root) sys_var_pluginvar(varname, o);
+ v= new (mem_root) sys_var_pluginvar(&chain, varname, o);
}
DBUG_ASSERT(v); /* check that an object was actually constructed */
- /*
- Add to the chain of variables.
- Done like this for easier debugging so that the
- pointer to v is not lost on optimized builds.
- */
- v->chain_sys_var(&chain);
} /* end for */
if (chain.first)
{
chain.last->next = NULL;
- if (mysql_add_sys_var_chain(chain.first, NULL))
+ if (mysql_add_sys_var_chain(chain.first))
{
sql_print_error("Plugin '%s' has conflicting system variables",
tmp->name.str);
@@ -3421,49 +3485,26 @@ err:
Help Verbose text with Plugin System Variables
****************************************************************************/
-static int option_cmp(my_option *a, my_option *b)
-{
- return my_strcasecmp(&my_charset_latin1, a->name, b->name);
-}
-
-void my_print_help_inc_plugins(my_option *main_options, uint size)
+void add_plugin_options(DYNAMIC_ARRAY *options, MEM_ROOT *mem_root)
{
- DYNAMIC_ARRAY all_options;
struct st_plugin_int *p;
- MEM_ROOT mem_root;
my_option *opt;
- init_alloc_root(&mem_root, 4096, 4096);
- my_init_dynamic_array(&all_options, sizeof(my_option), size, size/4);
-
- if (initialized)
- for (uint idx= 0; idx < plugin_array.elements; idx++)
- {
- p= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
-
- if (!p->plugin->system_vars ||
- !(opt= construct_help_options(&mem_root, p)))
- continue;
-
- /* Only options with a non-NULL comment are displayed in help text */
- for (;opt->id; opt++)
- if (opt->comment)
- insert_dynamic(&all_options, (uchar*) opt);
- }
-
- for (;main_options->id; main_options++)
- insert_dynamic(&all_options, (uchar*) main_options);
-
- sort_dynamic(&all_options, (qsort_cmp) option_cmp);
+ if (!initialized)
+ return;
- /* main_options now points to the empty option terminator */
- insert_dynamic(&all_options, (uchar*) main_options);
+ for (uint idx= 0; idx < plugin_array.elements; idx++)
+ {
+ p= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
- my_print_help((my_option*) all_options.buffer);
- my_print_variables((my_option*) all_options.buffer);
+ if (!(opt= construct_help_options(mem_root, p)))
+ continue;
- delete_dynamic(&all_options);
- free_root(&mem_root, MYF(0));
+ /* Only options with a non-NULL comment are displayed in help text */
+ for (;opt->name; opt++)
+ if (opt->comment)
+ insert_dynamic(options, (uchar*) opt);
+ }
}
diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h
index 72984865807..0cbd5a519c1 100644
--- a/sql/sql_plugin.h
+++ b/sql/sql_plugin.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 MySQL AB
+/* Copyright (C) 2005 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -16,7 +16,35 @@
#ifndef _sql_plugin_h
#define _sql_plugin_h
+/*
+ the following #define adds server-only members to enum_mysql_show_type,
+ that is defined in plugin.h
+*/
+#define SHOW_always_last SHOW_KEY_CACHE_LONG, \
+ SHOW_KEY_CACHE_LONGLONG, SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, \
+ SHOW_HAVE, SHOW_MY_BOOL, SHOW_HA_ROWS, SHOW_SYS, \
+ SHOW_LONG_NOFLUSH, SHOW_LONGLONG_STATUS, SHOW_LEX_STRING
+#include <mysql/plugin.h>
+#undef SHOW_always_last
+
+#include "m_string.h" /* LEX_STRING */
+#include "my_alloc.h" /* MEM_ROOT */
+
class sys_var;
+enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED};
+enum enum_plugin_load_option { PLUGIN_OFF, PLUGIN_ON, PLUGIN_FORCE,
+ PLUGIN_FORCE_PLUS_PERMANENT };
+extern const char *global_plugin_typelib_names[];
+
+#include <my_sys.h>
+
+#ifdef DBUG_OFF
+#define plugin_ref_to_int(A) A
+#define plugin_int_to_ref(A) A
+#else
+#define plugin_ref_to_int(A) (A ? A[0] : NULL)
+#define plugin_int_to_ref(A) &(A)
+#endif
/*
the following flags are valid for plugin_init()
@@ -27,18 +55,9 @@ class sys_var;
#define INITIAL_LEX_PLUGIN_LIST_SIZE 16
-/*
- the following #define adds server-only members to enum_mysql_show_type,
- that is defined in plugin.h
-*/
-#define SHOW_FUNC SHOW_FUNC, SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_LONGLONG, \
- SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, SHOW_HAVE, \
- SHOW_MY_BOOL, SHOW_HA_ROWS, SHOW_SYS, SHOW_LONG_NOFLUSH, \
- SHOW_LONGLONG_STATUS
-#include <mysql/plugin.h>
-#undef SHOW_FUNC
typedef enum enum_mysql_show_type SHOW_TYPE;
typedef struct st_mysql_show_var SHOW_VAR;
+typedef struct st_mysql_lex_string LEX_STRING;
#define MYSQL_ANY_PLUGIN -1
@@ -79,7 +98,7 @@ struct st_plugin_int
void *data; /* plugin type specific, e.g. handlerton */
MEM_ROOT mem_root; /* memory for dynamic plugin structures */
sys_var *system_vars; /* server variables for this plugin */
- bool is_mandatory; /* If true then plugin must not fail to load */
+ enum enum_plugin_load_option load_option; /* OFF, ON, FORCE, F+PERMANENT */
};
@@ -94,6 +113,7 @@ typedef struct st_plugin_int *plugin_ref;
#define plugin_data(pi,cast) ((cast)((pi)->data))
#define plugin_name(pi) (&((pi)->name))
#define plugin_state(pi) ((pi)->state)
+#define plugin_load_option(pi) ((pi)->load_option)
#define plugin_equals(p1,p2) ((p1) == (p2))
#else
typedef struct st_plugin_int **plugin_ref;
@@ -102,6 +122,7 @@ typedef struct st_plugin_int **plugin_ref;
#define plugin_data(pi,cast) ((cast)((pi)[0]->data))
#define plugin_name(pi) (&((pi)[0]->name))
#define plugin_state(pi) ((pi)[0]->state)
+#define plugin_load_option(pi) ((pi)[0]->load_option)
#define plugin_equals(p1,p2) ((p1) && (p2) && (p1)[0] == (p2)[0])
#endif
@@ -114,15 +135,15 @@ extern const LEX_STRING plugin_type_names[];
extern int plugin_init(int *argc, char **argv, int init_flags);
extern void plugin_shutdown(void);
-extern void my_print_help_inc_plugins(struct my_option *options, uint size);
+void add_plugin_options(DYNAMIC_ARRAY *options, MEM_ROOT *mem_root);
extern bool plugin_is_ready(const LEX_STRING *name, int type);
-#define my_plugin_lock_by_name(A,B,C) plugin_lock_by_name(A,B,C CALLER_INFO)
-#define my_plugin_lock_by_name_ci(A,B,C) plugin_lock_by_name(A,B,C ORIG_CALLER_INFO)
-#define my_plugin_lock(A,B) plugin_lock(A,B CALLER_INFO)
-#define my_plugin_lock_ci(A,B) plugin_lock(A,B ORIG_CALLER_INFO)
-extern plugin_ref plugin_lock(THD *thd, plugin_ref *ptr CALLER_INFO_PROTO);
+#define my_plugin_lock_by_name(A,B,C) plugin_lock_by_name(A,B,C)
+#define my_plugin_lock_by_name_ci(A,B,C) plugin_lock_by_name(A,B,C)
+#define my_plugin_lock(A,B) plugin_lock(A,B)
+#define my_plugin_lock_ci(A,B) plugin_lock(A,B)
+extern plugin_ref plugin_lock(THD *thd, plugin_ref *ptr);
extern plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name,
- int type CALLER_INFO_PROTO);
+ int type);
extern void plugin_unlock(THD *thd, plugin_ref plugin);
extern void plugin_unlock_list(THD *thd, plugin_ref *list, uint count);
extern bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
@@ -131,6 +152,7 @@ extern bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name);
extern bool plugin_register_builtin(struct st_mysql_plugin *plugin);
extern void plugin_thdvar_init(THD *thd);
extern void plugin_thdvar_cleanup(THD *thd);
+extern SHOW_COMP_OPTION plugin_status(const char *name, int len, size_t type);
extern bool check_valid_path(const char *path, size_t length);
typedef my_bool (plugin_foreach_func)(THD *thd,
diff --git a/sql/sql_plugin_services.h b/sql/sql_plugin_services.h
new file mode 100644
index 00000000000..f39e22f1e21
--- /dev/null
+++ b/sql/sql_plugin_services.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* support for Services */
+#include <service_versions.h>
+
+struct st_service_ref {
+ const char *name;
+ uint version;
+ void *service;
+};
+
+static struct my_snprintf_service_st my_snprintf_handler = {
+ my_snprintf,
+ my_vsnprintf
+};
+
+static struct thd_alloc_service_st thd_alloc_handler= {
+ thd_alloc,
+ thd_calloc,
+ thd_strdup,
+ thd_strmake,
+ thd_memdup,
+ thd_make_lex_string
+};
+
+static struct thd_wait_service_st thd_wait_handler= {
+ thd_wait_begin,
+ thd_wait_end
+};
+
+static struct my_thread_scheduler_service my_thread_scheduler_handler= {
+ my_thread_scheduler_set,
+ my_thread_scheduler_reset,
+};
+
+
+static struct st_service_ref list_of_services[]=
+{
+ { "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler },
+ { "thd_alloc_service", VERSION_thd_alloc, &thd_alloc_handler },
+ { "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
+ { "my_thread_scheduler_service",
+ VERSION_my_thread_scheduler, &my_thread_scheduler_handler },
+};
+
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 5ba375f9710..4a1d1ae7fe3 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995-2002 MySQL AB
+/* Copyright (C) 1995-2002 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -83,18 +83,36 @@ When one supplies long data for a placeholder:
at statement execute.
*/
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_class.h" // set_var.h: THD
+#include "set_var.h"
+#include "sql_prepare.h"
+#include "sql_parse.h" // insert_precheck, update_precheck, delete_precheck
+#include "sql_base.h" // open_normal_and_derived_tables
+#include "sql_cache.h" // query_cache_*
+#include "sql_view.h" // create_view_precheck
+#include "sql_delete.h" // mysql_prepare_delete
#include "sql_select.h" // for JOIN
+#include "sql_insert.h" // upgrade_lock_type_for_insert, mysql_prepare_insert
+#include "sql_update.h" // mysql_prepare_update
+#include "sql_db.h" // mysql_opt_change_db, mysql_change_db
+#include "sql_acl.h" // *_ACL
+#include "sql_derived.h" // mysql_derived_prepare,
+ // mysql_handle_derived
#include "sql_cursor.h"
#include "sp_head.h"
#include "sp.h"
#include "sp_cache.h"
+#include "probes_mysql.h"
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
#include <mysql.h>
#else
#include <mysql_com.h>
#endif
+#include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL
/**
A result class used to send cursor rows using the binary protocol.
@@ -105,7 +123,7 @@ class Select_fetch_protocol_binary: public select_send
Protocol_binary protocol;
public:
Select_fetch_protocol_binary(THD *thd);
- virtual bool send_fields(List<Item> &list, uint flags);
+ virtual bool send_result_set_metadata(List<Item> &list, uint flags);
virtual bool send_data(List<Item> &items);
virtual bool send_eof();
#ifdef EMBEDDED_LIBRARY
@@ -134,6 +152,7 @@ public:
THD *thd;
Select_fetch_protocol_binary result;
Item_param **param_array;
+ Server_side_cursor *cursor;
uint param_count;
uint last_errno;
uint flags;
@@ -162,6 +181,7 @@ public:
bool execute_loop(String *expanded_query,
bool open_cursor,
uchar *packet_arg, uchar *packet_end_arg);
+ bool execute_server_runnable(Server_runnable *server_runnable);
/* Destroy this statement */
void deallocate();
private:
@@ -170,8 +190,6 @@ private:
SELECT_LEX and other classes).
*/
MEM_ROOT main_mem_root;
- /* Version of the stored functions cache at the time of prepare. */
- ulong m_sp_cache_version;
private:
bool set_db(const char *db, uint db_length);
bool set_parameters(String *expanded_query,
@@ -182,6 +200,78 @@ private:
void swap_prepared_statement(Prepared_statement *copy);
};
+/**
+ Execute one SQL statement in an isolated context.
+*/
+
+class Execute_sql_statement: public Server_runnable
+{
+public:
+ Execute_sql_statement(LEX_STRING sql_text);
+ virtual bool execute_server_code(THD *thd);
+private:
+ LEX_STRING m_sql_text;
+};
+
+
+class Ed_connection;
+
+/**
+ Protocol_local: a helper class to intercept the result
+ of the data written to the network.
+*/
+
+class Protocol_local :public Protocol
+{
+public:
+ Protocol_local(THD *thd, Ed_connection *ed_connection);
+ ~Protocol_local() { free_root(&m_rset_root, MYF(0)); }
+protected:
+ virtual void prepare_for_resend();
+ virtual bool write();
+ virtual bool store_null();
+ virtual bool store_tiny(longlong from);
+ virtual bool store_short(longlong from);
+ virtual bool store_long(longlong from);
+ virtual bool store_longlong(longlong from, bool unsigned_flag);
+ virtual bool store_decimal(const my_decimal *);
+ virtual bool store(const char *from, size_t length, CHARSET_INFO *cs);
+ virtual bool store(const char *from, size_t length,
+ CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
+ virtual bool store(MYSQL_TIME *time);
+ virtual bool store_date(MYSQL_TIME *time);
+ virtual bool store_time(MYSQL_TIME *time);
+ virtual bool store(float value, uint32 decimals, String *buffer);
+ virtual bool store(double value, uint32 decimals, String *buffer);
+ virtual bool store(Field *field);
+
+ virtual bool send_result_set_metadata(List<Item> *list, uint flags);
+ virtual bool send_out_parameters(List<Item_param> *sp_params);
+#ifdef EMBEDDED_LIBRARY
+ void remove_last_row();
+#endif
+ virtual enum enum_protocol_type type() { return PROTOCOL_LOCAL; };
+
+ virtual bool send_ok(uint server_status, uint statement_warn_count,
+ ulonglong affected_rows, ulonglong last_insert_id,
+ const char *message);
+
+ virtual bool send_eof(uint server_status, uint statement_warn_count);
+ virtual bool send_error(uint sql_errno, const char *err_msg, const char* sqlstate);
+private:
+ bool store_string(const char *str, size_t length,
+ CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs);
+
+ bool store_column(const void *data, size_t length);
+ void opt_add_row_to_rset();
+private:
+ Ed_connection *m_connection;
+ MEM_ROOT m_rset_root;
+ List<Ed_row> *m_rset;
+ size_t m_column_count;
+ Ed_column *m_current_row;
+ Ed_column *m_current_column;
+};
/******************************************************************************
Implementation
@@ -249,7 +339,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
int2store(buff+5, columns);
int2store(buff+7, stmt->param_count);
buff[9]= 0; // Guard against a 4.1 client
- tmp= min(stmt->thd->total_warn_count, 65535);
+ tmp= min(stmt->thd->warning_info->statement_warn_count(), 65535);
int2store(buff+10, tmp);
/*
@@ -259,14 +349,14 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
error= my_net_write(net, buff, sizeof(buff));
if (stmt->param_count && ! error)
{
- error= thd->protocol_text.send_fields((List<Item> *)
+ error= thd->protocol_text.send_result_set_metadata((List<Item> *)
&stmt->lex->param_list,
Protocol::SEND_EOF);
}
if (!error)
/* Flag that a response has already been sent */
- thd->main_da.disable_status();
+ thd->stmt_da->disable_status();
DBUG_RETURN(error);
}
@@ -279,7 +369,7 @@ static bool send_prep_stmt(Prepared_statement *stmt,
thd->client_stmt_id= stmt->id;
thd->client_param_count= stmt->param_count;
thd->clear_error();
- thd->main_da.disable_status();
+ thd->stmt_da->disable_status();
return 0;
}
@@ -1058,9 +1148,9 @@ static bool insert_params_from_vars(Prepared_statement *stmt,
{
Item_param *param= *it;
varname= var_it++;
- entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
- (uchar*) varname->str,
- varname->length);
+ entry= (user_var_entry*)my_hash_search(&stmt->thd->user_vars,
+ (uchar*) varname->str,
+ varname->length);
if (param->set_from_user_var(stmt->thd, entry) ||
param->convert_str_value(stmt->thd))
DBUG_RETURN(1);
@@ -1095,7 +1185,7 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
uint32 length= 0;
THD *thd= stmt->thd;
- DBUG_ENTER("insert_params_from_vars");
+ DBUG_ENTER("insert_params_from_vars_with_log");
if (query->copy(stmt->query(), stmt->query_length(), default_charset_info))
DBUG_RETURN(1);
@@ -1105,8 +1195,8 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
Item_param *param= *it;
varname= var_it++;
- entry= (user_var_entry *) hash_search(&thd->user_vars, (uchar*) varname->str,
- varname->length);
+ entry= (user_var_entry *) my_hash_search(&thd->user_vars, (uchar*)
+ varname->str, varname->length);
/*
We have to call the setup_one_conversion_function() here to set
the parameter's members that might be needed further
@@ -1163,7 +1253,8 @@ static bool mysql_test_insert(Prepared_statement *stmt,
If we would use locks, then we have to ensure we are not using
TL_WRITE_DELAYED as having two such locks can cause table corruption.
*/
- if (open_normal_and_derived_tables(thd, table_list, 0))
+ if (open_normal_and_derived_tables(thd, table_list,
+ MYSQL_OPEN_FORCE_SHARED_MDL))
goto error;
if ((values= its++))
@@ -1244,7 +1335,7 @@ static int mysql_test_update(Prepared_statement *stmt,
DBUG_ENTER("mysql_test_update");
if (update_precheck(thd, table_list) ||
- open_tables(thd, &table_list, &table_count, 0))
+ open_tables(thd, &table_list, &table_count, MYSQL_OPEN_FORCE_SHARED_MDL))
goto error;
if (table_list->multitable_view)
@@ -1321,7 +1412,8 @@ static bool mysql_test_delete(Prepared_statement *stmt,
DBUG_ENTER("mysql_test_delete");
if (delete_precheck(thd, table_list) ||
- open_normal_and_derived_tables(thd, table_list, 0))
+ open_normal_and_derived_tables(thd, table_list,
+ MYSQL_OPEN_FORCE_SHARED_MDL))
goto error;
if (!table_list->table)
@@ -1367,10 +1459,10 @@ static int mysql_test_select(Prepared_statement *stmt,
ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
if (tables)
{
- if (check_table_access(thd, privilege, tables, UINT_MAX, FALSE))
+ if (check_table_access(thd, privilege, tables, FALSE, UINT_MAX, FALSE))
goto error;
}
- else if (check_access(thd, privilege, any_db,0,0,0,0))
+ else if (check_access(thd, privilege, any_db, NULL, NULL, 0, 0))
goto error;
if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
@@ -1379,7 +1471,7 @@ static int mysql_test_select(Prepared_statement *stmt,
goto error;
}
- if (open_normal_and_derived_tables(thd, tables, 0))
+ if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
goto error;
thd->used_tables= 0; // Updated by setup_fields
@@ -1405,7 +1497,7 @@ static int mysql_test_select(Prepared_statement *stmt,
unit->prepare call above.
*/
if (send_prep_stmt(stmt, lex->result->field_count(fields)) ||
- lex->result->send_fields(fields, Protocol::SEND_EOF) ||
+ lex->result->send_result_set_metadata(fields, Protocol::SEND_EOF) ||
thd->protocol->flush())
goto error;
DBUG_RETURN(2);
@@ -1436,10 +1528,11 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
THD *thd= stmt->thd;
DBUG_ENTER("mysql_test_do_fields");
- if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
+ if (tables && check_table_access(thd, SELECT_ACL, tables, FALSE,
+ UINT_MAX, FALSE))
DBUG_RETURN(TRUE);
- if (open_normal_and_derived_tables(thd, tables, 0))
+ if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
DBUG_RETURN(TRUE);
DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
}
@@ -1467,8 +1560,9 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
THD *thd= stmt->thd;
set_var_base *var;
- if ((tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
- || open_normal_and_derived_tables(thd, tables, 0))
+ if ((tables && check_table_access(thd, SELECT_ACL, tables, FALSE,
+ UINT_MAX, FALSE)) ||
+ open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
goto error;
while ((var= it++))
@@ -1503,8 +1597,9 @@ static bool mysql_test_call_fields(Prepared_statement *stmt,
THD *thd= stmt->thd;
Item *item;
- if ((tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE)) ||
- open_normal_and_derived_tables(thd, tables, 0))
+ if ((tables && check_table_access(thd, SELECT_ACL, tables, FALSE,
+ UINT_MAX, FALSE)) ||
+ open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
goto err;
while ((item= it++))
@@ -1587,7 +1682,8 @@ select_like_stmt_test_with_open(Prepared_statement *stmt,
prepared EXPLAIN yet so derived tables will clean up after
themself.
*/
- if (open_normal_and_derived_tables(stmt->thd, tables, 0))
+ if (open_normal_and_derived_tables(stmt->thd, tables,
+ MYSQL_OPEN_FORCE_SHARED_MDL))
DBUG_RETURN(TRUE);
DBUG_RETURN(select_like_stmt_test(stmt, specific_prepare,
@@ -1614,35 +1710,32 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
LEX *lex= stmt->lex;
SELECT_LEX *select_lex= &lex->select_lex;
bool res= FALSE;
- /* Skip first table, which is the table we are creating */
bool link_to_local;
- TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
- TABLE_LIST *tables= lex->query_tables;
+ TABLE_LIST *create_table= lex->query_tables;
+ TABLE_LIST *tables= lex->create_last_non_select_table->next_global;
if (create_table_precheck(thd, tables, create_table))
DBUG_RETURN(TRUE);
if (select_lex->item_list.elements)
{
+ /* Base table and temporary table are not in the same name space. */
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
- {
- lex->link_first_table_back(create_table, link_to_local);
- create_table->create= TRUE;
- /* Base table and temporary table are not in the same name space. */
- create_table->skip_temporary= true;
- }
+ create_table->open_type= OT_BASE_ONLY;
- if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
+ if (open_normal_and_derived_tables(stmt->thd, lex->query_tables,
+ MYSQL_OPEN_FORCE_SHARED_MDL))
DBUG_RETURN(TRUE);
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
- create_table= lex->unlink_first_table(&link_to_local);
-
select_lex->context.resolve_in_select_list= TRUE;
+ lex->unlink_first_table(&link_to_local);
+
res= select_like_stmt_test(stmt, 0, 0);
+
+ lex->link_first_table_back(create_table, link_to_local);
}
- else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
+ else
{
/*
Check that the source table exist, and also record
@@ -1650,12 +1743,11 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
we validate metadata of all CREATE TABLE statements,
which keeps metadata validation code simple.
*/
- if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
+ if (open_normal_and_derived_tables(stmt->thd, lex->query_tables,
+ MYSQL_OPEN_FORCE_SHARED_MDL))
DBUG_RETURN(TRUE);
}
- /* put tables back for PS rexecuting */
- lex->link_first_table_back(create_table, link_to_local);
DBUG_RETURN(res);
}
@@ -1685,7 +1777,7 @@ static bool mysql_test_create_view(Prepared_statement *stmt)
if (create_view_precheck(thd, tables, view, lex->create_view_mode))
goto err;
- if (open_normal_and_derived_tables(thd, tables, 0))
+ if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
goto err;
lex->view_prepare_mode= 1;
@@ -1867,6 +1959,10 @@ static bool check_prepared_statement(Prepared_statement *stmt)
lex->select_lex.context.resolve_in_table_list_only(select_lex->
get_table_list());
+ /* Reset warning count for each query that uses tables */
+ if (tables)
+ thd->warning_info->opt_clear_warning_info(thd->query_id);
+
switch (sql_command) {
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
@@ -1948,30 +2044,6 @@ static bool check_prepared_statement(Prepared_statement *stmt)
Note that we don't need to have cases in this list if they are
marked with CF_STATUS_COMMAND in sql_command_flags
*/
- case SQLCOM_SHOW_PROCESSLIST:
- case SQLCOM_SHOW_STORAGE_ENGINES:
- case SQLCOM_SHOW_PRIVILEGES:
- case SQLCOM_SHOW_COLUMN_TYPES:
- case SQLCOM_SHOW_ENGINE_LOGS:
- case SQLCOM_SHOW_ENGINE_STATUS:
- case SQLCOM_SHOW_ENGINE_MUTEX:
- case SQLCOM_SHOW_CREATE_DB:
- case SQLCOM_SHOW_GRANTS:
- case SQLCOM_SHOW_BINLOG_EVENTS:
- case SQLCOM_SHOW_MASTER_STAT:
- case SQLCOM_SHOW_SLAVE_STAT:
- case SQLCOM_SHOW_CREATE_PROC:
- case SQLCOM_SHOW_CREATE_FUNC:
- case SQLCOM_SHOW_CREATE_EVENT:
- case SQLCOM_SHOW_CREATE_TRIGGER:
- case SQLCOM_SHOW_CREATE:
- case SQLCOM_SHOW_PROC_CODE:
- case SQLCOM_SHOW_FUNC_CODE:
- case SQLCOM_SHOW_AUTHORS:
- case SQLCOM_SHOW_CONTRIBUTORS:
- case SQLCOM_SHOW_WARNS:
- case SQLCOM_SHOW_ERRORS:
- case SQLCOM_SHOW_BINLOGS:
case SQLCOM_DROP_TABLE:
case SQLCOM_RENAME_TABLE:
case SQLCOM_ALTER_TABLE:
@@ -2094,7 +2166,6 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length)
{
Protocol *save_protocol= thd->protocol;
Prepared_statement *stmt;
- bool error;
DBUG_ENTER("mysqld_stmt_prepare");
DBUG_PRINT("prep_query", ("%s", packet));
@@ -2114,22 +2185,9 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length)
DBUG_VOID_RETURN;
}
- /* Reset warnings from previous command */
- mysql_reset_errors(thd, 0);
- sp_cache_flush_obsolete(&thd->sp_proc_cache);
- sp_cache_flush_obsolete(&thd->sp_func_cache);
-
thd->protocol= &thd->protocol_binary;
- if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),QUERY_PRIOR);
-
- error= stmt->prepare(packet, packet_length);
-
- if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),WAIT_PRIOR);
-
- if (error)
+ if (stmt->prepare(packet, packet_length))
{
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
@@ -2179,9 +2237,9 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
convert it for error messages to be uniform.
*/
if ((entry=
- (user_var_entry*)hash_search(&thd->user_vars,
- (uchar*)lex->prepared_stmt_code.str,
- lex->prepared_stmt_code.length))
+ (user_var_entry*)my_hash_search(&thd->user_vars,
+ (uchar*)lex->prepared_stmt_code.str,
+ lex->prepared_stmt_code.length))
&& entry->value)
{
my_bool is_var_null;
@@ -2409,6 +2467,13 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
{
tables->reinit_before_use(thd);
}
+
+ /* Reset MDL tickets for procedures/functions */
+ for (Sroutine_hash_entry *rt=
+ (Sroutine_hash_entry*)thd->lex->sroutines_list.first;
+ rt; rt= rt->next)
+ rt->mdl_request.ticket= NULL;
+
/*
Cleanup of the special case of DELETE t1, t2 FROM t1, t2, t3 ...
(multi-delete). We do a full clean up, although at the moment all we
@@ -2496,15 +2561,12 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
DBUG_VOID_RETURN;
}
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
thd->profiling.set_query_source(stmt->query(), stmt->query_length());
#endif
DBUG_PRINT("exec_query", ("%s", stmt->query()));
DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
- sp_cache_flush_obsolete(&thd->sp_proc_cache);
- sp_cache_flush_obsolete(&thd->sp_func_cache);
-
open_cursor= test(flags & (ulong) CURSOR_TYPE_READ_ONLY);
thd->protocol= &thd->protocol_binary;
@@ -2515,7 +2577,6 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio););
DBUG_VOID_RETURN;
-
}
@@ -2606,18 +2667,11 @@ void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length)
thd->stmt_arena= stmt;
thd->set_n_backup_statement(stmt, &stmt_backup);
- if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(), QUERY_PRIOR);
-
cursor->fetch(num_rows);
- if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(), WAIT_PRIOR);
-
if (!cursor->is_open())
{
stmt->close_cursor();
- thd->cursor= 0;
reset_stmt_params(stmt);
}
@@ -2695,7 +2749,7 @@ void mysqld_stmt_close(THD *thd, char *packet)
Prepared_statement *stmt;
DBUG_ENTER("mysqld_stmt_close");
- thd->main_da.disable_status();
+ thd->stmt_da->disable_status();
if (!(stmt= find_prepared_statement(thd, stmt_id)))
DBUG_VOID_RETURN;
@@ -2770,7 +2824,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
status_var_increment(thd->status_var.com_stmt_send_long_data);
- thd->main_da.disable_status();
+ thd->stmt_da->disable_status();
#ifndef EMBEDDED_LIBRARY
/* Minimal size of long data packet is 6 bytes */
if (packet_length < MYSQL_LONG_DATA_HEADER)
@@ -2824,19 +2878,19 @@ Select_fetch_protocol_binary::Select_fetch_protocol_binary(THD *thd_arg)
:protocol(thd_arg)
{}
-bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags)
+bool Select_fetch_protocol_binary::send_result_set_metadata(List<Item> &list, uint flags)
{
bool rc;
Protocol *save_protocol= thd->protocol;
/*
- Protocol::send_fields caches the information about column types:
+ Protocol::send_result_set_metadata caches the information about column types:
this information is later used to send data. Therefore, the same
dedicated Protocol object must be used for all operations with
a cursor.
*/
thd->protocol= &protocol;
- rc= select_send::send_fields(list, flags);
+ rc= select_send::send_result_set_metadata(list, flags);
thd->protocol= save_protocol;
return rc;
@@ -2844,8 +2898,15 @@ bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags)
bool Select_fetch_protocol_binary::send_eof()
{
+ /*
+ Don't send EOF if we're in error condition (which implies we've already
+ sent or are sending an error)
+ */
+ if (thd->is_error())
+ return true;
+
::my_eof(thd);
- return FALSE;
+ return false;
}
@@ -2861,6 +2922,90 @@ Select_fetch_protocol_binary::send_data(List<Item> &fields)
return rc;
}
+/*******************************************************************
+* Reprepare_observer
+*******************************************************************/
+/** Push an error to the error stack and return TRUE for now. */
+
+bool
+Reprepare_observer::report_error(THD *thd)
+{
+ /*
+ This 'error' is purely internal to the server:
+ - No exception handler is invoked,
+ - No condition is added in the condition area (warn_list).
+ The diagnostics area is set to an error status to enforce
+ that this thread execution stops and returns to the caller,
+ backtracking all the way to Prepared_statement::execute_loop().
+ */
+ thd->stmt_da->set_error_status(thd, ER_NEED_REPREPARE,
+ ER(ER_NEED_REPREPARE), "HY000");
+ m_invalidated= TRUE;
+
+ return TRUE;
+}
+
+
+/*******************************************************************
+* Server_runnable
+*******************************************************************/
+
+Server_runnable::~Server_runnable()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+Execute_sql_statement::
+Execute_sql_statement(LEX_STRING sql_text)
+ :m_sql_text(sql_text)
+{}
+
+
+/**
+ Parse and execute a statement. Does not prepare the query.
+
+ Allows to execute a statement from within another statement.
+ The main property of the implementation is that it does not
+ affect the environment -- i.e. you can run many
+ executions without having to cleanup/reset THD in between.
+*/
+
+bool
+Execute_sql_statement::execute_server_code(THD *thd)
+{
+ bool error;
+
+ if (alloc_query(thd, m_sql_text.str, m_sql_text.length))
+ return TRUE;
+
+ Parser_state parser_state;
+ if (parser_state.init(thd, thd->query(), thd->query_length()))
+ return TRUE;
+
+ parser_state.m_lip.multi_statements= FALSE;
+ lex_start(thd);
+
+ error= parse_sql(thd, &parser_state, NULL) || thd->is_error();
+
+ if (error)
+ goto end;
+
+ thd->lex->set_trg_event_type_for_tables();
+
+ error= mysql_execute_command(thd);
+
+ /* report error issued during command execution */
+ if (error == 0 && thd->spcont == NULL)
+ general_log_write(thd, COM_STMT_EXECUTE,
+ thd->query(), thd->query_length());
+
+end:
+ lex_end(thd->lex);
+
+ return error;
+}
+
/***************************************************************************
Prepared_statement
****************************************************************************/
@@ -2871,10 +3016,10 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
thd(thd_arg),
result(thd_arg),
param_array(0),
+ cursor(0),
param_count(0),
last_errno(0),
- flags((uint) IS_IN_USE),
- m_sp_cache_version(0)
+ flags((uint) IS_IN_USE)
{
init_sql_alloc(&main_mem_root, thd_arg->variables.query_alloc_block_size,
thd_arg->variables.query_prealloc_size);
@@ -2958,12 +3103,8 @@ void Prepared_statement::cleanup_stmt()
DBUG_ENTER("Prepared_statement::cleanup_stmt");
DBUG_PRINT("enter",("stmt: 0x%lx", (long) this));
- DBUG_ASSERT(lex->sphead == 0);
- /* The order is important */
- lex->unit.cleanup();
cleanup_items(free_list);
thd->cleanup_after_query();
- close_thread_tables(thd);
thd->rollback_item_tree_changes();
DBUG_VOID_RETURN;
@@ -3079,6 +3220,8 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
}
parser_state.m_lip.stmt_prepare_mode= TRUE;
+ parser_state.m_lip.multi_statements= FALSE;
+
lex_start(thd);
error= parse_sql(thd, & parser_state, NULL) ||
@@ -3103,6 +3246,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
*/
DBUG_ASSERT(thd->change_list.is_empty());
+ /*
+ Marker used to release metadata locks acquired while the prepared
+ statement is being checked.
+ */
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
+
/*
The only case where we should have items in the thd->free_list is
after stmt->set_params_from_vars(), which may in some cases create
@@ -3118,12 +3267,14 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
to PREPARE stmt FROM "CREATE PROCEDURE ..."
*/
DBUG_ASSERT(lex->sphead == NULL || error != 0);
- if (lex->sphead)
- {
- delete lex->sphead;
- lex->sphead= NULL;
- }
+ /* The order is important */
+ lex->unit.cleanup();
+
+ /* No need to commit statement transaction, it's not started. */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ close_thread_tables(thd);
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
lex_end(lex);
cleanup_stmt();
thd->restore_backup_statement(this, &stmt_backup);
@@ -3135,20 +3286,6 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
init_stmt_after_parse(lex);
state= Query_arena::PREPARED;
flags&= ~ (uint) IS_IN_USE;
- /*
- This is for prepared statement validation purposes.
- A statement looks up and pre-loads all its stored functions
- at prepare. Later on, if a function is gone from the cache,
- execute may fail.
- Remember the cache version to be able to invalidate the prepared
- statement at execute if it changes.
- We only need to care about version of the stored functions cache:
- if a prepared statement uses a stored procedure, it's indirect,
- via a stored function. The only exception is SQLCOM_CALL,
- but the latter one looks up the stored procedure each time
- it's invoked, rather than once at prepare.
- */
- m_sp_cache_version= sp_cache_version(&thd->sp_func_cache);
/*
Log COM_EXECUTE to the general log. Note, that in case of SQL
@@ -3246,11 +3383,6 @@ Prepared_statement::set_parameters(String *expanded_query,
and execute of a new statement. If this happens repeatedly
more than MAX_REPREPARE_ATTEMPTS times, we give up.
- In future we need to be able to keep the metadata locks between
- prepare and execute, but right now open_and_lock_tables(), as
- well as close_thread_tables() are buried deep inside
- execution code (mysql_execute_command()).
-
@return TRUE if an error, FALSE if success
@retval TRUE either MAX_REPREPARE_ATTEMPTS has been reached,
or some general error
@@ -3295,21 +3427,15 @@ reexecute:
thd->m_reprepare_observer = &reprepare_observer;
}
- if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),QUERY_PRIOR);
-
error= execute(expanded_query, open_cursor) || thd->is_error();
- if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(), WAIT_PRIOR);
-
thd->m_reprepare_observer= NULL;
if (error && !thd->is_fatal_error && !thd->killed &&
reprepare_observer.is_invalidated() &&
reprepare_attempt++ < MAX_REPREPARE_ATTEMPTS)
{
- DBUG_ASSERT(thd->main_da.sql_errno() == ER_NEED_REPREPARE);
+ DBUG_ASSERT(thd->stmt_da->sql_errno() == ER_NEED_REPREPARE);
thd->clear_error();
error= reprepare();
@@ -3323,6 +3449,40 @@ reexecute:
}
+bool
+Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
+{
+ Statement stmt_backup;
+ bool error;
+ Query_arena *save_stmt_arena= thd->stmt_arena;
+ Item_change_list save_change_list;
+ thd->change_list.move_elements_to(&save_change_list);
+
+ state= CONVENTIONAL_EXECUTION;
+
+ if (!(lex= new (mem_root) st_lex_local))
+ return TRUE;
+
+ thd->set_n_backup_statement(this, &stmt_backup);
+ thd->set_n_backup_active_arena(this, &stmt_backup);
+ thd->stmt_arena= this;
+
+ error= server_runnable->execute_server_code(thd);
+
+ thd->cleanup_after_query();
+
+ thd->restore_active_arena(this, &stmt_backup);
+ thd->restore_backup_statement(this, &stmt_backup);
+ thd->stmt_arena= save_stmt_arena;
+
+ save_change_list.move_elements_to(&thd->change_list);
+
+ /* Items and memory will freed in destructor */
+
+ return error;
+}
+
+
/**
Reprepare this prepared statement.
@@ -3372,12 +3532,12 @@ Prepared_statement::reprepare()
#endif
/*
Clear possible warnings during reprepare, it has to be completely
- transparent to the user. We use mysql_reset_errors() since
+ transparent to the user. We use clear_warning_info() since
there were no separate query id issued for re-prepare.
Sic: we can't simply silence warnings during reprepare, because if
it's failed, we need to return all the warnings to the user.
*/
- mysql_reset_errors(thd, TRUE);
+ thd->warning_info->clear_warning_info(thd->query_id);
}
return error;
}
@@ -3456,13 +3616,12 @@ Prepared_statement::swap_prepared_statement(Prepared_statement *copy)
is allocated in the old arena.
*/
swap_variables(Item_param **, param_array, copy->param_array);
- /* Swap flags: this is perhaps unnecessary */
- swap_variables(uint, flags, copy->flags);
+ /* Don't swap flags: the copy has IS_SQL_PREPARE always set. */
+ /* swap_variables(uint, flags, copy->flags); */
/* Swap names, the old name is allocated in the wrong memory root */
swap_variables(LEX_STRING, name, copy->name);
/* Ditto */
swap_variables(char *, db, copy->db);
- swap_variables(ulong, m_sp_cache_version, copy->m_sp_cache_version);
DBUG_ASSERT(db_length == copy->db_length);
DBUG_ASSERT(param_count == copy->param_count);
@@ -3522,19 +3681,6 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
}
/*
- Reprepare the statement if we're using stored functions
- and the version of the stored routines cache has changed.
- */
- if (lex->uses_stored_routines() &&
- m_sp_cache_version != sp_cache_version(&thd->sp_func_cache) &&
- thd->m_reprepare_observer &&
- thd->m_reprepare_observer->report_error(thd))
- {
- return TRUE;
- }
-
-
- /*
For SHOW VARIABLES lex->result is NULL, as it's a non-SELECT
command. For such queries we don't return an error and don't
open a cursor -- the client library will recognize this case and
@@ -3595,7 +3741,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
to point at it even after we restore from backup. This is ok, as
expanded query was allocated in thd->mem_root.
*/
- stmt_backup.set_query_inner(thd->query(), thd->query_length());
+ stmt_backup.set_query_inner(thd->query_string);
/*
At first execution of prepared statement we may perform logical
@@ -3611,8 +3757,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
/* Go! */
if (open_cursor)
- error= mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
- &result, &cursor);
+ error= mysql_open_cursor(thd, &result, &cursor);
else
{
/*
@@ -3623,7 +3768,14 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
if (query_cache_send_result_to_client(thd, thd->query(),
thd->query_length()) <= 0)
{
+ MYSQL_QUERY_EXEC_START(thd->query(),
+ thd->thread_id,
+ (char *) (thd->db ? thd->db : ""),
+ thd->security_ctx->priv_user,
+ (char *) thd->security_ctx->host_or_ip,
+ 1);
error= mysql_execute_command(thd);
+ MYSQL_QUERY_EXEC_DONE(error);
}
}
@@ -3650,6 +3802,14 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
if (state == Query_arena::PREPARED)
state= Query_arena::EXECUTED;
+ if (error == 0 && this->lex->sql_command == SQLCOM_CALL)
+ {
+ if (is_sql_prepare())
+ thd->protocol_text.send_out_parameters(&this->lex->param_list);
+ else
+ thd->protocol->send_out_parameters(&this->lex->param_list);
+ }
+
/*
Log COM_EXECUTE to the general log. Note, that in case of SQL
prepared statements this causes two records to be output:
@@ -3683,3 +3843,573 @@ void Prepared_statement::deallocate()
/* Statement map calls delete stmt on erase */
thd->stmt_map.erase(this);
}
+
+
+/***************************************************************************
+* Ed_result_set
+***************************************************************************/
+/**
+ Use operator delete to free memory of Ed_result_set.
+ Accessing members of a class after the class has been destroyed
+ is a violation of the C++ standard but is commonly used in the
+ server code.
+*/
+
+void Ed_result_set::operator delete(void *ptr, size_t size) throw ()
+{
+ if (ptr)
+ {
+ /*
+ Make a stack copy, otherwise free_root() will attempt to
+ write to freed memory.
+ */
+ MEM_ROOT own_root= ((Ed_result_set*) ptr)->m_mem_root;
+ free_root(&own_root, MYF(0));
+ }
+}
+
+
+/**
+ Initialize an instance of Ed_result_set.
+
+ Instances of the class, as well as all result set rows, are
+ always allocated in the memory root passed over as the second
+ argument. In the constructor, we take over ownership of the
+ memory root. It will be freed when the class is destroyed.
+
+ sic: Ed_result_est is not designed to be allocated on stack.
+*/
+
+Ed_result_set::Ed_result_set(List<Ed_row> *rows_arg,
+ size_t column_count_arg,
+ MEM_ROOT *mem_root_arg)
+ :m_mem_root(*mem_root_arg),
+ m_column_count(column_count_arg),
+ m_rows(rows_arg),
+ m_next_rset(NULL)
+{
+ /* Take over responsibility for the memory */
+ clear_alloc_root(mem_root_arg);
+}
+
+/***************************************************************************
+* Ed_result_set
+***************************************************************************/
+
+/**
+ Create a new "execute direct" connection.
+*/
+
+Ed_connection::Ed_connection(THD *thd)
+ :m_warning_info(thd->query_id),
+ m_thd(thd),
+ m_rsets(0),
+ m_current_rset(0)
+{
+}
+
+
+/**
+ Free all result sets of the previous statement, if any,
+ and reset warnings and errors.
+
+ Called before execution of the next query.
+*/
+
+void
+Ed_connection::free_old_result()
+{
+ while (m_rsets)
+ {
+ Ed_result_set *rset= m_rsets->m_next_rset;
+ delete m_rsets;
+ m_rsets= rset;
+ }
+ m_current_rset= m_rsets;
+ m_diagnostics_area.reset_diagnostics_area();
+ m_warning_info.clear_warning_info(m_thd->query_id);
+}
+
+
+/**
+ A simple wrapper that uses a helper class to execute SQL statements.
+*/
+
+bool
+Ed_connection::execute_direct(LEX_STRING sql_text)
+{
+ Execute_sql_statement execute_sql_statement(sql_text);
+ DBUG_PRINT("ed_query", ("%s", sql_text.str));
+
+ return execute_direct(&execute_sql_statement);
+}
+
+
+/**
+ Execute a fragment of server functionality without an effect on
+ thd, and store results in memory.
+
+ Conventions:
+ - the code fragment must finish with OK, EOF or ERROR.
+ - the code fragment doesn't have to close thread tables,
+ free memory, commit statement transaction or do any other
+ cleanup that is normally done in the end of dispatch_command().
+
+ @param server_runnable A code fragment to execute.
+*/
+
+bool Ed_connection::execute_direct(Server_runnable *server_runnable)
+{
+ bool rc= FALSE;
+ Protocol_local protocol_local(m_thd, this);
+ Prepared_statement stmt(m_thd);
+ Protocol *save_protocol= m_thd->protocol;
+ Diagnostics_area *save_diagnostics_area= m_thd->stmt_da;
+ Warning_info *save_warning_info= m_thd->warning_info;
+
+ DBUG_ENTER("Ed_connection::execute_direct");
+
+ free_old_result(); /* Delete all data from previous execution, if any */
+
+ m_thd->protocol= &protocol_local;
+ m_thd->stmt_da= &m_diagnostics_area;
+ m_thd->warning_info= &m_warning_info;
+
+ rc= stmt.execute_server_runnable(server_runnable);
+ m_thd->protocol->end_statement();
+
+ m_thd->protocol= save_protocol;
+ m_thd->stmt_da= save_diagnostics_area;
+ m_thd->warning_info= save_warning_info;
+ /*
+ Protocol_local makes use of m_current_rset to keep
+ track of the last result set, while adding result sets to the end.
+ Reset it to point to the first result set instead.
+ */
+ m_current_rset= m_rsets;
+
+ DBUG_RETURN(rc);
+}
+
+
+/**
+ A helper method that is called only during execution.
+
+ Although Ed_connection doesn't support multi-statements,
+ a statement may generate many result sets. All subsequent
+ result sets are appended to the end.
+
+ @pre This is called only by Protocol_local.
+*/
+
+void
+Ed_connection::add_result_set(Ed_result_set *ed_result_set)
+{
+ if (m_rsets)
+ {
+ m_current_rset->m_next_rset= ed_result_set;
+ /* While appending, use m_current_rset as a pointer to the tail. */
+ m_current_rset= ed_result_set;
+ }
+ else
+ m_current_rset= m_rsets= ed_result_set;
+}
+
+
+/**
+ Release ownership of the current result set to the client.
+
+ Since we use a simple linked list for result sets,
+ this method uses a linear search of the previous result
+ set to exclude the released instance from the list.
+
+ @todo Use double-linked list, when this is really used.
+
+ XXX: This has never been tested with more than one result set!
+
+ @pre There must be a result set.
+*/
+
+Ed_result_set *
+Ed_connection::store_result_set()
+{
+ Ed_result_set *ed_result_set;
+
+ DBUG_ASSERT(m_current_rset);
+
+ if (m_current_rset == m_rsets)
+ {
+ /* Assign the return value */
+ ed_result_set= m_current_rset;
+ /* Exclude the return value from the list. */
+ m_current_rset= m_rsets= m_rsets->m_next_rset;
+ }
+ else
+ {
+ Ed_result_set *prev_rset= m_rsets;
+ /* Assign the return value. */
+ ed_result_set= m_current_rset;
+
+ /* Exclude the return value from the list */
+ while (prev_rset->m_next_rset != m_current_rset)
+ prev_rset= ed_result_set->m_next_rset;
+ m_current_rset= prev_rset->m_next_rset= m_current_rset->m_next_rset;
+ }
+ ed_result_set->m_next_rset= NULL; /* safety */
+
+ return ed_result_set;
+}
+
+/*************************************************************************
+* Protocol_local
+**************************************************************************/
+
+Protocol_local::Protocol_local(THD *thd, Ed_connection *ed_connection)
+ :Protocol(thd),
+ m_connection(ed_connection),
+ m_rset(NULL),
+ m_column_count(0),
+ m_current_row(NULL),
+ m_current_column(NULL)
+{
+ clear_alloc_root(&m_rset_root);
+}
+
+/**
+ Called between two result set rows.
+
+ Prepare structures to fill result set rows.
+ Unfortunately, we can't return an error here. If memory allocation
+ fails, we'll have to return an error later. And so is done
+ in methods such as @sa store_column().
+*/
+
+void Protocol_local::prepare_for_resend()
+{
+ DBUG_ASSERT(alloc_root_inited(&m_rset_root));
+
+ opt_add_row_to_rset();
+ /* Start a new row. */
+ m_current_row= (Ed_column *) alloc_root(&m_rset_root,
+ sizeof(Ed_column) * m_column_count);
+ m_current_column= m_current_row;
+}
+
+
+/**
+ In "real" protocols this is called to finish a result set row.
+ Unused in the local implementation.
+*/
+
+bool Protocol_local::write()
+{
+ return FALSE;
+}
+
+/**
+ A helper function to add the current row to the current result
+ set. Called in @sa prepare_for_resend(), when a new row is started,
+ and in send_eof(), when the result set is finished.
+*/
+
+void Protocol_local::opt_add_row_to_rset()
+{
+ if (m_current_row)
+ {
+ /* Add the old row to the result set */
+ Ed_row *ed_row= new (&m_rset_root) Ed_row(m_current_row, m_column_count);
+ if (ed_row)
+ m_rset->push_back(ed_row, &m_rset_root);
+ }
+}
+
+
+/**
+ Add a NULL column to the current row.
+*/
+
+bool Protocol_local::store_null()
+{
+ if (m_current_column == NULL)
+ return TRUE; /* prepare_for_resend() failed to allocate memory. */
+
+ bzero(m_current_column, sizeof(*m_current_column));
+ ++m_current_column;
+ return FALSE;
+}
+
+
+/**
+ A helper method to add any column to the current row
+ in its binary form.
+
+ Allocates memory for the data in the result set memory root.
+*/
+
+bool Protocol_local::store_column(const void *data, size_t length)
+{
+ if (m_current_column == NULL)
+ return TRUE; /* prepare_for_resend() failed to allocate memory. */
+ /*
+ alloc_root() automatically aligns memory, so we don't need to
+ do any extra alignment if we're pointing to, say, an integer.
+ */
+ m_current_column->str= (char*) memdup_root(&m_rset_root,
+ data,
+ length + 1 /* Safety */);
+ if (! m_current_column->str)
+ return TRUE;
+ m_current_column->str[length]= '\0'; /* Safety */
+ m_current_column->length= length;
+ ++m_current_column;
+ return FALSE;
+}
+
+
+/**
+ Store a string value in a result set column, optionally
+ having converted it to character_set_results.
+*/
+
+bool
+Protocol_local::store_string(const char *str, size_t length,
+ CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs)
+{
+ /* Store with conversion */
+ uint error_unused;
+
+ if (dst_cs && !my_charset_same(src_cs, dst_cs) &&
+ src_cs != &my_charset_bin &&
+ dst_cs != &my_charset_bin)
+ {
+ if (convert->copy(str, length, src_cs, dst_cs, &error_unused))
+ return TRUE;
+ str= convert->ptr();
+ length= convert->length();
+ }
+ return store_column(str, length);
+}
+
+
+/** Store a tiny int as is (1 byte) in a result set column. */
+
+bool Protocol_local::store_tiny(longlong value)
+{
+ char v= (char) value;
+ return store_column(&v, 1);
+}
+
+
+/** Store a short as is (2 bytes, host order) in a result set column. */
+
+bool Protocol_local::store_short(longlong value)
+{
+ int16 v= (int16) value;
+ return store_column(&v, 2);
+}
+
+
+/** Store a "long" as is (4 bytes, host order) in a result set column. */
+
+bool Protocol_local::store_long(longlong value)
+{
+ int32 v= (int32) value;
+ return store_column(&v, 4);
+}
+
+
+/** Store a "longlong" as is (8 bytes, host order) in a result set column. */
+
+bool Protocol_local::store_longlong(longlong value, bool unsigned_flag)
+{
+ int64 v= (int64) value;
+ return store_column(&v, 8);
+}
+
+
+/** Store a decimal in string format in a result set column */
+
+bool Protocol_local::store_decimal(const my_decimal *value)
+{
+ char buf[DECIMAL_MAX_STR_LENGTH];
+ String str(buf, sizeof (buf), &my_charset_bin);
+ int rc;
+
+ rc= my_decimal2string(E_DEC_FATAL_ERROR, value, 0, 0, 0, &str);
+
+ if (rc)
+ return TRUE;
+
+ return store_column(str.ptr(), str.length());
+}
+
+
+/** Convert to cs_results and store a string. */
+
+bool Protocol_local::store(const char *str, size_t length,
+ CHARSET_INFO *src_cs)
+{
+ CHARSET_INFO *dst_cs;
+
+ dst_cs= m_connection->m_thd->variables.character_set_results;
+ return store_string(str, length, src_cs, dst_cs);
+}
+
+
+/** Store a string. */
+
+bool Protocol_local::store(const char *str, size_t length,
+ CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs)
+{
+ return store_string(str, length, src_cs, dst_cs);
+}
+
+
+/* Store MYSQL_TIME (in binary format) */
+
+bool Protocol_local::store(MYSQL_TIME *time)
+{
+ return store_column(time, sizeof(MYSQL_TIME));
+}
+
+
+/** Store MYSQL_TIME (in binary format) */
+
+bool Protocol_local::store_date(MYSQL_TIME *time)
+{
+ return store_column(time, sizeof(MYSQL_TIME));
+}
+
+
+/** Store MYSQL_TIME (in binary format) */
+
+bool Protocol_local::store_time(MYSQL_TIME *time)
+{
+ return store_column(time, sizeof(MYSQL_TIME));
+}
+
+
+/* Store a floating point number, as is. */
+
+bool Protocol_local::store(float value, uint32 decimals, String *buffer)
+{
+ return store_column(&value, sizeof(float));
+}
+
+
+/* Store a double precision number, as is. */
+
+bool Protocol_local::store(double value, uint32 decimals, String *buffer)
+{
+ return store_column(&value, sizeof (double));
+}
+
+
+/* Store a Field. */
+
+bool Protocol_local::store(Field *field)
+{
+ if (field->is_null())
+ return store_null();
+ return field->send_binary(this);
+}
+
+
+/** Called to start a new result set. */
+
+bool Protocol_local::send_result_set_metadata(List<Item> *columns, uint)
+{
+ DBUG_ASSERT(m_rset == 0 && !alloc_root_inited(&m_rset_root));
+
+ init_sql_alloc(&m_rset_root, MEM_ROOT_BLOCK_SIZE, 0);
+
+ if (! (m_rset= new (&m_rset_root) List<Ed_row>))
+ return TRUE;
+
+ m_column_count= columns->elements;
+
+ return FALSE;
+}
+
+
+/**
+ Normally this is a separate result set with OUT parameters
+ of stored procedures. Currently unsupported for the local
+ version.
+*/
+
+bool Protocol_local::send_out_parameters(List<Item_param> *sp_params)
+{
+ return FALSE;
+}
+
+
+/** Called for statements that don't have a result set, at statement end. */
+
+bool
+Protocol_local::send_ok(uint server_status, uint statement_warn_count,
+ ulonglong affected_rows, ulonglong last_insert_id,
+ const char *message)
+{
+ /*
+ Just make sure nothing is sent to the client, we have grabbed
+ the status information in the connection diagnostics area.
+ */
+ return FALSE;
+}
+
+
+/**
+ Called at the end of a result set. Append a complete
+ result set to the list in Ed_connection.
+
+ Don't send anything to the client, but instead finish
+ building of the result set at hand.
+*/
+
+bool Protocol_local::send_eof(uint server_status, uint statement_warn_count)
+{
+ Ed_result_set *ed_result_set;
+
+ DBUG_ASSERT(m_rset);
+
+ opt_add_row_to_rset();
+ m_current_row= 0;
+
+ ed_result_set= new (&m_rset_root) Ed_result_set(m_rset, m_column_count,
+ &m_rset_root);
+
+ m_rset= NULL;
+
+ if (! ed_result_set)
+ return TRUE;
+
+ /* In case of successful allocation memory ownership was transferred. */
+ DBUG_ASSERT(!alloc_root_inited(&m_rset_root));
+
+ /*
+ Link the created Ed_result_set instance into the list of connection
+ result sets. Never fails.
+ */
+ m_connection->add_result_set(ed_result_set);
+ return FALSE;
+}
+
+
+/** Called to send an error to the client at the end of a statement. */
+
+bool
+Protocol_local::send_error(uint sql_errno, const char *err_msg, const char*)
+{
+ /*
+ Just make sure that nothing is sent to the client (default
+ implementation).
+ */
+ return FALSE;
+}
+
+
+#ifdef EMBEDDED_LIBRARY
+void Protocol_local::remove_last_row()
+{ }
+#endif
diff --git a/sql/sql_prepare.h b/sql/sql_prepare.h
new file mode 100644
index 00000000000..11017b127b1
--- /dev/null
+++ b/sql/sql_prepare.h
@@ -0,0 +1,367 @@
+#ifndef SQL_PREPARE_H
+#define SQL_PREPARE_H
+/* Copyright (C) 1995-2008 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "sql_error.h"
+
+class THD;
+struct LEX;
+
+/**
+ An interface that is used to take an action when
+ the locking module notices that a table version has changed
+ since the last execution. "Table" here may refer to any kind of
+ table -- a base table, a temporary table, a view or an
+ information schema table.
+
+ When we open and lock tables for execution of a prepared
+ statement, we must verify that they did not change
+ since statement prepare. If some table did change, the statement
+ parse tree *may* be no longer valid, e.g. in case it contains
+ optimizations that depend on table metadata.
+
+ This class provides an interface (a method) that is
+ invoked when such a situation takes place.
+ The implementation of the method simply reports an error, but
+ the exact details depend on the nature of the SQL statement.
+
+ At most 1 instance of this class is active at a time, in which
+ case THD::m_reprepare_observer is not NULL.
+
+ @sa check_and_update_table_version() for details of the
+ version tracking algorithm
+
+ @sa Open_tables_state::m_reprepare_observer for the life cycle
+ of metadata observers.
+*/
+
+class Reprepare_observer
+{
+public:
+ /**
+ Check if a change of metadata is OK. In future
+ the signature of this method may be extended to accept the old
+ and the new versions, but since currently the check is very
+ simple, we only need the THD to report an error.
+ */
+ bool report_error(THD *thd);
+ bool is_invalidated() const { return m_invalidated; }
+ void reset_reprepare_observer() { m_invalidated= FALSE; }
+private:
+ bool m_invalidated;
+};
+
+
+void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length);
+void mysqld_stmt_execute(THD *thd, char *packet, uint packet_length);
+void mysqld_stmt_close(THD *thd, char *packet);
+void mysql_sql_stmt_prepare(THD *thd);
+void mysql_sql_stmt_execute(THD *thd);
+void mysql_sql_stmt_close(THD *thd);
+void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length);
+void mysqld_stmt_reset(THD *thd, char *packet);
+void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
+void reinit_stmt_before_use(THD *thd, LEX *lex);
+
+/**
+ Execute a fragment of server code in an isolated context, so that
+ it doesn't leave any effect on THD. THD must have no open tables.
+ The code must not leave any open tables around.
+ The result of execution (if any) is stored in Ed_result.
+*/
+
+class Server_runnable
+{
+public:
+ virtual bool execute_server_code(THD *thd)= 0;
+ virtual ~Server_runnable();
+};
+
+
+/**
+ Execute direct interface.
+
+ @todo Implement support for prelocked mode.
+*/
+
+class Ed_row;
+
+/**
+ Ed_result_set -- a container with result set rows.
+ @todo Implement support for result set metadata and
+ automatic type conversion.
+*/
+
+class Ed_result_set: public Sql_alloc
+{
+public:
+ operator List<Ed_row>&() { return *m_rows; }
+ unsigned int size() const { return m_rows->elements; }
+
+ Ed_result_set(List<Ed_row> *rows_arg, size_t column_count,
+ MEM_ROOT *mem_root_arg);
+
+ /** We don't call member destructors, they all are POD types. */
+ ~Ed_result_set() {}
+
+ size_t get_field_count() const { return m_column_count; }
+
+ static void operator delete(void *ptr, size_t size) throw ();
+private:
+ Ed_result_set(const Ed_result_set &); /* not implemented */
+ Ed_result_set &operator=(Ed_result_set &); /* not implemented */
+private:
+ MEM_ROOT m_mem_root;
+ size_t m_column_count;
+ List<Ed_row> *m_rows;
+ Ed_result_set *m_next_rset;
+ friend class Ed_connection;
+};
+
+
+class Ed_connection
+{
+public:
+ /**
+ Construct a new "execute direct" connection.
+
+ The connection can be used to execute SQL statements.
+ If the connection failed to initialize, the error
+ will be returned on the attempt to execute a statement.
+
+ @pre thd must have no open tables
+ while the connection is used. However,
+ Ed_connection works okay in LOCK TABLES mode.
+ Other properties of THD, such as the current warning
+ information, errors, etc. do not matter and are
+ preserved by Ed_connection. One thread may have many
+ Ed_connections created for it.
+ */
+ Ed_connection(THD *thd);
+
+ /**
+ Execute one SQL statement.
+
+ Until this method is executed, no other methods of
+ Ed_connection can be used. Life cycle of Ed_connection is:
+
+ Initialized -> a statement has been executed ->
+ look at result, move to next result ->
+ look at result, move to next result ->
+ ...
+ moved beyond the last result == Initialized.
+
+ This method can be called repeatedly. Once it's invoked,
+ results of the previous execution are lost.
+
+ A result of execute_direct() can be either:
+
+ - success, no result set rows. In this case get_field_count()
+ returns 0. This happens after execution of INSERT, UPDATE,
+ DELETE, DROP and similar statements. Some other methods, such
+ as get_affected_rows() can be used to retrieve additional
+ result information.
+
+ - success, there are some result set rows (maybe 0). E.g.
+ happens after SELECT. In this case get_field_count() returns
+ the number of columns in a result set and store_result()
+ can be used to retrieve a result set..
+
+ - an error, methods to retrieve error information can
+ be used.
+
+ @return execution status
+ @retval FALSE success, use get_field_count()
+ to determine what to do next.
+ @retval TRUE error, use get_last_error()
+ to see the error number.
+ */
+ bool execute_direct(LEX_STRING sql_text);
+
+ /**
+ Same as the previous, but takes an instance of Server_runnable
+ instead of SQL statement text.
+
+ @return execution status
+
+ @retval FALSE success, use get_field_count()
+ if your code fragment is supposed to
+ return a result set
+ @retval TRUE failure
+ */
+ bool execute_direct(Server_runnable *server_runnable);
+
+ /**
+ Get the number of result set fields.
+
+ This method is valid only if we have a result:
+ execute_direct() has been called. Otherwise
+ the returned value is undefined.
+
+ @sa Documentation for C API function
+ mysql_field_count()
+ */
+ ulong get_field_count() const
+ {
+ return m_current_rset ? m_current_rset->get_field_count() : 0;
+ }
+
+ /**
+ Get the number of affected (deleted, updated)
+ rows for the current statement. Can be
+ used for statements with get_field_count() == 0.
+
+ @sa Documentation for C API function
+ mysql_affected_rows().
+ */
+ ulonglong get_affected_rows() const
+ {
+ return m_diagnostics_area.affected_rows();
+ }
+
+ /**
+ Get the last insert id, if any.
+
+ @sa Documentation for mysql_insert_id().
+ */
+ ulonglong get_last_insert_id() const
+ {
+ return m_diagnostics_area.last_insert_id();
+ }
+
+ /**
+ Get the total number of warnings for the last executed
+ statement. Note, that there is only one warning list even
+ if a statement returns multiple results.
+
+ @sa Documentation for C API function
+ mysql_num_warnings().
+ */
+ ulong get_warn_count() const
+ {
+ return m_warning_info.warn_count();
+ }
+ /**
+ Get the server warnings as a result set.
+ The result set has fixed metadata:
+ The first column is the level.
+ The second is a numeric code.
+ The third is warning text.
+ */
+ List<MYSQL_ERROR> *get_warn_list() { return &m_warning_info.warn_list(); }
+ /**
+ The following members are only valid if execute_direct()
+ or move_to_next_result() returned an error.
+ They never fail, but if they are called when there is no
+ result, or no error, the result is not defined.
+ */
+ const char *get_last_error() const { return m_diagnostics_area.message(); }
+ unsigned int get_last_errno() const { return m_diagnostics_area.sql_errno(); }
+ const char *get_last_sqlstate() const { return m_diagnostics_area.get_sqlstate(); }
+
+ /**
+ Provided get_field_count() is not 0, this never fails. You don't
+ need to free the result set, this is done automatically when
+ you advance to the next result set or destroy the connection.
+ Not returning const because of List iterator not accepting
+ Should be used when you would like Ed_connection to manage
+ result set memory for you.
+ */
+ Ed_result_set *use_result_set() { return m_current_rset; }
+ /**
+ Provided get_field_count() is not 0, this never fails. You
+ must free the returned result set. This can be called only
+ once after execute_direct().
+ Should be used when you would like to get the results
+ and destroy the connection.
+ */
+ Ed_result_set *store_result_set();
+
+ /**
+ If the query returns multiple results, this method
+ can be checked if there is another result beyond the next
+ one.
+ Never fails.
+ */
+ bool has_next_result() const { return test(m_current_rset->m_next_rset); }
+ /**
+ Only valid to call if has_next_result() returned true.
+ Otherwise the result is undefined.
+ */
+ bool move_to_next_result()
+ {
+ m_current_rset= m_current_rset->m_next_rset;
+ return test(m_current_rset);
+ }
+
+ ~Ed_connection() { free_old_result(); }
+private:
+ Diagnostics_area m_diagnostics_area;
+ Warning_info m_warning_info;
+ /**
+ Execute direct interface does not support multi-statements, only
+ multi-results. So we never have a situation when we have
+ a mix of result sets and OK or error packets. We either
+ have a single result set, a single error, or a single OK,
+ or we have a series of result sets, followed by an OK or error.
+ */
+ THD *m_thd;
+ Ed_result_set *m_rsets;
+ Ed_result_set *m_current_rset;
+ friend class Protocol_local;
+private:
+ void free_old_result();
+ void add_result_set(Ed_result_set *ed_result_set);
+private:
+ Ed_connection(const Ed_connection &); /* not implemented */
+ Ed_connection &operator=(Ed_connection &); /* not implemented */
+};
+
+
+/** One result set column. */
+
+struct Ed_column: public LEX_STRING
+{
+ /** Implementation note: destructor for this class is never called. */
+};
+
+
+/** One result set record. */
+
+class Ed_row: public Sql_alloc
+{
+public:
+ const Ed_column &operator[](const unsigned int column_index) const
+ {
+ return *get_column(column_index);
+ }
+ const Ed_column *get_column(const unsigned int column_index) const
+ {
+ DBUG_ASSERT(column_index < size());
+ return m_column_array + column_index;
+ }
+ size_t size() const { return m_column_count; }
+
+ Ed_row(Ed_column *column_array_arg, size_t column_count_arg)
+ :m_column_array(column_array_arg),
+ m_column_count(column_count_arg)
+ {}
+private:
+ Ed_column *m_column_array;
+ size_t m_column_count; /* TODO: change to point to metadata */
+};
+
+#endif // SQL_PREPARE_H
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
new file mode 100644
index 00000000000..4e1dac269b7
--- /dev/null
+++ b/sql/sql_priv.h
@@ -0,0 +1,286 @@
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/**
+ @file
+
+ @details
+ Mostly this file is used in the server. But a little part of it is used in
+ mysqlbinlog too (definition of SELECT_DISTINCT and others).
+ The consequence is that 90% of the file is wrapped in \#ifndef MYSQL_CLIENT,
+ except the part which must be in the server and in the client.
+*/
+
+#ifndef SQL_PRIV_INCLUDED
+#define SQL_PRIV_INCLUDED
+
+#ifndef MYSQL_CLIENT
+
+/*
+ Generates a warning that a feature is deprecated. After a specified
+ version asserts that the feature is removed.
+
+ Using it as
+
+ WARN_DEPRECATED(thd, 6,2, "BAD", "'GOOD'");
+
+ Will result in a warning
+
+ "The syntax 'BAD' is deprecated and will be removed in MySQL 6.2. Please
+ use 'GOOD' instead"
+
+ Note that in macro arguments BAD is not quoted, while 'GOOD' is.
+ Note that the version is TWO numbers, separated with a comma
+ (two macro arguments, that is)
+*/
+#define WARN_DEPRECATED(Thd,VerHi,VerLo,Old,New) \
+ do { \
+ compile_time_assert(MYSQL_VERSION_ID < VerHi * 10000 + VerLo * 100); \
+ if (((THD *) Thd) != NULL) \
+ push_warning_printf(((THD *) Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \
+ ER_WARN_DEPRECATED_SYNTAX, \
+ ER(ER_WARN_DEPRECATED_SYNTAX), \
+ (Old), (New)); \
+ else \
+ sql_print_warning("The syntax '%s' is deprecated and will be removed " \
+ "in a future release. Please use %s instead.", \
+ (Old), (New)); \
+ } while(0)
+
+/*************************************************************************/
+
+#endif
+
+/*
+ This is included in the server and in the client.
+ Options for select set by the yacc parser (stored in lex->options).
+
+ NOTE
+ log_event.h defines OPTIONS_WRITTEN_TO_BIN_LOG to specify what THD
+ options list are written into binlog. These options can NOT change their
+ values, or it will break replication between version.
+
+ context is encoded as following:
+ SELECT - SELECT_LEX_NODE::options
+ THD - THD::options
+ intern - neither. used only as
+ func(..., select_node->options | thd->options | OPTION_XXX, ...)
+
+ TODO: separate three contexts above, move them to separate bitfields.
+*/
+
+#define SELECT_DISTINCT (1ULL << 0) // SELECT, user
+#define SELECT_STRAIGHT_JOIN (1ULL << 1) // SELECT, user
+#define SELECT_DESCRIBE (1ULL << 2) // SELECT, user
+#define SELECT_SMALL_RESULT (1ULL << 3) // SELECT, user
+#define SELECT_BIG_RESULT (1ULL << 4) // SELECT, user
+#define OPTION_FOUND_ROWS (1ULL << 5) // SELECT, user
+#define OPTION_TO_QUERY_CACHE (1ULL << 6) // SELECT, user
+#define SELECT_NO_JOIN_CACHE (1ULL << 7) // intern
+/** always the opposite of OPTION_NOT_AUTOCOMMIT except when in fix_autocommit() */
+#define OPTION_AUTOCOMMIT (1ULL << 8) // THD, user
+#define OPTION_BIG_SELECTS (1ULL << 9) // THD, user
+#define OPTION_LOG_OFF (1ULL << 10) // THD, user
+#define OPTION_QUOTE_SHOW_CREATE (1ULL << 11) // THD, user, unused
+#define TMP_TABLE_ALL_COLUMNS (1ULL << 12) // SELECT, intern
+#define OPTION_WARNINGS (1ULL << 13) // THD, user
+#define OPTION_AUTO_IS_NULL (1ULL << 14) // THD, user, binlog
+#define OPTION_FOUND_COMMENT (1ULL << 15) // SELECT, intern, parser
+#define OPTION_SAFE_UPDATES (1ULL << 16) // THD, user
+#define OPTION_BUFFER_RESULT (1ULL << 17) // SELECT, user
+#define OPTION_BIN_LOG (1ULL << 18) // THD, user
+#define OPTION_NOT_AUTOCOMMIT (1ULL << 19) // THD, user
+#define OPTION_BEGIN (1ULL << 20) // THD, intern
+#define OPTION_TABLE_LOCK (1ULL << 21) // THD, intern
+#define OPTION_QUICK (1ULL << 22) // SELECT (for DELETE)
+#define OPTION_KEEP_LOG (1ULL << 23) // THD, user
+
+/* The following is used to detect a conflict with DISTINCT */
+#define SELECT_ALL (1ULL << 24) // SELECT, user, parser
+/** The following can be set when importing tables in a 'wrong order'
+ to suppress foreign key checks */
+#define OPTION_NO_FOREIGN_KEY_CHECKS (1ULL << 26) // THD, user, binlog
+/** The following speeds up inserts to InnoDB tables by suppressing unique
+ key checks in some cases */
+#define OPTION_RELAXED_UNIQUE_CHECKS (1ULL << 27) // THD, user, binlog
+#define SELECT_NO_UNLOCK (1ULL << 28) // SELECT, intern
+#define OPTION_SCHEMA_TABLE (1ULL << 29) // SELECT, intern
+/** Flag set if setup_tables already done */
+#define OPTION_SETUP_TABLES_DONE (1ULL << 30) // intern
+/** If not set then the thread will ignore all warnings with level notes. */
+#define OPTION_SQL_NOTES (1ULL << 31) // THD, user
+/**
+ Force the used temporary table to be a MyISAM table (because we will use
+ fulltext functions when reading from it.
+*/
+#define TMP_TABLE_FORCE_MYISAM (1ULL << 32)
+#define OPTION_PROFILING (1ULL << 33)
+/**
+ Indicates that this is a HIGH_PRIORITY SELECT.
+ Currently used only for printing of such selects.
+ Type of locks to be acquired is specified directly.
+*/
+#define SELECT_HIGH_PRIORITY (1ULL << 34) // SELECT, user
+/**
+ Is set in slave SQL thread when there was an
+ error on master, which, when is not reproducible
+ on slave (i.e. the query succeeds on slave),
+ is not terminal to the state of repliation,
+ and should be ignored. The slave SQL thread,
+ however, needs to rollback the effects of the
+ succeeded statement to keep replication consistent.
+*/
+#define OPTION_MASTER_SQL_ERROR (1ULL << 35)
+
+/*
+ Dont report errors for individual rows,
+ But just report error on commit (or read ofcourse)
+ Note! Reserved for use in MySQL Cluster
+*/
+#define OPTION_ALLOW_BATCH (ULL(1) << 36) // THD, intern (slave)
+
+/* The rest of the file is included in the server only */
+#ifndef MYSQL_CLIENT
+
+/* @@optimizer_switch flags. These must be in sync with optimizer_switch_typelib */
+#define OPTIMIZER_SWITCH_INDEX_MERGE (1ULL << 0)
+#define OPTIMIZER_SWITCH_INDEX_MERGE_UNION (1ULL << 1)
+#define OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION (1ULL << 2)
+#define OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT (1ULL << 3)
+#define OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN (1ULL << 4)
+#define OPTIMIZER_SWITCH_LAST (1ULL << 5)
+
+/* The following must be kept in sync with optimizer_switch_str in mysqld.cc */
+#define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
+ OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
+ OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION | \
+ OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT | \
+ OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN)
+
+
+/*
+ Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
+ use strictly more than 64 bits by adding one more define above, you should
+ contact the replication team because the replication code should then be
+ updated (to store more bytes on disk).
+
+ NOTE: When adding new SQL_MODE types, make sure to also add them to
+ the scripts used for creating the MySQL system tables
+ in scripts/mysql_system_tables.sql and scripts/mysql_system_tables_fix.sql
+
+*/
+
+// uncachable cause
+#define UNCACHEABLE_DEPENDENT 1
+#define UNCACHEABLE_RAND 2
+#define UNCACHEABLE_SIDEEFFECT 4
+/// forcing to save JOIN for explain
+#define UNCACHEABLE_EXPLAIN 8
+/** Don't evaluate subqueries in prepare even if they're not correlated */
+#define UNCACHEABLE_PREPARE 16
+/* For uncorrelated SELECT in an UNION with some correlated SELECTs */
+#define UNCACHEABLE_UNITED 32
+#define UNCACHEABLE_CHECKOPTION 64
+
+/* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */
+#define UNDEF_POS (-1)
+
+/* BINLOG_DUMP options */
+
+#define BINLOG_DUMP_NON_BLOCK 1
+
+/*
+ Some defines for exit codes for ::is_equal class functions.
+*/
+#define IS_EQUAL_NO 0
+#define IS_EQUAL_YES 1
+#define IS_EQUAL_PACK_LENGTH 2
+
+enum enum_parsing_place
+{
+ NO_MATTER,
+ IN_HAVING,
+ SELECT_LIST,
+ IN_WHERE,
+ IN_ON
+};
+
+
+enum enum_var_type
+{
+ OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
+};
+
+class sys_var;
+
+enum enum_yes_no_unknown
+{
+ TVL_YES, TVL_NO, TVL_UNKNOWN
+};
+
+#ifdef MYSQL_SERVER
+
+#endif /* MYSQL_SERVER */
+
+#ifdef MYSQL_SERVER
+/*
+ A set of constants used for checking non aggregated fields and sum
+ functions mixture in the ONLY_FULL_GROUP_BY_MODE.
+*/
+#define NON_AGG_FIELD_USED 1
+#define SUM_FUNC_USED 2
+
+/*
+ External variables
+*/
+
+/* sql_yacc.cc */
+#ifndef DBUG_OFF
+extern void turn_parser_debug_on();
+
+#endif
+
+/**
+ convert a hex digit into number.
+*/
+
+inline int hexchar_to_int(char c)
+{
+ if (c <= '9' && c >= '0')
+ return c-'0';
+ c|=32;
+ if (c <= 'f' && c >= 'a')
+ return c-'a'+10;
+ return -1;
+}
+
+/* This must match the path length limit in the ER_NOT_RW_DIR error msg. */
+#define ER_NOT_RW_DIR_PATHSIZE 200
+
+#define IS_TABLESPACES_TABLESPACE_NAME 0
+#define IS_TABLESPACES_ENGINE 1
+#define IS_TABLESPACES_TABLESPACE_TYPE 2
+#define IS_TABLESPACES_LOGFILE_GROUP_NAME 3
+#define IS_TABLESPACES_EXTENT_SIZE 4
+#define IS_TABLESPACES_AUTOEXTEND_SIZE 5
+#define IS_TABLESPACES_MAXIMUM_SIZE 6
+#define IS_TABLESPACES_NODEGROUP_ID 7
+#define IS_TABLESPACES_TABLESPACE_COMMENT 8
+
+#endif /* MYSQL_SERVER */
+
+#endif /* MYSQL_CLIENT */
+
+#endif /* SQL_PRIV_INCLUDED */
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index c661f3744aa..ce3d786cf92 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -29,8 +29,12 @@
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_profile.h"
#include "my_sys.h"
+#include "sql_show.h" // schema_table_store_record
+#include "sql_class.h" // THD
#define TIME_FLOAT_DIGITS 9
/** two vals encoded: (dec*100)+len */
@@ -38,16 +42,13 @@
#define MAX_QUERY_LENGTH 300
-/* Reserved for systems that can't record the function name in source. */
-const char * const _unknown_func_ = "<unknown>";
-
/**
Connects Information_Schema and Profiling.
*/
int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables,
Item *cond)
{
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
return(thd->profiling.fill_statistics_info(thd, tables, cond));
#else
my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILE", "enable-profiling");
@@ -129,11 +130,31 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table)
}
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
+#if defined(ENABLED_PROFILING)
#define RUSAGE_USEC(tv) ((tv).tv_sec*1000*1000 + (tv).tv_usec)
#define RUSAGE_DIFF_USEC(tv1, tv2) (RUSAGE_USEC((tv1))-RUSAGE_USEC((tv2)))
+#ifdef _WIN32
+static ULONGLONG FileTimeToQuadWord(FILETIME *ft)
+{
+ // Overlay FILETIME onto a ULONGLONG.
+ union {
+ ULONGLONG qwTime;
+ FILETIME ft;
+ } u;
+
+ u.ft = *ft;
+ return u.qwTime;
+}
+
+
+// Get time difference between to FILETIME objects in seconds.
+static double GetTimeDiffInSeconds(FILETIME *a, FILETIME *b)
+{
+ return ((FileTimeToQuadWord(a) - FileTimeToQuadWord(b)) / 1e7);
+}
+#endif
PROF_MEASUREMENT::PROF_MEASUREMENT(QUERY_PROFILE *profile_arg, const char
*status_arg)
@@ -156,8 +177,7 @@ PROF_MEASUREMENT::PROF_MEASUREMENT(QUERY_PROFILE *profile_arg,
PROF_MEASUREMENT::~PROF_MEASUREMENT()
{
- if (allocated_status_memory != NULL)
- my_free(allocated_status_memory, MYF(0));
+ my_free(allocated_status_memory);
status= function= file= NULL;
}
@@ -224,6 +244,12 @@ void PROF_MEASUREMENT::collect()
time_usecs= (double) my_getsystime() / 10.0; /* 1 sec was 1e7, now is 1e6 */
#ifdef HAVE_GETRUSAGE
getrusage(RUSAGE_SELF, &rusage);
+#elif defined(_WIN32)
+ FILETIME ftDummy;
+ // NOTE: Get{Process|Thread}Times has a granularity of the clock interval,
+ // which is typically ~15ms. So intervals shorter than that will not be
+ // measurable by this function.
+ GetProcessTimes(GetCurrentProcess(), &ftDummy, &ftDummy, &ftKernel, &ftUser);
#endif
}
@@ -241,8 +267,7 @@ QUERY_PROFILE::~QUERY_PROFILE()
while (! entries.is_empty())
delete entries.pop();
- if (query_source != NULL)
- my_free(query_source, MYF(0));
+ my_free(query_source);
}
/**
@@ -341,7 +366,7 @@ void PROFILING::start_new_query(const char *initial_state)
finish_current_query();
}
- enabled= (((thd)->options & OPTION_PROFILING) != 0);
+ enabled= ((thd->variables.option_bits & OPTION_PROFILING) != 0);
if (! enabled) DBUG_VOID_RETURN;
@@ -379,7 +404,7 @@ void PROFILING::finish_current_query()
status_change("ending", NULL, NULL, 0);
if ((enabled) && /* ON at start? */
- ((thd->options & OPTION_PROFILING) != 0) && /* and ON at end? */
+ ((thd->variables.option_bits & OPTION_PROFILING) != 0) && /* and ON at end? */
(current->query_source != NULL) &&
(! current->entries.is_empty()))
{
@@ -415,7 +440,7 @@ bool PROFILING::show_profiles()
MYSQL_TYPE_DOUBLE));
field_list.push_back(new Item_empty_string("Query", 40));
- if (thd->protocol->send_fields(&field_list,
+ if (thd->protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
@@ -593,6 +618,23 @@ int PROFILING::fill_statistics_info(THD *thd_arg, TABLE_LIST *tables, Item *cond
table->field[5]->store_decimal(&cpu_stime_decimal);
table->field[4]->set_notnull();
table->field[5]->set_notnull();
+#elif defined(_WIN32)
+ my_decimal cpu_utime_decimal, cpu_stime_decimal;
+
+ double2my_decimal(E_DEC_FATAL_ERROR,
+ GetTimeDiffInSeconds(&entry->ftUser,
+ &previous->ftUser),
+ &cpu_utime_decimal);
+ double2my_decimal(E_DEC_FATAL_ERROR,
+ GetTimeDiffInSeconds(&entry->ftKernel,
+ &previous->ftKernel),
+ &cpu_stime_decimal);
+
+ // Store the result.
+ table->field[4]->store_decimal(&cpu_utime_decimal);
+ table->field[5]->store_decimal(&cpu_stime_decimal);
+ table->field[4]->set_notnull();
+ table->field[5]->set_notnull();
#else
/* TODO: Add CPU-usage info for non-BSD systems */
#endif
diff --git a/sql/sql_profile.h b/sql/sql_profile.h
index 245959e0953..7d17dc69b88 100644
--- a/sql/sql_profile.h
+++ b/sql/sql_profile.h
@@ -16,13 +16,11 @@
#ifndef _SQL_PROFILE_H
#define _SQL_PROFILE_H
-#ifndef __func__
-#ifdef __FUNCTION__
-#define __func__ __FUNCTION__
-#else
-#define __func__ "unknown function"
-#endif
-#endif
+class Item;
+struct TABLE_LIST;
+class THD;
+typedef struct st_field_info ST_FIELD_INFO;
+typedef struct st_schema_table ST_SCHEMA_TABLE;
extern ST_FIELD_INFO query_profile_statistics_info[];
int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond);
@@ -41,8 +39,9 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table);
#define PROFILE_ALL (uint)(~0)
-#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
-#include "mysql_priv.h"
+#if defined(ENABLED_PROFILING)
+#include "sql_priv.h"
+#include "unireg.h"
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
@@ -83,7 +82,7 @@ public:
for (i= first; i != NULL; i= after_i)
{
after_i= i->next;
- my_free((char *) i, MYF(0));
+ my_free(i);
}
elements= 0;
}
@@ -130,7 +129,7 @@ public:
last= NULL;
first= first->next;
- my_free((char *)old_item, MYF(0));
+ my_free(old_item);
elements--;
return ret;
@@ -173,6 +172,8 @@ private:
char *status;
#ifdef HAVE_GETRUSAGE
struct rusage rusage;
+#elif defined(_WIN32)
+ FILETIME ftKernel, ftUser;
#endif
char *function;
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
new file mode 100644
index 00000000000..0810459cb49
--- /dev/null
+++ b/sql/sql_reload.cc
@@ -0,0 +1,440 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 */
+
+#include "sql_reload.h"
+#include "sql_priv.h"
+#include "mysqld.h" // select_errors
+#include "sql_class.h" // THD
+#include "sql_acl.h" // acl_reload
+#include "sql_servers.h" // servers_reload
+#include "sql_connect.h" // reset_mqh
+#include "sql_base.h" // close_cached_tables
+#include "sql_db.h" // my_dbopt_cleanup
+#include "hostname.h" // hostname_cache_refresh
+#include "sql_repl.h" // reset_master, reset_slave
+#include "debug_sync.h"
+
+
+/**
+ Reload/resets privileges and the different caches.
+
+ @param thd Thread handler (can be NULL!)
+ @param options What should be reset/reloaded (tables, privileges, slave...)
+ @param tables Tables to flush (if any)
+ @param write_to_binlog < 0 if there was an error while interacting with the binary log inside
+ reload_acl_and_cache,
+ 0 if we should not write to the binary log,
+ > 0 if we can write to the binlog.
+
+
+ @note Depending on 'options', it may be very bad to write the
+ query to the binlog (e.g. FLUSH SLAVE); this is a
+ pointer where reload_acl_and_cache() will put 0 if
+ it thinks we really should not write to the binlog.
+ Otherwise it will put 1.
+
+ @return Error status code
+ @retval 0 Ok
+ @retval !=0 Error; thd->killed is set or thd->is_error() is true
+*/
+
+bool reload_acl_and_cache(THD *thd, unsigned long options,
+ TABLE_LIST *tables, int *write_to_binlog)
+{
+ bool result=0;
+ select_errors=0; /* Write if more errors */
+ int tmp_write_to_binlog= *write_to_binlog= 1;
+
+ DBUG_ASSERT(!thd || !thd->in_sub_stmt);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (options & REFRESH_GRANT)
+ {
+ THD *tmp_thd= 0;
+ /*
+ If reload_acl_and_cache() is called from SIGHUP handler we have to
+ allocate temporary THD for execution of acl_reload()/grant_reload().
+ */
+ if (!thd && (thd= (tmp_thd= new THD)))
+ {
+ thd->thread_stack= (char*) &tmp_thd;
+ thd->store_globals();
+ }
+
+ if (thd)
+ {
+ bool reload_acl_failed= acl_reload(thd);
+ bool reload_grants_failed= grant_reload(thd);
+ bool reload_servers_failed= servers_reload(thd);
+
+ if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
+ {
+ result= 1;
+ /*
+ When an error is returned, my_message may have not been called and
+ the client will hang waiting for a response.
+ */
+ my_error(ER_UNKNOWN_ERROR, MYF(0), "FLUSH PRIVILEGES failed");
+ }
+ }
+
+ if (tmp_thd)
+ {
+ delete tmp_thd;
+ /* Remember that we don't have a THD */
+ my_pthread_setspecific_ptr(THR_THD, 0);
+ thd= 0;
+ }
+ reset_mqh((LEX_USER *)NULL, TRUE);
+ }
+#endif
+ if (options & REFRESH_LOG)
+ {
+ /*
+ Flush the normal query log, the update log, the binary log,
+ the slow query log, the relay log (if it exists) and the log
+ tables.
+ */
+
+ options|= REFRESH_BINARY_LOG;
+ options|= REFRESH_RELAY_LOG;
+ options|= REFRESH_SLOW_LOG;
+ options|= REFRESH_GENERAL_LOG;
+ options|= REFRESH_ENGINE_LOG;
+ options|= REFRESH_ERROR_LOG;
+ }
+
+ if (options & REFRESH_ERROR_LOG)
+ if (flush_error_log())
+ result= 1;
+
+ if ((options & REFRESH_SLOW_LOG) && opt_slow_log)
+ logger.flush_slow_log();
+
+ if ((options & REFRESH_GENERAL_LOG) && opt_log)
+ logger.flush_general_log();
+
+ if (options & REFRESH_ENGINE_LOG)
+ if (ha_flush_logs(NULL))
+ result= 1;
+
+ if (options & REFRESH_BINARY_LOG)
+ {
+ /*
+ Writing this command to the binlog may result in infinite loops
+ when doing mysqlbinlog|mysql, and anyway it does not really make
+ sense to log it automatically (would cause more trouble to users
+ than it would help them)
+ */
+ tmp_write_to_binlog= 0;
+ if (mysql_bin_log.is_open())
+ {
+ if (mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE))
+ *write_to_binlog= -1;
+ }
+ }
+ if (options & REFRESH_RELAY_LOG)
+ {
+#ifdef HAVE_REPLICATION
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (rotate_relay_log(active_mi))
+ *write_to_binlog= -1;
+ mysql_mutex_unlock(&LOCK_active_mi);
+#endif
+ }
+#ifdef HAVE_QUERY_CACHE
+ if (options & REFRESH_QUERY_CACHE_FREE)
+ {
+ query_cache.pack(); // FLUSH QUERY CACHE
+ options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
+ }
+ if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
+ {
+ query_cache.flush(); // RESET QUERY CACHE
+ }
+#endif /*HAVE_QUERY_CACHE*/
+
+ DBUG_ASSERT(!thd || thd->locked_tables_mode ||
+ !thd->mdl_context.has_locks() ||
+ thd->handler_tables_hash.records ||
+ thd->global_read_lock.is_acquired());
+
+ /*
+ Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
+ (see sql_yacc.yy)
+ */
+ if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
+ {
+ if ((options & REFRESH_READ_LOCK) && thd)
+ {
+ /*
+ On the first hand we need write lock on the tables to be flushed,
+ on the other hand we must not try to aspire a global read lock
+ if we have a write locked table as this would lead to a deadlock
+ when trying to reopen (and re-lock) the table after the flush.
+ */
+ if (thd->locked_tables_mode)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ return 1;
+ }
+ /*
+ Writing to the binlog could cause deadlocks, as we don't log
+ UNLOCK TABLES
+ */
+ tmp_write_to_binlog= 0;
+ if (thd->global_read_lock.lock_global_read_lock(thd))
+ return 1; // Killed
+ if (close_cached_tables(thd, tables,
+ ((options & REFRESH_FAST) ? FALSE : TRUE),
+ thd->variables.lock_wait_timeout))
+ result= 1;
+
+ if (thd->global_read_lock.make_global_read_lock_block_commit(thd)) // Killed
+ {
+ /* Don't leave things in a half-locked state */
+ thd->global_read_lock.unlock_global_read_lock(thd);
+ return 1;
+ }
+ }
+ else
+ {
+ if (thd && thd->locked_tables_mode)
+ {
+ /*
+ If we are under LOCK TABLES we should have a write
+ lock on tables which we are going to flush.
+ */
+ if (tables)
+ {
+ for (TABLE_LIST *t= tables; t; t= t->next_local)
+ if (!find_table_for_mdl_upgrade(thd->open_tables, t->db,
+ t->table_name, FALSE))
+ return 1;
+ }
+ else
+ {
+ for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
+ {
+ if (! tab->mdl_ticket->is_upgradable_or_exclusive())
+ {
+ my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),
+ tab->s->table_name.str);
+ return 1;
+ }
+ }
+ }
+ }
+
+ if (close_cached_tables(thd, tables,
+ ((options & REFRESH_FAST) ? FALSE : TRUE),
+ (thd ? thd->variables.lock_wait_timeout :
+ LONG_TIMEOUT)))
+ result= 1;
+ }
+ my_dbopt_cleanup();
+ }
+ if (options & REFRESH_HOSTS)
+ hostname_cache_refresh();
+ if (thd && (options & REFRESH_STATUS))
+ refresh_status(thd);
+ if (options & REFRESH_THREADS)
+ flush_thread_cache();
+#ifdef HAVE_REPLICATION
+ if (options & REFRESH_MASTER)
+ {
+ DBUG_ASSERT(thd);
+ tmp_write_to_binlog= 0;
+ if (reset_master(thd))
+ {
+ result=1;
+ }
+ }
+#endif
+#ifdef OPENSSL
+ if (options & REFRESH_DES_KEY_FILE)
+ {
+ if (des_key_file && load_des_key_file(des_key_file))
+ result= 1;
+ }
+#endif
+#ifdef HAVE_REPLICATION
+ if (options & REFRESH_SLAVE)
+ {
+ tmp_write_to_binlog= 0;
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (reset_slave(thd, active_mi))
+ result=1;
+ mysql_mutex_unlock(&LOCK_active_mi);
+ }
+#endif
+ if (options & REFRESH_USER_RESOURCES)
+ reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
+ if (*write_to_binlog != -1)
+ *write_to_binlog= tmp_write_to_binlog;
+ /*
+ If the query was killed then this function must fail.
+ */
+ return result || (thd ? thd->killed : 0);
+}
+
+
+/**
+ Implementation of FLUSH TABLES <table_list> WITH READ LOCK.
+
+ In brief: take exclusive locks, expel tables from the table
+ cache, reopen the tables, enter the 'LOCKED TABLES' mode,
+ downgrade the locks.
+ Note: the function is written to be called from
+ mysql_execute_command(), it is not reusable in arbitrary
+ execution context.
+
+ Required privileges
+ -------------------
+ Since the statement implicitly enters LOCK TABLES mode,
+ it requires LOCK TABLES privilege on every table.
+ But since the rest of FLUSH commands require
+ the global RELOAD_ACL, it also requires RELOAD_ACL.
+
+ Compatibility with the global read lock
+ ---------------------------------------
+ We don't wait for the GRL, since neither the
+ 5.1 combination that this new statement is intended to
+ replace (LOCK TABLE <list> WRITE; FLUSH TABLES;),
+ nor FLUSH TABLES WITH READ LOCK do.
+ @todo: this is not implemented, Dmitry disagrees.
+ Currently we wait for GRL in another connection,
+ but are compatible with a GRL in our own connection.
+
+ Behaviour under LOCK TABLES
+ ---------------------------
+ Bail out: i.e. don't perform an implicit UNLOCK TABLES.
+ This is not consistent with LOCK TABLES statement, but is
+ in line with behaviour of FLUSH TABLES WITH READ LOCK, and we
+ try to not introduce any new statements with implicit
+ semantics.
+
+ Compatibility with parallel updates
+ -----------------------------------
+ As a result, we will wait for all open transactions
+ against the tables to complete. After the lock downgrade,
+ new transactions will be able to read the tables, but not
+ write to them.
+
+ Differences from FLUSH TABLES <list>
+ -------------------------------------
+ - you can't flush WITH READ LOCK a non-existent table
+ - you can't flush WITH READ LOCK under LOCK TABLES
+
+ Effect on views and temporary tables.
+ ------------------------------------
+ You can only apply this command to existing base tables.
+ If a view with such name exists, ER_WRONG_OBJECT is returned.
+ If a temporary table with such name exists, it's ignored:
+ if there is a base table, it's used, otherwise ER_NO_SUCH_TABLE
+ is returned.
+
+ Handling of MERGE tables
+ ------------------------
+ For MERGE table this statement will open and lock child tables
+ for read (it is impossible to lock parent table without it).
+ Child tables won't be flushed unless they are explicitly present
+ in the statement's table list.
+
+ Implicit commit
+ ---------------
+ This statement causes an implicit commit before and
+ after it.
+
+ HANDLER SQL
+ -----------
+ If this connection has HANDLERs open against
+ some of the tables being FLUSHed, these handlers
+ are implicitly flushed (lose their position).
+*/
+
+bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
+{
+ Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
+ TABLE_LIST *table_list;
+
+ /*
+ This is called from SQLCOM_FLUSH, the transaction has
+ been committed implicitly.
+ */
+
+ if (thd->locked_tables_mode)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ goto error;
+ }
+
+ /*
+ Acquire SNW locks on tables to be flushed. Don't acquire global
+ IX and database-scope IX locks on the tables as this will make
+ this statement incompatible with FLUSH TABLES WITH READ LOCK.
+ */
+ if (lock_table_names(thd, all_tables, NULL,
+ thd->variables.lock_wait_timeout,
+ MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
+ goto error;
+
+ DEBUG_SYNC(thd,"flush_tables_with_read_lock_after_acquire_locks");
+
+ for (table_list= all_tables; table_list;
+ table_list= table_list->next_global)
+ {
+ /* Request removal of table from cache. */
+ tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
+ table_list->db,
+ table_list->table_name, FALSE);
+ /* Reset ticket to satisfy asserts in open_tables(). */
+ table_list->mdl_request.ticket= NULL;
+ }
+
+ /*
+ Before opening and locking tables the below call also waits
+ for old shares to go away, so the fact that we don't pass
+ MYSQL_LOCK_IGNORE_FLUSH flag to it is important.
+ Also we don't pass MYSQL_OPEN_HAS_MDL_LOCK flag as we want
+ to open underlying tables if merge table is flushed.
+ For underlying tables of the merge the below call has to
+ acquire SNW locks to ensure that they can be locked for
+ read without further waiting.
+ */
+ if (open_and_lock_tables(thd, all_tables, FALSE,
+ MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK,
+ &lock_tables_prelocking_strategy) ||
+ thd->locked_tables_list.init_locked_tables(thd))
+ {
+ goto error;
+ }
+ thd->variables.option_bits|= OPTION_TABLE_LOCK;
+
+ /*
+ We don't downgrade MDL_SHARED_NO_WRITE here as the intended
+ post effect of this call is identical to LOCK TABLES <...> READ,
+ and we didn't use thd->in_lock_talbes and
+ thd->sql_command= SQLCOM_LOCK_TABLES hacks to enter the LTM.
+ */
+
+ return FALSE;
+
+error:
+ return TRUE;
+}
+
+
+
diff --git a/sql/sql_reload.h b/sql/sql_reload.h
new file mode 100644
index 00000000000..ebb3d78c003
--- /dev/null
+++ b/sql/sql_reload.h
@@ -0,0 +1,26 @@
+#ifndef SQL_RELOAD_INCLUDED
+#define SQL_RELOAD_INCLUDED
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 */
+
+class THD;
+struct TABLE_LIST;
+
+bool reload_acl_and_cache(THD *thd, unsigned long options,
+ TABLE_LIST *tables, int *write_to_binlog);
+
+bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables);
+
+#endif
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index df7054c94d0..6a7b0b0b3ad 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2006 MySQL AB
+/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -17,9 +17,17 @@
Atomic rename of table; RENAME TABLE t1 to t2, tmp to t1 [,...]
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_rename.h"
+#include "sql_cache.h" // query_cache_*
+#include "sql_table.h" // build_table_filename
+#include "sql_view.h" // mysql_frm_type, mysql_rename_view
#include "sql_trigger.h"
-
+#include "lock.h" // MYSQL_OPEN_SKIP_TEMPORARY
+#include "sql_base.h" // tdc_remove_table, lock_table_names,
+#include "sql_handler.h" // mysql_ha_rm_tables
+#include "datadict.h"
static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list,
bool skip_error);
@@ -45,17 +53,14 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
if the user is trying to to do this in a transcation context
*/
- if (thd->locked_tables || thd->active_transaction())
+ if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction())
{
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
DBUG_RETURN(1);
}
- mysql_ha_rm_tables(thd, table_list, FALSE);
-
- if (wait_if_global_read_lock(thd,0,1))
- DBUG_RETURN(1);
+ mysql_ha_rm_tables(thd, table_list);
if (logger.is_log_table_enabled(QUERY_LOG_GENERAL) ||
logger.is_log_table_enabled(QUERY_LOG_SLOW))
@@ -134,14 +139,19 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
}
}
- pthread_mutex_lock(&LOCK_open);
- if (lock_table_names_exclusively(thd, table_list))
- {
- pthread_mutex_unlock(&LOCK_open);
+ if (lock_table_names(thd, table_list, 0, thd->variables.lock_wait_timeout,
+ MYSQL_OPEN_SKIP_TEMPORARY))
goto err;
- }
+
+ for (ren_table= table_list; ren_table; ren_table= ren_table->next_local)
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, ren_table->db,
+ ren_table->table_name, FALSE);
error=0;
+ /*
+ An exclusive lock on table names is satisfactory to ensure
+ no other thread accesses this table.
+ */
if ((ren_table=rename_tables(thd,table_list,0)))
{
/* Rename didn't succeed; rename back the tables in reverse order */
@@ -163,17 +173,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
error= 1;
}
- /*
- An exclusive lock on table names is satisfactory to ensure
- no other thread accesses this table.
- However, NDB assumes that handler::rename_tables is called under
- LOCK_open. And it indeed is, from ALTER TABLE.
- TODO: remove this limitation.
- We still should unlock LOCK_open as early as possible, to provide
- higher concurrency - query_cache_invalidate can take minutes to
- complete.
- */
- pthread_mutex_unlock(&LOCK_open);
if (!silent && !error)
{
@@ -185,12 +184,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
if (!error)
query_cache_invalidate3(thd, table_list, 0);
- pthread_mutex_lock(&LOCK_open);
- unlock_table_names(thd, table_list, (TABLE_LIST*) 0);
- pthread_mutex_unlock(&LOCK_open);
-
err:
- start_waiting_global_read_lock(thd);
DBUG_RETURN(error || binlog_error);
}
@@ -274,7 +268,7 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
build_table_filename(name, sizeof(name) - 1,
ren_table->db, old_alias, reg_ext, 0);
- frm_type= mysql_frm_type(thd, name, &table_type);
+ frm_type= dd_frm_type(thd, name, &table_type);
switch (frm_type)
{
case FRMTYPE_TABLE:
@@ -286,6 +280,7 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
{
if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
old_alias,
+ ren_table->table_name,
new_db,
new_alias)))
{
diff --git a/sql/sql_rename.h b/sql/sql_rename.h
new file mode 100644
index 00000000000..7fbf9f1e5cd
--- /dev/null
+++ b/sql/sql_rename.h
@@ -0,0 +1,27 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_RENAME_INCLUDED
+#define SQL_RENAME_INCLUDED
+
+class THD;
+struct TABLE_LIST;
+
+bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent);
+bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db,
+ char *new_table_name, char *new_table_alias,
+ bool skip_error);
+
+#endif /* SQL_RENAME_INCLUDED */
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index cb5aac863c0..7bca41f1265 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2006 MySQL AB & Sasha
+/* Copyright (C) 2000-2006 MySQL AB & Sasha, 2008-2009 Sun Microsystems, Inc
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
@@ -13,14 +13,18 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_parse.h" // check_access
#ifdef HAVE_REPLICATION
#include "rpl_mi.h"
#include "sql_repl.h"
+#include "sql_acl.h" // SUPER_ACL
#include "log_event.h"
#include "rpl_filter.h"
#include <my_dir.h>
+#include "rpl_handler.h"
int max_binlog_dump_events = 0; // unlimited
my_bool opt_sporadic_binlog_dump_fail = 0;
@@ -28,6 +32,14 @@ my_bool opt_sporadic_binlog_dump_fail = 0;
static int binlog_dump_count = 0;
#endif
+/**
+ a copy of active_mi->rli->slave_skip_counter, for showing in SHOW VARIABLES,
+ INFORMATION_SCHEMA.GLOBAL_VARIABLES and @@sql_slave_skip_counter without
+ taking all the mutexes needed to access active_mi->rli->slave_skip_counter
+ properly.
+*/
+uint sql_slave_skip_counter;
+
/*
fake_rotate_event() builds a fake (=which does not exist physically in any
binlog) Rotate event, which contains the name of the binlog we are going to
@@ -80,6 +92,32 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
DBUG_RETURN(0);
}
+/*
+ Reset thread transmit packet buffer for event sending
+
+ This function allocates header bytes for event transmission, and
+ should be called before store the event data to the packet buffer.
+*/
+static int reset_transmit_packet(THD *thd, ushort flags,
+ ulong *ev_offset, const char **errmsg)
+{
+ int ret= 0;
+ String *packet= &thd->packet;
+
+ /* reserve and set default header */
+ packet->length(0);
+ packet->set("\0", 1, &my_charset_bin);
+
+ if (RUN_HOOK(binlog_transmit, reserve_header, (thd, flags, packet)))
+ {
+ *errmsg= "Failed to run hook 'reserve_header'";
+ my_errno= ER_UNKNOWN_ERROR;
+ ret= 1;
+ }
+ *ev_offset= packet->length();
+ return ret;
+}
+
static int send_file(THD *thd)
{
NET* net = &thd->net;
@@ -116,13 +154,14 @@ static int send_file(THD *thd)
if (!strcmp(fname,"/dev/null"))
goto end;
- if ((fd = my_open(fname, O_RDONLY, MYF(0))) < 0)
+ if ((fd= mysql_file_open(key_file_send_file,
+ fname, O_RDONLY, MYF(0))) < 0)
{
errmsg = "on open of file";
goto err;
}
- while ((long) (bytes= my_read(fd, buf, IO_SIZE, MYF(0))) > 0)
+ while ((long) (bytes= mysql_file_read(fd, buf, IO_SIZE, MYF(0))) > 0)
{
if (my_net_write(net, buf, bytes))
{
@@ -143,7 +182,7 @@ static int send_file(THD *thd)
err:
my_net_set_read_timeout(net, old_timeout);
if (fd >= 0)
- (void) my_close(fd, MYF(0));
+ mysql_file_close(fd, MYF(0));
if (errmsg)
{
sql_print_error("Failed in send_file() %s", errmsg);
@@ -178,7 +217,7 @@ void adjust_linfo_offsets(my_off_t purge_offset)
{
THD *tmp;
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
I_List_iterator<THD> it(threads);
while ((tmp=it++))
@@ -186,7 +225,7 @@ void adjust_linfo_offsets(my_off_t purge_offset)
LOG_INFO* linfo;
if ((linfo = tmp->current_linfo))
{
- pthread_mutex_lock(&linfo->lock);
+ mysql_mutex_lock(&linfo->lock);
/*
Index file offset can be less that purge offset only if
we just started reading the index file. In that case
@@ -196,10 +235,10 @@ void adjust_linfo_offsets(my_off_t purge_offset)
linfo->fatal = (linfo->index_file_offset != 0);
else
linfo->index_file_offset -= purge_offset;
- pthread_mutex_unlock(&linfo->lock);
+ mysql_mutex_unlock(&linfo->lock);
}
}
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
}
@@ -209,7 +248,7 @@ bool log_in_use(const char* log_name)
THD *tmp;
bool result = 0;
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
I_List_iterator<THD> it(threads);
while ((tmp=it++))
@@ -217,38 +256,25 @@ bool log_in_use(const char* log_name)
LOG_INFO* linfo;
if ((linfo = tmp->current_linfo))
{
- pthread_mutex_lock(&linfo->lock);
+ mysql_mutex_lock(&linfo->lock);
result = !memcmp(log_name, linfo->log_file_name, log_name_len);
- pthread_mutex_unlock(&linfo->lock);
+ mysql_mutex_unlock(&linfo->lock);
if (result)
break;
}
}
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
return result;
}
bool purge_error_message(THD* thd, int res)
{
- uint errmsg= 0;
-
- switch (res) {
- case 0: break;
- case LOG_INFO_EOF: errmsg= ER_UNKNOWN_TARGET_BINLOG; break;
- case LOG_INFO_IO: errmsg= ER_IO_ERR_LOG_INDEX_READ; break;
- case LOG_INFO_INVALID:errmsg= ER_BINLOG_PURGE_PROHIBITED; break;
- case LOG_INFO_SEEK: errmsg= ER_FSEEK_FAIL; break;
- case LOG_INFO_MEM: errmsg= ER_OUT_OF_RESOURCES; break;
- case LOG_INFO_FATAL: errmsg= ER_BINLOG_PURGE_FATAL_ERR; break;
- case LOG_INFO_IN_USE: errmsg= ER_LOG_IN_USE; break;
- case LOG_INFO_EMFILE: errmsg= ER_BINLOG_PURGE_EMFILE; break;
- default: errmsg= ER_LOG_PURGE_UNKNOWN_ERR; break;
- }
+ uint errcode;
- if (errmsg)
+ if ((errcode= purge_log_get_error_code(res)) != 0)
{
- my_message(errmsg, ER(errmsg), MYF(0));
+ my_message(errcode, ER(errcode), MYF(0));
return TRUE;
}
my_ok(thd);
@@ -335,6 +361,73 @@ Increase max_allowed_packet on master";
}
+/**
+ An auxiliary function for calling in mysql_binlog_send
+ to initialize the heartbeat timeout in waiting for a binlogged event.
+
+ @param[in] thd THD to access a user variable
+
+ @return heartbeat period an ulonglong of nanoseconds
+ or zero if heartbeat was not demanded by slave
+*/
+static ulonglong get_heartbeat_period(THD * thd)
+{
+ my_bool null_value;
+ LEX_STRING name= { C_STRING_WITH_LEN("master_heartbeat_period")};
+ user_var_entry *entry=
+ (user_var_entry*) my_hash_search(&thd->user_vars, (uchar*) name.str,
+ name.length);
+ return entry? entry->val_int(&null_value) : 0;
+}
+
+/*
+ Function prepares and sends repliation heartbeat event.
+
+ @param net net object of THD
+ @param packet buffer to store the heartbeat instance
+ @param event_coordinates binlog file name and position of the last
+ real event master sent from binlog
+
+ @note
+ Among three essential pieces of heartbeat data Log_event::when
+ is computed locally.
+ The error to send is serious and should force terminating
+ the dump thread.
+*/
+static int send_heartbeat_event(NET* net, String* packet,
+ const struct event_coordinates *coord)
+{
+ DBUG_ENTER("send_heartbeat_event");
+ char header[LOG_EVENT_HEADER_LEN];
+ /*
+ 'when' (the timestamp) is set to 0 so that slave could distinguish between
+ real and fake Rotate events (if necessary)
+ */
+ memset(header, 0, 4); // when
+
+ header[EVENT_TYPE_OFFSET] = HEARTBEAT_LOG_EVENT;
+
+ char* p= coord->file_name + dirname_length(coord->file_name);
+
+ uint ident_len = strlen(p);
+ ulong event_len = ident_len + LOG_EVENT_HEADER_LEN;
+ int4store(header + SERVER_ID_OFFSET, server_id);
+ int4store(header + EVENT_LEN_OFFSET, event_len);
+ int2store(header + FLAGS_OFFSET, 0);
+
+ int4store(header + LOG_POS_OFFSET, coord->pos); // log_pos
+
+ packet->append(header, sizeof(header));
+ packet->append(p, ident_len); // log_file_name
+
+ if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) ||
+ net_flush(net))
+ {
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
/*
TODO: Clean up loop to only have one call to send_file()
*/
@@ -345,13 +438,18 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
LOG_INFO linfo;
char *log_file_name = linfo.log_file_name;
char search_file_name[FN_REFLEN], *name;
+
+ ulong ev_offset;
+
IO_CACHE log;
File file = -1;
String* packet = &thd->packet;
int error;
const char *errmsg = "Unknown error";
NET* net = &thd->net;
- pthread_mutex_t *log_lock;
+ mysql_mutex_t *log_lock;
+ mysql_cond_t *log_cond;
+
bool binlog_can_be_corrupted= FALSE;
#ifndef DBUG_OFF
int left_events = max_binlog_dump_events;
@@ -361,6 +459,30 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
DBUG_PRINT("enter",("log_ident: '%s' pos: %ld", log_ident, (long) pos));
bzero((char*) &log,sizeof(log));
+ /*
+ heartbeat_period from @master_heartbeat_period user variable
+ */
+ ulonglong heartbeat_period= get_heartbeat_period(thd);
+ struct timespec heartbeat_buf;
+ struct event_coordinates coord_buf;
+ struct timespec *heartbeat_ts= NULL;
+ struct event_coordinates *coord= NULL;
+ if (heartbeat_period != LL(0))
+ {
+ heartbeat_ts= &heartbeat_buf;
+ set_timespec_nsec(*heartbeat_ts, 0);
+ coord= &coord_buf;
+ coord->file_name= log_file_name; // initialization basing on what slave remembers
+ coord->pos= pos;
+ }
+ sql_print_information("Start binlog_dump to slave_server(%d), pos(%s, %lu)",
+ thd->server_id, log_ident, (ulong)pos);
+ if (RUN_HOOK(binlog_transmit, transmit_start, (thd, flags, log_ident, pos)))
+ {
+ errmsg= "Failed to run hook 'transmit_start'";
+ my_errno= ER_UNKNOWN_ERROR;
+ goto err;
+ }
#ifndef DBUG_OFF
if (opt_sporadic_binlog_dump_fail && (binlog_dump_count++ % 2))
@@ -399,9 +521,9 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
goto err;
}
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->current_linfo = &linfo;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0)
{
@@ -416,11 +538,9 @@ impossible position";
goto err;
}
- /*
- We need to start a packet with something other than 255
- to distinguish it from error
- */
- packet->set("\0", 1, &my_charset_bin); /* This is the start of a new packet */
+ /* reset transmit packet for the fake rotate event below */
+ if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
+ goto err;
/*
Tell the client about the log name with a fake Rotate event;
@@ -460,7 +580,7 @@ impossible position";
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
goto err;
}
- packet->set("\0", 1, &my_charset_bin);
+
/*
Adding MAX_LOG_EVENT_HEADER_LEN, since a binlog event can become
this larger than the corresponding packet (query) sent
@@ -473,9 +593,15 @@ impossible position";
mysql_bin_log, and it's already inited, and it will be destroyed
only at shutdown).
*/
- log_lock = mysql_bin_log.get_log_lock();
+ log_lock= mysql_bin_log.get_log_lock();
+ log_cond= mysql_bin_log.get_log_cond();
if (pos > BIN_LOG_HEADER_SIZE)
{
+ /* reset transmit packet for the event read from binary log
+ file */
+ if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
+ goto err;
+
/*
Try to find a Format_description_log_event at the beginning of
the binlog
@@ -483,29 +609,30 @@ impossible position";
if (!(error = Log_event::read_log_event(&log, packet, log_lock)))
{
/*
- The packet has offsets equal to the normal offsets in a binlog
- event +1 (the first character is \0).
+ The packet has offsets equal to the normal offsets in a
+ binlog event + ev_offset (the first ev_offset characters are
+ the header (default \0)).
*/
DBUG_PRINT("info",
("Looked for a Format_description_log_event, found event type %d",
- (*packet)[EVENT_TYPE_OFFSET+1]));
- if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT)
+ (*packet)[EVENT_TYPE_OFFSET+ev_offset]));
+ if ((*packet)[EVENT_TYPE_OFFSET+ev_offset] == FORMAT_DESCRIPTION_EVENT)
{
- binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+1] &
+ binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+ev_offset] &
LOG_EVENT_BINLOG_IN_USE_F);
- (*packet)[FLAGS_OFFSET+1] &= ~LOG_EVENT_BINLOG_IN_USE_F;
+ (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F;
/*
mark that this event with "log_pos=0", so the slave
should not increment master's binlog position
(rli->group_master_log_pos)
*/
- int4store((char*) packet->ptr()+LOG_POS_OFFSET+1, 0);
+ int4store((char*) packet->ptr()+LOG_POS_OFFSET+ev_offset, 0);
/*
if reconnect master sends FD event with `created' as 0
to avoid destroying temp tables.
*/
int4store((char*) packet->ptr()+LOG_EVENT_MINIMAL_HEADER_LEN+
- ST_CREATED_OFFSET+1, (ulong) 0);
+ ST_CREATED_OFFSET+ev_offset, (ulong) 0);
/* send it */
if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
{
@@ -531,8 +658,6 @@ impossible position";
Format_description_log_event will be found naturally if it is written.
*/
}
- /* reset the packet as we wrote to it in any case */
- packet->set("\0", 1, &my_charset_bin);
} /* end of if (pos > BIN_LOG_HEADER_SIZE); */
else
{
@@ -544,6 +669,12 @@ impossible position";
while (!net->error && net->vio != 0 && !thd->killed)
{
+ Log_event_type event_type= UNKNOWN_EVENT;
+
+ /* reset the transmit packet for the event read from binary log
+ file */
+ if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
+ goto err;
while (!(error = Log_event::read_log_event(&log, packet, log_lock)))
{
#ifndef DBUG_OFF
@@ -555,16 +686,31 @@ impossible position";
goto err;
}
#endif
+ /*
+ log's filename does not change while it's active
+ */
+ if (coord)
+ coord->pos= uint4korr(packet->ptr() + ev_offset + LOG_POS_OFFSET);
- if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT)
+ event_type= (Log_event_type)((*packet)[LOG_EVENT_OFFSET+ev_offset]);
+ if (event_type == FORMAT_DESCRIPTION_EVENT)
{
- binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+1] &
+ binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+ev_offset] &
LOG_EVENT_BINLOG_IN_USE_F);
- (*packet)[FLAGS_OFFSET+1] &= ~LOG_EVENT_BINLOG_IN_USE_F;
+ (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F;
}
- else if ((*packet)[EVENT_TYPE_OFFSET+1] == STOP_EVENT)
+ else if (event_type == STOP_EVENT)
binlog_can_be_corrupted= FALSE;
+ pos = my_b_tell(&log);
+ if (RUN_HOOK(binlog_transmit, before_send_event,
+ (thd, flags, packet, log_file_name, pos)))
+ {
+ my_errno= ER_UNKNOWN_ERROR;
+ errmsg= "run 'before_send_event' hook failed";
+ goto err;
+ }
+
if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
{
errmsg = "Failed on my_net_write()";
@@ -572,9 +718,8 @@ impossible position";
goto err;
}
- DBUG_PRINT("info", ("log event code %d",
- (*packet)[LOG_EVENT_OFFSET+1] ));
- if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT)
+ DBUG_PRINT("info", ("log event code %d", event_type));
+ if (event_type == LOAD_EVENT)
{
if (send_file(thd))
{
@@ -583,7 +728,17 @@ impossible position";
goto err;
}
}
- packet->set("\0", 1, &my_charset_bin);
+
+ if (RUN_HOOK(binlog_transmit, after_send_event, (thd, flags, packet)))
+ {
+ errmsg= "Failed to run hook 'after_send_event'";
+ my_errno= ER_UNKNOWN_ERROR;
+ goto err;
+ }
+
+ /* reset transmit packet for next loop */
+ if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
+ goto err;
}
/*
@@ -634,6 +789,11 @@ impossible position";
}
#endif
+ /* reset the transmit packet for the event read from binary log
+ file */
+ if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
+ goto err;
+
/*
No one will update the log while we are reading
now, but we'll be quick and just read one record
@@ -644,40 +804,97 @@ impossible position";
has not been updated since last read.
*/
- pthread_mutex_lock(log_lock);
- switch (error= Log_event::read_log_event(&log, packet, (pthread_mutex_t*) 0)) {
+ mysql_mutex_lock(log_lock);
+ switch (error= Log_event::read_log_event(&log, packet, (mysql_mutex_t*) 0)) {
case 0:
/* we read successfully, so we'll need to send it to the slave */
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
read_packet = 1;
+ if (coord)
+ coord->pos= uint4korr(packet->ptr() + ev_offset + LOG_POS_OFFSET);
+ event_type= (Log_event_type)((*packet)[LOG_EVENT_OFFSET+ev_offset]);
break;
case LOG_READ_EOF:
+ {
+ int ret;
+ ulong signal_cnt;
DBUG_PRINT("wait",("waiting for data in binary log"));
if (thd->server_id==0) // for mysqlbinlog (mysqlbinlog.server_id==0)
{
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
goto end;
}
- if (!thd->killed)
- {
- /* Note that the following call unlocks lock_log */
- mysql_bin_log.wait_for_update(thd, 0);
- }
- else
- pthread_mutex_unlock(log_lock);
- DBUG_PRINT("wait",("binary log received update"));
- break;
- default:
- pthread_mutex_unlock(log_lock);
+#ifndef DBUG_OFF
+ ulong hb_info_counter= 0;
+#endif
+ const char* old_msg= thd->proc_info;
+ signal_cnt= mysql_bin_log.signal_cnt;
+ do
+ {
+ if (coord)
+ {
+ DBUG_ASSERT(heartbeat_ts && heartbeat_period != 0);
+ set_timespec_nsec(*heartbeat_ts, heartbeat_period);
+ }
+ thd->enter_cond(log_cond, log_lock,
+ "Master has sent all binlog to slave; "
+ "waiting for binlog to be updated");
+ ret= mysql_bin_log.wait_for_update_bin_log(thd, heartbeat_ts);
+ DBUG_ASSERT(ret == 0 || (heartbeat_period != 0 && coord != NULL));
+ if (ret == ETIMEDOUT || ret == ETIME)
+ {
+#ifndef DBUG_OFF
+ if (hb_info_counter < 3)
+ {
+ sql_print_information("master sends heartbeat message");
+ hb_info_counter++;
+ if (hb_info_counter == 3)
+ sql_print_information("the rest of heartbeat info skipped ...");
+ }
+#endif
+ /* reset transmit packet for the heartbeat event */
+ if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
+ {
+ thd->exit_cond(old_msg);
+ goto err;
+ }
+ if (send_heartbeat_event(net, packet, coord))
+ {
+ errmsg = "Failed on my_net_write()";
+ my_errno= ER_UNKNOWN_ERROR;
+ thd->exit_cond(old_msg);
+ goto err;
+ }
+ }
+ else
+ {
+ DBUG_PRINT("wait",("binary log received update or a broadcast signal caught"));
+ }
+ } while (signal_cnt == mysql_bin_log.signal_cnt && !thd->killed);
+ thd->exit_cond(old_msg);
+ }
+ break;
+
+ default:
+ mysql_mutex_unlock(log_lock);
test_for_non_eof_log_read_errors(error, &errmsg);
goto err;
}
if (read_packet)
- {
- thd_proc_info(thd, "Sending binlog event to slave");
+ {
+ thd_proc_info(thd, "Sending binlog event to slave");
+ pos = my_b_tell(&log);
+ if (RUN_HOOK(binlog_transmit, before_send_event,
+ (thd, flags, packet, log_file_name, pos)))
+ {
+ my_errno= ER_UNKNOWN_ERROR;
+ errmsg= "run 'before_send_event' hook failed";
+ goto err;
+ }
+
if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) )
{
errmsg = "Failed on my_net_write()";
@@ -685,7 +902,7 @@ impossible position";
goto err;
}
- if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT)
+ if (event_type == LOAD_EVENT)
{
if (send_file(thd))
{
@@ -694,11 +911,13 @@ impossible position";
goto err;
}
}
- packet->set("\0", 1, &my_charset_bin);
- /*
- No need to net_flush because we will get to flush later when
- we hit EOF pretty quick
- */
+
+ if (RUN_HOOK(binlog_transmit, after_send_event, (thd, flags, packet)))
+ {
+ my_errno= ER_UNKNOWN_ERROR;
+ errmsg= "Failed to run hook 'after_send_event'";
+ goto err;
+ }
}
log.error=0;
@@ -729,8 +948,12 @@ impossible position";
break;
end_io_cache(&log);
- (void) my_close(file, MYF(MY_WME));
+ mysql_file_close(file, MYF(MY_WME));
+ /* reset transmit packet for the possible fake rotate event */
+ if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
+ goto err;
+
/*
Call fake_rotate_event() in case the previous log (the one which
we have just finished reading) did not contain a Rotate event
@@ -748,26 +971,28 @@ impossible position";
goto err;
}
- packet->length(0);
- packet->append('\0');
+ if (coord)
+ coord->file_name= log_file_name; // reset to the next
}
}
end:
end_io_cache(&log);
- (void)my_close(file, MYF(MY_WME));
+ mysql_file_close(file, MYF(MY_WME));
+ RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
my_eof(thd);
thd_proc_info(thd, "Waiting to finalize termination");
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
thd->variables.max_allowed_packet= old_max_allowed_packet;
DBUG_VOID_RETURN;
err:
thd_proc_info(thd, "Waiting to finalize termination");
end_io_cache(&log);
+ RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
/*
Exclude iteration through thread list
this is needed for purge_logs() - it will iterate through
@@ -775,11 +1000,11 @@ err:
this mutex will make sure that it never tried to update our linfo
after we return from this stack frame
*/
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
if (file >= 0)
- (void) my_close(file, MYF(MY_WME));
+ mysql_file_close(file, MYF(MY_WME));
thd->variables.max_allowed_packet= old_max_allowed_packet;
my_message(my_errno, errmsg, MYF(0));
@@ -795,7 +1020,7 @@ err:
@param mi Pointer to Master_info object for the slave's IO thread.
- @param net_report If true, saves the exit status into thd->main_da.
+ @param net_report If true, saves the exit status into thd->stmt_da.
@retval 0 success
@retval 1 error
@@ -806,7 +1031,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
int thread_mask;
DBUG_ENTER("start_slave");
- if (check_access(thd, SUPER_ACL, any_db,0,0,0,0))
+ if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0))
DBUG_RETURN(1);
lock_slave_threads(mi); // this allows us to cleanly read slave_running
// Get a mask of _stopped_ threads
@@ -833,7 +1058,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
*/
if (thread_mask & SLAVE_SQL)
{
- pthread_mutex_lock(&mi->rli.data_lock);
+ mysql_mutex_lock(&mi->rli.data_lock);
if (thd->lex->mi.pos)
{
@@ -887,7 +1112,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
ER(ER_MISSING_SKIP_SLAVE));
}
- pthread_mutex_unlock(&mi->rli.data_lock);
+ mysql_mutex_unlock(&mi->rli.data_lock);
}
else if (thd->lex->mi.pos || thd->lex->mi.relay_log_pos)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNTIL_COND_IGNORED,
@@ -933,7 +1158,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
@param mi Pointer to Master_info object for the slave's IO thread.
- @param net_report If true, saves the exit status into thd->main_da.
+ @param net_report If true, saves the exit status into thd->stmt_da.
@retval 0 success
@retval 1 error
@@ -946,7 +1171,7 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report )
if (!thd)
thd = current_thd;
- if (check_access(thd, SUPER_ACL, any_db,0,0,0,0))
+ if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0))
DBUG_RETURN(1);
thd_proc_info(thd, "Killing slave");
int thread_mask;
@@ -1030,14 +1255,8 @@ int reset_slave(THD *thd, Master_info* mi)
goto err;
}
- /*
- Clear master's log coordinates and reset host/user/etc to the values
- specified in mysqld's options (only for good display of SHOW SLAVE STATUS;
- next init_master_info() (in start_slave() for example) would have set them
- the same way; but here this is for the case where the user does SHOW SLAVE
- STATUS; before doing START SLAVE;
- */
- init_master_info_with_options(mi);
+ /* Clear master's log coordinates */
+ init_master_log_pos(mi);
/*
Reset errors (the idea is that we forget about the
old master).
@@ -1050,19 +1269,22 @@ int reset_slave(THD *thd, Master_info* mi)
end_master_info(mi);
// and delete these two files
fn_format(fname, master_info_file, mysql_data_home, "", 4+32);
- if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
+ if (mysql_file_stat(key_file_master_info, fname, &stat_area, MYF(0)) &&
+ mysql_file_delete(key_file_master_info, fname, MYF(MY_WME)))
{
error=1;
goto err;
}
// delete relay_log_info_file
fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32);
- if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
+ if (mysql_file_stat(key_file_relay_log_info, fname, &stat_area, MYF(0)) &&
+ mysql_file_delete(key_file_relay_log_info, fname, MYF(MY_WME)))
{
error=1;
goto err;
}
+ RUN_HOOK(binlog_relay_io, after_reset_slave, (thd, mi));
err:
unlock_slave_threads(mi);
if (error)
@@ -1074,7 +1296,7 @@ err:
Kill all Binlog_dump threads which previously talked to the same slave
("same" means with the same server id). Indeed, if the slave stops, if the
- Binlog_dump thread is waiting (pthread_cond_wait) for binlog update, then it
+ Binlog_dump thread is waiting (mysql_cond_wait) for binlog update, then it
will keep existing until a query is written to the binlog. If the master is
idle, then this could last long, and if the slave reconnects, we could have 2
Binlog_dump threads in SHOW PROCESSLIST, until a query is written to the
@@ -1092,7 +1314,7 @@ err:
void kill_zombie_dump_threads(uint32 slave_server_id)
{
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
I_List_iterator<THD> it(threads);
THD *tmp;
@@ -1101,11 +1323,11 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
if (tmp->command == COM_BINLOG_DUMP &&
tmp->server_id == slave_server_id)
{
- pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
+ mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
break;
}
}
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
if (tmp)
{
/*
@@ -1114,7 +1336,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
again. We just to do kill the thread ourselves.
*/
tmp->awake(THD::KILL_QUERY);
- pthread_mutex_unlock(&tmp->LOCK_thd_data);
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
}
}
@@ -1136,6 +1358,7 @@ bool change_master(THD* thd, Master_info* mi)
int thread_mask;
const char* errmsg= 0;
bool need_relay_log_purge= 1;
+ bool ret= FALSE;
char saved_host[HOSTNAME_LENGTH + 1];
uint saved_port;
char saved_log_name[FN_REFLEN];
@@ -1144,22 +1367,35 @@ bool change_master(THD* thd, Master_info* mi)
lock_slave_threads(mi);
init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
+ LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
if (thread_mask) // We refuse if any slave thread is running
{
my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
- unlock_slave_threads(mi);
- DBUG_RETURN(TRUE);
+ ret= TRUE;
+ goto err;
}
thd_proc_info(thd, "Changing master");
- LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
+ /*
+ We need to check if there is an empty master_host. Otherwise
+ change master succeeds, a master.info file is created containing
+ empty master_host string and when issuing: start slave; an error
+ is thrown stating that the server is not configured as slave.
+ (See BUG#28796).
+ */
+ if(lex_mi->host && !*lex_mi->host)
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "MASTER_HOST");
+ unlock_slave_threads(mi);
+ DBUG_RETURN(TRUE);
+ }
// TODO: see if needs re-write
if (init_master_info(mi, master_info_file, relay_log_info_file, 0,
thread_mask))
{
my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
- unlock_slave_threads(mi);
- DBUG_RETURN(TRUE);
+ ret= TRUE;
+ goto err;
}
/*
@@ -1206,13 +1442,46 @@ bool change_master(THD* thd, Master_info* mi)
mi->port = lex_mi->port;
if (lex_mi->connect_retry)
mi->connect_retry = lex_mi->connect_retry;
+ if (lex_mi->heartbeat_opt != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
+ mi->heartbeat_period = lex_mi->heartbeat_period;
+ else
+ mi->heartbeat_period= (float) min(SLAVE_MAX_HEARTBEAT_PERIOD,
+ (slave_net_timeout/2.0));
+ mi->received_heartbeats= LL(0); // counter lives until master is CHANGEd
+ /*
+ reset the last time server_id list if the current CHANGE MASTER
+ is mentioning IGNORE_SERVER_IDS= (...)
+ */
+ if (lex_mi->repl_ignore_server_ids_opt == LEX_MASTER_INFO::LEX_MI_ENABLE)
+ reset_dynamic(&mi->ignore_server_ids);
+ for (uint i= 0; i < lex_mi->repl_ignore_server_ids.elements; i++)
+ {
+ ulong s_id;
+ get_dynamic(&lex_mi->repl_ignore_server_ids, (uchar*) &s_id, i);
+ if (s_id == ::server_id && replicate_same_server_id)
+ {
+ my_error(ER_SLAVE_IGNORE_SERVER_IDS, MYF(0), s_id);
+ ret= TRUE;
+ goto err;
+ }
+ else
+ {
+ if (bsearch((const ulong *) &s_id,
+ mi->ignore_server_ids.buffer,
+ mi->ignore_server_ids.elements, sizeof(ulong),
+ (int (*) (const void*, const void*))
+ change_master_server_id_cmp) == NULL)
+ insert_dynamic(&mi->ignore_server_ids, (uchar*) &s_id);
+ }
+ }
+ sort_dynamic(&mi->ignore_server_ids, (qsort_cmp) change_master_server_id_cmp);
- if (lex_mi->ssl != LEX_MASTER_INFO::SSL_UNCHANGED)
- mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::SSL_ENABLE);
+ if (lex_mi->ssl != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
+ mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::LEX_MI_ENABLE);
- if (lex_mi->ssl_verify_server_cert != LEX_MASTER_INFO::SSL_UNCHANGED)
+ if (lex_mi->ssl_verify_server_cert != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
mi->ssl_verify_server_cert=
- (lex_mi->ssl_verify_server_cert == LEX_MASTER_INFO::SSL_ENABLE);
+ (lex_mi->ssl_verify_server_cert == LEX_MASTER_INFO::LEX_MI_ENABLE);
if (lex_mi->ssl_ca)
strmake(mi->ssl_ca, lex_mi->ssl_ca, sizeof(mi->ssl_ca)-1);
@@ -1235,9 +1504,11 @@ bool change_master(THD* thd, Master_info* mi)
if (lex_mi->relay_log_name)
{
need_relay_log_purge= 0;
- strmake(mi->rli.group_relay_log_name,lex_mi->relay_log_name,
+ char relay_log_name[FN_REFLEN];
+ mi->rli.relay_log.make_log_name(relay_log_name, lex_mi->relay_log_name);
+ strmake(mi->rli.group_relay_log_name, relay_log_name,
sizeof(mi->rli.group_relay_log_name)-1);
- strmake(mi->rli.event_relay_log_name,lex_mi->relay_log_name,
+ strmake(mi->rli.event_relay_log_name, relay_log_name,
sizeof(mi->rli.event_relay_log_name)-1);
}
@@ -1284,8 +1555,8 @@ bool change_master(THD* thd, Master_info* mi)
if (flush_master_info(mi, FALSE, FALSE))
{
my_error(ER_RELAY_LOG_INIT, MYF(0), "Failed to flush master info file");
- unlock_slave_threads(mi);
- DBUG_RETURN(TRUE);
+ ret= TRUE;
+ goto err;
}
if (need_relay_log_purge)
{
@@ -1296,8 +1567,8 @@ bool change_master(THD* thd, Master_info* mi)
&errmsg))
{
my_error(ER_RELAY_LOG_FAIL, MYF(0), errmsg);
- unlock_slave_threads(mi);
- DBUG_RETURN(TRUE);
+ ret= TRUE;
+ goto err;
}
}
else
@@ -1312,8 +1583,8 @@ bool change_master(THD* thd, Master_info* mi)
&msg, 0))
{
my_error(ER_RELAY_LOG_INIT, MYF(0), msg);
- unlock_slave_threads(mi);
- DBUG_RETURN(TRUE);
+ ret= TRUE;
+ goto err;
}
}
/*
@@ -1334,7 +1605,7 @@ bool change_master(THD* thd, Master_info* mi)
if (!mi->rli.group_master_log_name[0]) // uninitialized case
mi->rli.group_master_log_pos=0;
- pthread_mutex_lock(&mi->rli.data_lock);
+ mysql_mutex_lock(&mi->rli.data_lock);
mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */
/* Clear the errors, for a clean start */
mi->rli.clear_error();
@@ -1356,13 +1627,16 @@ bool change_master(THD* thd, Master_info* mi)
not exist anymore).
*/
flush_relay_log_info(&mi->rli);
- pthread_cond_broadcast(&mi->data_cond);
- pthread_mutex_unlock(&mi->rli.data_lock);
+ mysql_cond_broadcast(&mi->data_cond);
+ mysql_mutex_unlock(&mi->rli.data_lock);
+err:
unlock_slave_threads(mi);
thd_proc_info(thd, 0);
- my_ok(thd);
- DBUG_RETURN(FALSE);
+ if (ret == FALSE)
+ my_ok(thd);
+ delete_dynamic(&lex_mi->repl_ignore_server_ids); //freeing of parser-time alloc
+ DBUG_RETURN(ret);
}
@@ -1383,7 +1657,11 @@ int reset_master(THD* thd)
ER(ER_FLUSH_MASTER_BINLOG_CLOSED), MYF(ME_BELL+ME_WAITTANG));
return 1;
}
- return mysql_bin_log.reset_logs(thd);
+
+ if (mysql_bin_log.reset_logs(thd))
+ return 1;
+ RUN_HOOK(binlog_transmit, after_reset_master, (thd, 0 /* flags */));
+ return 0;
}
int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
@@ -1421,25 +1699,42 @@ bool mysql_show_binlog_events(THD* thd)
bool ret = TRUE;
IO_CACHE log;
File file = -1;
+ MYSQL_BIN_LOG *binary_log= NULL;
int old_max_allowed_packet= thd->variables.max_allowed_packet;
DBUG_ENTER("mysql_show_binlog_events");
Log_event::init_show_field_list(&field_list);
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
Format_description_log_event *description_event= new
Format_description_log_event(3); /* MySQL 4.0 by default */
- /*
- Wait for handlers to insert any pending information
- into the binlog. For e.g. ndb which updates the binlog asynchronously
- this is needed so that the uses sees all its own commands in the binlog
- */
- ha_binlog_wait(thd);
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS ||
+ thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
- if (mysql_bin_log.is_open())
+ /* select wich binary log to use: binlog or relay */
+ if ( thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS )
+ {
+ /*
+ Wait for handlers to insert any pending information
+ into the binlog. For e.g. ndb which updates the binlog asynchronously
+ this is needed so that the uses sees all its own commands in the binlog
+ */
+ ha_binlog_wait(thd);
+
+ binary_log= &mysql_bin_log;
+ }
+ else /* showing relay log contents */
+ {
+ if (!active_mi)
+ DBUG_RETURN(TRUE);
+
+ binary_log= &(active_mi->rli.relay_log);
+ }
+
+ if (binary_log->is_open())
{
LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
SELECT_LEX_UNIT *unit= &thd->lex->unit;
@@ -1447,7 +1742,7 @@ bool mysql_show_binlog_events(THD* thd)
my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
char search_file_name[FN_REFLEN], *name;
const char *log_file_name = lex_mi->log_file_name;
- pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
+ mysql_mutex_t *log_lock = binary_log->get_log_lock();
LOG_INFO linfo;
Log_event* ev;
@@ -1457,21 +1752,21 @@ bool mysql_show_binlog_events(THD* thd)
name= search_file_name;
if (log_file_name)
- mysql_bin_log.make_log_name(search_file_name, log_file_name);
+ binary_log->make_log_name(search_file_name, log_file_name);
else
name=0; // Find first log
linfo.index_file_offset = 0;
- if (mysql_bin_log.find_log_pos(&linfo, name, 1))
+ if (binary_log->find_log_pos(&linfo, name, 1))
{
errmsg = "Could not find target log";
goto err;
}
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->current_linfo = &linfo;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0)
goto err;
@@ -1481,7 +1776,7 @@ bool mysql_show_binlog_events(THD* thd)
*/
thd->variables.max_allowed_packet += MAX_LOG_EVENT_HEADER;
- pthread_mutex_lock(log_lock);
+ mysql_mutex_lock(log_lock);
/*
open_binlog() sought to position 4.
@@ -1491,7 +1786,7 @@ bool mysql_show_binlog_events(THD* thd)
This code will fail on a mixed relay log (one which has Format_desc then
Rotate then Format_desc).
*/
- ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,description_event);
+ ev= Log_event::read_log_event(&log, (mysql_mutex_t*)0, description_event);
if (ev)
{
if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
@@ -1512,7 +1807,7 @@ bool mysql_show_binlog_events(THD* thd)
}
for (event_count = 0;
- (ev = Log_event::read_log_event(&log,(pthread_mutex_t*) 0,
+ (ev = Log_event::read_log_event(&log, (mysql_mutex_t*) 0,
description_event)); )
{
if (event_count >= limit_start &&
@@ -1520,7 +1815,7 @@ bool mysql_show_binlog_events(THD* thd)
{
errmsg = "Net error";
delete ev;
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
goto err;
}
@@ -1534,11 +1829,11 @@ bool mysql_show_binlog_events(THD* thd)
if (event_count < limit_end && log.error)
{
errmsg = "Wrong offset or I/O error";
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
goto err;
}
- pthread_mutex_unlock(log_lock);
+ mysql_mutex_unlock(log_lock);
}
ret= FALSE;
@@ -1548,7 +1843,7 @@ err:
if (file >= 0)
{
end_io_cache(&log);
- (void) my_close(file, MYF(MY_WME));
+ mysql_file_close(file, MYF(MY_WME));
}
if (errmsg)
@@ -1557,9 +1852,9 @@ err:
else
my_eof(thd);
- pthread_mutex_lock(&LOCK_thread_count);
+ mysql_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
- pthread_mutex_unlock(&LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
thd->variables.max_allowed_packet= old_max_allowed_packet;
DBUG_RETURN(ret);
}
@@ -1585,7 +1880,7 @@ bool show_binlog_info(THD* thd)
field_list.push_back(new Item_empty_string("Binlog_Do_DB",255));
field_list.push_back(new Item_empty_string("Binlog_Ignore_DB",255));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
protocol->prepare_for_resend();
@@ -1637,16 +1932,16 @@ bool show_binlogs(THD* thd)
field_list.push_back(new Item_empty_string("Log_name", 255));
field_list.push_back(new Item_return_int("File_size", 20,
MYSQL_TYPE_LONGLONG));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
- pthread_mutex_lock(mysql_bin_log.get_log_lock());
+ mysql_mutex_lock(mysql_bin_log.get_log_lock());
mysql_bin_log.lock_index();
index_file=mysql_bin_log.get_index_file();
mysql_bin_log.raw_get_current_log(&cur); // dont take mutex
- pthread_mutex_unlock(mysql_bin_log.get_log_lock()); // lockdep, OK
+ mysql_mutex_unlock(mysql_bin_log.get_log_lock()); // lockdep, OK
cur_dir_len= dirname_length(cur.log_file_name);
@@ -1669,11 +1964,12 @@ bool show_binlogs(THD* thd)
else
{
/* this is an old log, open it and find the size */
- if ((file= my_open(fname, O_RDONLY | O_SHARE | O_BINARY,
- MYF(0))) >= 0)
+ if ((file= mysql_file_open(key_file_binlog,
+ fname, O_RDONLY | O_SHARE | O_BINARY,
+ MYF(0))) >= 0)
{
- file_length= (ulonglong) my_seek(file, 0L, MY_SEEK_END, MYF(0));
- my_close(file, MYF(0));
+ file_length= (ulonglong) mysql_file_seek(file, 0L, MY_SEEK_END, MYF(0));
+ mysql_file_close(file, MYF(0));
}
}
protocol->store(file_length);
@@ -1708,7 +2004,7 @@ int log_loaded_block(IO_CACHE* file)
uchar* buffer= (uchar*) my_b_get_buffer_start(file);
uint max_event_size= current_thd->variables.max_allowed_packet;
lf_info= (LOAD_FILE_INFO*) file->arg;
- if (lf_info->thd->current_stmt_binlog_row_based)
+ if (lf_info->thd->is_current_stmt_binlog_format_row())
DBUG_RETURN(0);
if (lf_info->last_pos_in_file != HA_POS_ERROR &&
lf_info->last_pos_in_file >= my_b_get_pos_in_file(file))
@@ -1741,124 +2037,4 @@ int log_loaded_block(IO_CACHE* file)
DBUG_RETURN(0);
}
-/*
- Replication System Variables
-*/
-
-class sys_var_slave_skip_counter :public sys_var
-{
-public:
- sys_var_slave_skip_counter(sys_var_chain *chain, const char *name_arg)
- :sys_var(name_arg)
- { chain_sys_var(chain); }
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
- /*
- We can't retrieve the value of this, so we don't have to define
- type() or value_ptr()
- */
-};
-
-class sys_var_sync_binlog_period :public sys_var_long_ptr
-{
-public:
- sys_var_sync_binlog_period(sys_var_chain *chain, const char *name_arg,
- ulong *value_ptr)
- :sys_var_long_ptr(chain, name_arg,value_ptr) {}
- bool update(THD *thd, set_var *var);
-};
-
-static sys_var_chain vars = { NULL, NULL };
-
-static sys_var_const sys_log_slave_updates(&vars, "log_slave_updates",
- OPT_GLOBAL, SHOW_MY_BOOL,
- (uchar*) &opt_log_slave_updates);
-static sys_var_const sys_relay_log(&vars, "relay_log",
- OPT_GLOBAL, SHOW_CHAR_PTR,
- (uchar*) &opt_relay_logname);
-static sys_var_const sys_relay_log_index(&vars, "relay_log_index",
- OPT_GLOBAL, SHOW_CHAR_PTR,
- (uchar*) &opt_relaylog_index_name);
-static sys_var_const sys_relay_log_info_file(&vars, "relay_log_info_file",
- OPT_GLOBAL, SHOW_CHAR_PTR,
- (uchar*) &relay_log_info_file);
-static sys_var_bool_ptr sys_relay_log_purge(&vars, "relay_log_purge",
- &relay_log_purge);
-static sys_var_const sys_relay_log_space_limit(&vars,
- "relay_log_space_limit",
- OPT_GLOBAL, SHOW_LONGLONG,
- (uchar*)
- &relay_log_space_limit);
-static sys_var_const sys_slave_load_tmpdir(&vars, "slave_load_tmpdir",
- OPT_GLOBAL, SHOW_CHAR_PTR,
- (uchar*) &slave_load_tmpdir);
-static sys_var_long_ptr sys_slave_net_timeout(&vars, "slave_net_timeout",
- &slave_net_timeout);
-static sys_var_const sys_slave_skip_errors(&vars, "slave_skip_errors",
- OPT_GLOBAL, SHOW_CHAR,
- (uchar*) slave_skip_error_names);
-static sys_var_long_ptr sys_slave_trans_retries(&vars, "slave_transaction_retries",
- &slave_trans_retries);
-static sys_var_sync_binlog_period sys_sync_binlog_period(&vars, "sync_binlog", &sync_binlog_period);
-static sys_var_slave_skip_counter sys_slave_skip_counter(&vars, "sql_slave_skip_counter");
-
-
-bool sys_var_slave_skip_counter::check(THD *thd, set_var *var)
-{
- int result= 0;
- pthread_mutex_lock(&LOCK_active_mi);
- pthread_mutex_lock(&active_mi->rli.run_lock);
- if (active_mi->rli.slave_running)
- {
- my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
- result=1;
- }
- pthread_mutex_unlock(&active_mi->rli.run_lock);
- pthread_mutex_unlock(&LOCK_active_mi);
- var->save_result.ulong_value= (ulong) var->value->val_int();
- return result;
-}
-
-
-bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
-{
- pthread_mutex_lock(&LOCK_active_mi);
- pthread_mutex_lock(&active_mi->rli.run_lock);
- /*
- The following test should normally never be true as we test this
- in the check function; To be safe against multiple
- SQL_SLAVE_SKIP_COUNTER request, we do the check anyway
- */
- if (!active_mi->rli.slave_running)
- {
- pthread_mutex_lock(&active_mi->rli.data_lock);
- active_mi->rli.slave_skip_counter= var->save_result.ulong_value;
- pthread_mutex_unlock(&active_mi->rli.data_lock);
- }
- pthread_mutex_unlock(&active_mi->rli.run_lock);
- pthread_mutex_unlock(&LOCK_active_mi);
- return 0;
-}
-
-
-bool sys_var_sync_binlog_period::update(THD *thd, set_var *var)
-{
- sync_binlog_period= (ulong) var->save_result.ulonglong_value;
- return 0;
-}
-
-int init_replication_sys_vars()
-{
- if (mysql_add_sys_var_chain(vars.first, my_long_options))
- {
- /* should not happen */
- fprintf(stderr, "failed to initialize replication system variables");
- unireg_abort(1);
- }
- return 0;
-}
-
#endif /* HAVE_REPLICATION */
-
-
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index d5c9040f8dc..4d3b0b8d62c 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -13,6 +13,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#ifndef SQL_REPL_INCLUDED
+#define SQL_REPL_INCLUDED
+
#include "rpl_filter.h"
#ifdef HAVE_REPLICATION
@@ -62,6 +65,8 @@ typedef struct st_load_file_info
int log_loaded_block(IO_CACHE* file);
int init_replication_sys_vars();
+void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
#endif /* HAVE_REPLICATION */
+#endif /* SQL_REPL_INCLUDED */
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index c17cb946fa3..ef2dd1d76e1 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -28,15 +28,33 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
#include "sql_select.h"
-#include "sql_cursor.h"
-
+#include "sql_cache.h" // query_cache_*
+#include "sql_table.h" // primary_key_name
+#include "probes_mysql.h"
+#include "key.h" // key_copy, key_cmp, key_cmp_if_same
+#include "lock.h" // mysql_unlock_some_tables,
+ // mysql_unlock_read_tables
+#include "sql_show.h" // append_identifier
+#include "sql_base.h" // setup_wild, setup_fields, fill_record
+#include "sql_parse.h" // check_stack_overrun
+#include "sql_partition.h" // make_used_partitions_str
+#include "sql_acl.h" // *_ACL
+#include "sql_test.h" // print_where, print_keyuse_array,
+ // print_sjm, print_plan, TEST_join
+#include "records.h" // init_read_record, end_read_record
+#include "filesort.h" // filesort_free_buffers
+#include "sql_union.h" // mysql_union
+#include "debug_sync.h" // DEBUG_SYNC
#include <m_ctype.h>
#include <my_bit.h>
#include <hash.h>
#include <ft_global.h>
+#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
+
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"MAYBE_REF","ALL","range","index","fulltext",
"ref_or_null","unique_subquery","index_subquery",
@@ -72,8 +90,10 @@ static bool best_extension_by_limited_search(JOIN *join,
double read_time, uint depth,
uint prune_level);
static uint determine_search_depth(JOIN* join);
+C_MODE_START
static int join_tab_cmp(const void* ptr1, const void* ptr2);
static int join_tab_cmp_straight(const void* ptr1, const void* ptr2);
+C_MODE_END
/*
TODO: 'find_best' is here only temporarily until 'greedy_search' is
tested and approved.
@@ -117,10 +137,8 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
static COND *optimize_cond(JOIN *join, COND *conds,
List<TABLE_LIST> *join_list,
Item::cond_result *cond_value);
-static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static bool open_tmp_table(TABLE *table);
-static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
- ulonglong options);
+static bool create_myisam_tmp_table(TABLE *,TMP_TABLE_PARAM *, ulonglong, my_bool);
static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table,
Procedure *proc);
@@ -171,6 +189,14 @@ static COND *make_cond_for_table(COND *cond,table_map table,
table_map used_table);
static Item* part_of_refkey(TABLE *form,Field *field);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
+static bool test_if_cheaper_ordering(const JOIN_TAB *tab,
+ ORDER *order, TABLE *table,
+ key_map usable_keys, int key,
+ ha_rows select_limit,
+ int *new_key, int *new_key_direction,
+ ha_rows *new_select_limit,
+ uint *new_used_key_parts= NULL,
+ uint *saved_best_key_parts= NULL);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes,
key_map *map);
@@ -222,6 +248,7 @@ static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table);
static void copy_sum_funcs(Item_sum **func_ptr, Item_sum **end);
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr);
+static bool prepare_sum_aggregators(Item_sum **func_ptr, bool need_distinct);
static bool init_sum_functions(Item_sum **func, Item_sum **end);
static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table,bool need_order,
@@ -241,6 +268,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
bool res;
register SELECT_LEX *select_lex = &lex->select_lex;
DBUG_ENTER("handle_select");
+ MYSQL_SELECT_START(thd->query());
if (select_lex->master_unit()->is_union() ||
select_lex->master_unit()->fake_select_lex)
@@ -264,7 +292,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
select_lex->group_list.first,
select_lex->having,
lex->proc_list.first,
- select_lex->options | thd->options |
+ select_lex->options | thd->variables.option_bits |
setup_tables_done_option,
result, unit, select_lex);
}
@@ -272,8 +300,9 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
thd->is_error()));
res|= thd->is_error();
if (unlikely(res))
- result->abort();
+ result->abort_result_set();
+ MYSQL_SELECT_DONE((int) res, (ulong) thd->limit_found_rows);
DBUG_RETURN(res);
}
@@ -824,6 +853,7 @@ JOIN::optimize()
if (optimized)
DBUG_RETURN(0);
optimized= 1;
+ DEBUG_SYNC(thd, "before_join_optimize");
thd_proc_info(thd, "optimizing");
row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
@@ -1055,7 +1085,7 @@ JOIN::optimize()
error= 0;
DBUG_RETURN(0);
}
- if (!(thd->options & OPTION_BIG_SELECTS) &&
+ if (!(thd->variables.option_bits & OPTION_BIG_SELECTS) &&
best_read > (double) thd->variables.max_join_size &&
!(select_options & SELECT_DESCRIBE))
{ /* purecov: inspected */
@@ -1063,15 +1093,15 @@ JOIN::optimize()
error= -1;
DBUG_RETURN(1);
}
- if (const_tables && !thd->locked_tables &&
+ if (const_tables && !thd->locked_tables_mode &&
!(select_options & SELECT_NO_UNLOCK))
- mysql_unlock_some_tables(thd, table, const_tables);
+ mysql_unlock_some_tables(thd, all_tables, const_tables);
if (!conds && outer_join)
{
/* Handle the case where we have an OUTER JOIN without a WHERE */
conds=new Item_int((longlong) 1,1); // Always true
}
- select= make_select(*table, const_table_map,
+ select= make_select(*all_tables, const_table_map,
const_table_map, conds, 1, &error);
if (error)
{ /* purecov: inspected */
@@ -1140,10 +1170,14 @@ JOIN::optimize()
{
having= new Item_int((longlong) 0,1);
zero_result_cause= "Impossible HAVING noticed after reading const tables";
+ error= 0;
DBUG_RETURN(0);
}
}
+ /* Cache constant expressions in WHERE, HAVING, ON clauses. */
+ cache_const_exprs();
+
if (make_join_select(this, select, conds))
{
zero_result_cause=
@@ -1332,7 +1366,11 @@ JOIN::optimize()
if (test_if_subpart(group_list, order) ||
(!group_list && tmp_table_param.sum_func_count))
+ {
order=0;
+ if (is_indexed_agg_distinct(this, NULL))
+ sort_and_group= 0;
+ }
// Can't use sort on head table if using join buffering
if (full_join)
@@ -1531,8 +1569,16 @@ JOIN::optimize()
single table queries, thus it is sufficient to test only the first
join_tab element of the plan for its access method.
*/
+ bool need_distinct= TRUE;
if (join_tab->is_using_loose_index_scan())
+ {
tmp_table_param.precomputed_group_by= TRUE;
+ if (join_tab->is_using_agg_loose_index_scan())
+ {
+ need_distinct= FALSE;
+ tmp_table_param.precomputed_group_by= FALSE;
+ }
+ }
/* Create a tmp table if distinct or if the sort is too complicated */
if (need_tmp)
@@ -1560,15 +1606,10 @@ JOIN::optimize()
if (!(exec_tmp_table1=
create_tmp_table(thd, &tmp_table_param, all_fields,
- tmp_group,
- group_list ? 0 : select_distinct,
+ tmp_group, group_list ? 0 : select_distinct,
group_list && simple_group,
- select_options,
- tmp_rows_limit,
- (char *) "")))
- {
+ select_options, tmp_rows_limit, "")))
DBUG_RETURN(1);
- }
/*
We don't have to store rows in temp table that doesn't match HAVING if:
@@ -1593,6 +1634,7 @@ JOIN::optimize()
HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
alloc_group_fields(this, group_list) ||
make_sum_func_list(all_fields, fields_list, 1) ||
+ prepare_sum_aggregators(sum_funcs, need_distinct) ||
setup_sum_funcs(thd, sum_funcs))
{
DBUG_RETURN(1);
@@ -1602,6 +1644,7 @@ JOIN::optimize()
else
{
if (make_sum_func_list(all_fields, fields_list, 0) ||
+ prepare_sum_aggregators(sum_funcs, need_distinct) ||
setup_sum_funcs(thd, sum_funcs))
{
DBUG_RETURN(1);
@@ -1794,8 +1837,8 @@ JOIN::exec()
(zero_result_cause?zero_result_cause:"No tables used"));
else
{
- if (result->send_fields(*columns_list,
- Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ if (result->send_result_set_metadata(*columns_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
{
DBUG_VOID_RETURN;
}
@@ -2043,8 +2086,7 @@ JOIN::exec()
curr_join->select_distinct &&
!curr_join->group_list,
1, curr_join->select_options,
- HA_POS_ERROR,
- (char *) "")))
+ HA_POS_ERROR, "")))
DBUG_VOID_RETURN;
curr_join->exec_tmp_table2= exec_tmp_table2;
}
@@ -2082,7 +2124,9 @@ JOIN::exec()
}
}
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
- 1, TRUE))
+ 1, TRUE) ||
+ prepare_sum_aggregators(curr_join->sum_funcs,
+ !curr_join->join_tab->is_using_agg_loose_index_scan()))
DBUG_VOID_RETURN;
curr_join->group_list= 0;
if (!curr_join->sort_and_group &&
@@ -2186,13 +2230,17 @@ JOIN::exec()
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
1, TRUE) ||
+ prepare_sum_aggregators(curr_join->sum_funcs,
+ !curr_join->join_tab ||
+ !curr_join->join_tab->
+ is_using_agg_loose_index_scan()) ||
setup_sum_funcs(curr_join->thd, curr_join->sum_funcs) ||
thd->is_fatal_error)
DBUG_VOID_RETURN;
}
if (curr_join->group_list || curr_join->order)
{
- DBUG_PRINT("info",("Sorting for send_fields"));
+ DBUG_PRINT("info",("Sorting for send_result_set_metadata"));
thd_proc_info(thd, "Sorting result");
/* If we have already done the group, add HAVING to sorted table */
if (curr_join->tmp_having && ! curr_join->group_list &&
@@ -2305,35 +2353,13 @@ JOIN::exec()
curr_join->fields= curr_fields_list;
curr_join->procedure= procedure;
- if (is_top_level_join() && thd->cursor && tables != const_tables)
- {
- /*
- We are here if this is JOIN::exec for the last select of the main unit
- and the client requested to open a cursor.
- We check that not all tables are constant because this case is not
- handled by do_select() separately, and this case is not implemented
- for cursors yet.
- */
- DBUG_ASSERT(error == 0);
- /*
- curr_join is used only for reusable joins - that is,
- to perform SELECT for each outer row (like in subselects).
- This join is main, so we know for sure that curr_join == join.
- */
- DBUG_ASSERT(curr_join == this);
- /* Open cursor for the last join sweep */
- error= thd->cursor->open(this);
- }
- else
- {
- thd_proc_info(thd, "Sending data");
- DBUG_PRINT("info", ("%s", thd->proc_info));
- result->send_fields((procedure ? curr_join->procedure_fields_list :
- *curr_fields_list),
- Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
- error= do_select(curr_join, curr_fields_list, NULL, procedure);
- thd->limit_found_rows= curr_join->send_records;
- }
+ thd_proc_info(thd, "Sending data");
+ DBUG_PRINT("info", ("%s", thd->proc_info));
+ result->send_result_set_metadata((procedure ? curr_join->procedure_fields_list :
+ *curr_fields_list),
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
+ error= do_select(curr_join, curr_fields_list, NULL, procedure);
+ thd->limit_found_rows= curr_join->send_records;
/* Accumulate the counts from all join iterations of all join parts. */
thd->examined_row_count+= curr_join->examined_rows;
@@ -2543,16 +2569,6 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
join->exec();
- if (thd->cursor && thd->cursor->is_open())
- {
- /*
- A cursor was opened for the last sweep in exec().
- We are here only if this is mysql_select for top-level SELECT_LEX_UNIT
- and there were no error.
- */
- free_join= 0;
- }
-
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
select_lex->where= join->conds_history;
@@ -2580,9 +2596,7 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
{
int error;
DBUG_ENTER("get_quick_record_count");
-#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
uchar buff[STACK_BUFF_ALLOC];
-#endif
if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
DBUG_RETURN(0); // Fatal error flag is set
if (select)
@@ -2818,7 +2832,10 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
goto error; // Fatal error
}
else
+ {
found_const_table_map|= s->table->map;
+ s->table->pos_in_table_list->optimized_away= TRUE;
+ }
}
/* loop until no more const tables are found */
@@ -2924,8 +2941,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
!table->fulltext_searched &&
!table->pos_in_table_list->embedding)
{
- if ((table->key_info[key].flags & (HA_NOSAME | HA_END_SPACE_KEY))
- == HA_NOSAME)
+ if (table->key_info[key].flags & HA_NOSAME)
{
if (const_ref == eq_part)
{ // Found everything for ref.
@@ -3055,7 +3071,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
join->join_tab=stat;
join->map2table=stat_ref;
- join->table= join->all_tables=table_vector;
+ join->all_tables= table_vector;
join->const_tables=const_count;
join->found_const_table_map=found_const_table_map;
@@ -3757,19 +3773,19 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
cond_func=(Item_func_match *)cond;
else if (func->arg_count == 2)
{
- Item *arg0= func->arguments()[0],
- *arg1= func->arguments()[1];
+ Item *arg0=(Item *)(func->arguments()[0]),
+ *arg1=(Item *)(func->arguments()[1]);
if (arg1->const_item() && arg1->cols() == 1 &&
- ((functype == Item_func::GE_FUNC && arg1->val_real() > 0) ||
- (functype == Item_func::GT_FUNC && arg1->val_real() >= 0)) &&
arg0->type() == Item::FUNC_ITEM &&
- ((Item_func *) arg0)->functype() == Item_func::FT_FUNC)
+ ((Item_func *) arg0)->functype() == Item_func::FT_FUNC &&
+ ((functype == Item_func::GE_FUNC && arg1->val_real() > 0) ||
+ (functype == Item_func::GT_FUNC && arg1->val_real() >=0)))
cond_func= (Item_func_match *) arg0;
- else if (arg0->const_item() && arg0->cols() == 1 &&
- ((functype == Item_func::LE_FUNC && arg0->val_real() > 0) ||
- (functype == Item_func::LT_FUNC && arg0->val_real() >= 0)) &&
+ else if (arg0->const_item() &&
arg1->type() == Item::FUNC_ITEM &&
- ((Item_func *) arg1)->functype() == Item_func::FT_FUNC)
+ ((Item_func *) arg1)->functype() == Item_func::FT_FUNC &&
+ ((functype == Item_func::LE_FUNC && arg0->val_real() > 0) ||
+ (functype == Item_func::LT_FUNC && arg0->val_real() >=0)))
cond_func= (Item_func_match *) arg1;
}
}
@@ -4062,7 +4078,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
save_pos++;
}
i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
- VOID(set_dynamic(keyuse,(uchar*) &key_end,i));
+ (void) set_dynamic(keyuse,(uchar*) &key_end,i);
keyuse->elements=i;
}
return FALSE;
@@ -4111,6 +4127,82 @@ static 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.
+
+
+ Check if the query is a subject to AGGFN(DISTINCT) using loose index scan
+ (QUICK_GROUP_MIN_MAX_SELECT).
+ Optionally (if out_args is supplied) will push the arguments of
+ AGGFN(DISTINCT) to the list
+
+ @param join the join to check
+ @param[out] out_args list of aggregate function arguments
+ @return does the query qualify for indexed AGGFN(DISTINCT)
+ @retval true it does
+ @retval false AGGFN(DISTINCT) must apply distinct in it.
+*/
+
+bool
+is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
+{
+ Item_sum **sum_item_ptr;
+ bool result= false;
+
+ if (join->tables != 1 || /* reference more than 1 table */
+ join->select_distinct || /* or a DISTINCT */
+ join->select_lex->olap == ROLLUP_TYPE) /* Check (B3) for ROLLUP */
+ return false;
+
+ if (join->make_sum_func_list(join->all_fields, join->fields_list, true))
+ return false;
+
+ for (sum_item_ptr= join->sum_funcs; *sum_item_ptr; sum_item_ptr++)
+ {
+ Item_sum *sum_item= *sum_item_ptr;
+ Item *expr;
+ /* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */
+ switch (sum_item->sum_func())
+ {
+ case Item_sum::MIN_FUNC:
+ case Item_sum::MAX_FUNC:
+ continue;
+ case Item_sum::COUNT_DISTINCT_FUNC:
+ break;
+ case Item_sum::AVG_DISTINCT_FUNC:
+ case Item_sum::SUM_DISTINCT_FUNC:
+ if (sum_item->get_arg_count() == 1)
+ break;
+ /* fall through */
+ default: return false;
+ }
+ /*
+ We arrive here for every COUNT(DISTINCT),AVG(DISTINCT) or SUM(DISTINCT).
+ Collect the arguments of the aggregate functions to a list.
+ We don't worry about duplicates as these will be sorted out later in
+ get_best_group_min_max
+ */
+ for (uint i= 0; i < sum_item->get_arg_count(); i++)
+ {
+ expr= sum_item->get_arg(i);
+ /* The AGGFN(DISTINCT) arg is not an attribute? */
+ if (expr->real_item()->type() != Item::FIELD_ITEM)
+ return false;
+
+ /*
+ If we came to this point the AGGFN(DISTINCT) loose index scan
+ optimization is applicable
+ */
+ if (out_args)
+ out_args->push_back((Item_field *) expr->real_item());
+ result= true;
+ }
+ }
+ return result;
+}
+
+
+/**
Discover the indexes that can be used for GROUP BY or DISTINCT queries.
If the query has a GROUP BY clause, find all indexes that contain all
@@ -4152,6 +4244,10 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
item->walk(&Item::collect_item_field_processor, 0,
(uchar*) &indexed_fields);
}
+ else if (is_indexed_agg_distinct(join, &indexed_fields))
+ {
+ join->sort_and_group= 1;
+ }
else
return;
@@ -4399,7 +4495,8 @@ best_access_path(JOIN *join,
in ReuseRangeEstimateForRef-3.
*/
if (table->quick_keys.is_set(key) &&
- const_part & (1 << table->quick_key_parts[key]) &&
+ (const_part & ((1 << table->quick_key_parts[key])-1)) ==
+ (((key_part_map)1 << table->quick_key_parts[key])-1) &&
table->quick_n_ranges[key] == 1 &&
records > (double) table->quick_rows[key])
{
@@ -5137,8 +5234,8 @@ greedy_search(JOIN *join,
the interleaving state to the one of the non-extended partial plan
on exit.
*/
- IF_DBUG(bool is_interleave_error= )
- check_interleaving_with_nj (best_table);
+ bool is_interleave_error __attribute__((unused))=
+ check_interleaving_with_nj (best_table);
/* This has been already checked by best_extension_by_limited_search */
DBUG_ASSERT(!is_interleave_error);
@@ -5674,7 +5771,7 @@ get_best_combination(JOIN *join)
{
TABLE *form;
*j= *join->best_positions[tablenr].table;
- form=join->table[tablenr]=j->table;
+ form=join->all_tables[tablenr]=j->table;
used_tables|= form->map;
form->reginfo.join_tab=j;
if (!*j->on_expr_ref)
@@ -5833,8 +5930,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
DBUG_RETURN(0);
if (j->type == JT_CONST)
j->table->const_table= 1;
- else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY |
- HA_END_SPACE_KEY)) != HA_NOSAME) ||
+ else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) != HA_NOSAME) ||
keyparts != keyinfo->key_parts || null_ref_key)
{
/* Must read with repeat */
@@ -5948,7 +6044,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table)
DBUG_RETURN(TRUE); /* purecov: inspected */
join_tab= parent->join_tab_reexec;
- table= &parent->table_reexec[0]; parent->table_reexec[0]= temp_table;
+ parent->table_reexec[0]= temp_table;
tables= 1;
const_tables= 0;
const_table_map= 0;
@@ -6380,7 +6476,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
/* Push condition to storage engine if this is enabled
and the condition is not guarded */
tab->table->file->pushed_cond= NULL;
- if (thd->variables.engine_condition_pushdown)
+ if (thd->variables.optimizer_switch &
+ OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN)
{
COND *push_cond=
make_cond_for_table(tmp, current_map, current_map);
@@ -6871,7 +6968,7 @@ void JOIN_TAB::cleanup()
select= 0;
delete quick;
quick= 0;
- x_free(cache.buff);
+ my_free(cache.buff);
cache.buff= 0;
limit= 0;
if (table)
@@ -6970,7 +7067,7 @@ void JOIN::join_free()
We are not using tables anymore
Unlock all tables. We may be in an INSERT .... SELECT statement.
*/
- if (can_unlock && lock && thd->lock &&
+ if (can_unlock && lock && thd->lock && ! thd->locked_tables_mode &&
!(select_options & SELECT_NO_UNLOCK) &&
!select_lex->subquery_in_having &&
(select_lex == (thd->lex->unit.fake_select_lex ?
@@ -7004,24 +7101,23 @@ void JOIN::cleanup(bool full)
{
DBUG_ENTER("JOIN::cleanup");
- if (table)
+ if (all_tables)
{
JOIN_TAB *tab,*end;
/*
Only a sorted table may be cached. This sorted table is always the
- first non const table in join->table
+ first non const table in join->all_tables
*/
if (tables > const_tables) // Test for not-const tables
{
- free_io_cache(table[const_tables]);
- filesort_free_buffers(table[const_tables],full);
+ free_io_cache(all_tables[const_tables]);
+ filesort_free_buffers(all_tables[const_tables],full);
}
if (full)
{
for (tab= join_tab, end= tab+tables; tab != end; tab++)
tab->cleanup();
- table= 0;
}
else
{
@@ -7283,8 +7379,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
*simple_order=0;
else
{
- Item *comp_item=0;
- if (cond && const_expression_in_where(cond,order->item[0], &comp_item))
+ if (cond && const_expression_in_where(cond,order->item[0]))
{
DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
continue;
@@ -7314,6 +7409,46 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
}
+/**
+ Filter out ORDER items those are equal to constants in WHERE
+
+ This function is a limited version of remove_const() for use
+ with non-JOIN statements (i.e. single-table UPDATE and DELETE).
+
+
+ @param order Linked list of ORDER BY arguments
+ @param cond WHERE expression
+
+ @return pointer to new filtered ORDER list or NULL if whole list eliminated
+
+ @note
+ This function overwrites input order list.
+*/
+
+ORDER *simple_remove_const(ORDER *order, COND *where)
+{
+ if (!order || !where)
+ return order;
+
+ ORDER *first= NULL, *prev= NULL;
+ for (; order; order= order->next)
+ {
+ DBUG_ASSERT(!order->item[0]->with_sum_func); // should never happen
+ if (!const_expression_in_where(where, order->item[0]))
+ {
+ if (!first)
+ first= order;
+ if (prev)
+ prev->next= order;
+ prev= order;
+ }
+ }
+ if (prev)
+ prev->next= NULL;
+ return first;
+}
+
+
static int
return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
List<Item> &fields, bool send_row, ulonglong select_options,
@@ -7336,7 +7471,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
if (having && having->val_int() == 0)
send_row=0;
}
- if (!(result->send_fields(fields,
+ if (!(result->send_result_set_metadata(fields,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
{
bool send_error= FALSE;
@@ -7366,7 +7501,7 @@ static void clear_tables(JOIN *join)
are not re-calculated.
*/
for (uint i=join->const_tables ; i < join->tables ; i++)
- mark_as_null_row(join->table[i]); // All fields are NULL
+ mark_as_null_row(join->all_tables[i]); // All fields are NULL
}
/*****************************************************************************
@@ -8506,10 +8641,9 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
left_item->collation.collation == value->collation.collation))
{
Item *tmp=value->clone_item();
- tmp->collation.set(right_item->collation);
-
if (tmp)
{
+ tmp->collation.set(right_item->collation);
thd->change_item_tree(args + 1, tmp);
func->update_used_tables();
if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC)
@@ -8530,10 +8664,9 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
right_item->collation.collation == value->collation.collation))
{
Item *tmp= value->clone_item();
- tmp->collation.set(left_item->collation);
-
if (tmp)
{
+ tmp->collation.set(left_item->collation);
thd->change_item_tree(args, tmp);
value= tmp;
func->update_used_tables();
@@ -9265,18 +9398,26 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
/**
- Remove const and eq items.
+ Handles the reqursive job for remove_eq_conds()
- @return
- Return new item, or NULL if no condition @n
- cond_value is set to according:
- - COND_OK : query is possible (field = constant)
- - COND_TRUE : always true ( 1 = 1 )
- - COND_FALSE : always false ( 1 = 2 )
+ Remove const and eq items. Return new item, or NULL if no condition
+ cond_value is set to according:
+ COND_OK query is possible (field = constant)
+ COND_TRUE always true ( 1 = 1 )
+ COND_FALSE always false ( 1 = 2 )
+
+ SYNPOSIS
+ remove_eq_conds()
+ thd THD environment
+ cond the condition to handle
+ cond_value the resulting value of the condition
+
+ RETURN
+ *COND with the simplified condition
*/
-COND *
-remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
+static COND *
+internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
{
if (cond->type() == Item::COND_ITEM)
{
@@ -9290,12 +9431,12 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
Item *item;
while ((item=li++))
{
- Item *new_item=remove_eq_conds(thd, item, &tmp_cond_value);
+ Item *new_item=internal_remove_eq_conds(thd, item, &tmp_cond_value);
if (!new_item)
li.remove();
else if (item != new_item)
{
- VOID(li.replace(new_item));
+ (void) li.replace(new_item);
should_fix_fields=1;
}
if (*cond_value == Item::COND_UNDEF)
@@ -9339,54 +9480,19 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
else if (cond->type() == Item::FUNC_ITEM &&
((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
{
- /*
- Handles this special case for some ODBC applications:
- The are requesting the row that was just updated with a auto_increment
- value with this construct:
-
- SELECT * from table_name where auto_increment_column IS NULL
- This will be changed to:
- SELECT * from table_name where auto_increment_column = LAST_INSERT_ID
- */
-
Item_func_isnull *func=(Item_func_isnull*) cond;
Item **args= func->arguments();
if (args[0]->type() == Item::FIELD_ITEM)
{
Field *field=((Item_field*) args[0])->field;
- if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null &&
- (thd->options & OPTION_AUTO_IS_NULL) &&
- (thd->first_successful_insert_id_in_prev_stmt > 0 &&
- thd->substitute_null_with_insert_id))
- {
-#ifdef HAVE_QUERY_CACHE
- query_cache_abort(&thd->net);
-#endif
- COND *new_cond;
- if ((new_cond= new Item_func_eq(args[0],
- new Item_int("last_insert_id()",
- thd->read_first_successful_insert_id_in_prev_stmt(),
- MY_INT64_NUM_DECIMAL_DIGITS))))
- {
- cond=new_cond;
- /*
- Item_func_eq can't be fixed after creation so we do not check
- cond->fixed, also it do not need tables so we use 0 as second
- argument.
- */
- cond->fix_fields(thd, &cond);
- }
- /*
- IS NULL should be mapped to LAST_INSERT_ID only for first row, so
- clear for next row
- */
- thd->substitute_null_with_insert_id= FALSE;
- }
/* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */
- else if (((field->type() == MYSQL_TYPE_DATE) ||
- (field->type() == MYSQL_TYPE_DATETIME)) &&
- (field->flags & NOT_NULL_FLAG) &&
- !field->table->maybe_null)
+ /*
+ datetime_field IS NULL has to be modified to
+ datetime_field == 0
+ */
+ if (((field->type() == MYSQL_TYPE_DATE) ||
+ (field->type() == MYSQL_TYPE_DATETIME)) &&
+ (field->flags & NOT_NULL_FLAG) && !field->table->maybe_null)
{
COND *new_cond;
if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2))))
@@ -9427,6 +9533,85 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
return cond; // Point at next and level
}
+
+/**
+ Remove const and eq items. Return new item, or NULL if no condition
+ cond_value is set to according:
+ COND_OK query is possible (field = constant)
+ COND_TRUE always true ( 1 = 1 )
+ COND_FALSE always false ( 1 = 2 )
+
+ SYNPOSIS
+ remove_eq_conds()
+ thd THD environment
+ cond the condition to handle
+ cond_value the resulting value of the condition
+
+ NOTES
+ calls the inner_remove_eq_conds to check all the tree reqursively
+
+ RETURN
+ *COND with the simplified condition
+*/
+
+COND *
+remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
+{
+ if (cond->type() == Item::FUNC_ITEM &&
+ ((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
+ {
+ /*
+ Handles this special case for some ODBC applications:
+ The are requesting the row that was just updated with a auto_increment
+ value with this construct:
+
+ SELECT * from table_name where auto_increment_column IS NULL
+ This will be changed to:
+ SELECT * from table_name where auto_increment_column = LAST_INSERT_ID
+ */
+
+ Item_func_isnull *func=(Item_func_isnull*) cond;
+ Item **args= func->arguments();
+ if (args[0]->type() == Item::FIELD_ITEM)
+ {
+ Field *field=((Item_field*) args[0])->field;
+ if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null &&
+ (thd->variables.option_bits & OPTION_AUTO_IS_NULL) &&
+ (thd->first_successful_insert_id_in_prev_stmt > 0 &&
+ thd->substitute_null_with_insert_id))
+ {
+#ifdef HAVE_QUERY_CACHE
+ query_cache_abort(&thd->query_cache_tls);
+#endif
+ COND *new_cond;
+ if ((new_cond= new Item_func_eq(args[0],
+ new Item_int("last_insert_id()",
+ thd->read_first_successful_insert_id_in_prev_stmt(),
+ MY_INT64_NUM_DECIMAL_DIGITS))))
+ {
+ cond=new_cond;
+ /*
+ Item_func_eq can't be fixed after creation so we do not check
+ cond->fixed, also it do not need tables so we use 0 as second
+ argument.
+ */
+ cond->fix_fields(thd, &cond);
+ }
+ /*
+ IS NULL should be mapped to LAST_INSERT_ID only for first row, so
+ clear for next row
+ */
+ thd->substitute_null_with_insert_id= FALSE;
+
+ *cond_value= Item::COND_OK;
+ return cond;
+ }
+ }
+ }
+ return internal_remove_eq_conds(thd, cond, cond_value); // Scan all the condition
+}
+
+
/*
Check if equality can be used in removing components of GROUP BY/DISTINCT
@@ -9463,13 +9648,50 @@ test_if_equality_guarantees_uniqueness(Item *l, Item *r)
l->collation.collation == r->collation.collation)));
}
-/**
- Return TRUE if the item is a const value in all the WHERE clause.
+
+/*
+ Return TRUE if i1 and i2 (if any) are equal items,
+ or if i1 is a wrapper item around the f2 field.
*/
-static bool
-const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
+static bool equal(Item *i1, Item *i2, Field *f2)
{
+ DBUG_ASSERT((i2 == NULL) ^ (f2 == NULL));
+
+ if (i2 != NULL)
+ return i1->eq(i2, 1);
+ else if (i1->type() == Item::FIELD_ITEM)
+ return f2->eq(((Item_field *) i1)->field);
+ else
+ return FALSE;
+}
+
+
+/**
+ Test if a field or an item is equal to a constant value in WHERE
+
+ @param cond WHERE clause expression
+ @param comp_item Item to find in WHERE expression
+ (if comp_field != NULL)
+ @param comp_field Field to find in WHERE expression
+ (if comp_item != NULL)
+ @param[out] const_item intermediate arg, set to Item pointer to NULL
+
+ @return TRUE if the field is a constant value in WHERE
+
+ @note
+ comp_item and comp_field parameters are mutually exclusive.
+*/
+bool
+const_expression_in_where(COND *cond, Item *comp_item, Field *comp_field,
+ Item **const_item)
+{
+ DBUG_ASSERT((comp_item == NULL) ^ (comp_field == NULL));
+
+ Item *intermediate= NULL;
+ if (const_item == NULL)
+ const_item= &intermediate;
+
if (cond->type() == Item::COND_ITEM)
{
bool and_level= (((Item_cond*) cond)->functype()
@@ -9478,7 +9700,8 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
Item *item;
while ((item=li++))
{
- bool res=const_expression_in_where(item, comp_item, const_item);
+ bool res=const_expression_in_where(item, comp_item, comp_field,
+ const_item);
if (res) // Is a const value
{
if (and_level)
@@ -9490,14 +9713,14 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
return and_level ? 0 : 1;
}
else if (cond->eq_cmp_result() != Item::COND_OK)
- { // boolan compare function
+ { // boolean compare function
Item_func* func= (Item_func*) cond;
if (func->functype() != Item_func::EQUAL_FUNC &&
func->functype() != Item_func::EQ_FUNC)
return 0;
Item *left_item= ((Item_func*) cond)->arguments()[0];
Item *right_item= ((Item_func*) cond)->arguments()[1];
- if (left_item->eq(comp_item,1))
+ if (equal(left_item, comp_item, comp_field))
{
if (test_if_equality_guarantees_uniqueness (left_item, right_item))
{
@@ -9507,7 +9730,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
return 1;
}
}
- else if (right_item->eq(comp_item,1))
+ else if (equal(right_item, comp_item, comp_field))
{
if (test_if_equality_guarantees_uniqueness (right_item, left_item))
{
@@ -9521,6 +9744,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
return 0;
}
+
/****************************************************************************
Create internal temporary table
****************************************************************************/
@@ -9775,7 +9999,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_sum *item_sum=(Item_sum*) item;
result= item_sum->create_tmp_field(group, table, convert_blob_length);
if (!result)
- thd->fatal_error();
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
return result;
}
case Item::FIELD_ITEM:
@@ -9910,7 +10134,7 @@ void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps)
Create a temp table according to a field list.
Given field pointers are changed to point at tmp_table for
- send_fields. The table object is self contained: it's
+ send_result_set_metadata. The table object is self contained: it's
allocated in its own memory root, as well as Field objects
created for table columns.
This function will replace Item_sum items in 'fields' list with
@@ -9941,7 +10165,7 @@ 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,
- char *table_alias)
+ const char *table_alias)
{
MEM_ROOT *mem_root_save, own_root;
TABLE *table;
@@ -10099,6 +10323,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
share->primary_key= MAX_KEY; // Indicate no primary key
share->keys_for_keyread.init();
share->keys_in_use.init();
+ if (param->schema_table)
+ share->db= INFORMATION_SCHEMA_NAME;
/* Calculate which type of fields we will store in the temporary table */
@@ -10266,9 +10492,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
/* If result table is small; use a heap */
/* future: storage engine selection can be made dynamic? */
- if (blob_count || using_unique_constraint ||
- (select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
- OPTION_BIG_TABLES || (select_options & TMP_TABLE_FORCE_MYISAM))
+ if (blob_count || using_unique_constraint
+ || (thd->variables.big_tables && !(select_options & SELECT_SMALL_RESULT))
+ || (select_options & TMP_TABLE_FORCE_MYISAM))
{
share->db_plugin= ha_lock_engine(0, myisam_hton);
table->file= get_new_handler(share, &table->mem_root,
@@ -10596,7 +10822,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
share->db_record_offset= 1;
if (share->db_type() == myisam_hton)
{
- if (create_myisam_tmp_table(table,param,select_options))
+ if (create_myisam_tmp_table(table, param, select_options,
+ thd->variables.big_tables))
goto err;
}
if (open_tmp_table(table))
@@ -10663,9 +10890,11 @@ TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list)
bzero(share, sizeof(*share));
table->field= field;
table->s= share;
+ table->temp_pool_slot= MY_BIT_NONE;
share->blob_field= blob_field;
share->fields= field_count;
share->blob_ptr_size= portable_sizeof_char_ptr;
+ share->db_low_byte_first=1; // True for HEAP and MyISAM
setup_tmp_table_column_bitmaps(table, bitmaps);
/* Create all fields and calculate the total length of record */
@@ -10730,6 +10959,18 @@ TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list)
null_bit= 1;
}
}
+ if (cur_field->type() == MYSQL_TYPE_BIT &&
+ cur_field->key_type() == HA_KEYTYPE_BIT)
+ {
+ /* This is a Field_bit since key_type is HA_KEYTYPE_BIT */
+ static_cast<Field_bit*>(cur_field)->set_bit_ptr(null_pos, null_bit);
+ null_bit+= cur_field->field_length & 7;
+ if (null_bit > 7)
+ {
+ null_pos++;
+ null_bit-= 8;
+ }
+ }
cur_field->reset();
field_pos+= cur_field->pack_length();
@@ -10759,7 +11000,7 @@ static bool open_tmp_table(TABLE *table)
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
- ulonglong options)
+ ulonglong options, my_bool big_tables)
{
int error;
MI_KEYDEF keydef;
@@ -10846,8 +11087,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
MI_CREATE_INFO create_info;
bzero((char*) &create_info,sizeof(create_info));
- if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
- OPTION_BIG_TABLES)
+ if (big_tables && !(options & SELECT_SMALL_RESULT))
create_info.data_file_length= ~(ulonglong) 0;
if ((error=mi_create(share->table_name.str, share->keys, &keydef,
@@ -10929,8 +11169,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
We don't want this error to be converted to a warning, e.g. in case of
INSERT IGNORE ... SELECT.
*/
- thd->fatal_error();
- table->file->print_error(error,MYF(0));
+ table->file->print_error(error, MYF(ME_FATALERROR));
DBUG_RETURN(1);
}
@@ -10949,7 +11188,8 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
thd_proc_info(thd, "converting HEAP to MyISAM");
if (create_myisam_tmp_table(&new_table, param,
- thd->lex->select_lex.options | thd->options))
+ thd->lex->select_lex.options | thd->variables.option_bits,
+ thd->variables.big_tables))
goto err2;
if (open_tmp_table(&new_table))
goto err1;
@@ -11133,7 +11373,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
if (table)
{
- VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
+ (void) table->file->extra(HA_EXTRA_WRITE_CACHE);
empty_record(table);
if (table->group && join->tmp_table_param.sum_func_count &&
table->s->keys && !table->file->inited)
@@ -11166,7 +11406,6 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
so we don't touch it here.
*/
join->examined_rows++;
- join->thd->row_count++;
DBUG_ASSERT(join->examined_rows <= 1);
}
else if (join->send_row_on_empty_set())
@@ -11175,6 +11414,13 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
fields);
rc= join->result->send_data(*columns_list);
}
+ /*
+ An error can happen when evaluating the conds
+ (the join condition and piece of where clause
+ relevant to this join table).
+ */
+ if (join->thd->is_error())
+ error= NESTED_LOOP_ERROR;
}
else
{
@@ -11188,24 +11434,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
if (error == NESTED_LOOP_NO_MORE_ROWS)
error= NESTED_LOOP_OK;
- if (table == NULL) // If sending data to client
- /*
- The following will unlock all cursors if the command wasn't an
- update command
- */
- join->join_free(); // Unlock all cursors
- if (error == NESTED_LOOP_OK)
- {
- /*
- Sic: this branch works even if rc != 0, e.g. when
- send_data above returns an error.
- */
- if (table == NULL && join->result->send_eof()) // If sending data to client
- rc= 1; // Don't send error
- DBUG_PRINT("info",("%ld records output", (long) join->send_records));
- }
- else
- rc= -1;
+
if (table)
{
int tmp, new_errno= 0;
@@ -11222,6 +11451,29 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
if (new_errno)
table->file->print_error(new_errno,MYF(0));
}
+ else
+ {
+ /*
+ The following will unlock all cursors if the command wasn't an
+ update command
+ */
+ join->join_free(); // Unlock all cursors
+ }
+ if (error == NESTED_LOOP_OK)
+ {
+ /*
+ Sic: this branch works even if rc != 0, e.g. when
+ send_data above returns an error.
+ */
+ if (!table) // If sending data to client
+ {
+ if (join->result->send_eof())
+ rc= 1; // Don't send error
+ }
+ DBUG_PRINT("info",("%ld records output", (long) join->send_records));
+ }
+ else
+ rc= -1;
#ifndef DBUG_OFF
if (rc)
{
@@ -11392,37 +11644,23 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
enum_nested_loop_state rc;
READ_RECORD *info= &join_tab->read_record;
- if (join->resume_nested_loop)
- {
- /* If not the last table, plunge down the nested loop */
- if (join_tab < join->join_tab + join->tables - 1)
- rc= (*join_tab->next_select)(join, join_tab + 1, 0);
- else
- {
- join->resume_nested_loop= FALSE;
- rc= NESTED_LOOP_OK;
- }
- }
- else
- {
- join->return_tab= join_tab;
-
- if (join_tab->last_inner)
- {
- /* join_tab is the first inner table for an outer join operation. */
+ join->return_tab= join_tab;
- /* Set initial state of guard variables for this table.*/
- join_tab->found=0;
- join_tab->not_null_compl= 1;
+ if (join_tab->last_inner)
+ {
+ /* join_tab is the first inner table for an outer join operation. */
- /* Set first_unmatched for the last inner table of this group */
- join_tab->last_inner->first_unmatched= join_tab;
- }
- join->thd->row_count= 0;
+ /* Set initial state of guard variables for this table.*/
+ join_tab->found=0;
+ join_tab->not_null_compl= 1;
- error= (*join_tab->read_first_record)(join_tab);
- rc= evaluate_join_record(join, join_tab, error);
+ /* Set first_unmatched for the last inner table of this group */
+ join_tab->last_inner->first_unmatched= join_tab;
}
+ join->thd->warning_info->reset_current_row_for_warning();
+
+ error= (*join_tab->read_first_record)(join_tab);
+ rc= evaluate_join_record(join, join_tab, error);
while (rc == NESTED_LOOP_OK)
{
@@ -11539,7 +11777,6 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
(See above join->return_tab= tab).
*/
join->examined_rows++;
- join->thd->row_count++;
DBUG_PRINT("counts", ("join->examined_rows++: %lu",
(ulong) join->examined_rows));
@@ -11548,6 +11785,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
enum enum_nested_loop_state rc;
/* A match from join_tab is found for the current partial join. */
rc= (*join_tab->next_select)(join, join_tab+1, 0);
+ join->thd->warning_info->inc_current_row_for_warning();
if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
return rc;
if (join->return_tab < join_tab)
@@ -11561,7 +11799,10 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
return NESTED_LOOP_NO_MORE_ROWS;
}
else
+ {
+ join->thd->warning_info->inc_current_row_for_warning();
join_tab->read_record.unlock_row(join_tab);
+ }
}
else
{
@@ -11570,7 +11811,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
with the beginning coinciding with the current partial join.
*/
join->examined_rows++;
- join->thd->row_count++;
+ join->thd->warning_info->inc_current_row_for_warning();
join_tab->read_record.unlock_row(join_tab);
}
return NESTED_LOOP_OK;
@@ -12125,10 +12366,8 @@ join_init_quick_read_record(JOIN_TAB *tab)
}
-int rr_sequential(READ_RECORD *info);
-int init_read_record_seq(JOIN_TAB *tab)
+int read_first_record_seq(JOIN_TAB *tab)
{
- tab->read_record.read_record= rr_sequential;
if (tab->read_record.file->ha_rnd_init(1))
return 1;
return (*tab->read_record.read_record)(&tab->read_record);
@@ -12229,11 +12468,6 @@ join_ft_read_first(JOIN_TAB *tab)
if (!table->file->inited)
table->file->ha_index_init(tab->ref.key, 1);
-#if NOT_USED_YET
- /* as ft-key doesn't use store_key's, see also FT_SELECT::init() */
- if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref))
- return -1;
-#endif
table->file->ft_init();
if ((error= table->file->ft_read(table->record[0])))
@@ -12321,6 +12555,12 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!end_of_records)
{
int error;
+ if (join->tables &&
+ join->join_tab->is_using_loose_index_scan())
+ {
+ /* Copy non-aggregated fields when loose index scan is used. */
+ copy_fields(&join->tmp_table_param);
+ }
if (join->having && join->having->val_int() == 0)
DBUG_RETURN(NESTED_LOOP_OK); // Didn't match having
error=0;
@@ -12476,7 +12716,7 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (end_of_records)
DBUG_RETURN(NESTED_LOOP_OK);
join->first_record=1;
- VOID(test_if_group_changed(join->group_fields));
+ (void) test_if_group_changed(join->group_fields);
}
if (idx < (int) join->send_group_parts)
{
@@ -12519,22 +12759,6 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (copy_funcs(join->tmp_table_param.items_to_copy, join->thd))
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
-#ifdef TO_BE_DELETED
- if (!table->uniques) // If not unique handling
- {
- /* Copy null values from group to row */
- ORDER *group;
- for (group=table->group ; group ; group=group->next)
- {
- Item *item= *group->item;
- if (item->maybe_null)
- {
- Field *field=item->get_tmp_table_field();
- field->ptr[-1]= (uchar) (field->is_null() ? 1 : 0);
- }
- }
- }
-#endif
if (!join->having || join->having->val_int())
{
int error;
@@ -12743,7 +12967,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (end_of_records)
DBUG_RETURN(NESTED_LOOP_OK);
join->first_record=1;
- VOID(test_if_group_changed(join->group_fields));
+ (void) test_if_group_changed(join->group_fields);
}
if (idx < (int) join->send_group_parts)
{
@@ -12936,7 +13160,8 @@ part_of_refkey(TABLE *table,Field *field)
@param order Sort order
@param table Table to sort
@param idx Index to check
- @param used_key_parts Return value for used key parts.
+ @param used_key_parts [out] NULL by default, otherwise return value for
+ used key parts.
@note
@@ -12955,13 +13180,14 @@ part_of_refkey(TABLE *table,Field *field)
*/
static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
- uint *used_key_parts)
+ uint *used_key_parts= NULL)
{
KEY_PART_INFO *key_part,*key_part_end;
key_part=table->key_info[idx].key_part;
key_part_end=key_part+table->key_info[idx].key_parts;
key_part_map const_key_parts=table->const_key_parts[idx];
int reverse=0;
+ uint key_parts;
my_bool on_pk_suffix= FALSE;
DBUG_ENTER("test_if_order_by_key");
@@ -13002,15 +13228,16 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
*/
if (key_part == key_part_end && reverse == 0)
{
- *used_key_parts= 0;
- DBUG_RETURN(1);
+ key_parts= 0;
+ reverse= 1;
+ goto ok;
}
}
else
DBUG_RETURN(0);
}
- if (key_part->field != field)
+ if (key_part->field != field || !field->part_of_sortkey.is_set(idx))
DBUG_RETURN(0);
/* set flag to 1 if we can use read-next on key, else to -1 */
@@ -13026,7 +13253,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
uint used_key_parts_secondary= table->key_info[idx].key_parts;
uint used_key_parts_pk=
(uint) (key_part - table->key_info[table->s->primary_key].key_part);
- *used_key_parts= used_key_parts_pk + used_key_parts_secondary;
+ key_parts= used_key_parts_pk + used_key_parts_secondary;
if (reverse == -1 &&
(!(table->file->index_flags(idx, used_key_parts_secondary - 1, 1) &
@@ -13037,11 +13264,14 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
}
else
{
- *used_key_parts= (uint) (key_part - table->key_info[idx].key_part);
+ key_parts= (uint) (key_part - table->key_info[idx].key_part);
if (reverse == -1 &&
- !(table->file->index_flags(idx, *used_key_parts-1, 1) & HA_READ_PREV))
+ !(table->file->index_flags(idx, key_parts-1, 1) & HA_READ_PREV))
reverse= 0; // Index can't be used
}
+ok:
+ if (used_key_parts != NULL)
+ *used_key_parts= key_parts;
DBUG_RETURN(reverse);
}
@@ -13159,7 +13389,6 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
uint nr;
uint min_length= (uint) ~0;
uint best= MAX_KEY;
- uint not_used;
KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part;
KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts;
@@ -13170,7 +13399,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
table->key_info[nr].key_parts >= ref_key_parts &&
is_subkey(table->key_info[nr].key_part, ref_key_part,
ref_key_part_end) &&
- test_if_order_by_key(order, table, nr, &not_used))
+ test_if_order_by_key(order, table, nr))
{
min_length= table->key_info[nr].key_length;
best= nr;
@@ -13464,185 +13693,18 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
goto check_reverse_order;
}
{
- /*
- Check whether there is an index compatible with the given order
- usage of which is cheaper than usage of the ref_key index (ref_key>=0)
- or a table scan.
- It may be the case if ORDER/GROUP BY is used with LIMIT.
- */
- uint nr;
- key_map keys;
uint best_key_parts= 0;
uint saved_best_key_parts= 0;
int best_key_direction= 0;
- ha_rows best_records= 0;
- double read_time;
int best_key= -1;
- bool is_best_covering= FALSE;
- double fanout= 1;
JOIN *join= tab->join;
- uint tablenr= tab - join->join_tab;
ha_rows table_records= table->file->stats.records;
- bool group= join->group && order == join->group_list;
- ha_rows ref_key_quick_rows= HA_POS_ERROR;
-
- /*
- If not used with LIMIT, only use keys if the whole query can be
- resolved with a key; This is because filesort() is usually faster than
- retrieving all rows through an index.
- */
- if (select_limit >= table_records)
- {
- keys= *table->file->keys_to_use_for_scanning();
- keys.merge(table->covering_keys);
- /*
- We are adding here also the index specified in FORCE INDEX clause,
- if any.
- This is to allow users to use index in ORDER BY.
- */
- if (table->force_index)
- keys.merge(group ? table->keys_in_use_for_group_by :
- table->keys_in_use_for_order_by);
- keys.intersect(usable_keys);
- }
- else
- keys= usable_keys;
-
- if (ref_key >= 0 && table->covering_keys.is_set(ref_key))
- ref_key_quick_rows= table->quick_rows[ref_key];
-
- read_time= join->best_positions[tablenr].read_time;
- for (uint i= tablenr+1; i < join->tables; i++)
- fanout*= join->best_positions[i].records_read; // fanout is always >= 1
-
- for (nr=0; nr < table->s->keys ; nr++)
- {
- int direction;
-
- if (keys.is_set(nr) &&
- (direction= test_if_order_by_key(order, table, nr, &used_key_parts)))
- {
- /*
- At this point we are sure that ref_key is a non-ordering
- key (where "ordering key" is a key that will return rows
- in the order required by ORDER BY).
- */
- DBUG_ASSERT (ref_key != (int) nr);
-
- bool is_covering= table->covering_keys.is_set(nr) ||
- (nr == table->s->primary_key &&
- table->file->primary_key_is_clustered());
-
- /*
- Don't use an index scan with ORDER BY without limit.
- For GROUP BY without limit always use index scan
- if there is a suitable index.
- Why we hold to this asymmetry hardly can be explained
- rationally. It's easy to demonstrate that using
- temporary table + filesort could be cheaper for grouping
- queries too.
- */
- if (is_covering ||
- select_limit != HA_POS_ERROR ||
- (ref_key < 0 && (group || table->force_index)))
- {
- double rec_per_key;
- double index_scan_time;
- KEY *keyinfo= tab->table->key_info+nr;
- if (select_limit == HA_POS_ERROR)
- select_limit= table_records;
- if (group)
- {
- /*
- Used_key_parts can be larger than keyinfo->key_parts
- when using a secondary index clustered with a primary
- key (e.g. as in Innodb).
- See Bug #28591 for details.
- */
- rec_per_key= used_key_parts &&
- used_key_parts <= keyinfo->key_parts ?
- keyinfo->rec_per_key[used_key_parts-1] : 1;
- set_if_bigger(rec_per_key, 1);
- /*
- With a grouping query each group containing on average
- rec_per_key records produces only one row that will
- be included into the result set.
- */
- if (select_limit > table_records/rec_per_key)
- select_limit= table_records;
- else
- select_limit= (ha_rows) (select_limit*rec_per_key);
- }
- /*
- If tab=tk is not the last joined table tn then to get first
- L records from the result set we can expect to retrieve
- only L/fanout(tk,tn) where fanout(tk,tn) says how many
- rows in the record set on average will match each row tk.
- Usually our estimates for fanouts are too pessimistic.
- So the estimate for L/fanout(tk,tn) will be too optimistic
- and as result we'll choose an index scan when using ref/range
- access + filesort will be cheaper.
- */
- select_limit= (ha_rows) (select_limit < fanout ?
- 1 : select_limit/fanout);
- /*
- We assume that each of the tested indexes is not correlated
- with ref_key. Thus, to select first N records we have to scan
- N/selectivity(ref_key) index entries.
- selectivity(ref_key) = #scanned_records/#table_records =
- table->quick_condition_rows/table_records.
- In any case we can't select more than #table_records.
- N/(table->quick_condition_rows/table_records) > table_records
- <=> N > table->quick_condition_rows.
- */
- if (select_limit > table->quick_condition_rows)
- select_limit= table_records;
- else
- select_limit= (ha_rows) (select_limit *
- (double) table_records /
- table->quick_condition_rows);
- rec_per_key= keyinfo->rec_per_key[keyinfo->key_parts-1];
- set_if_bigger(rec_per_key, 1);
- /*
- Here we take into account the fact that rows are
- accessed in sequences rec_per_key records in each.
- Rows in such a sequence are supposed to be ordered
- by rowid/primary key. When reading the data
- in a sequence we'll touch not more pages than the
- table file contains.
- TODO. Use the formula for a disk sweep sequential access
- to calculate the cost of accessing data rows for one
- index entry.
- */
- index_scan_time= select_limit/rec_per_key *
- min(rec_per_key, table->file->scan_time());
- if ((ref_key < 0 && is_covering) ||
- (ref_key < 0 && (group || table->force_index)) ||
- index_scan_time < read_time)
- {
- ha_rows quick_records= table_records;
- if ((is_best_covering && !is_covering) ||
- (is_covering && ref_key_quick_rows < select_limit))
- continue;
- if (table->quick_keys.is_set(nr))
- quick_records= table->quick_rows[nr];
- if (best_key < 0 ||
- (select_limit <= min(quick_records,best_records) ?
- keyinfo->key_parts < best_key_parts :
- quick_records < best_records))
- {
- best_key= nr;
- best_key_parts= keyinfo->key_parts;
- saved_best_key_parts= used_key_parts;
- best_records= quick_records;
- is_best_covering= is_covering;
- best_key_direction= direction;
- }
- }
- }
- }
- }
+ test_if_cheaper_ordering(tab, order, table, usable_keys,
+ ref_key, select_limit,
+ &best_key, &best_key_direction,
+ &select_limit, &best_key_parts,
+ &saved_best_key_parts);
/*
filesort() and join cache are usually faster than reading in
@@ -13746,7 +13808,7 @@ check_reverse_order:
*/
if (!select->quick->reverse_sorted())
{
- QUICK_SELECT_DESC *tmp;
+ QUICK_SELECT_I *tmp;
int quick_type= select->quick->get_type();
if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
@@ -13759,16 +13821,14 @@ check_reverse_order:
}
/* ORDER BY range_key DESC */
- tmp= new QUICK_SELECT_DESC((QUICK_RANGE_SELECT*)(select->quick),
- used_key_parts);
- if (!tmp || tmp->error)
+ tmp= select->quick->make_reverse(used_key_parts);
+ if (!tmp)
{
- delete tmp;
select->quick= save_quick;
tab->limit= 0;
DBUG_RETURN(0); // Reverse sort not supported
}
- select->quick=tmp;
+ select->set_quick(tmp);
}
}
else if (tab->type != JT_NEXT && tab->type != JT_REF_OR_NULL &&
@@ -13935,44 +13995,6 @@ err:
DBUG_RETURN(-1);
}
-#ifdef NOT_YET
-/**
- Add the HAVING criteria to table->select.
-*/
-
-static bool fix_having(JOIN *join, Item **having)
-{
- (*having)->update_used_tables(); // Some tables may have been const
- JOIN_TAB *table=&join->join_tab[join->const_tables];
- table_map used_tables= join->const_table_map | table->table->map;
-
- DBUG_EXECUTE("where",print_where(*having,"having", QT_ORDINARY););
- Item* sort_table_cond=make_cond_for_table(*having,used_tables,used_tables);
- if (sort_table_cond)
- {
- if (!table->select)
- if (!(table->select=new SQL_SELECT))
- return 1;
- if (!table->select->cond)
- table->select->cond=sort_table_cond;
- else // This should never happen
- if (!(table->select->cond= new Item_cond_and(table->select->cond,
- sort_table_cond)) ||
- table->select->cond->fix_fields(join->thd, &table->select->cond))
- return 1;
- table->select_cond=table->select->cond;
- table->select_cond->top_level_item();
- DBUG_EXECUTE("where",print_where(table->select_cond,
- "select and having",
- QT_ORDINARY););
- *having=make_cond_for_table(*having,~ (table_map) 0,~used_tables);
- DBUG_EXECUTE("where",
- print_where(*having,"having after make_cond", QT_ORDINARY););
- }
- return 0;
-}
-#endif
-
/*****************************************************************************
Remove duplicates from tmp table
@@ -14197,10 +14219,10 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
extra_length= ALIGN_SIZE(key_length)-key_length;
}
- if (hash_init(&hash, &my_charset_bin, (uint) file->stats.records, 0,
- key_length, (hash_get_key) 0, 0, 0))
+ if (my_hash_init(&hash, &my_charset_bin, (uint) file->stats.records, 0,
+ key_length, (my_hash_get_key) 0, 0, 0))
{
- my_free((char*) key_buffer,MYF(0));
+ my_free(key_buffer);
DBUG_RETURN(1);
}
@@ -14239,7 +14261,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
key_pos+= *field_length++;
}
/* Check if it exists before */
- if (hash_search(&hash, org_key_pos, key_length))
+ if (my_hash_search(&hash, org_key_pos, key_length))
{
/* Duplicated found ; Remove the row */
if ((error=file->ha_delete_row(record)))
@@ -14252,15 +14274,15 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
}
key_pos+=extra_length;
}
- my_free((char*) key_buffer,MYF(0));
- hash_free(&hash);
+ my_free(key_buffer);
+ my_hash_free(&hash);
file->extra(HA_EXTRA_NO_CACHE);
(void) file->ha_rnd_end();
DBUG_RETURN(0);
err:
- my_free((char*) key_buffer,MYF(0));
- hash_free(&hash);
+ my_free(key_buffer);
+ my_hash_free(&hash);
file->extra(HA_EXTRA_NO_CACHE);
(void) file->ha_rnd_end();
if (error)
@@ -14342,7 +14364,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
sizeof(CACHE_FIELD*))))
{
- my_free((uchar*) cache->buff,MYF(0)); /* purecov: inspected */
+ my_free(cache->buff); /* purecov: inspected */
cache->buff=0; /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
@@ -14966,7 +14988,7 @@ setup_new_fields(THD *thd, List<Item> &fields,
optimize away 'order by'.
*/
-static ORDER *
+ORDER *
create_distinct_group(THD *thd, Item **ref_pointer_array,
ORDER *order_list, List<Item> &fields,
List<Item> &all_fields,
@@ -15230,8 +15252,7 @@ calc_group_buffer(JOIN *join,ORDER *group)
default:
/* This case should never be choosen */
DBUG_ASSERT(0);
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- join->thd->fatal_error();
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
}
}
parts++;
@@ -15323,7 +15344,7 @@ test_if_group_changed(List<Cached_item> &list)
Only FIELD_ITEM:s and FUNC_ITEM:s needs to be saved between groups.
Change old item_field to use a new field with points at saved fieldvalue
- This function is only called before use of send_fields.
+ This function is only called before use of send_result_set_metadata.
@param thd THD pointer
@param param temporary table parameters
@@ -15354,7 +15375,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
Item *pos;
List_iterator_fast<Item> li(all_fields);
Copy_field *copy= NULL;
- IF_DBUG(Copy_field *copy_start);
+ Copy_field *copy_start __attribute__((unused));
res_selected_fields.empty();
res_all_fields.empty();
List_iterator_fast<Item> itr(res_all_fields);
@@ -15367,7 +15388,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
goto err2;
param->copy_funcs.empty();
- IF_DBUG(copy_start= copy);
+ copy_start= copy;
for (i= 0; (pos= li++); i++)
{
Field *field;
@@ -15563,7 +15584,7 @@ bool JOIN::alloc_func_list()
Initialize 'sum_funcs' array with all Item_sum objects.
@param field_list All items
- @param send_fields Items in select list
+ @param send_result_set_metadata Items in select list
@param before_group_by Set to 1 if this is called before GROUP BY handling
@param recompute Set to TRUE if sum_funcs must be recomputed
@@ -15573,7 +15594,7 @@ bool JOIN::alloc_func_list()
1 error
*/
-bool JOIN::make_sum_func_list(List<Item> &field_list, List<Item> &send_fields,
+bool JOIN::make_sum_func_list(List<Item> &field_list, List<Item> &send_result_set_metadata,
bool before_group_by, bool recompute)
{
List_iterator_fast<Item> it(field_list);
@@ -15595,7 +15616,7 @@ bool JOIN::make_sum_func_list(List<Item> &field_list, List<Item> &send_fields,
if (before_group_by && rollup.state == ROLLUP::STATE_INITED)
{
rollup.state= ROLLUP::STATE_READY;
- if (rollup_make_fields(field_list, send_fields, &func))
+ if (rollup_make_fields(field_list, send_result_set_metadata, &func))
DBUG_RETURN(TRUE); // Should never happen
}
else if (rollup.state == ROLLUP::STATE_NONE)
@@ -15770,7 +15791,22 @@ static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr)
DBUG_ENTER("setup_sum_funcs");
while ((func= *(func_ptr++)))
{
- if (func->setup(thd))
+ if (func->aggregator_setup(thd))
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+static bool prepare_sum_aggregators(Item_sum **func_ptr, bool need_distinct)
+{
+ Item_sum *func;
+ DBUG_ENTER("prepare_sum_aggregators");
+ while ((func= *(func_ptr++)))
+ {
+ if (func->set_aggregator(need_distinct && func->has_with_distinct() ?
+ Aggregator::DISTINCT_AGGREGATOR :
+ Aggregator::SIMPLE_AGGREGATOR))
DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
@@ -15820,7 +15856,7 @@ init_sum_functions(Item_sum **func_ptr, Item_sum **end_ptr)
/* If rollup, calculate the upper sum levels */
for ( ; *func_ptr ; func_ptr++)
{
- if ((*func_ptr)->add())
+ if ((*func_ptr)->aggregator_add())
return 1;
}
return 0;
@@ -15832,7 +15868,7 @@ update_sum_func(Item_sum **func_ptr)
{
Item_sum *func;
for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
- if (func->add())
+ if (func->aggregator_add())
return 1;
return 0;
}
@@ -16776,7 +16812,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{
const COND *pushed_cond= tab->table->file->pushed_cond;
- if (thd->variables.engine_condition_pushdown && pushed_cond)
+ if ((thd->variables.optimizer_switch &
+ OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN) && pushed_cond)
{
extra.append(STRING_WITH_LEN("; Using where with pushed "
"condition"));
@@ -16811,7 +16848,12 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if (key_read)
{
if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ {
+ QUICK_GROUP_MIN_MAX_SELECT *qgs=
+ (QUICK_GROUP_MIN_MAX_SELECT *) tab->select->quick;
extra.append(STRING_WITH_LEN("; Using index for group-by"));
+ qgs->append_loose_scan_type(&extra);
+ }
else
extra.append(STRING_WITH_LEN("; Using index"));
}
@@ -16919,7 +16961,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
first->group_list.first,
first->having,
thd->lex->proc_list.first,
- first->options | thd->options | SELECT_DESCRIBE,
+ first->options | thd->variables.option_bits | SELECT_DESCRIBE,
result, unit, first);
}
DBUG_RETURN(res || thd->is_error());
@@ -16942,18 +16984,35 @@ static void print_join(THD *thd,
{
/* List is reversed => we should reverse it before using */
List_iterator_fast<TABLE_LIST> ti(*tables);
- TABLE_LIST **table= (TABLE_LIST **)thd->alloc(sizeof(TABLE_LIST*) *
- tables->elements);
- if (table == 0)
+ TABLE_LIST **table;
+ uint non_const_tables= 0;
+
+ for (TABLE_LIST *t= ti++; t ; t= ti++)
+ if (!t->optimized_away)
+ non_const_tables++;
+ if (!non_const_tables)
+ {
+ str->append(STRING_WITH_LEN("dual"));
+ return; // all tables were optimized away
+ }
+ ti.rewind();
+
+ if (!(table= (TABLE_LIST **)thd->alloc(sizeof(TABLE_LIST*) *
+ non_const_tables)))
return; // out of memory
- for (TABLE_LIST **t= table + (tables->elements - 1); t >= table; t--)
- *t= ti++;
+ TABLE_LIST *tmp, **t= table + (non_const_tables - 1);
+ while ((tmp= ti++))
+ {
+ if (tmp->optimized_away)
+ continue;
+ *t--= tmp;
+ }
DBUG_ASSERT(tables->elements >= 1);
(*table)->print(thd, str, query_type);
- TABLE_LIST **end= table + tables->elements;
+ TABLE_LIST **end= table + non_const_tables;
for (TABLE_LIST **tbl= table + 1; tbl < end; tbl++)
{
TABLE_LIST *curr= *tbl;
@@ -17119,8 +17178,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
/* First add options */
if (options & SELECT_STRAIGHT_JOIN)
str->append(STRING_WITH_LEN("straight_join "));
- if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) &&
- (this == &thd->lex->select_lex))
+ if (options & SELECT_HIGH_PRIORITY)
str->append(STRING_WITH_LEN("high_priority "));
if (options & SELECT_DISTINCT)
str->append(STRING_WITH_LEN("distinct "));
@@ -17270,5 +17328,392 @@ bool JOIN::change_result(select_result *res)
}
/**
+ Cache constant expressions in WHERE, HAVING, ON conditions.
+*/
+
+void JOIN::cache_const_exprs()
+{
+ bool cache_flag= FALSE;
+ bool *analyzer_arg= &cache_flag;
+
+ /* No need in cache if all tables are constant. */
+ if (const_tables == tables)
+ return;
+
+ if (conds)
+ conds->compile(&Item::cache_const_expr_analyzer, (uchar **)&analyzer_arg,
+ &Item::cache_const_expr_transformer, (uchar *)&cache_flag);
+ cache_flag= FALSE;
+ if (having)
+ having->compile(&Item::cache_const_expr_analyzer, (uchar **)&analyzer_arg,
+ &Item::cache_const_expr_transformer, (uchar *)&cache_flag);
+
+ for (JOIN_TAB *tab= join_tab + const_tables; tab < join_tab + tables ; tab++)
+ {
+ if (*tab->on_expr_ref)
+ {
+ cache_flag= FALSE;
+ (*tab->on_expr_ref)->compile(&Item::cache_const_expr_analyzer,
+ (uchar **)&analyzer_arg,
+ &Item::cache_const_expr_transformer,
+ (uchar *)&cache_flag);
+ }
+ }
+}
+
+
+/**
+ Find a cheaper access key than a given @a key
+
+ @param tab NULL or JOIN_TAB of the accessed table
+ @param order Linked list of ORDER BY arguments
+ @param table Table if tab == NULL or tab->table
+ @param usable_keys Key map to find a cheaper key in
+ @param ref_key
+ * 0 <= key < MAX_KEY - key number (hint) to start the search
+ * -1 - no key number provided
+ @param select_limit LIMIT value
+ @param [out] new_key Key number if success, otherwise undefined
+ @param [out] new_key_direction Return -1 (reverse) or +1 if success,
+ otherwise undefined
+ @param [out] new_select_limit Return adjusted LIMIT
+ @param [out] new_used_key_parts NULL by default, otherwise return number
+ of new_key prefix columns if success
+ or undefined if the function fails
+ @param [out] saved_best_key_parts NULL by default, otherwise preserve the
+ value for further use in QUICK_SELECT_DESC
+
+ @note
+ This function takes into account table->quick_condition_rows statistic
+ (that is calculated by the make_join_statistics function).
+ However, single table procedures such as mysql_update() and mysql_delete()
+ never call make_join_statistics, so they have to update it manually
+ (@see get_index_for_order()).
+*/
+
+static bool
+test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
+ key_map usable_keys, int ref_key,
+ ha_rows select_limit,
+ int *new_key, int *new_key_direction,
+ ha_rows *new_select_limit, uint *new_used_key_parts,
+ uint *saved_best_key_parts)
+{
+ DBUG_ENTER("test_if_cheaper_ordering");
+ /*
+ Check whether there is an index compatible with the given order
+ usage of which is cheaper than usage of the ref_key index (ref_key>=0)
+ or a table scan.
+ It may be the case if ORDER/GROUP BY is used with LIMIT.
+ */
+ ha_rows best_select_limit= HA_POS_ERROR;
+ JOIN *join= tab ? tab->join : NULL;
+ uint nr;
+ key_map keys;
+ uint best_key_parts= 0;
+ int best_key_direction= 0;
+ ha_rows best_records= 0;
+ double read_time;
+ int best_key= -1;
+ bool is_best_covering= FALSE;
+ double fanout= 1;
+ ha_rows table_records= table->file->stats.records;
+ bool group= join && join->group && order == join->group_list;
+ ha_rows ref_key_quick_rows= HA_POS_ERROR;
+
+ /*
+ If not used with LIMIT, only use keys if the whole query can be
+ resolved with a key; This is because filesort() is usually faster than
+ retrieving all rows through an index.
+ */
+ if (select_limit >= table_records)
+ {
+ keys= *table->file->keys_to_use_for_scanning();
+ keys.merge(table->covering_keys);
+
+ /*
+ We are adding here also the index specified in FORCE INDEX clause,
+ if any.
+ This is to allow users to use index in ORDER BY.
+ */
+ if (table->force_index)
+ keys.merge(group ? table->keys_in_use_for_group_by :
+ table->keys_in_use_for_order_by);
+ keys.intersect(usable_keys);
+ }
+ else
+ keys= usable_keys;
+
+ if (ref_key >= 0 && table->covering_keys.is_set(ref_key))
+ ref_key_quick_rows= table->quick_rows[ref_key];
+
+ if (join)
+ {
+ uint tablenr= tab - join->join_tab;
+ read_time= join->best_positions[tablenr].read_time;
+ for (uint i= tablenr+1; i < join->tables; i++)
+ fanout*= join->best_positions[i].records_read; // fanout is always >= 1
+ }
+ else
+ read_time= table->file->scan_time();
+
+ for (nr=0; nr < table->s->keys ; nr++)
+ {
+ int direction;
+ uint used_key_parts;
+
+ if (keys.is_set(nr) &&
+ (direction= test_if_order_by_key(order, table, nr, &used_key_parts)))
+ {
+ /*
+ At this point we are sure that ref_key is a non-ordering
+ key (where "ordering key" is a key that will return rows
+ in the order required by ORDER BY).
+ */
+ DBUG_ASSERT (ref_key != (int) nr);
+
+ bool is_covering= table->covering_keys.is_set(nr) ||
+ (nr == table->s->primary_key &&
+ table->file->primary_key_is_clustered());
+
+ /*
+ Don't use an index scan with ORDER BY without limit.
+ For GROUP BY without limit always use index scan
+ if there is a suitable index.
+ Why we hold to this asymmetry hardly can be explained
+ rationally. It's easy to demonstrate that using
+ temporary table + filesort could be cheaper for grouping
+ queries too.
+ */
+ if (is_covering ||
+ select_limit != HA_POS_ERROR ||
+ (ref_key < 0 && (group || table->force_index)))
+ {
+ double rec_per_key;
+ double index_scan_time;
+ KEY *keyinfo= table->key_info+nr;
+ if (select_limit == HA_POS_ERROR)
+ select_limit= table_records;
+ if (group)
+ {
+ /*
+ Used_key_parts can be larger than keyinfo->key_parts
+ when using a secondary index clustered with a primary
+ key (e.g. as in Innodb).
+ See Bug #28591 for details.
+ */
+ rec_per_key= used_key_parts &&
+ used_key_parts <= keyinfo->key_parts ?
+ keyinfo->rec_per_key[used_key_parts-1] : 1;
+ set_if_bigger(rec_per_key, 1);
+ /*
+ With a grouping query each group containing on average
+ rec_per_key records produces only one row that will
+ be included into the result set.
+ */
+ if (select_limit > table_records/rec_per_key)
+ select_limit= table_records;
+ else
+ select_limit= (ha_rows) (select_limit*rec_per_key);
+ }
+ /*
+ If tab=tk is not the last joined table tn then to get first
+ L records from the result set we can expect to retrieve
+ only L/fanout(tk,tn) where fanout(tk,tn) says how many
+ rows in the record set on average will match each row tk.
+ Usually our estimates for fanouts are too pessimistic.
+ So the estimate for L/fanout(tk,tn) will be too optimistic
+ and as result we'll choose an index scan when using ref/range
+ access + filesort will be cheaper.
+ */
+ select_limit= (ha_rows) (select_limit < fanout ?
+ 1 : select_limit/fanout);
+ /*
+ We assume that each of the tested indexes is not correlated
+ with ref_key. Thus, to select first N records we have to scan
+ N/selectivity(ref_key) index entries.
+ selectivity(ref_key) = #scanned_records/#table_records =
+ table->quick_condition_rows/table_records.
+ In any case we can't select more than #table_records.
+ N/(table->quick_condition_rows/table_records) > table_records
+ <=> N > table->quick_condition_rows.
+ */
+ if (select_limit > table->quick_condition_rows)
+ select_limit= table_records;
+ else
+ select_limit= (ha_rows) (select_limit *
+ (double) table_records /
+ table->quick_condition_rows);
+ rec_per_key= keyinfo->rec_per_key[keyinfo->key_parts-1];
+ set_if_bigger(rec_per_key, 1);
+ /*
+ Here we take into account the fact that rows are
+ accessed in sequences rec_per_key records in each.
+ Rows in such a sequence are supposed to be ordered
+ by rowid/primary key. When reading the data
+ in a sequence we'll touch not more pages than the
+ table file contains.
+ TODO. Use the formula for a disk sweep sequential access
+ to calculate the cost of accessing data rows for one
+ index entry.
+ */
+ index_scan_time= select_limit/rec_per_key *
+ min(rec_per_key, table->file->scan_time());
+ if ((ref_key < 0 && is_covering) ||
+ (ref_key < 0 && (group || table->force_index)) ||
+ index_scan_time < read_time)
+ {
+ ha_rows quick_records= table_records;
+ if ((is_best_covering && !is_covering) ||
+ (is_covering && ref_key_quick_rows < select_limit))
+ continue;
+ if (table->quick_keys.is_set(nr))
+ quick_records= table->quick_rows[nr];
+ if (best_key < 0 ||
+ (select_limit <= min(quick_records,best_records) ?
+ keyinfo->key_parts < best_key_parts :
+ quick_records < best_records))
+ {
+ best_key= nr;
+ best_key_parts= keyinfo->key_parts;
+ if (saved_best_key_parts)
+ *saved_best_key_parts= used_key_parts;
+ best_records= quick_records;
+ is_best_covering= is_covering;
+ best_key_direction= direction;
+ best_select_limit= select_limit;
+ }
+ }
+ }
+ }
+ }
+
+ if (best_key < 0 || best_key == ref_key)
+ DBUG_RETURN(FALSE);
+
+ *new_key= best_key;
+ *new_key_direction= best_key_direction;
+ *new_select_limit= best_select_limit;
+ if (new_used_key_parts != NULL)
+ *new_used_key_parts= best_key_parts;
+
+ DBUG_RETURN(TRUE);
+}
+
+
+/**
+ Find a key to apply single table UPDATE/DELETE by a given ORDER
+
+ @param order Linked list of ORDER BY arguments
+ @param table Table to find a key
+ @param select Pointer to access/update select->quick (if any)
+ @param limit LIMIT clause parameter
+ @param [out] need_sort TRUE if filesort needed
+ @param [out] reverse
+ TRUE if the key is reversed again given ORDER (undefined if key == MAX_KEY)
+
+ @return
+ - MAX_KEY if no key found (need_sort == TRUE)
+ - MAX_KEY if quick select result order is OK (need_sort == FALSE)
+ - key number (either index scan or quick select) (need_sort == FALSE)
+
+ @note
+ Side effects:
+ - may deallocate or deallocate and replace select->quick;
+ - may set table->quick_condition_rows and table->quick_rows[...]
+ to table->file->stats.records.
+*/
+
+uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
+ ha_rows limit, bool *need_sort, bool *reverse)
+{
+ if (select && select->quick && select->quick->unique_key_range())
+ { // Single row select (always "ordered"): Ok to use with key field UPDATE
+ *need_sort= FALSE;
+ /*
+ Returning of MAX_KEY here prevents updating of used_key_is_modified
+ in mysql_update(). Use quick select "as is".
+ */
+ return MAX_KEY;
+ }
+
+ if (!order)
+ {
+ *need_sort= FALSE;
+ if (select && select->quick)
+ return select->quick->index; // index or MAX_KEY, use quick select as is
+ else
+ return table->file->key_used_on_scan; // MAX_KEY or index for some engines
+ }
+
+ if (!is_simple_order(order)) // just to cut further expensive checks
+ {
+ *need_sort= TRUE;
+ return MAX_KEY;
+ }
+
+ if (select && select->quick)
+ {
+ if (select->quick->index == MAX_KEY)
+ {
+ *need_sort= TRUE;
+ return MAX_KEY;
+ }
+
+ uint used_key_parts;
+ switch (test_if_order_by_key(order, table, select->quick->index,
+ &used_key_parts)) {
+ case 1: // desired order
+ *need_sort= FALSE;
+ return select->quick->index;
+ case 0: // unacceptable order
+ *need_sort= TRUE;
+ return MAX_KEY;
+ case -1: // desired order, but opposite direction
+ {
+ QUICK_SELECT_I *reverse_quick;
+ if ((reverse_quick=
+ select->quick->make_reverse(used_key_parts)))
+ {
+ select->set_quick(reverse_quick);
+ *need_sort= FALSE;
+ return select->quick->index;
+ }
+ else
+ {
+ *need_sort= TRUE;
+ return MAX_KEY;
+ }
+ }
+ }
+ DBUG_ASSERT(0);
+ }
+ else if (limit != HA_POS_ERROR)
+ { // check if some index scan & LIMIT is more efficient than filesort
+
+ /*
+ Update quick_condition_rows since single table UPDATE/DELETE procedures
+ don't call make_join_statistics() and leave this variable uninitialized.
+ */
+ table->quick_condition_rows= table->file->stats.records;
+
+ int key, direction;
+ if (test_if_cheaper_ordering(NULL, order, table,
+ table->keys_in_use_for_order_by, -1,
+ limit,
+ &key, &direction, &limit) &&
+ !is_key_used(table, key, table->write_set))
+ {
+ *need_sort= FALSE;
+ *reverse= (direction < 0);
+ return key;
+ }
+ }
+ *need_sort= TRUE;
+ return MAX_KEY;
+}
+
+
+/**
@} (end of group Query_Optimizer)
*/
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 1823eee842d..93885e23f76 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1,3 +1,6 @@
+#ifndef SQL_SELECT_INCLUDED
+#define SQL_SELECT_INCLUDED
+
/* Copyright (C) 2000-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -27,6 +30,10 @@
#include "procedure.h"
#include <myisam.h>
+#include "sql_array.h" /* Array */
+#include "records.h" /* READ_RECORD */
+#include "opt_range.h" /* SQL_SELECT, QUICK_SELECT_I */
+
typedef struct keyuse_t {
TABLE *table;
@@ -145,7 +152,6 @@ enum enum_nested_loop_state
typedef enum_nested_loop_state
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
-typedef int (*Read_record_func)(struct st_join_table *tab);
Next_select_func setup_end_select_func(JOIN *join);
@@ -173,7 +179,7 @@ typedef struct st_join_table {
*/
uint packed_info;
- Read_record_func read_first_record;
+ READ_RECORD::Setup_func read_first_record;
Next_select_func next_select;
READ_RECORD read_record;
/*
@@ -181,8 +187,8 @@ typedef struct st_join_table {
if it is executed by an alternative full table scan when the left operand of
the subquery predicate is evaluated to NULL.
*/
- Read_record_func save_read_first_record;/* to save read_first_record */
- int (*save_read_record) (READ_RECORD *);/* to save read_record.read_record */
+ READ_RECORD::Setup_func save_read_first_record;/* to save read_first_record */
+ READ_RECORD::Read_func save_read_record;/* to save read_record.read_record */
double worst_seeks;
key_map const_keys; /**< Keys with constant part */
key_map checked_keys; /**< Keys checked in find_best */
@@ -229,6 +235,11 @@ typedef struct st_join_table {
(select->quick->get_type() ==
QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
}
+ bool is_using_agg_loose_index_scan ()
+ {
+ return (is_using_loose_index_scan() &&
+ ((QUICK_GROUP_MIN_MAX_SELECT *)select->quick)->is_agg_distinct());
+ }
} JOIN_TAB;
enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
@@ -286,7 +297,7 @@ public:
JOIN_TAB *join_tab,**best_ref;
JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs
JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution
- TABLE **table,**all_tables,*sort_by_table;
+ TABLE **all_tables,*sort_by_table;
uint tables,const_tables;
uint send_group_parts;
/**
@@ -298,11 +309,6 @@ public:
bool sort_and_group;
bool first_record,full_join,group, no_field_update;
bool do_send_rows;
- /**
- TRUE when we want to resume nested loop iterations when
- fetching data from a cursor
- */
- bool resume_nested_loop;
table_map const_table_map,found_const_table_map;
/*
Bitmap of all inner tables from outer joins
@@ -460,7 +466,7 @@ public:
select_result *result_arg)
{
join_tab= join_tab_save= 0;
- table= 0;
+ all_tables= 0;
tables= 0;
const_tables= 0;
join_list= 0;
@@ -468,7 +474,6 @@ public:
sort_and_group= 0;
first_record= 0;
do_send_rows= 1;
- resume_nested_loop= FALSE;
send_records= 0;
found_records= 0;
fetch_limit= HA_POS_ERROR;
@@ -570,6 +575,7 @@ public:
return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 ||
select_lex == unit->fake_select_lex));
}
+ void cache_const_exprs();
private:
/**
TRUE if the query contains an aggregate function but has no GROUP
@@ -586,14 +592,13 @@ typedef struct st_select_check {
} SELECT_CHECK;
extern const char *join_type_str[];
-void TEST_join(JOIN *join);
/* Extern functions in sql_select.cc */
bool store_val_in_field(Field *field, Item *val, enum_check_fields check_flag);
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,
- char* alias);
+ const char* alias);
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param,
List<Item> &fields, bool reset_with_sum_func);
@@ -610,6 +615,8 @@ Field* create_tmp_field_from_field(THD *thd, Field* org_field,
const char *name, TABLE *table,
Item_field *item, uint convert_blob_length);
+bool is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args);
+
/* functions from opt_sum.cc */
bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
@@ -657,7 +664,7 @@ public:
enum store_key_result result;
THD *thd= to_field->table->in_use;
enum_check_fields saved_count_cuted_fields= thd->count_cuted_fields;
- ulong sql_mode= thd->variables.sql_mode;
+ ulonglong sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -789,9 +796,58 @@ bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
+int get_quick_record(SQL_SELECT *select);
+SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length,
+ SORT_FIELD *sortorder);
+int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+ List<Item> &fields, List <Item> &all_fields, ORDER *order);
+int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+ List<Item> &fields, List<Item> &all_fields, ORDER *order,
+ bool *hidden_group_fields);
+bool fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
+ Item **ref_pointer_array, ORDER *group_list= NULL);
+
+bool handle_select(THD *thd, LEX *lex, select_result *result,
+ ulong setup_tables_done_option);
+bool mysql_select(THD *thd, Item ***rref_pointer_array,
+ TABLE_LIST *tables, uint wild_num, List<Item> &list,
+ COND *conds, uint og_num, ORDER *order, ORDER *group,
+ Item *having, ORDER *proc_param, ulonglong select_type,
+ select_result *result, SELECT_LEX_UNIT *unit,
+ SELECT_LEX *select_lex);
+void free_underlaid_joins(THD *thd, SELECT_LEX *select);
+bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
+ select_result *result);
+Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
+ Item ***copy_func, Field **from_field,
+ Field **def_field,
+ bool group, bool modify_item,
+ bool table_cant_handle_bit_fields,
+ bool make_copy_field,
+ uint convert_blob_length);
+
+/*
+ General routine to change field->ptr of a NULL-terminated array of Field
+ objects. Useful when needed to call val_int, val_str or similar and the
+ field data is not in table->record[0] but in some other structure.
+ set_key_field_ptr changes all fields of an index using a key_info object.
+ All methods presume that there is at least one field to change.
+*/
+
+TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list);
+
inline bool optimizer_flag(THD *thd, uint flag)
{
return (thd->variables.optimizer_switch & flag);
}
+uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
+ ha_rows limit, bool *need_sort, bool *reverse);
+ORDER *simple_remove_const(ORDER *order, COND *where);
+bool const_expression_in_where(COND *cond, Item *comp_item,
+ Field *comp_field= NULL,
+ Item **const_item= NULL);
+
+
+#endif /* SQL_SELECT_INCLUDED */
diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc
index 1655426bb4a..bc845ed2cdd 100644
--- a/sql/sql_servers.cc
+++ b/sql/sql_servers.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -33,12 +33,18 @@
currently running transactions etc will not be disrupted.
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "sql_servers.h"
+#include "unireg.h"
+#include "sql_base.h" // close_mysql_tables
+#include "records.h" // init_read_record, end_read_record
#include "hash_filo.h"
#include <m_ctype.h>
#include <stdarg.h>
#include "sp_head.h"
#include "sp.h"
+#include "transaction.h"
+#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
/*
We only use 1 mutex to guard the data structures - THR_LOCK_servers.
@@ -47,7 +53,7 @@
static HASH servers_cache;
static MEM_ROOT mem;
-static rw_lock_t THR_LOCK_servers;
+static mysql_rwlock_t THR_LOCK_servers;
static bool get_server_from_table_to_cache(TABLE *table);
@@ -89,6 +95,26 @@ static uchar *servers_cache_get_key(FOREIGN_SERVER *server, size_t *length,
DBUG_RETURN((uchar*) server->server_name);
}
+#ifdef HAVE_PSI_INTERFACE
+static PSI_rwlock_key key_rwlock_THR_LOCK_servers;
+
+static PSI_rwlock_info all_servers_cache_rwlocks[]=
+{
+ { &key_rwlock_THR_LOCK_servers, "THR_LOCK_servers", PSI_FLAG_GLOBAL}
+};
+
+static void init_servers_cache_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_servers_cache_rwlocks);
+ PSI_server->register_rwlock(category, all_servers_cache_rwlocks, count);
+}
+#endif /* HAVE_PSI_INTERFACE */
/*
Initialize structures responsible for servers used in federated
@@ -115,20 +141,24 @@ bool servers_init(bool dont_read_servers_table)
bool return_val= FALSE;
DBUG_ENTER("servers_init");
+#ifdef HAVE_PSI_INTERFACE
+ init_servers_cache_psi_keys();
+#endif
+
/* init the mutex */
- if (my_rwlock_init(&THR_LOCK_servers, NULL))
+ if (mysql_rwlock_init(key_rwlock_THR_LOCK_servers, &THR_LOCK_servers))
DBUG_RETURN(TRUE);
/* initialise our servers cache */
- if (hash_init(&servers_cache, system_charset_info, 32, 0, 0,
- (hash_get_key) servers_cache_get_key, 0, 0))
+ if (my_hash_init(&servers_cache, system_charset_info, 32, 0, 0,
+ (my_hash_get_key) servers_cache_get_key, 0, 0))
{
return_val= TRUE; /* we failed, out of memory? */
goto end;
}
/* Initialize the mem root for data */
- init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
+ init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
if (dont_read_servers_table)
goto end;
@@ -140,7 +170,6 @@ bool servers_init(bool dont_read_servers_table)
DBUG_RETURN(TRUE);
thd->thread_stack= (char*) &thd;
thd->store_globals();
- lex_start(thd);
/*
It is safe to call servers_reload() since servers_* arrays and hashes which
will be freed there are global static objects and thus are initialized
@@ -180,7 +209,7 @@ static bool servers_load(THD *thd, TABLE_LIST *tables)
my_hash_reset(&servers_cache);
free_root(&mem, MYF(0));
- init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
+ init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
init_read_record(&read_record_info,thd,table=tables[0].table,NULL,1,0,
FALSE);
@@ -224,30 +253,20 @@ bool servers_reload(THD *thd)
bool return_val= TRUE;
DBUG_ENTER("servers_reload");
- if (thd->locked_tables)
- { // Can't have locked tables here
- thd->lock=thd->locked_tables;
- thd->locked_tables=0;
- close_thread_tables(thd);
- }
-
DBUG_PRINT("info", ("locking servers_cache"));
- rw_wrlock(&THR_LOCK_servers);
+ mysql_rwlock_wrlock(&THR_LOCK_servers);
- bzero((char*) tables, sizeof(tables));
- tables[0].alias= tables[0].table_name= (char*) "servers";
- tables[0].db= (char*) "mysql";
- tables[0].lock_type= TL_READ;
+ tables[0].init_one_table("mysql", 5, "servers", 7, "servers", TL_READ);
- if (simple_open_n_lock_tables(thd, tables))
+ if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{
/*
Execution might have been interrupted; only print the error message
if an error condition has been raised.
*/
- if (thd->main_da.is_error())
+ if (thd->stmt_da->is_error())
sql_print_error("Can't open and lock privilege tables: %s",
- thd->main_da.message());
+ thd->stmt_da->message());
return_val= FALSE;
goto end;
}
@@ -261,9 +280,9 @@ bool servers_reload(THD *thd)
}
end:
- close_thread_tables(thd);
+ close_mysql_tables(thd);
DBUG_PRINT("info", ("unlocking servers_cache"));
- rw_unlock(&THR_LOCK_servers);
+ mysql_rwlock_unlock(&THR_LOCK_servers);
DBUG_RETURN(return_val);
}
@@ -371,12 +390,10 @@ insert_server(THD *thd, FOREIGN_SERVER *server)
DBUG_ENTER("insert_server");
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.alias= tables.table_name= (char*) "servers";
+ tables.init_one_table("mysql", 5, "servers", 7, "servers", TL_WRITE);
/* need to open before acquiring THR_LOCK_plugin or it will deadlock */
- if (! (table= open_ltable(thd, &tables, TL_WRITE, 0)))
+ if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
goto end;
/* insert the server into the table */
@@ -516,6 +533,7 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
{
int error;
DBUG_ENTER("insert_server_record");
+ tmp_disable_binlog(table->in_use);
table->use_all_columns();
empty_record(table);
@@ -552,6 +570,8 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
}
else
error= ER_FOREIGN_SERVER_EXISTS;
+
+ reenable_binlog(table->in_use);
DBUG_RETURN(error);
}
@@ -589,17 +609,15 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
DBUG_PRINT("info", ("server name server->server_name %s",
server_options->server_name));
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.alias= tables.table_name= (char*) "servers";
+ tables.init_one_table("mysql", 5, "servers", 7, "servers", TL_WRITE);
- rw_wrlock(&THR_LOCK_servers);
+ mysql_rwlock_wrlock(&THR_LOCK_servers);
/* hit the memory hit first */
if ((error= delete_server_record_in_cache(server_options)))
goto end;
- if (! (table= open_ltable(thd, &tables, TL_WRITE, 0)))
+ if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
{
error= my_errno;
goto end;
@@ -608,16 +626,16 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
error= delete_server_record(table, name.str, name.length);
/* close the servers table before we call closed_cached_connection_tables */
- close_thread_tables(thd);
+ close_mysql_tables(thd);
- if (close_cached_connection_tables(thd, TRUE, &name))
+ if (close_cached_connection_tables(thd, &name))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR, "Server connection in use");
}
end:
- rw_unlock(&THR_LOCK_servers);
+ mysql_rwlock_unlock(&THR_LOCK_servers);
DBUG_RETURN(error);
}
@@ -652,9 +670,10 @@ delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options)
server_options->server_name_length));
- if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache,
- (uchar*) server_options->server_name,
- server_options->server_name_length)))
+ if (!(server= (FOREIGN_SERVER *)
+ my_hash_search(&servers_cache,
+ (uchar*) server_options->server_name,
+ server_options->server_name_length)))
{
DBUG_PRINT("info", ("server_name %s length %d not found!",
server_options->server_name,
@@ -669,8 +688,8 @@ delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options)
server->server_name,
server->server_name_length));
- VOID(hash_delete(&servers_cache, (uchar*) server));
-
+ my_hash_delete(&servers_cache, (uchar*) server);
+
error= 0;
end:
@@ -712,11 +731,10 @@ int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered)
TABLE_LIST tables;
DBUG_ENTER("update_server");
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*)"mysql";
- tables.alias= tables.table_name= (char*)"servers";
+ tables.init_one_table("mysql", 5, "servers", 7, "servers",
+ TL_WRITE);
- if (!(table= open_ltable(thd, &tables, TL_WRITE, 0)))
+ if (!(table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
{
error= my_errno;
goto end;
@@ -776,7 +794,7 @@ int update_server_record_in_cache(FOREIGN_SERVER *existing,
/*
delete the existing server struct from the server cache
*/
- VOID(hash_delete(&servers_cache, (uchar*)existing));
+ my_hash_delete(&servers_cache, (uchar*)existing);
/*
Insert the altered server struct into the server cache
@@ -863,6 +881,7 @@ update_server_record(TABLE *table, FOREIGN_SERVER *server)
{
int error=0;
DBUG_ENTER("update_server_record");
+ tmp_disable_binlog(table->in_use);
table->use_all_columns();
/* set the field that's the PK to the value we're looking for */
table->field[0]->store(server->server_name,
@@ -896,6 +915,7 @@ update_server_record(TABLE *table, FOREIGN_SERVER *server)
}
end:
+ reenable_binlog(table->in_use);
DBUG_RETURN(error);
}
@@ -921,6 +941,7 @@ delete_server_record(TABLE *table,
{
int error;
DBUG_ENTER("delete_server_record");
+ tmp_disable_binlog(table->in_use);
table->use_all_columns();
/* set the field that's the PK to the value we're looking for */
@@ -942,6 +963,7 @@ delete_server_record(TABLE *table,
table->file->print_error(error, MYF(0));
}
+ reenable_binlog(table->in_use);
DBUG_RETURN(error);
}
@@ -968,11 +990,11 @@ int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
DBUG_PRINT("info", ("server_options->server_name %s",
server_options->server_name));
- rw_wrlock(&THR_LOCK_servers);
+ mysql_rwlock_wrlock(&THR_LOCK_servers);
/* hit the memory first */
- if (hash_search(&servers_cache, (uchar*) server_options->server_name,
- server_options->server_name_length))
+ if (my_hash_search(&servers_cache, (uchar*) server_options->server_name,
+ server_options->server_name_length))
goto end;
@@ -989,7 +1011,7 @@ int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
DBUG_PRINT("info", ("error returned %d", error));
end:
- rw_unlock(&THR_LOCK_servers);
+ mysql_rwlock_unlock(&THR_LOCK_servers);
DBUG_RETURN(error);
}
@@ -1018,11 +1040,11 @@ int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
DBUG_PRINT("info", ("server_options->server_name %s",
server_options->server_name));
- rw_wrlock(&THR_LOCK_servers);
+ mysql_rwlock_wrlock(&THR_LOCK_servers);
- if (!(existing= (FOREIGN_SERVER *) hash_search(&servers_cache,
- (uchar*) name.str,
- name.length)))
+ if (!(existing= (FOREIGN_SERVER *) my_hash_search(&servers_cache,
+ (uchar*) name.str,
+ name.length)))
goto end;
altered= (FOREIGN_SERVER *)alloc_root(&mem,
@@ -1033,9 +1055,9 @@ int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
error= update_server(thd, existing, altered);
/* close the servers table before we call closed_cached_connection_tables */
- close_thread_tables(thd);
+ close_mysql_tables(thd);
- if (close_cached_connection_tables(thd, FALSE, &name))
+ if (close_cached_connection_tables(thd, &name))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR, "Server connection in use");
@@ -1043,7 +1065,7 @@ int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
end:
DBUG_PRINT("info", ("error returned %d", error));
- rw_unlock(&THR_LOCK_servers);
+ mysql_rwlock_unlock(&THR_LOCK_servers);
DBUG_RETURN(error);
}
@@ -1201,7 +1223,7 @@ prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
void servers_free(bool end)
{
DBUG_ENTER("servers_free");
- if (!hash_inited(&servers_cache))
+ if (!my_hash_inited(&servers_cache))
DBUG_VOID_RETURN;
if (!end)
{
@@ -1209,9 +1231,9 @@ void servers_free(bool end)
my_hash_reset(&servers_cache);
DBUG_VOID_RETURN;
}
- rwlock_destroy(&THR_LOCK_servers);
+ mysql_rwlock_destroy(&THR_LOCK_servers);
free_root(&mem,MYF(0));
- hash_free(&servers_cache);
+ my_hash_free(&servers_cache);
DBUG_VOID_RETURN;
}
@@ -1291,10 +1313,10 @@ FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name,
}
DBUG_PRINT("info", ("locking servers_cache"));
- rw_rdlock(&THR_LOCK_servers);
- if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache,
- (uchar*) server_name,
- server_name_length)))
+ mysql_rwlock_rdlock(&THR_LOCK_servers);
+ if (!(server= (FOREIGN_SERVER *) my_hash_search(&servers_cache,
+ (uchar*) server_name,
+ server_name_length)))
{
DBUG_PRINT("info", ("server_name %s length %u not found!",
server_name, (unsigned) server_name_length));
@@ -1305,7 +1327,7 @@ FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name,
server= clone_server(mem, server, buff);
DBUG_PRINT("info", ("unlocking servers_cache"));
- rw_unlock(&THR_LOCK_servers);
+ mysql_rwlock_unlock(&THR_LOCK_servers);
DBUG_RETURN(server);
}
diff --git a/sql/sql_servers.h b/sql/sql_servers.h
index 63c691893d1..3c338bbe3f9 100644
--- a/sql/sql_servers.h
+++ b/sql/sql_servers.h
@@ -1,3 +1,6 @@
+#ifndef SQL_SERVERS_INCLUDED
+#define SQL_SERVERS_INCLUDED
+
/* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -13,8 +16,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+#include "my_global.h" /* uint */
#include "slave.h" // for tables_ok(), rpl_filter
+class THD;
+typedef struct st_lex_server_options LEX_SERVER_OPTIONS;
+typedef struct st_mem_root MEM_ROOT;
+
/* structs */
typedef struct st_federated_server
{
@@ -41,3 +49,5 @@ int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options);
/* lookup functions */
FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name,
FOREIGN_SERVER *server_buffer);
+
+#endif /* SQL_SERVERS_INCLUDED */
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index ee0e2bf5ce7..2c71fe5dd48 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -9,28 +9,48 @@
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 02110-1301 USA */
+ 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 */
/* Function with list databases, tables or fields */
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_acl.h" // fill_schema_*_privileges
#include "sql_select.h" // For select_describe
+#include "sql_base.h" // close_tables_for_reopen
#include "sql_show.h"
+#include "sql_table.h" // filename_to_tablename,
+ // primary_key_name,
+ // build_table_filename
#include "repl_failsafe.h"
+#include "sql_parse.h" // check_access, check_table_access
+#include "sql_partition.h" // partition_element
+#include "sql_db.h" // check_db_dir_existence, load_db_opt_by_name
+#include "sql_time.h" // interval_type_to_name
+#include "tztime.h" // struct Time_zone
+#include "sql_acl.h" // TABLE_ACLS, check_grant, DB_ACLS, acl_get,
+ // check_grant_db
+#include "filesort.h" // filesort_free_buffers
#include "sp.h"
#include "sp_head.h"
+#include "sp_pcontext.h"
+#include "set_var.h"
#include "sql_trigger.h"
#include "authors.h"
#include "contributors.h"
+#include "sql_partition.h"
#ifdef HAVE_EVENT_SCHEDULER
#include "events.h"
#include "event_data_objects.h"
#endif
#include <my_dir.h>
+#include "lock.h" // MYSQL_OPEN_IGNORE_FLUSH
#include "debug_sync.h"
+#include "datadict.h" // dd_frm_type()
#define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
@@ -78,6 +98,14 @@ static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
static void store_key_options(THD *thd, String *packet, TABLE *table,
KEY *key_info);
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+static void get_cs_converted_string_value(THD *thd,
+ String *input_str,
+ String *output_str,
+ CHARSET_INFO *cs,
+ bool use_hex);
+#endif
+
static void
append_algorithm(TABLE_LIST *table, String *buff);
@@ -185,6 +213,11 @@ static my_bool show_plugins(THD *thd, plugin_ref plugin,
}
table->field[9]->set_notnull();
+ table->field[10]->store(
+ global_plugin_typelib_names[plugin_load_option(plugin)],
+ strlen(global_plugin_typelib_names[plugin_load_option(plugin)]),
+ cs);
+
return schema_table_store_record(thd, table);
}
@@ -217,7 +250,7 @@ bool mysqld_show_authors(THD *thd)
field_list.push_back(new Item_empty_string("Location",40));
field_list.push_back(new Item_empty_string("Comment",80));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
@@ -251,7 +284,7 @@ bool mysqld_show_contributors(THD *thd)
field_list.push_back(new Item_empty_string("Location",40));
field_list.push_back(new Item_empty_string("Comment",80));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
@@ -311,6 +344,7 @@ static struct show_privileges_st sys_privileges[]=
{"Shutdown","Server Admin", "To shut down the server"},
{"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."},
{"Trigger","Tables", "To use triggers"},
+ {"Create tablespace", "Server Admin", "To create/alter/drop tablespaces"},
{"Update", "Tables", "To update existing rows"},
{"Usage","Server Admin","No privileges - allow connect only"},
{NullS, NullS, NullS}
@@ -326,7 +360,7 @@ bool mysqld_show_privileges(THD *thd)
field_list.push_back(new Item_empty_string("Context",15));
field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
@@ -345,94 +379,6 @@ bool mysqld_show_privileges(THD *thd)
}
-/***************************************************************************
- List all column types
-***************************************************************************/
-
-struct show_column_type_st
-{
- const char *type;
- uint size;
- const char *min_value;
- const char *max_value;
- uint precision;
- uint scale;
- const char *nullable;
- const char *auto_increment;
- const char *unsigned_attr;
- const char *zerofill;
- const char *searchable;
- const char *case_sensitivity;
- const char *default_value;
- const char *comment;
-};
-
-/* TODO: Add remaning types */
-
-static struct show_column_type_st sys_column_types[]=
-{
- {"tinyint",
- 1, "-128", "127", 0, 0, "YES", "YES",
- "NO", "YES", "YES", "NO", "NULL,0",
- "A very small integer"},
- {"tinyint unsigned",
- 1, "0" , "255", 0, 0, "YES", "YES",
- "YES", "YES", "YES", "NO", "NULL,0",
- "A very small integer"},
-};
-
-bool mysqld_show_column_types(THD *thd)
-{
- List<Item> field_list;
- Protocol *protocol= thd->protocol;
- DBUG_ENTER("mysqld_show_column_types");
-
- field_list.push_back(new Item_empty_string("Type",30));
- field_list.push_back(new Item_int("Size",(longlong) 1,
- MY_INT64_NUM_DECIMAL_DIGITS));
- field_list.push_back(new Item_empty_string("Min_Value",20));
- field_list.push_back(new Item_empty_string("Max_Value",20));
- field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT));
- field_list.push_back(new Item_return_int("Scale", 4, MYSQL_TYPE_SHORT));
- field_list.push_back(new Item_empty_string("Nullable",4));
- field_list.push_back(new Item_empty_string("Auto_Increment",4));
- field_list.push_back(new Item_empty_string("Unsigned",4));
- field_list.push_back(new Item_empty_string("Zerofill",4));
- field_list.push_back(new Item_empty_string("Searchable",4));
- field_list.push_back(new Item_empty_string("Case_Sensitive",4));
- field_list.push_back(new Item_empty_string("Default",NAME_CHAR_LEN));
- field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN));
-
- if (protocol->send_fields(&field_list,
- Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
- DBUG_RETURN(TRUE);
-
- /* TODO: Change the loop to not use 'i' */
- for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
- {
- protocol->prepare_for_resend();
- protocol->store(sys_column_types[i].type, system_charset_info);
- protocol->store((ulonglong) sys_column_types[i].size);
- protocol->store(sys_column_types[i].min_value, system_charset_info);
- protocol->store(sys_column_types[i].max_value, system_charset_info);
- protocol->store_short((longlong) sys_column_types[i].precision);
- protocol->store_short((longlong) sys_column_types[i].scale);
- protocol->store(sys_column_types[i].nullable, system_charset_info);
- protocol->store(sys_column_types[i].auto_increment, system_charset_info);
- protocol->store(sys_column_types[i].unsigned_attr, system_charset_info);
- protocol->store(sys_column_types[i].zerofill, system_charset_info);
- protocol->store(sys_column_types[i].searchable, system_charset_info);
- protocol->store(sys_column_types[i].case_sensitivity, system_charset_info);
- protocol->store(sys_column_types[i].default_value, system_charset_info);
- protocol->store(sys_column_types[i].comment, system_charset_info);
- if (protocol->write())
- DBUG_RETURN(TRUE);
- }
- my_eof(thd);
- DBUG_RETURN(FALSE);
-}
-
-
/*
find_files() - find files in a given directory.
@@ -513,7 +459,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
end= strend(buff);
if (end != buff && end[-1] == FN_LIBCHAR)
end[-1]= 0; // Remove end FN_LIBCHAR
- if (!my_stat(buff, file->mystat, MYF(0)))
+ if (!mysql_file_stat(key_file_misc, buff, file->mystat, MYF(0)))
continue;
}
#endif
@@ -566,7 +512,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
table_list.table_name= uname;
table_list.table_name_length= file_name_len;
table_list.grant.privilege=col_access;
- if (check_grant(thd, TABLE_ACLS, &table_list, 1, 1, 1))
+ if (check_grant(thd, TABLE_ACLS, &table_list, TRUE, 1, TRUE))
continue;
}
#endif
@@ -581,7 +527,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
DBUG_PRINT("info",("found: %d files", files->elements));
my_dirend(dirp);
- VOID(ha_find_files(thd, db, path, wild, dir, files));
+ (void) ha_find_files(thd, db, path, wild, dir, files);
DBUG_RETURN(FIND_FILES_OK);
}
@@ -650,9 +596,11 @@ public:
return m_view_access_denied_message_ptr;
}
- bool handle_error(uint sql_errno, const char *message,
- MYSQL_ERROR::enum_warning_level level, THD *thd) {
- /*
+ bool handle_condition(THD *thd, uint sql_errno, const char * /* sqlstate */,
+ MYSQL_ERROR::enum_warning_level level,
+ const char *message, MYSQL_ERROR ** /* cond_hdl */)
+ {
+ /*
The handler does not handle the errors raised by itself.
At this point we know if top_view is really a view.
*/
@@ -662,7 +610,7 @@ public:
m_handling= TRUE;
bool is_handled;
-
+
switch (sql_errno)
{
case ER_TABLEACCESS_DENIED_ERROR:
@@ -713,20 +661,30 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
Protocol *protocol= thd->protocol;
char buff[2048];
String buffer(buff, sizeof(buff), system_charset_info);
+ List<Item> field_list;
+ bool error= TRUE;
DBUG_ENTER("mysqld_show_create");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->table_name));
+ /*
+ Metadata locks taken during SHOW CREATE should be released when
+ the statmement completes as it is an information statement.
+ */
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
+
/* We want to preserve the tree for views. */
thd->lex->view_prepare_mode= TRUE;
{
Show_create_error_handler view_error_suppressor(thd, table_list);
thd->push_internal_handler(&view_error_suppressor);
- bool error= open_normal_and_derived_tables(thd, table_list, 0);
+ bool open_error=
+ open_normal_and_derived_tables(thd, table_list,
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL);
thd->pop_internal_handler();
- if (error && (thd->killed || thd->main_da.is_error()))
- DBUG_RETURN(TRUE);
+ if (open_error && (thd->killed || thd->is_error()))
+ goto exit;
}
/* TODO: add environment variables show when it become possible */
@@ -734,7 +692,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
my_error(ER_WRONG_OBJECT, MYF(0),
table_list->db, table_list->table_name, "VIEW");
- DBUG_RETURN(TRUE);
+ goto exit;
}
buffer.length(0);
@@ -746,9 +704,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
view_store_create_info(thd, table_list, &buffer) :
store_create_info(thd, table_list, &buffer, NULL,
FALSE /* show_database */)))
- DBUG_RETURN(TRUE);
+ goto exit;
- List<Item> field_list;
if (table_list->view)
{
field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN));
@@ -767,9 +724,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
max(buffer.length(),1024)));
}
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
- DBUG_RETURN(TRUE);
+ goto exit;
+
protocol->prepare_for_resend();
if (table_list->view)
protocol->store(table_list->view_name.str, system_charset_info);
@@ -797,10 +755,16 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
if (protocol->write())
- DBUG_RETURN(TRUE);
+ goto exit;
+ error= FALSE;
my_eof(thd);
- DBUG_RETURN(FALSE);
+
+exit:
+ close_thread_tables(thd);
+ /* Release any metadata locks taken during SHOW CREATE. */
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+ DBUG_RETURN(error);
}
bool mysqld_show_create_db(THD *thd, char *dbname,
@@ -832,7 +796,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
DBUG_RETURN(TRUE);
}
#endif
- if (is_schema_db(dbname))
+ if (is_infoschema_db(dbname))
{
dbname= INFORMATION_SCHEMA_NAME.str;
create.default_table_charset= system_charset_info;
@@ -851,7 +815,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
field_list.push_back(new Item_empty_string("Create Database",1024));
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
@@ -897,7 +861,8 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
DBUG_ENTER("mysqld_list_fields");
DBUG_PRINT("enter",("table: %s",table_list->table_name));
- if (open_normal_and_derived_tables(thd, table_list, 0))
+ if (open_normal_and_derived_tables(thd, table_list,
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
DBUG_VOID_RETURN;
table= table_list->table;
@@ -919,41 +884,12 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
}
restore_record(table, s->default_values); // Get empty record
table->use_all_columns();
- if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS))
+ if (thd->protocol->send_result_set_metadata(&field_list, Protocol::SEND_DEFAULTS))
DBUG_VOID_RETURN;
my_eof(thd);
DBUG_VOID_RETURN;
}
-
-int
-mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd)
-{
- Protocol *protocol= thd->protocol;
- String *packet= protocol->storage_packet();
- DBUG_ENTER("mysqld_dump_create_info");
- DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name.str));
-
- protocol->prepare_for_resend();
- if (store_create_info(thd, table_list, packet, NULL,
- FALSE /* show_database */))
- DBUG_RETURN(-1);
-
- if (fd < 0)
- {
- if (protocol->write())
- DBUG_RETURN(-1);
- protocol->flush();
- }
- else
- {
- if (my_write(fd, (const uchar*) packet->ptr(), packet->length(),
- MYF(MY_WME)))
- DBUG_RETURN(-1);
- }
- DBUG_RETURN(0);
-}
-
/*
Go through all character combinations and ensure that sql_lex.cc can
parse it as an identifier.
@@ -1019,7 +955,7 @@ append_identifier(THD *thd, String *packet, const char *name, uint length)
it's a keyword
*/
- VOID(packet->reserve(length*2 + 2));
+ (void) packet->reserve(length*2 + 2);
quote_char= (char) q;
packet->append(&quote_char, 1, system_charset_info);
@@ -1072,7 +1008,7 @@ int get_quote_char_for_identifier(THD *thd, const char *name, uint length)
if (length &&
!is_keyword(name,length) &&
!require_quotes(name, length) &&
- !(thd->options & OPTION_QUOTE_SHOW_CREATE))
+ !(thd->variables.option_bits & OPTION_QUOTE_SHOW_CREATE))
return EOF;
if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
return '"';
@@ -1110,20 +1046,21 @@ static void append_directory(THD *thd, String *packet, const char *dir_type,
#define LIST_PROCESS_HOST_LEN 64
-static bool get_field_default_value(THD *thd, TABLE *table,
+static bool get_field_default_value(THD *thd, Field *timestamp_field,
Field *field, String *def_value,
bool quoted)
{
bool has_default;
bool has_now_default;
enum enum_field_types field_type= field->type();
- /*
+
+ /*
We are using CURRENT_TIMESTAMP instead of NOW because it is
more standard
*/
- has_now_default= table->timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_UN_FIELD;
-
+ has_now_default= (timestamp_field == field &&
+ field->unireg_check != Field::TIMESTAMP_UN_FIELD);
+
has_default= (field_type != FIELD_TYPE_BLOB &&
!(field->flags & NO_DEFAULT_VALUE_FLAG) &&
field->unireg_check != Field::NEXT_NUMBER &&
@@ -1176,6 +1113,7 @@ static bool get_field_default_value(THD *thd, TABLE *table,
return has_default;
}
+
/*
Build a CREATE TABLE statement for a table.
@@ -1325,7 +1263,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" NULL"));
}
- if (get_field_default_value(thd, table, field, &def_value, 1))
+ if (get_field_default_value(thd, table->timestamp_field,
+ field, &def_value, 1))
{
packet->append(STRING_WITH_LEN(" DEFAULT "));
packet->append(def_value.ptr(), def_value.length(), system_charset_info);
@@ -1440,7 +1379,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" /*!50100 TABLESPACE "));
packet->append(for_str, strlen(for_str));
packet->append(STRING_WITH_LEN(" STORAGE DISK */"));
- my_free(for_str, MYF(0));
+ my_free(for_str);
}
/*
@@ -1483,7 +1422,6 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
end= longlong10_to_str(create_info.auto_increment_value, buff,10);
packet->append(buff, (uint) (end - buff));
}
-
if (share->table_charset &&
!(thd->variables.sql_mode & MODE_MYSQL323) &&
@@ -1577,12 +1515,13 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
((part_syntax= generate_partition_syntax(table->part_info,
&part_syntax_len,
FALSE,
- show_table_options))))
+ show_table_options,
+ NULL, NULL))))
{
- packet->append(STRING_WITH_LEN("\n/*!50100"));
+ table->part_info->set_show_version_string(packet);
packet->append(part_syntax, part_syntax_len);
packet->append(STRING_WITH_LEN(" */"));
- my_free(part_syntax, MYF(0));
+ my_free(part_syntax);
}
}
#endif
@@ -1627,6 +1566,14 @@ static void store_key_options(THD *thd, String *packet, TABLE *table,
end= longlong10_to_str(key_info->block_size, buff, 10);
packet->append(buff, (uint) (end - buff));
}
+ DBUG_ASSERT(test(key_info->flags & HA_USES_COMMENT) ==
+ (key_info->comment.length > 0));
+ if (key_info->flags & HA_USES_COMMENT)
+ {
+ packet->append(STRING_WITH_LEN(" COMMENT "));
+ append_unescaped(packet, key_info->comment.str,
+ key_info->comment.length);
+ }
}
}
@@ -1780,13 +1727,37 @@ public:
time_t start_time;
uint command;
const char *user,*host,*db,*proc_info,*state_info;
- char *query;
+ CSET_STRING query_string;
};
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List<thread_info>;
#endif
+static const char *thread_state_info(THD *tmp)
+{
+#ifndef EMBEDDED_LIBRARY
+ if (tmp->net.reading_or_writing)
+ {
+ if (tmp->net.reading_or_writing == 2)
+ return "Writing to net";
+ else if (tmp->command == COM_SLEEP)
+ return "";
+ else
+ return "Reading from net";
+ }
+ else
+#endif
+ {
+ if (tmp->proc_info)
+ return tmp->proc_info;
+ else if (tmp->mysys_var && tmp->mysys_var->current_cond)
+ return "Waiting on cond";
+ else
+ return NULL;
+ }
+}
+
void mysqld_list_processes(THD *thd,const char *user, bool verbose)
{
Item *field;
@@ -1809,11 +1780,11 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
field->maybe_null=1;
field_list.push_back(field=new Item_empty_string("Info",max_query_length));
field->maybe_null=1;
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_VOID_RETURN;
- VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
if (!thd->killed)
{
I_List_iterator<THD> it(threads);
@@ -1845,41 +1816,30 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if ((thd_info->db=tmp->db)) // Safe test
thd_info->db=thd->strdup(thd_info->db);
thd_info->command=(int) tmp->command;
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
if ((mysys_var= tmp->mysys_var))
- pthread_mutex_lock(&mysys_var->mutex);
+ mysql_mutex_lock(&mysys_var->mutex);
thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
-#ifndef EMBEDDED_LIBRARY
- thd_info->state_info= (char*) (tmp->locked ? "Locked" :
- tmp->net.reading_or_writing ?
- (tmp->net.reading_or_writing == 2 ?
- "Writing to net" :
- thd_info->command == COM_SLEEP ? "" :
- "Reading from net") :
- tmp->proc_info ? tmp->proc_info :
- tmp->mysys_var &&
- tmp->mysys_var->current_cond ?
- "Waiting on cond" : NullS);
-#else
- thd_info->state_info= (char*)"Writing to net";
-#endif
+ thd_info->state_info= thread_state_info(tmp);
if (mysys_var)
- pthread_mutex_unlock(&mysys_var->mutex);
+ mysql_mutex_unlock(&mysys_var->mutex);
- thd_info->start_time= tmp->start_time;
- thd_info->query=0;
/* Lock THD mutex that protects its data when looking at it. */
- pthread_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->query())
{
uint length= min(max_query_length, tmp->query_length());
- thd_info->query= (char*) thd->strmake(tmp->query(),length);
+ char *q= thd->strmake(tmp->query(),length);
+ /* Safety: in case strmake failed, we set length to 0. */
+ thd_info->query_string=
+ CSET_STRING(q, q ? length : 0, tmp->query_charset());
}
- pthread_mutex_unlock(&tmp->LOCK_thd_data);
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
+ thd_info->start_time= tmp->start_time;
thread_infos.append(thd_info);
}
}
}
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_mutex_unlock(&LOCK_thread_count);
thread_info *thd_info;
time_t now= my_time(0);
@@ -1899,7 +1859,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
else
protocol->store_null();
protocol->store(thd_info->state_info, system_charset_info);
- protocol->store(thd_info->query, system_charset_info);
+ protocol->store(thd_info->query_string.str(),
+ thd_info->query_string.charset());
if (protocol->write())
break; /* purecov: inspected */
}
@@ -1918,7 +1879,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
user= thd->security_ctx->master_access & PROCESS_ACL ?
NullS : thd->security_ctx->priv_user;
- VOID(pthread_mutex_lock(&LOCK_thread_count));
+ mysql_mutex_lock(&LOCK_thread_count);
if (!thd->killed)
{
@@ -1961,8 +1922,9 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
table->field[3]->set_notnull();
}
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
if ((mysys_var= tmp->mysys_var))
- pthread_mutex_lock(&mysys_var->mutex);
+ mysql_mutex_lock(&mysys_var->mutex);
/* COMMAND */
if ((val= (char *) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0)))
table->field[4]->store(val, strlen(val), cs);
@@ -1973,32 +1935,19 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
table->field[5]->store((longlong)(tmp->start_time ?
now - tmp->start_time : 0), FALSE);
/* STATE */
-#ifndef EMBEDDED_LIBRARY
- val= (char*) (tmp->locked ? "Locked" :
- tmp->net.reading_or_writing ?
- (tmp->net.reading_or_writing == 2 ?
- "Writing to net" :
- tmp->command == COM_SLEEP ? "" :
- "Reading from net") :
- tmp->proc_info ? tmp->proc_info :
- tmp->mysys_var &&
- tmp->mysys_var->current_cond ?
- "Waiting on cond" : NullS);
-#else
- val= (char *) (tmp->proc_info ? tmp->proc_info : NullS);
-#endif
- if (val)
+ if ((val= thread_state_info(tmp)))
{
table->field[6]->store(val, strlen(val), cs);
table->field[6]->set_notnull();
}
if (mysys_var)
- pthread_mutex_unlock(&mysys_var->mutex);
+ mysql_mutex_unlock(&mysys_var->mutex);
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
/* INFO */
/* Lock THD mutex that protects its data when looking at it. */
- pthread_mutex_lock(&tmp->LOCK_thd_data);
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->query())
{
table->field[7]->store(tmp->query(),
@@ -2006,17 +1955,17 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
tmp->query_length()), cs);
table->field[7]->set_notnull();
}
- pthread_mutex_unlock(&tmp->LOCK_thd_data);
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
if (schema_table_store_record(thd, table))
{
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_mutex_unlock(&LOCK_thread_count);
DBUG_RETURN(1);
}
}
}
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_mutex_unlock(&LOCK_thread_count);
DBUG_RETURN(0);
}
@@ -2026,10 +1975,13 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
static DYNAMIC_ARRAY all_status_vars;
static bool status_vars_inited= 0;
+
+C_MODE_START
static int show_var_cmp(const void *var1, const void *var2)
{
return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
}
+C_MODE_END
/*
deletes all the SHOW_UNDEF elements from the array and calls
@@ -2075,7 +2027,7 @@ int add_status_vars(SHOW_VAR *list)
{
int res= 0;
if (status_vars_inited)
- pthread_mutex_lock(&LOCK_status);
+ mysql_mutex_lock(&LOCK_status);
if (!all_status_vars.buffer && // array is not allocated yet - do it now
my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 200, 20))
{
@@ -2090,7 +2042,7 @@ int add_status_vars(SHOW_VAR *list)
sort_dynamic(&all_status_vars, show_var_cmp);
err:
if (status_vars_inited)
- pthread_mutex_unlock(&LOCK_status);
+ mysql_mutex_unlock(&LOCK_status);
return res;
}
@@ -2152,7 +2104,7 @@ void remove_status_vars(SHOW_VAR *list)
{
if (status_vars_inited)
{
- pthread_mutex_lock(&LOCK_status);
+ mysql_mutex_lock(&LOCK_status);
SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
int a= 0, b= all_status_vars.elements, c= (a+b)/2;
@@ -2173,7 +2125,7 @@ void remove_status_vars(SHOW_VAR *list)
all[c].type= SHOW_UNDEF;
}
shrink_var_array(&all_status_vars);
- pthread_mutex_unlock(&LOCK_status);
+ mysql_mutex_unlock(&LOCK_status);
}
else
{
@@ -2263,7 +2215,7 @@ static bool show_status_array(THD *thd, const char *wild,
char *value=var->value;
const char *pos, *end; // We assign a lot of const's
- pthread_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
if (show_type == SHOW_SYS)
{
@@ -2283,7 +2235,8 @@ static bool show_status_array(THD *thd, const char *wild,
value= ((char *) status_var + (ulong) value);
/* fall through */
case SHOW_DOUBLE:
- end= buff + sprintf(buff, "%f", *(double*) value);
+ /* 6 is the default precision for '%f' in sprintf() */
+ end= buff + my_fcvt(*(double *) value, 6, buff, NULL);
break;
case SHOW_LONG_STATUS:
value= ((char *) status_var + (ulong) value);
@@ -2331,6 +2284,15 @@ static bool show_status_array(THD *thd, const char *wild,
end= strend(pos);
break;
}
+ case SHOW_LEX_STRING:
+ {
+ LEX_STRING *ls=(LEX_STRING*)value;
+ if (!(pos= ls->str))
+ end= pos= "";
+ else
+ end= pos + ls->length;
+ break;
+ }
case SHOW_KEY_CACHE_LONG:
value= (char*) dflt_key_cache + (ulong)value;
end= int10_to_str(*(long*) value, buff, 10);
@@ -2350,7 +2312,7 @@ static bool show_status_array(THD *thd, const char *wild,
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
table->field[1]->set_notnull();
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
if (schema_table_store_record(thd, table))
{
@@ -2373,7 +2335,7 @@ void calc_sum_of_all_status(STATUS_VAR *to)
DBUG_ENTER("calc_sum_of_all_status");
/* Ensure that thread id not killed during loop */
- VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
I_List_iterator<THD> it(threads);
THD *tmp;
@@ -2385,7 +2347,7 @@ void calc_sum_of_all_status(STATUS_VAR *to)
while ((tmp= it++))
add_to_status(to, &tmp->status_var);
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
}
@@ -2434,7 +2396,7 @@ int make_table_list(THD *thd, SELECT_LEX *sel,
Table_ident *table_ident;
table_ident= new Table_ident(thd, *db_name, *table_name, 1);
sel->init_query();
- if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
+ if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ))
return 1;
return 0;
}
@@ -2806,8 +2768,8 @@ int make_db_list(THD *thd, List<LEX_STRING> *files,
*/
if (lookup_field_vals->db_value.str)
{
- if (is_schema_db(lookup_field_vals->db_value.str,
- lookup_field_vals->db_value.length))
+ if (is_infoschema_db(lookup_field_vals->db_value.str,
+ lookup_field_vals->db_value.length))
{
*with_i_schema= 1;
if (files->push_back(i_s_name_copy))
@@ -2964,9 +2926,9 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
Check that table is relevant in current transaction.
(used for ndb engine, see ndbcluster_find_files(), ha_ndbcluster.cc)
*/
- VOID(ha_find_files(thd, db_name->str, path,
+ (void) ha_find_files(thd, db_name->str, path,
lookup_field_vals->table_value.str, 0,
- table_names));
+ table_names);
}
return 0;
}
@@ -3008,7 +2970,11 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
@param[in] thd thread handler
@param[in] tables TABLE_LIST for I_S table
@param[in] schema_table pointer to I_S structure
- @param[in] open_tables_state_backup pointer to Open_tables_state object
+ @param[in] can_deadlock Indicates that deadlocks are possible
+ due to metadata locks, so to avoid
+ them we should not wait in case if
+ conflicting lock is present.
+ @param[in] open_tables_state_backup pointer to Open_tables_backup object
which is used to save|restore original
status of variables related to
open tables state
@@ -3021,7 +2987,8 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
static int
fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
ST_SCHEMA_TABLE *schema_table,
- Open_tables_state *open_tables_state_backup)
+ bool can_deadlock,
+ Open_tables_backup *open_tables_state_backup)
{
LEX *lex= thd->lex;
bool res;
@@ -3048,8 +3015,14 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
*/
lex->sql_command= SQLCOM_SHOW_FIELDS;
res= open_normal_and_derived_tables(thd, show_table_list,
- MYSQL_LOCK_IGNORE_FLUSH);
+ (MYSQL_OPEN_IGNORE_FLUSH |
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
+ (can_deadlock ?
+ MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
lex->sql_command= save_sql_command;
+
+ DEBUG_SYNC(thd, "after_open_table_ignore_flush");
+
/*
get_all_tables() returns 1 on failure and 0 on success thus
return only these and not the result code of ::process_table()
@@ -3074,7 +3047,8 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
table, res, db_name,
table_name));
thd->temporary_tables= 0;
- close_tables_for_reopen(thd, &show_table_list);
+ close_tables_for_reopen(thd, &show_table_list,
+ open_tables_state_backup->mdl_system_tables_svp);
DBUG_RETURN(error);
}
@@ -3108,7 +3082,7 @@ static int fill_schema_table_names(THD *thd, TABLE *table,
char path[FN_REFLEN + 1];
(void) build_table_filename(path, sizeof(path) - 1, db_name->str,
table_name->str, reg_ext, 0);
- switch (mysql_frm_type(thd, path, &not_used)) {
+ switch (dd_frm_type(thd, path, &not_used)) {
case FRMTYPE_ERROR:
table->field[3]->store(STRING_WITH_LEN("ERROR"),
system_charset_info);
@@ -3124,7 +3098,7 @@ static int fill_schema_table_names(THD *thd, TABLE *table,
default:
DBUG_ASSERT(0);
}
- if (thd->is_error() && thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
+ if (thd->is_error() && thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
{
thd->clear_error();
return 0;
@@ -3187,6 +3161,61 @@ uint get_table_open_method(TABLE_LIST *tables,
/**
+ Try acquire high priority share metadata lock on a table (with
+ optional wait for conflicting locks to go away).
+
+ @param thd Thread context.
+ @param mdl_request Pointer to memory to be used for MDL_request
+ object for a lock request.
+ @param table Table list element for the table
+ @param can_deadlock Indicates that deadlocks are possible due to
+ metadata locks, so to avoid them we should not
+ wait in case if conflicting lock is present.
+
+ @note This is an auxiliary function to be used in cases when we want to
+ access table's description by looking up info in TABLE_SHARE without
+ going through full-blown table open.
+ @note This function assumes that there are no other metadata lock requests
+ in the current metadata locking context.
+
+ @retval FALSE No error, if lock was obtained TABLE_LIST::mdl_request::ticket
+ is set to non-NULL value.
+ @retval TRUE Some error occured (probably thread was killed).
+*/
+
+static bool
+try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
+ bool can_deadlock)
+{
+ bool error;
+ table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
+ MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION);
+
+ if (can_deadlock)
+ {
+ /*
+ When .FRM is being open in order to get data for an I_S table,
+ we might have some tables not only open but also locked.
+ E.g. this happens when a SHOW or I_S statement is run
+ under LOCK TABLES or inside a stored function.
+ By waiting for the conflicting metadata lock to go away we
+ might create a deadlock which won't entirely belong to the
+ MDL subsystem and thus won't be detectable by this subsystem's
+ deadlock detector. To avoid such situation, when there are
+ other locked tables, we prefer not to wait on a conflicting
+ lock.
+ */
+ error= thd->mdl_context.try_acquire_lock(&table->mdl_request);
+ }
+ else
+ error= thd->mdl_context.acquire_lock(&table->mdl_request,
+ thd->variables.lock_wait_timeout);
+
+ return error;
+}
+
+
+/**
@brief Fill I_S table with data from FRM file only
@param[in] thd thread handler
@@ -3195,6 +3224,10 @@ uint get_table_open_method(TABLE_LIST *tables,
@param[in] db_name database name
@param[in] table_name table name
@param[in] schema_table_idx I_S table index
+ @param[in] can_deadlock Indicates that deadlocks are possible
+ due to metadata locks, so to avoid
+ them we should not wait in case if
+ conflicting lock is present.
@return Operation status
@retval 0 Table is processed and we can continue
@@ -3203,80 +3236,168 @@ uint get_table_open_method(TABLE_LIST *tables,
open_tables function for this table
*/
-static int fill_schema_table_from_frm(THD *thd,TABLE *table,
- ST_SCHEMA_TABLE *schema_table,
+static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
+ ST_SCHEMA_TABLE *schema_table,
LEX_STRING *db_name,
LEX_STRING *table_name,
- enum enum_schema_tables schema_table_idx)
+ enum enum_schema_tables schema_table_idx,
+ bool can_deadlock)
{
+ TABLE *table= tables->table;
TABLE_SHARE *share;
TABLE tbl;
TABLE_LIST table_list;
uint res= 0;
- int error;
+ int not_used;
+ my_hash_value_type hash_value;
char key[MAX_DBKEY_LENGTH];
uint key_length;
+ char db_name_buff[NAME_LEN + 1], table_name_buff[NAME_LEN + 1];
bzero((char*) &table_list, sizeof(TABLE_LIST));
bzero((char*) &tbl, sizeof(TABLE));
- table_list.table_name= table_name->str;
- table_list.db= db_name->str;
+ if (lower_case_table_names)
+ {
+ /*
+ In lower_case_table_names > 0 metadata locking and table definition
+ cache subsystems require normalized (lowercased) database and table
+ names as input.
+ */
+ strmov(db_name_buff, db_name->str);
+ strmov(table_name_buff, table_name->str);
+ my_casedn_str(files_charset_info, db_name_buff);
+ my_casedn_str(files_charset_info, table_name_buff);
+ table_list.db= db_name_buff;
+ table_list.table_name= table_name_buff;
+ }
+ else
+ {
+ table_list.table_name= table_name->str;
+ table_list.db= db_name->str;
+ }
+
+ /*
+ TODO: investigate if in this particular situation we can get by
+ simply obtaining internal lock of the data-dictionary
+ instead of obtaining full-blown metadata lock.
+ */
+ if (try_acquire_high_prio_shared_mdl_lock(thd, &table_list, can_deadlock))
+ {
+ /*
+ Some error occured (most probably we have been killed while
+ waiting for conflicting locks to go away), let the caller to
+ handle the situation.
+ */
+ return 1;
+ }
+
+ if (! table_list.mdl_request.ticket)
+ {
+ /*
+ We are in situation when we have encountered conflicting metadata
+ lock and deadlocks can occur due to waiting for it to go away.
+ So instead of waiting skip this table with an appropriate warning.
+ */
+ DBUG_ASSERT(can_deadlock);
+
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_I_S_SKIPPED_TABLE,
+ ER(ER_WARN_I_S_SKIPPED_TABLE),
+ table_list.db, table_list.table_name);
+ return 0;
+ }
+
+ if (schema_table->i_s_requested_object & OPEN_TRIGGER_ONLY)
+ {
+ init_sql_alloc(&tbl.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
+ if (!Table_triggers_list::check_n_load(thd, db_name->str,
+ table_name->str, &tbl, 1))
+ {
+ table_list.table= &tbl;
+ res= schema_table->process_table(thd, &table_list, table,
+ res, db_name, table_name);
+ delete tbl.triggers;
+ }
+ free_root(&tbl.mem_root, MYF(0));
+ goto end;
+ }
+
key_length= create_table_def_key(thd, key, &table_list, 0);
- pthread_mutex_lock(&LOCK_open);
+ hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
+ mysql_mutex_lock(&LOCK_open);
share= get_table_share(thd, &table_list, key,
- key_length, OPEN_VIEW, &error);
+ key_length, OPEN_VIEW, &not_used, hash_value);
if (!share)
{
res= 0;
- goto err;
+ goto end_unlock;
}
-
+
if (share->is_view)
{
if (schema_table->i_s_requested_object & OPEN_TABLE_ONLY)
{
/* skip view processing */
res= 0;
- goto err1;
+ goto end_share;
}
else if (schema_table->i_s_requested_object & OPEN_VIEW_FULL)
{
/*
- tell get_all_tables() to fall back to
+ tell get_all_tables() to fall back to
open_normal_and_derived_tables()
*/
res= 1;
- goto err1;
+ goto end_share;
}
}
- if (share->is_view ||
- !open_table_from_share(thd, share, table_name->str, 0,
- (READ_KEYINFO | COMPUTE_TYPES |
- EXTRA_RECORD | OPEN_FRM_FILE_ONLY),
+ if (share->is_view)
+ {
+ if (open_new_frm(thd, share, table_name->str,
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
+ HA_GET_INDEX | HA_TRY_READ_ONLY),
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD |
+ OPEN_VIEW_NO_PARSE,
+ thd->open_options, &tbl, &table_list, thd->mem_root))
+ goto end_share;
+ table_list.view= (LEX*) share->is_view;
+ res= schema_table->process_table(thd, &table_list, table,
+ res, db_name, table_name);
+ goto end_share;
+ }
+
+ if (!open_table_from_share(thd, share, table_name->str, 0,
+ (EXTRA_RECORD | OPEN_FRM_FILE_ONLY),
thd->open_options, &tbl, FALSE))
{
tbl.s= share;
table_list.table= &tbl;
- table_list.view= (st_lex*) share->is_view;
+ table_list.view= (LEX*) share->is_view;
res= schema_table->process_table(thd, &table_list, table,
res, db_name, table_name);
- closefrm(&tbl, true);
- goto err;
+ free_root(&tbl.mem_root, MYF(0));
+ my_free((void *) tbl.alias);
}
-err1:
- release_table_share(share, RELEASE_NORMAL);
+end_share:
+ release_table_share(share);
-err:
- pthread_mutex_unlock(&LOCK_open);
+end_unlock:
+ mysql_mutex_unlock(&LOCK_open);
+ /*
+ Don't release the MDL lock, it can be part of a transaction.
+ If it is not, it will be released by the call to
+ MDL_context::rollback_to_savepoint() in the caller.
+ */
+
+end:
thd->clear_error();
return res;
}
-
/**
@brief Fill I_S tables whose data are retrieved
from frm files and storage engine
@@ -3301,7 +3422,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
LEX *lex= thd->lex;
TABLE *table= tables->table;
SELECT_LEX *old_all_select_lex= lex->all_selects_list;
- enum_sql_command save_sql_command= lex->sql_command;
SELECT_LEX *lsel= tables->schema_select_lex;
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
SELECT_LEX sel;
@@ -3314,25 +3434,48 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
COND *partial_cond= 0;
uint derived_tables= lex->derived_tables;
int error= 1;
- Open_tables_state open_tables_state_backup;
+ Open_tables_backup open_tables_state_backup;
bool save_view_prepare_mode= lex->view_prepare_mode;
Query_tables_list query_tables_list_backup;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *sctx= thd->security_ctx;
#endif
uint table_open_method;
+ bool can_deadlock;
DBUG_ENTER("get_all_tables");
+ /*
+ In cases when SELECT from I_S table being filled by this call is
+ part of statement which also uses other tables or is being executed
+ under LOCK TABLES or is part of transaction which also uses other
+ tables waiting for metadata locks which happens below might result
+ in deadlocks.
+ To avoid them we don't wait if conflicting metadata lock is
+ encountered and skip table with emitting an appropriate warning.
+ */
+ can_deadlock= thd->mdl_context.has_locks();
+
lex->view_prepare_mode= TRUE;
lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
+ /*
+ Restore Query_tables_list::sql_command value, which was reset
+ above, as ST_SCHEMA_TABLE::process_table() functions often rely
+ that this value reflects which SHOW statement is executed.
+ */
+ lex->sql_command= query_tables_list_backup.sql_command;
/*
We should not introduce deadlocks even if we already have some
tables open and locked, since we won't lock tables which we will
- open and will ignore possible name-locks for these tables.
+ open and will ignore pending exclusive metadata locks for these
+ tables by using high-priority requests for shared metadata locks.
*/
thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
+ schema_table_idx= get_schema_table_idx(schema_table);
+ tables->table_open_method= table_open_method=
+ get_table_open_method(tables, schema_table, schema_table_idx);
+ DBUG_PRINT("open_method", ("%d", tables->table_open_method));
/*
this branch processes SHOW FIELDS, SHOW INDEXES commands.
see sql_parse.cc, prepare_schema_table() function where
@@ -3341,11 +3484,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
if (lsel && lsel->table_list.first)
{
error= fill_schema_show_cols_or_idxs(thd, tables, schema_table,
+ can_deadlock,
&open_tables_state_backup);
goto err;
}
- schema_table_idx= get_schema_table_idx(schema_table);
if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
{
error= 0;
@@ -3384,9 +3527,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
else
partial_cond= make_cond_for_info_schema(cond, tables);
- tables->table_open_method= table_open_method=
- get_table_open_method(tables, schema_table, schema_table_idx);
-
if (lex->describe)
{
/* EXPLAIN SELECT */
@@ -3400,8 +3540,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
while ((db_name= it++))
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!(check_access(thd,SELECT_ACL, db_name->str,
- &thd->col_access, 0, 1, with_i_schema) ||
+ if (!(check_access(thd, SELECT_ACL, db_name->str,
+ &thd->col_access, NULL, 0, 1) ||
(!thd->col_access && check_grant_db(thd, db_name->str))) ||
sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
@@ -3438,6 +3578,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
(!lookup_field_vals.table_value.length ||
lookup_field_vals.wild_table_value))
{
+ table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
if (schema_table_store_record(thd, table))
goto err; /* Out of space in temporary table */
continue;
@@ -3452,11 +3593,12 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
}
else
{
- if (!(table_open_method & ~OPEN_FRM_ONLY) &&
+ if (!(table_open_method & ~OPEN_FRM_ONLY) &&
!with_i_schema)
{
- if (!fill_schema_table_from_frm(thd, table, schema_table, db_name,
- table_name, schema_table_idx))
+ if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name,
+ table_name, schema_table_idx,
+ can_deadlock))
continue;
}
@@ -3482,18 +3624,20 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
schema_table->i_s_requested_object;
DEBUG_SYNC(thd, "before_open_in_get_all_tables");
res= open_normal_and_derived_tables(thd, show_table_list,
- MYSQL_LOCK_IGNORE_FLUSH);
- lex->sql_command= save_sql_command;
+ (MYSQL_OPEN_IGNORE_FLUSH |
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
+ (can_deadlock ? MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
+ lex->sql_command= query_tables_list_backup.sql_command;
/*
XXX: show_table_list has a flag i_is_requested,
and when it's set, open_normal_and_derived_tables()
can return an error without setting an error message
in THD, which is a hack. This is why we have to
check for res, then for thd->is_error() only then
- for thd->main_da.sql_errno().
+ for thd->stmt_da->sql_errno().
*/
if (res && thd->is_error() &&
- thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
+ thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
{
/*
Hide error for not existing table.
@@ -3518,7 +3662,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
res= schema_table->process_table(thd, show_table_list, table,
res, &orig_db_name,
&tmp_lex_string);
- close_tables_for_reopen(thd, &show_table_list);
+ close_tables_for_reopen(thd, &show_table_list,
+ open_tables_state_backup.mdl_system_tables_svp);
}
DBUG_ASSERT(!lex->query_tables_own_last);
if (res)
@@ -3541,7 +3686,6 @@ err:
lex->derived_tables= derived_tables;
lex->all_selects_list= old_all_select_lex;
lex->view_prepare_mode= save_view_prepare_mode;
- lex->sql_command= save_sql_command;
DBUG_RETURN(error);
}
@@ -3550,6 +3694,7 @@ bool store_schema_shemata(THD* thd, TABLE *table, LEX_STRING *db_name,
CHARSET_INFO *cs)
{
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);
@@ -3598,7 +3743,7 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
path_len= build_table_filename(path, sizeof(path) - 1,
lookup_field_vals.db_value.str, "", "", 0);
path[path_len-1]= 0;
- if (!my_stat(path,&stat_info,MYF(0)))
+ if (!mysql_file_stat(key_file_misc, path, &stat_info, MYF(0)))
DBUG_RETURN(0);
}
@@ -3641,6 +3786,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
DBUG_ENTER("get_schema_tables_record");
restore_record(table, s->default_values);
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(db_name->str, db_name->length, cs);
table->field[2]->store(table_name->str, table_name->length, cs);
@@ -3672,6 +3818,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool is_partitioned= FALSE;
#endif
+
if (share->tmp_table == SYSTEM_TMP_TABLE)
table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
else if (share->tmp_table)
@@ -3685,75 +3832,93 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
continue;
table->field[i]->set_notnull();
}
+
+ /* Collect table info from the table share */
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (share->db_type() == partition_hton &&
- share->partition_info_len)
+ share->partition_info_str_len)
{
tmp_db_type= share->default_part_db_type;
is_partitioned= TRUE;
}
#endif
+
tmp_buff= (char *) ha_resolve_storage_engine_name(tmp_db_type);
table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
table->field[5]->store((longlong) share->frm_version, TRUE);
ptr=option_buff;
+
if (share->min_rows)
{
ptr=strmov(ptr," min_rows=");
ptr=longlong10_to_str(share->min_rows,ptr,10);
}
+
if (share->max_rows)
{
ptr=strmov(ptr," max_rows=");
ptr=longlong10_to_str(share->max_rows,ptr,10);
}
+
if (share->avg_row_length)
{
ptr=strmov(ptr," avg_row_length=");
ptr=longlong10_to_str(share->avg_row_length,ptr,10);
}
+
if (share->db_create_options & HA_OPTION_PACK_KEYS)
ptr=strmov(ptr," pack_keys=1");
+
if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
ptr=strmov(ptr," pack_keys=0");
+
/* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
if (share->db_create_options & HA_OPTION_CHECKSUM)
ptr=strmov(ptr," checksum=1");
+
if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
ptr=strmov(ptr," delay_key_write=1");
+
if (share->row_type != ROW_TYPE_DEFAULT)
ptr=strxmov(ptr, " row_format=",
ha_row_type[(uint) share->row_type],
NullS);
+
if (share->key_block_size)
{
ptr= strmov(ptr, " KEY_BLOCK_SIZE=");
ptr= longlong10_to_str(share->key_block_size, ptr, 10);
}
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (is_partitioned)
ptr= strmov(ptr, " partitioned");
#endif
+
table->field[19]->store(option_buff+1,
(ptr == option_buff ? 0 :
(uint) (ptr-option_buff)-1), cs);
tmp_buff= (share->table_charset ?
share->table_charset->name : "default");
+
table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);
if (share->comment.str)
table->field[20]->store(share->comment.str, share->comment.length, cs);
- if (file)
+ /* Collect table info from the storage engine */
+
+ if(file)
{
/* If info() fails, then there's nothing else to do */
if ((info_error= file->info(HA_STATUS_VARIABLE |
HA_STATUS_TIME |
HA_STATUS_AUTO)) != 0)
goto err;
-
+
enum row_type row_type = file->get_row_type();
switch (row_type) {
case ROW_TYPE_NOT_USED:
@@ -3782,7 +3947,9 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
tmp_buff= "Paged";
break;
}
+
table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
+
if (!tables->schema_table)
{
table->field[7]->store((longlong) file->stats.records, TRUE);
@@ -3840,21 +4007,146 @@ err:
column with the error text, and clear the error so that the operation
can continue.
*/
- const char *error= thd->is_error() ? thd->main_da.message() : "";
+ const char *error= thd->is_error() ? thd->stmt_da->message() : "";
table->field[20]->store(error, strlen(error), cs);
if (thd->is_error())
{
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->main_da.sql_errno(), thd->main_da.message());
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
thd->clear_error();
}
}
-
+
DBUG_RETURN(schema_table_store_record(thd, table));
}
+/**
+ @brief Store field characteristics into appropriate I_S table columns
+
+ @param[in] table I_S table
+ @param[in] field processed field
+ @param[in] cs I_S table charset
+ @param[in] offset offset from beginning of table
+ to DATE_TYPE column in I_S table
+
+ @return void
+*/
+
+void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs,
+ uint offset)
+{
+ bool is_blob;
+ int decimals, field_length;
+ const char *tmp_buff;
+ char column_type_buff[MAX_FIELD_WIDTH];
+ String column_type(column_type_buff, sizeof(column_type_buff), cs);
+
+ field->sql_type(column_type);
+ /* DTD_IDENTIFIER column */
+ table->field[offset + 7]->store(column_type.ptr(), column_type.length(), cs);
+ table->field[offset + 7]->set_notnull();
+ /*
+ DATA_TYPE column:
+ MySQL column type has the following format:
+ base_type [(dimension)] [unsigned] [zerofill].
+ For DATA_TYPE column we extract only base type.
+ */
+ tmp_buff= strchr(column_type.ptr(), '(');
+ if (!tmp_buff)
+ /*
+ if there is no dimention part then check the presence of
+ [unsigned] [zerofill] attributes and cut them of if exist.
+ */
+ tmp_buff= strchr(column_type.ptr(), ' ');
+ table->field[offset]->store(column_type.ptr(),
+ (tmp_buff ? tmp_buff - column_type.ptr() :
+ column_type.length()), cs);
+
+ is_blob= (field->type() == MYSQL_TYPE_BLOB);
+ if (field->has_charset() || is_blob ||
+ field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type
+ field->real_type() == MYSQL_TYPE_STRING) // For binary type
+ {
+ uint32 octet_max_length= field->max_display_length();
+ if (is_blob && octet_max_length != (uint32) 4294967295U)
+ octet_max_length /= field->charset()->mbmaxlen;
+ longlong char_max_len= is_blob ?
+ (longlong) octet_max_length / field->charset()->mbminlen :
+ (longlong) octet_max_length / field->charset()->mbmaxlen;
+ /* CHARACTER_MAXIMUM_LENGTH column*/
+ table->field[offset + 1]->store(char_max_len, TRUE);
+ table->field[offset + 1]->set_notnull();
+ /* CHARACTER_OCTET_LENGTH column */
+ table->field[offset + 2]->store((longlong) octet_max_length, TRUE);
+ table->field[offset + 2]->set_notnull();
+ }
+
+ /*
+ Calculate field_length and decimals.
+ They are set to -1 if they should not be set (we should return NULL)
+ */
+
+ decimals= field->decimals();
+ switch (field->type()) {
+ case MYSQL_TYPE_NEWDECIMAL:
+ field_length= ((Field_new_decimal*) field)->precision;
+ break;
+ case MYSQL_TYPE_DECIMAL:
+ field_length= field->field_length - (decimals ? 2 : 1);
+ break;
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_INT24:
+ field_length= field->max_display_length() - 1;
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ field_length= field->max_display_length() -
+ ((field->flags & UNSIGNED_FLAG) ? 0 : 1);
+ break;
+ case MYSQL_TYPE_BIT:
+ field_length= field->max_display_length();
+ decimals= -1; // return NULL
+ break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ field_length= field->field_length;
+ if (decimals == NOT_FIXED_DEC)
+ decimals= -1; // return NULL
+ break;
+ default:
+ field_length= decimals= -1;
+ break;
+ }
+
+ /* NUMERIC_PRECISION column */
+ if (field_length >= 0)
+ {
+ table->field[offset + 3]->store((longlong) field_length, TRUE);
+ table->field[offset + 3]->set_notnull();
+ }
+ /* NUMERIC_SCALE column */
+ if (decimals >= 0)
+ {
+ table->field[offset + 4]->store((longlong) decimals, TRUE);
+ table->field[offset + 4]->set_notnull();
+ }
+ if (field->has_charset())
+ {
+ /* CHARACTER_SET_NAME column*/
+ tmp_buff= field->charset()->csname;
+ table->field[offset + 5]->store(tmp_buff, strlen(tmp_buff), cs);
+ table->field[offset + 5]->set_notnull();
+ /* COLLATION_NAME column */
+ tmp_buff= field->charset()->name;
+ table->field[offset + 6]->store(tmp_buff, strlen(tmp_buff), cs);
+ table->field[offset + 6]->set_notnull();
+ }
+}
+
+
static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
TABLE *table, bool res,
LEX_STRING *db_name,
@@ -3864,7 +4156,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
const char *wild= lex->wild ? lex->wild->ptr() : NullS;
CHARSET_INFO *cs= system_charset_info;
TABLE *show_table;
- Field **ptr,*field;
+ Field **ptr, *field, *timestamp_field;
int count;
DBUG_ENTER("get_schema_column_record");
@@ -3875,10 +4167,10 @@ 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
- */
+ */
if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->main_da.sql_errno(), thd->main_da.message());
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
thd->clear_error();
res= 0;
}
@@ -3887,33 +4179,32 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
show_table= tables->table;
count= 0;
- restore_record(show_table, s->default_values);
+ ptr= show_table->field;
+ timestamp_field= show_table->timestamp_field;
show_table->use_all_columns(); // Required for default
+ restore_record(show_table, s->default_values);
- for (ptr= show_table->field; (field= *ptr) ; ptr++)
+ for (; (field= *ptr) ; ptr++)
{
- const char *tmp_buff;
uchar *pos;
- bool is_blob;
- uint flags=field->flags;
char tmp[MAX_FIELD_WIDTH];
String type(tmp,sizeof(tmp), system_charset_info);
- int decimals, field_length;
+
+ DEBUG_SYNC(thd, "get_schema_column");
if (wild && wild[0] &&
wild_case_compare(system_charset_info, field->field_name,wild))
continue;
- flags= field->flags;
count++;
/* Get default row, with all NULL fields set to NULL */
restore_record(table, s->default_values);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint col_access;
- check_access(thd,SELECT_ACL | EXTRA_ACL, db_name->str,
+ check_access(thd,SELECT_ACL, db_name->str,
&tables->grant.privilege, 0, 0, test(tables->schema_table));
- col_access= get_column_grant(thd, &tables->grant,
+ col_access= get_column_grant(thd, &tables->grant,
db_name->str, table_name->str,
field->field_name) & COL_ACLS;
if (!tables->schema_table && !col_access)
@@ -3930,6 +4221,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
#endif
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(db_name->str, db_name->length, cs);
table->field[2]->store(table_name->str, table_name->length, cs);
table->field[3]->store(field->field_name, strlen(field->field_name),
@@ -3937,107 +4229,16 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
table->field[4]->store((longlong) count, TRUE);
field->sql_type(type);
table->field[14]->store(type.ptr(), type.length(), cs);
- /*
- MySQL column type has the following format:
- base_type [(dimension)] [unsigned] [zerofill].
- For DATA_TYPE column we extract only base type.
- */
- tmp_buff= strchr(type.ptr(), '(');
- if (!tmp_buff)
- /*
- if there is no dimention part then check the presence of
- [unsigned] [zerofill] attributes and cut them of if exist.
- */
- tmp_buff= strchr(type.ptr(), ' ');
- table->field[7]->store(type.ptr(),
- (tmp_buff ? tmp_buff - type.ptr() :
- type.length()), cs);
- if (get_field_default_value(thd, show_table, field, &type, 0))
+ if (get_field_default_value(thd, timestamp_field, field, &type, 0))
{
table->field[5]->store(type.ptr(), type.length(), cs);
table->field[5]->set_notnull();
}
- pos=(uchar*) ((flags & NOT_NULL_FLAG) ? "NO" : "YES");
+ pos=(uchar*) ((field->flags & NOT_NULL_FLAG) ? "NO" : "YES");
table->field[6]->store((const char*) pos,
strlen((const char*) pos), cs);
- is_blob= (field->type() == MYSQL_TYPE_BLOB);
- if (field->has_charset() || is_blob ||
- field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type
- field->real_type() == MYSQL_TYPE_STRING) // For binary type
- {
- uint32 octet_max_length= field->max_display_length();
- if (is_blob && octet_max_length != (uint32) 4294967295U)
- octet_max_length /= field->charset()->mbmaxlen;
- longlong char_max_len= is_blob ?
- (longlong) octet_max_length / field->charset()->mbminlen :
- (longlong) octet_max_length / field->charset()->mbmaxlen;
- table->field[8]->store(char_max_len, TRUE);
- table->field[8]->set_notnull();
- table->field[9]->store((longlong) octet_max_length, TRUE);
- table->field[9]->set_notnull();
- }
-
- /*
- Calculate field_length and decimals.
- They are set to -1 if they should not be set (we should return NULL)
- */
-
- decimals= field->decimals();
- switch (field->type()) {
- case MYSQL_TYPE_NEWDECIMAL:
- field_length= ((Field_new_decimal*) field)->precision;
- break;
- case MYSQL_TYPE_DECIMAL:
- field_length= field->field_length - (decimals ? 2 : 1);
- break;
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_INT24:
- field_length= field->max_display_length() - 1;
- break;
- case MYSQL_TYPE_LONGLONG:
- field_length= field->max_display_length() -
- ((field->flags & UNSIGNED_FLAG) ? 0 : 1);
- break;
- case MYSQL_TYPE_BIT:
- field_length= field->max_display_length();
- decimals= -1; // return NULL
- break;
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- field_length= field->field_length;
- if (decimals == NOT_FIXED_DEC)
- decimals= -1; // return NULL
- break;
- default:
- field_length= decimals= -1;
- break;
- }
-
- if (field_length >= 0)
- {
- table->field[10]->store((longlong) field_length, TRUE);
- table->field[10]->set_notnull();
- }
- if (decimals >= 0)
- {
- table->field[11]->store((longlong) decimals, TRUE);
- table->field[11]->set_notnull();
- }
-
- if (field->has_charset())
- {
- pos=(uchar*) field->charset()->csname;
- table->field[12]->store((const char*) pos,
- strlen((const char*) pos), cs);
- table->field[12]->set_notnull();
- pos=(uchar*) field->charset()->name;
- table->field[13]->store((const char*) pos,
- strlen((const char*) pos), cs);
- table->field[13]->set_notnull();
- }
+ store_column_type(table, field, cs, 7);
pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
(field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
(field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
@@ -4046,7 +4247,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
if (field->unireg_check == Field::NEXT_NUMBER)
table->field[16]->store(STRING_WITH_LEN("auto_increment"), cs);
- if (show_table->timestamp_field == field &&
+ if (timestamp_field == field &&
field->unireg_check != Field::TIMESTAMP_DN_FIELD)
table->field[16]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"),
cs);
@@ -4059,7 +4260,6 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
}
-
int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
{
CHARSET_INFO **cs;
@@ -4067,7 +4267,9 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
TABLE *table= tables->table;
CHARSET_INFO *scs= system_charset_info;
- for (cs= all_charsets ; cs < all_charsets+255 ; cs++)
+ for (cs= all_charsets ;
+ cs < all_charsets + array_elements(all_charsets) ;
+ cs++)
{
CHARSET_INFO *tmp_cs= cs[0];
if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) &&
@@ -4172,7 +4374,9 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
TABLE *table= tables->table;
CHARSET_INFO *scs= system_charset_info;
- for (cs= all_charsets ; cs < all_charsets+255 ; cs++ )
+ for (cs= all_charsets ;
+ cs < all_charsets + array_elements(all_charsets) ;
+ cs++ )
{
CHARSET_INFO **cl;
CHARSET_INFO *tmp_cs= cs[0];
@@ -4180,7 +4384,9 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
(tmp_cs->state & MY_CS_HIDDEN) ||
!(tmp_cs->state & MY_CS_PRIMARY))
continue;
- for (cl= all_charsets; cl < all_charsets+255 ;cl ++)
+ for (cl= all_charsets;
+ cl < all_charsets + array_elements(all_charsets) ;
+ cl ++)
{
CHARSET_INFO *tmp_cl= cl[0];
if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
@@ -4213,17 +4419,22 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
CHARSET_INFO **cs;
TABLE *table= tables->table;
CHARSET_INFO *scs= system_charset_info;
- for (cs= all_charsets ; cs < all_charsets+255 ; cs++ )
+ for (cs= all_charsets ;
+ cs < all_charsets + array_elements(all_charsets) ;
+ cs++ )
{
CHARSET_INFO **cl;
CHARSET_INFO *tmp_cs= cs[0];
if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
!(tmp_cs->state & MY_CS_PRIMARY))
continue;
- for (cl= all_charsets; cl < all_charsets+255 ;cl ++)
+ for (cl= all_charsets;
+ cl < all_charsets + array_elements(all_charsets) ;
+ cl ++)
{
CHARSET_INFO *tmp_cl= cl[0];
- if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
+ if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
+ (tmp_cl->state & MY_CS_HIDDEN) ||
!my_charset_same(tmp_cs,tmp_cl))
continue;
restore_record(table, s->default_values);
@@ -4246,6 +4457,169 @@ static inline void copy_field_as_string(Field *to_field, Field *from_field)
}
+/**
+ @brief Store record into I_S.PARAMETERS table
+
+ @param[in] thd thread handler
+ @param[in] table I_S table
+ @param[in] proc_table 'mysql.proc' table
+ @param[in] wild wild string, not used for now,
+ will be useful
+ if we add 'SHOW PARAMETERs'
+ @param[in] full_access if 1 user has privileges on the routine
+ @param[in] sp_user user in 'user@host' format
+
+ @return Operation status
+ @retval 0 ok
+ @retval 1 error
+*/
+
+bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
+ const char *wild, bool full_access,
+ const char *sp_user)
+{
+ TABLE_SHARE share;
+ TABLE tbl;
+ CHARSET_INFO *cs= system_charset_info;
+ char params_buff[MAX_FIELD_WIDTH], returns_buff[MAX_FIELD_WIDTH],
+ sp_db_buff[NAME_LEN], sp_name_buff[NAME_LEN], path[FN_REFLEN],
+ definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 1];
+ String params(params_buff, sizeof(params_buff), cs);
+ String returns(returns_buff, sizeof(returns_buff), cs);
+ String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
+ String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
+ String definer(definer_buff, sizeof(definer_buff), cs);
+ sp_head *sp;
+ uint routine_type;
+ bool free_sp_head;
+ DBUG_ENTER("store_schema_params");
+
+ bzero((char*) &tbl, sizeof(TABLE));
+ (void) build_table_filename(path, sizeof(path), "", "", "", 0);
+ init_tmp_table_share(thd, &share, "", 0, "", path);
+
+ get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_DB], &sp_db);
+ get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_NAME], &sp_name);
+ get_field(thd->mem_root,proc_table->field[MYSQL_PROC_FIELD_DEFINER],&definer);
+ routine_type= (uint) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
+
+ if (!full_access)
+ full_access= !strcmp(sp_user, definer.ptr());
+ if (!full_access &&
+ check_some_routine_access(thd, sp_db.ptr(),sp_name.ptr(),
+ routine_type == TYPE_ENUM_PROCEDURE))
+ DBUG_RETURN(0);
+
+ params.length(0);
+ get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST],
+ &params);
+ returns.length(0);
+ if (routine_type == TYPE_ENUM_FUNCTION)
+ get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS],
+ &returns);
+
+ sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
+ (ulong) proc_table->
+ field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(),
+ routine_type,
+ returns.c_ptr_safe(),
+ params.c_ptr_safe(),
+ &free_sp_head);
+
+ if (sp)
+ {
+ Field *field;
+ Create_field *field_def;
+ String tmp_string;
+ if (routine_type == TYPE_ENUM_FUNCTION)
+ {
+ restore_record(table, s->default_values);
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
+ table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
+ table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
+ table->field[3]->store((longlong) 0, TRUE);
+ get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
+ &tmp_string);
+ table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ field_def= &sp->m_return_field_def;
+ field= make_field(&share, (uchar*) 0, field_def->length,
+ (uchar*) "", 0, field_def->pack_flag,
+ field_def->sql_type, field_def->charset,
+ field_def->geom_type, Field::NONE,
+ field_def->interval, "");
+
+ field->table= &tbl;
+ tbl.in_use= thd;
+ store_column_type(table, field, cs, 6);
+ if (schema_table_store_record(thd, table))
+ {
+ free_table_share(&share);
+ if (free_sp_head)
+ delete sp;
+ DBUG_RETURN(1);
+ }
+ }
+
+ sp_pcontext *spcont= sp->get_parse_context();
+ uint params= spcont->context_var_count();
+ for (uint i= 0 ; i < params ; i++)
+ {
+ const char *tmp_buff;
+ sp_variable_t *spvar= spcont->find_variable(i);
+ field_def= &spvar->field_def;
+ switch (spvar->mode) {
+ case sp_param_in:
+ tmp_buff= "IN";
+ break;
+ case sp_param_out:
+ tmp_buff= "OUT";
+ break;
+ case sp_param_inout:
+ tmp_buff= "INOUT";
+ break;
+ default:
+ tmp_buff= "";
+ break;
+ }
+
+ restore_record(table, s->default_values);
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
+ table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
+ table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
+ table->field[3]->store((longlong) i + 1, TRUE);
+ table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
+ table->field[4]->set_notnull();
+ table->field[5]->store(spvar->name.str, spvar->name.length, cs);
+ table->field[5]->set_notnull();
+ get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
+ &tmp_string);
+ table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
+
+ field= make_field(&share, (uchar*) 0, field_def->length,
+ (uchar*) "", 0, field_def->pack_flag,
+ field_def->sql_type, field_def->charset,
+ field_def->geom_type, Field::NONE,
+ field_def->interval, spvar->name.str);
+
+ field->table= &tbl;
+ tbl.in_use= thd;
+ store_column_type(table, field, cs, 6);
+ if (schema_table_store_record(thd, table))
+ {
+ free_table_share(&share);
+ if (free_sp_head)
+ delete sp;
+ DBUG_RETURN(1);
+ }
+ }
+ if (free_sp_head)
+ delete sp;
+ }
+ free_table_share(&share);
+ DBUG_RETURN(0);
+}
+
+
bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
const char *wild, bool full_access, const char *sp_user)
{
@@ -4253,66 +4627,124 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
LEX *lex= thd->lex;
CHARSET_INFO *cs= system_charset_info;
char sp_db_buff[NAME_LEN + 1], sp_name_buff[NAME_LEN + 1],
- definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 2];
+ definer_buff[USERNAME_LENGTH + HOSTNAME_LENGTH + 2],
+ returns_buff[MAX_FIELD_WIDTH];
+
String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
String definer(definer_buff, sizeof(definer_buff), cs);
+ String returns(returns_buff, sizeof(returns_buff), cs);
- proc_table->field[0]->val_str(&sp_db);
- proc_table->field[1]->val_str(&sp_name);
- proc_table->field[11]->val_str(&definer);
+ proc_table->field[MYSQL_PROC_FIELD_DB]->val_str(&sp_db);
+ proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str(&sp_name);
+ proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str(&definer);
if (!full_access)
full_access= !strcmp(sp_user, definer.c_ptr_safe());
if (!full_access &&
check_some_routine_access(thd, sp_db.c_ptr_safe(), sp_name.c_ptr_safe(),
- proc_table->field[2]->val_int() ==
- TYPE_ENUM_PROCEDURE))
+ proc_table->field[MYSQL_PROC_MYSQL_TYPE]->
+ val_int() == TYPE_ENUM_PROCEDURE))
return 0;
if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
- proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE) ||
+ proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
+ TYPE_ENUM_PROCEDURE) ||
(lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
- proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION) ||
+ proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
+ TYPE_ENUM_FUNCTION) ||
(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
{
restore_record(table, s->default_values);
if (!wild || !wild[0] || !wild_compare(sp_name.c_ptr_safe(), wild, 0))
{
- int enum_idx= (int) proc_table->field[5]->val_int();
+ int enum_idx= (int) proc_table->field[MYSQL_PROC_FIELD_ACCESS]->val_int();
table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
- copy_field_as_string(table->field[0], proc_table->field[3]);
+
+ copy_field_as_string(table->field[0],
+ proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]);
+ table->field[1]->store(STRING_WITH_LEN("def"), cs);
table->field[2]->store(sp_db.ptr(), sp_db.length(), cs);
- copy_field_as_string(table->field[4], proc_table->field[2]);
- if (proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION)
+ copy_field_as_string(table->field[4],
+ proc_table->field[MYSQL_PROC_MYSQL_TYPE]);
+
+ if (proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
+ TYPE_ENUM_FUNCTION)
{
- copy_field_as_string(table->field[5], proc_table->field[9]);
- table->field[5]->set_notnull();
+ sp_head *sp;
+ bool free_sp_head;
+ proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str(&returns);
+ sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
+ (ulong) proc_table->
+ field[MYSQL_PROC_FIELD_SQL_MODE]->
+ val_int(),
+ TYPE_ENUM_FUNCTION,
+ returns.c_ptr_safe(),
+ "", &free_sp_head);
+
+ if (sp)
+ {
+ char path[FN_REFLEN];
+ TABLE_SHARE share;
+ TABLE tbl;
+ Field *field;
+ Create_field *field_def= &sp->m_return_field_def;
+
+ bzero((char*) &tbl, sizeof(TABLE));
+ (void) build_table_filename(path, sizeof(path), "", "", "", 0);
+ init_tmp_table_share(thd, &share, "", 0, "", path);
+ field= make_field(&share, (uchar*) 0, field_def->length,
+ (uchar*) "", 0, field_def->pack_flag,
+ field_def->sql_type, field_def->charset,
+ field_def->geom_type, Field::NONE,
+ field_def->interval, "");
+
+ field->table= &tbl;
+ tbl.in_use= thd;
+ store_column_type(table, field, cs, 5);
+ free_table_share(&share);
+ if (free_sp_head)
+ delete sp;
+ }
}
+
if (full_access)
{
- copy_field_as_string(table->field[7], proc_table->field[19]);
- table->field[7]->set_notnull();
+ copy_field_as_string(table->field[14],
+ proc_table->field[MYSQL_PROC_FIELD_BODY_UTF8]);
+ table->field[14]->set_notnull();
}
- table->field[6]->store(STRING_WITH_LEN("SQL"), cs);
- table->field[10]->store(STRING_WITH_LEN("SQL"), cs);
- copy_field_as_string(table->field[11], proc_table->field[6]);
- table->field[12]->store(sp_data_access_name[enum_idx].str,
+ table->field[13]->store(STRING_WITH_LEN("SQL"), cs);
+ table->field[17]->store(STRING_WITH_LEN("SQL"), cs);
+ copy_field_as_string(table->field[18],
+ proc_table->field[MYSQL_PROC_FIELD_DETERMINISTIC]);
+ table->field[19]->store(sp_data_access_name[enum_idx].str,
sp_data_access_name[enum_idx].length , cs);
- copy_field_as_string(table->field[14], proc_table->field[7]);
+ copy_field_as_string(table->field[21],
+ proc_table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]);
bzero((char *)&time, sizeof(time));
- ((Field_timestamp *) proc_table->field[12])->get_time(&time);
- table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ ((Field_timestamp *) proc_table->field[MYSQL_PROC_FIELD_CREATED])->
+ get_time(&time);
+ table->field[22]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
bzero((char *)&time, sizeof(time));
- ((Field_timestamp *) proc_table->field[13])->get_time(&time);
- table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
- copy_field_as_string(table->field[17], proc_table->field[14]);
- copy_field_as_string(table->field[18], proc_table->field[15]);
- table->field[19]->store(definer.ptr(), definer.length(), cs);
- copy_field_as_string(table->field[20], proc_table->field[16]);
- copy_field_as_string(table->field[21], proc_table->field[17]);
- copy_field_as_string(table->field[22], proc_table->field[18]);
+ ((Field_timestamp *) proc_table->field[MYSQL_PROC_FIELD_MODIFIED])->
+ get_time(&time);
+ table->field[23]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ copy_field_as_string(table->field[24],
+ proc_table->field[MYSQL_PROC_FIELD_SQL_MODE]);
+ copy_field_as_string(table->field[25],
+ proc_table->field[MYSQL_PROC_FIELD_COMMENT]);
+
+ table->field[26]->store(definer.ptr(), definer.length(), cs);
+ copy_field_as_string(table->field[27],
+ proc_table->
+ field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]);
+ copy_field_as_string(table->field[28],
+ proc_table->
+ field[MYSQL_PROC_FIELD_COLLATION_CONNECTION]);
+ copy_field_as_string(table->field[29],
+ proc_table->field[MYSQL_PROC_FIELD_DB_COLLATION]);
return schema_table_store_record(thd, table);
}
@@ -4330,7 +4762,9 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
TABLE *table= tables->table;
bool full_access;
char definer[USER_HOST_BUFF_SIZE];
- Open_tables_state open_tables_state_backup;
+ Open_tables_backup open_tables_state_backup;
+ enum enum_schema_tables schema_table_idx=
+ get_schema_table_idx(tables->schema_table);
DBUG_ENTER("fill_schema_proc");
strxmov(definer, thd->security_ctx->priv_user, "@",
@@ -4342,7 +4776,8 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
proc_tables.table_name= proc_tables.alias= (char*) "proc";
proc_tables.table_name_length= 4;
proc_tables.lock_type= TL_READ;
- full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1, TRUE);
+ full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, FALSE,
+ 1, TRUE);
if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup)))
{
DBUG_RETURN(1);
@@ -4353,14 +4788,19 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
res= (res == HA_ERR_END_OF_FILE) ? 0 : 1;
goto err;
}
- if (store_schema_proc(thd, table, proc_table, wild, full_access, definer))
+
+ if (schema_table_idx == SCH_PROCEDURES ?
+ store_schema_proc(thd, table, proc_table, wild, full_access, definer) :
+ store_schema_params(thd, table, proc_table, wild, full_access, definer))
{
res= 1;
goto err;
}
while (!proc_table->file->index_next(proc_table->record[0]))
{
- if (store_schema_proc(thd, table, proc_table, wild, full_access, definer))
+ if (schema_table_idx == SCH_PROCEDURES ?
+ store_schema_proc(thd, table, proc_table, wild, full_access, definer):
+ store_schema_params(thd, table, proc_table, wild, full_access, definer))
{
res= 1;
goto err;
@@ -4391,7 +4831,7 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
*/
if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->main_da.sql_errno(), thd->main_da.message());
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
thd->clear_error();
res= 0;
}
@@ -4412,6 +4852,7 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
{
restore_record(table, s->default_values);
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(db_name->str, db_name->length, cs);
table->field[2]->store(table_name->str, table_name->length, cs);
table->field[3]->store((longlong) ((key_info->flags &
@@ -4459,6 +4900,11 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
else
table->field[14]->store("", 0, cs);
table->field[14]->set_notnull();
+ DBUG_ASSERT(test(key_info->flags & HA_USES_COMMENT) ==
+ (key_info->comment.length > 0));
+ if (key_info->flags & HA_USES_COMMENT)
+ table->field[15]->store(key_info->comment.str,
+ key_info->comment.length, cs);
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
}
@@ -4474,24 +4920,15 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
LEX_STRING *table_name)
{
CHARSET_INFO *cs= system_charset_info;
- DBUG_ENTER("get_schema_views_record");
- LEX_STRING *tmp_db_name, *tmp_table_name;
char definer[USER_HOST_BUFF_SIZE];
uint definer_len;
bool updatable_view;
- /*
- if SELECT FROM I_S.VIEWS uses only fields
- which have OPEN_FRM_ONLY flag then 'tables'
- structure is zeroed and only tables->view is set.
- (see fill_schema_table_from_frm() function).
- So we should disable other fields filling.
- */
- bool only_share= !tables->definer.user.str;
+ DBUG_ENTER("get_schema_views_record");
if (tables->view)
{
Security_context *sctx= thd->security_ctx;
- if (!only_share && !tables->allowed_show)
+ if (!tables->allowed_show)
{
if (!my_strcasecmp(system_charset_info, tables->definer.user.str,
sctx->priv_user) &&
@@ -4509,55 +4946,62 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
TABLE_LIST table_list;
uint view_access;
memset(&table_list, 0, sizeof(table_list));
- table_list.db= tables->view_db.str;
- table_list.table_name= tables->view_name.str;
+ table_list.db= tables->db;
+ table_list.table_name= tables->table_name;
table_list.grant.privilege= thd->col_access;
view_access= get_table_grant(thd, &table_list);
- if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
- (SHOW_VIEW_ACL|SELECT_ACL))
- tables->allowed_show= TRUE;
+ if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
+ (SHOW_VIEW_ACL|SELECT_ACL))
+ tables->allowed_show= TRUE;
}
}
#endif
}
restore_record(table, s->default_values);
- tmp_db_name= &tables->view_db;
- tmp_table_name= &tables->view_name;
- if (only_share)
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
+ table->field[1]->store(db_name->str, db_name->length, cs);
+ table->field[2]->store(table_name->str, table_name->length, cs);
+
+ if (tables->allowed_show)
{
- tmp_db_name= db_name;
- tmp_table_name= table_name;
+ table->field[3]->store(tables->view_body_utf8.str,
+ tables->view_body_utf8.length,
+ cs);
}
- table->field[1]->store(tmp_db_name->str, tmp_db_name->length, cs);
- table->field[2]->store(tmp_table_name->str, tmp_table_name->length, cs);
- if (!only_share)
- {
- if (tables->allowed_show)
- {
- table->field[3]->store(tables->view_body_utf8.str,
- tables->view_body_utf8.length,
- cs);
- }
- if (tables->with_check != VIEW_CHECK_NONE)
- {
- if (tables->with_check == VIEW_CHECK_LOCAL)
- table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs);
- else
- table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs);
- }
+ if (tables->with_check != VIEW_CHECK_NONE)
+ {
+ if (tables->with_check == VIEW_CHECK_LOCAL)
+ table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs);
else
- table->field[4]->store(STRING_WITH_LEN("NONE"), cs);
+ table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs);
+ }
+ else
+ table->field[4]->store(STRING_WITH_LEN("NONE"), cs);
+ /*
+ Only try to fill in the information about view updatability
+ if it is requested as part of the top-level query (i.e.
+ it's select * from i_s.views, as opposed to, say, select
+ security_type from i_s.views). Do not try to access the
+ underlying tables if there was an error when opening the
+ view: all underlying tables are released back to the table
+ definition cache on error inside open_normal_and_derived_tables().
+ If a field is not assigned explicitly, it defaults to NULL.
+ */
+ if (res == FALSE &&
+ table->pos_in_table_list->table_open_method & OPEN_FULL_TABLE)
+ {
updatable_view= 0;
if (tables->algorithm != VIEW_ALGORITHM_TMPTABLE)
{
/*
- We should use tables->view->select_lex.item_list here and
- can not use Field_iterator_view because the view always uses
- temporary algorithm during opening for I_S and
- TABLE_LIST fields 'field_translation' & 'field_translation_end'
- are uninitialized is this case.
+ We should use tables->view->select_lex.item_list here
+ and can not use Field_iterator_view because the view
+ always uses temporary algorithm during opening for I_S
+ and TABLE_LIST fields 'field_translation'
+ & 'field_translation_end' are uninitialized is this
+ case.
*/
List<Item> *fields= &tables->view->select_lex.item_list;
List_iterator<Item> it(*fields);
@@ -4582,31 +5026,33 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
table->field[5]->store(STRING_WITH_LEN("YES"), cs);
else
table->field[5]->store(STRING_WITH_LEN("NO"), cs);
- definer_len= (strxmov(definer, tables->definer.user.str, "@",
- tables->definer.host.str, NullS) - definer);
- table->field[6]->store(definer, definer_len, cs);
- if (tables->view_suid)
- table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs);
- else
- table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs);
+ }
- table->field[8]->store(tables->view_creation_ctx->get_client_cs()->csname,
- strlen(tables->view_creation_ctx->
- get_client_cs()->csname), cs);
+ definer_len= (strxmov(definer, tables->definer.user.str, "@",
+ tables->definer.host.str, NullS) - definer);
+ table->field[6]->store(definer, definer_len, cs);
+ if (tables->view_suid)
+ table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs);
+ else
+ table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs);
+
+ table->field[8]->store(tables->view_creation_ctx->get_client_cs()->csname,
+ strlen(tables->view_creation_ctx->
+ get_client_cs()->csname), cs);
+
+ table->field[9]->store(tables->view_creation_ctx->
+ get_connection_cl()->name,
+ strlen(tables->view_creation_ctx->
+ get_connection_cl()->name), cs);
- table->field[9]->store(tables->view_creation_ctx->
- get_connection_cl()->name,
- strlen(tables->view_creation_ctx->
- get_connection_cl()->name), cs);
- }
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
if (res && thd->is_error())
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->main_da.sql_errno(), thd->main_da.message());
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
}
- if (res)
+ if (res)
thd->clear_error();
DBUG_RETURN(0);
}
@@ -4618,6 +5064,7 @@ bool store_constraints(THD *thd, TABLE *table, LEX_STRING *db_name,
{
CHARSET_INFO *cs= system_charset_info;
restore_record(table, s->default_values);
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(db_name->str, db_name->length, cs);
table->field[2]->store(key_name, key_len, cs);
table->field[3]->store(db_name->str, db_name->length, cs);
@@ -4637,7 +5084,7 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
{
if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->main_da.sql_errno(), thd->main_da.message());
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -4677,8 +5124,8 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
while ((f_key_info=it++))
{
if (store_constraints(thd, table, db_name, table_name,
- f_key_info->forein_id->str,
- strlen(f_key_info->forein_id->str),
+ f_key_info->foreign_id->str,
+ strlen(f_key_info->foreign_id->str),
"FOREIGN KEY", 11))
DBUG_RETURN(1);
}
@@ -4702,10 +5149,12 @@ static bool store_trigger(THD *thd, TABLE *table, LEX_STRING *db_name,
LEX_STRING sql_mode_rep;
restore_record(table, s->default_values);
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(db_name->str, db_name->length, cs);
table->field[2]->store(trigger_name->str, trigger_name->length, cs);
table->field[3]->store(trg_event_type_names[event].str,
trg_event_type_names[event].length, cs);
+ table->field[4]->store(STRING_WITH_LEN("def"), cs);
table->field[5]->store(db_name->str, db_name->length, cs);
table->field[6]->store(table_name->str, table_name->length, cs);
table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs);
@@ -4715,8 +5164,7 @@ static bool store_trigger(THD *thd, TABLE *table, LEX_STRING *db_name,
table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
- sys_var_thd_sql_mode::symbolic_mode_representation(thd, sql_mode,
- &sql_mode_rep);
+ sql_mode_string_representation(thd, sql_mode, &sql_mode_rep);
table->field[17]->store(sql_mode_rep.str, sql_mode_rep.length, cs);
table->field[18]->store(definer_buffer->str, definer_buffer->length, cs);
table->field[19]->store(client_cs_name->str, client_cs_name->length, cs);
@@ -4742,7 +5190,7 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables,
{
if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->main_da.sql_errno(), thd->main_da.message());
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -4751,7 +5199,7 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables,
Table_triggers_list *triggers= tables->table->triggers;
int event, timing;
- if (check_table_access(thd, TRIGGER_ACL, tables, 1, TRUE))
+ if (check_table_access(thd, TRIGGER_ACL, tables, FALSE, 1, TRUE))
goto ret;
for (event= 0; event < (int)TRG_EVENT_MAX; event++)
@@ -4801,8 +5249,10 @@ void store_key_column_usage(TABLE *table, LEX_STRING *db_name,
longlong idx)
{
CHARSET_INFO *cs= system_charset_info;
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(db_name->str, db_name->length, cs);
table->field[2]->store(key_name, key_len, cs);
+ table->field[3]->store(STRING_WITH_LEN("def"), cs);
table->field[4]->store(db_name->str, db_name->length, cs);
table->field[5]->store(table_name->str, table_name->length, cs);
table->field[6]->store(con_type, con_len, cs);
@@ -4821,7 +5271,7 @@ static int get_schema_key_column_usage_record(THD *thd,
{
if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->main_da.sql_errno(), thd->main_da.message());
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -4874,8 +5324,8 @@ static int get_schema_key_column_usage_record(THD *thd,
f_idx++;
restore_record(table, s->default_values);
store_key_column_usage(table, db_name, table_name,
- f_key_info->forein_id->str,
- f_key_info->forein_id->length,
+ f_key_info->foreign_id->str,
+ f_key_info->foreign_id->length,
f_info->str, f_info->length,
(longlong) f_idx);
table->field[8]->store((longlong) f_idx, TRUE);
@@ -4901,7 +5351,8 @@ static int get_schema_key_column_usage_record(THD *thd,
#ifdef WITH_PARTITION_STORAGE_ENGINE
-static void collect_partition_expr(List<char> &field_list, String *str)
+static void collect_partition_expr(THD *thd, List<char> &field_list,
+ String *str)
{
List_iterator<char> part_it(field_list);
ulong no_fields= field_list.elements;
@@ -4909,12 +5360,63 @@ static void collect_partition_expr(List<char> &field_list, String *str)
str->length(0);
while ((field_str= part_it++))
{
- str->append(field_str);
+ append_identifier(thd, str, field_str, strlen(field_str));
if (--no_fields != 0)
str->append(",");
}
return;
}
+
+
+/*
+ Convert a string in a given character set to a string which can be
+ used for FRM file storage in which case use_hex is TRUE and we store
+ the character constants as hex strings in the character set encoding
+ their field have. In the case of SHOW CREATE TABLE and the
+ PARTITIONS information schema table we instead provide utf8 strings
+ to the user and convert to the utf8 character set.
+
+ SYNOPSIS
+ get_cs_converted_part_value_from_string()
+ item Item from which constant comes
+ input_str String as provided by val_str after
+ conversion to character set
+ output_str Out value: The string created
+ cs Character set string is encoded in
+ NULL for INT_RESULT's here
+ use_hex TRUE => hex string created
+ FALSE => utf8 constant string created
+
+ RETURN VALUES
+ TRUE Error
+ FALSE Ok
+*/
+
+int get_cs_converted_part_value_from_string(THD *thd,
+ Item *item,
+ String *input_str,
+ String *output_str,
+ CHARSET_INFO *cs,
+ bool use_hex)
+{
+ if (item->result_type() == INT_RESULT)
+ {
+ longlong value= item->val_int();
+ output_str->set(value, system_charset_info);
+ return FALSE;
+ }
+ if (!input_str)
+ {
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+ return TRUE;
+ }
+ get_cs_converted_string_value(thd,
+ input_str,
+ output_str,
+ cs,
+ use_hex);
+ return FALSE;
+}
#endif
@@ -4925,9 +5427,10 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
{
TABLE* table= schema_table;
CHARSET_INFO *cs= system_charset_info;
- PARTITION_INFO stat_info;
+ PARTITION_STATS stat_info;
MYSQL_TIME time;
file->get_dynamic_partition_info(&stat_info, part_id);
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[12]->store((longlong) stat_info.records, TRUE);
table->field[13]->store((longlong) stat_info.mean_rec_length, TRUE);
table->field[14]->store((longlong) stat_info.data_file_length, TRUE);
@@ -4986,7 +5489,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
if(ts)
{
table->field[24]->store(ts, strlen(ts), cs);
- my_free(ts, MYF(0));
+ my_free(ts);
}
else
table->field[24]->set_null();
@@ -4995,6 +5498,51 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
return;
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+static int
+get_partition_column_description(THD *thd,
+ partition_info *part_info,
+ part_elem_value *list_value,
+ String &tmp_str)
+{
+ uint num_elements= part_info->part_field_list.elements;
+ uint i;
+ DBUG_ENTER("get_partition_column_description");
+
+ for (i= 0; i < num_elements; i++)
+ {
+ part_column_list_val *col_val= &list_value->col_val_array[i];
+ if (col_val->max_value)
+ tmp_str.append(partition_keywords[PKW_MAXVALUE].str);
+ else if (col_val->null_value)
+ tmp_str.append("NULL");
+ else
+ {
+ char buffer[MAX_KEY_LENGTH];
+ String str(buffer, sizeof(buffer), &my_charset_bin);
+ String val_conv;
+ Item *item= col_val->item_expression;
+
+ if (!(item= part_info->get_column_item(item,
+ part_info->part_field_array[i])))
+ {
+ DBUG_RETURN(1);
+ }
+ String *res= item->val_str(&str);
+ if (get_cs_converted_part_value_from_string(thd, item, res, &val_conv,
+ part_info->part_field_array[i]->charset(),
+ FALSE))
+ {
+ DBUG_RETURN(1);
+ }
+ tmp_str.append(val_conv);
+ }
+ if (i != num_elements - 1)
+ tmp_str.append(",");
+ }
+ DBUG_RETURN(0);
+}
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
TABLE *table, bool res,
@@ -5016,7 +5564,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
{
if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->main_da.sql_errno(), thd->main_da.message());
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -5030,6 +5578,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
uint part_pos= 0, part_id= 0;
restore_record(table, s->default_values);
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(db_name->str, db_name->length, cs);
table->field[2]->store(table_name->str, table_name->length, cs);
@@ -5037,12 +5586,18 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
/* Partition method*/
switch (part_info->part_type) {
case RANGE_PARTITION:
- table->field[7]->store(partition_keywords[PKW_RANGE].str,
- partition_keywords[PKW_RANGE].length, cs);
- break;
case LIST_PARTITION:
- table->field[7]->store(partition_keywords[PKW_LIST].str,
- partition_keywords[PKW_LIST].length, cs);
+ tmp_res.length(0);
+ if (part_info->part_type == RANGE_PARTITION)
+ tmp_res.append(partition_keywords[PKW_RANGE].str,
+ partition_keywords[PKW_RANGE].length);
+ else
+ tmp_res.append(partition_keywords[PKW_LIST].str,
+ partition_keywords[PKW_LIST].length);
+ if (part_info->column_list)
+ tmp_res.append(partition_keywords[PKW_COLUMNS].str,
+ partition_keywords[PKW_COLUMNS].length);
+ table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs);
break;
case HASH_PARTITION:
tmp_res.length(0);
@@ -5059,8 +5614,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
break;
default:
DBUG_ASSERT(0);
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- current_thd->fatal_error();
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
DBUG_RETURN(1);
}
table->field[7]->set_notnull();
@@ -5073,7 +5627,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
}
else if (part_info->list_of_part_fields)
{
- collect_partition_expr(part_info->part_field_list, &tmp_str);
+ collect_partition_expr(thd, part_info->part_field_list, &tmp_str);
table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs);
}
table->field[9]->set_notnull();
@@ -5102,7 +5656,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
}
else if (part_info->list_of_subpart_fields)
{
- collect_partition_expr(part_info->subpart_field_list, &tmp_str);
+ collect_partition_expr(thd, part_info->subpart_field_list, &tmp_str);
table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs);
}
table->field[10]->set_notnull();
@@ -5120,36 +5674,70 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
/* Partition description */
if (part_info->part_type == RANGE_PARTITION)
{
- if (part_elem->range_value != LONGLONG_MAX)
- table->field[11]->store((longlong) part_elem->range_value, FALSE);
+ if (part_info->column_list)
+ {
+ List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
+ part_elem_value *list_value= list_val_it++;
+ tmp_str.length(0);
+ if (get_partition_column_description(thd,
+ part_info,
+ list_value,
+ tmp_str))
+ {
+ DBUG_RETURN(1);
+ }
+ table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
+ }
else
- table->field[11]->store(partition_keywords[PKW_MAXVALUE].str,
+ {
+ if (part_elem->range_value != LONGLONG_MAX)
+ table->field[11]->store((longlong) part_elem->range_value, FALSE);
+ else
+ table->field[11]->store(partition_keywords[PKW_MAXVALUE].str,
partition_keywords[PKW_MAXVALUE].length, cs);
+ }
table->field[11]->set_notnull();
}
else if (part_info->part_type == LIST_PARTITION)
{
List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
part_elem_value *list_value;
- uint no_items= part_elem->list_val_list.elements;
+ uint num_items= part_elem->list_val_list.elements;
tmp_str.length(0);
tmp_res.length(0);
if (part_elem->has_null_value)
{
tmp_str.append("NULL");
- if (no_items > 0)
+ if (num_items > 0)
tmp_str.append(",");
}
while ((list_value= list_val_it++))
{
- if (!list_value->unsigned_flag)
- tmp_res.set(list_value->value, cs);
+ if (part_info->column_list)
+ {
+ if (part_info->part_field_list.elements > 1U)
+ tmp_str.append("(");
+ if (get_partition_column_description(thd,
+ part_info,
+ list_value,
+ tmp_str))
+ {
+ DBUG_RETURN(1);
+ }
+ if (part_info->part_field_list.elements > 1U)
+ tmp_str.append(")");
+ }
else
- tmp_res.set((ulonglong)list_value->value, cs);
- tmp_str.append(tmp_res);
- if (--no_items != 0)
+ {
+ if (!list_value->unsigned_flag)
+ tmp_res.set(list_value->value, cs);
+ else
+ tmp_res.set((ulonglong)list_value->value, cs);
+ tmp_str.append(tmp_res);
+ }
+ if (--num_items != 0)
tmp_str.append(",");
- };
+ }
table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
table->field[11]->set_notnull();
}
@@ -5198,52 +5786,6 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
}
-#ifdef NOT_USED
-static interval_type get_real_interval_type(interval_type i_type)
-{
- switch (i_type) {
- case INTERVAL_YEAR:
- return INTERVAL_YEAR;
-
- case INTERVAL_QUARTER:
- case INTERVAL_YEAR_MONTH:
- case INTERVAL_MONTH:
- return INTERVAL_MONTH;
-
- case INTERVAL_WEEK:
- case INTERVAL_DAY:
- return INTERVAL_DAY;
-
- case INTERVAL_DAY_HOUR:
- case INTERVAL_HOUR:
- return INTERVAL_HOUR;
-
- case INTERVAL_DAY_MINUTE:
- case INTERVAL_HOUR_MINUTE:
- case INTERVAL_MINUTE:
- return INTERVAL_MINUTE;
-
- case INTERVAL_DAY_SECOND:
- case INTERVAL_HOUR_SECOND:
- case INTERVAL_MINUTE_SECOND:
- case INTERVAL_SECOND:
- return INTERVAL_SECOND;
-
- case INTERVAL_DAY_MICROSECOND:
- case INTERVAL_HOUR_MICROSECOND:
- case INTERVAL_MINUTE_MICROSECOND:
- case INTERVAL_SECOND_MICROSECOND:
- case INTERVAL_MICROSECOND:
- return INTERVAL_MICROSECOND;
- case INTERVAL_LAST:
- DBUG_ASSERT(0);
- }
- DBUG_ASSERT(0);
- return INTERVAL_SECOND;
-}
-
-#endif
-
#ifdef HAVE_EVENT_SCHEDULER
/*
Loads an event from mysql.event and copies it's data to a row of
@@ -5286,12 +5828,10 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
has access.
*/
if (thd->lex->sql_command != SQLCOM_SHOW_EVENTS &&
- check_access(thd, EVENT_ACL, et.dbname.str, 0, 0, 1,
- is_schema_db(et.dbname.str, et.dbname.length)))
+ check_access(thd, EVENT_ACL, et.dbname.str, NULL, NULL, 0, 1))
DBUG_RETURN(0);
- /* ->field[0] is EVENT_CATALOG and is by default NULL */
-
+ sch_table->field[ISE_EVENT_CATALOG]->store(STRING_WITH_LEN("def"), scs);
sch_table->field[ISE_EVENT_SCHEMA]->
store(et.dbname.str, et.dbname.length,scs);
sch_table->field[ISE_EVENT_NAME]->
@@ -5309,8 +5849,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
/* SQL_MODE */
{
LEX_STRING sql_mode;
- sys_var_thd_sql_mode::symbolic_mode_representation(thd, et.sql_mode,
- &sql_mode);
+ sql_mode_string_representation(thd, et.sql_mode, &sql_mode);
sch_table->field[ISE_SQL_MODE]->
store(sql_mode.str, sql_mode.length, scs);
}
@@ -5473,10 +6012,10 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
schema_table_idx == SCH_GLOBAL_VARIABLES)
option_type= OPT_GLOBAL;
- rw_rdlock(&LOCK_system_variables_hash);
- res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars),
+ mysql_rwlock_rdlock(&LOCK_system_variables_hash);
+ res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, option_type),
option_type, NULL, "", tables->table, upper_case_names, cond);
- rw_unlock(&LOCK_system_variables_hash);
+ mysql_rwlock_unlock(&LOCK_system_variables_hash);
DBUG_RETURN(res);
}
@@ -5512,14 +6051,14 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
tmp1= &thd->status_var;
}
- pthread_mutex_lock(&LOCK_status);
+ mysql_mutex_lock(&LOCK_status);
if (option_type == OPT_GLOBAL)
calc_sum_of_all_status(&tmp);
res= show_status_array(thd, wild,
(SHOW_VAR *)all_status_vars.buffer,
option_type, tmp1, "", tables->table,
upper_case_names, cond);
- pthread_mutex_unlock(&LOCK_status);
+ mysql_mutex_unlock(&LOCK_status);
DBUG_RETURN(res);
}
@@ -5554,7 +6093,7 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
{
if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->main_da.sql_errno(), thd->main_da.message());
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -5572,10 +6111,12 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
while ((f_key_info= it++))
{
restore_record(table, s->default_values);
+ table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(db_name->str, db_name->length, cs);
table->field[9]->store(table_name->str, table_name->length, cs);
- table->field[2]->store(f_key_info->forein_id->str,
- f_key_info->forein_id->length, cs);
+ table->field[2]->store(f_key_info->foreign_id->str,
+ f_key_info->foreign_id->length, cs);
+ table->field[3]->store(STRING_WITH_LEN("def"), cs);
table->field[4]->store(f_key_info->referenced_db->str,
f_key_info->referenced_db->length, cs);
table->field[10]->store(f_key_info->referenced_table->str,
@@ -5797,7 +6338,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
SELECT_LEX *select_lex= thd->lex->current_select;
if (!(table= create_tmp_table(thd, tmp_table_param,
field_list, (ORDER*) 0, 0, 0,
- (select_lex->options | thd->options |
+ (select_lex->options | thd->variables.option_bits |
TMP_TABLE_ALL_COLUMNS),
HA_POS_ERROR, table_list->alias)))
DBUG_RETURN(0);
@@ -5972,7 +6513,7 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
- int fields_arr[]= {2, 3, 4, 19, 16, 15, 14, 18, 20, 21, 22, -1};
+ int fields_arr[]= {2, 3, 4, 26, 23, 22, 21, 25, 27, 28, 29, -1};
int *field_num= fields_arr;
ST_FIELD_INFO *field_info;
Name_resolution_context *context= &thd->lex->select_lex.context;
@@ -6109,7 +6650,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
strlen(schema_table->table_name), 0);
if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
!sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
- 0, 0, TL_READ))
+ 0, 0, TL_READ, MDL_SHARED_READ))
{
DBUG_RETURN(1);
}
@@ -6207,32 +6748,33 @@ bool get_schema_tables_result(JOIN *join,
DBUG_RETURN(result);
}
-struct run_hton_fill_schema_files_args
+struct run_hton_fill_schema_table_args
{
TABLE_LIST *tables;
COND *cond;
};
-static my_bool run_hton_fill_schema_files(THD *thd, plugin_ref plugin,
+static my_bool run_hton_fill_schema_table(THD *thd, plugin_ref plugin,
void *arg)
{
- struct run_hton_fill_schema_files_args *args=
- (run_hton_fill_schema_files_args *) arg;
+ struct run_hton_fill_schema_table_args *args=
+ (run_hton_fill_schema_table_args *) arg;
handlerton *hton= plugin_data(plugin, handlerton *);
- if(hton->fill_files_table && hton->state == SHOW_OPTION_YES)
- hton->fill_files_table(hton, thd, args->tables, args->cond);
+ if (hton->fill_is_table && hton->state == SHOW_OPTION_YES)
+ hton->fill_is_table(hton, thd, args->tables, args->cond,
+ get_schema_table_idx(args->tables->schema_table));
return false;
}
-int fill_schema_files(THD *thd, TABLE_LIST *tables, COND *cond)
+int hton_fill_schema_table(THD *thd, TABLE_LIST *tables, COND *cond)
{
- DBUG_ENTER("fill_schema_files");
+ DBUG_ENTER("hton_fill_schema_table");
- struct run_hton_fill_schema_files_args args;
+ struct run_hton_fill_schema_table_args args;
args.tables= tables;
args.cond= cond;
- plugin_foreach(thd, run_hton_fill_schema_files,
+ plugin_foreach(thd, run_hton_fill_schema_table,
MYSQL_STORAGE_ENGINE_PLUGIN, &args);
DBUG_RETURN(0);
@@ -6241,7 +6783,7 @@ int fill_schema_files(THD *thd, TABLE_LIST *tables, COND *cond)
ST_FIELD_INFO schema_fields_info[]=
{
- {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
+ {"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,
@@ -6255,7 +6797,7 @@ ST_FIELD_INFO schema_fields_info[]=
ST_FIELD_INFO tables_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 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, "Name",
SKIP_OPEN_TABLE},
@@ -6287,14 +6829,15 @@ ST_FIELD_INFO tables_fields_info[]=
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", OPEN_FULL_TABLE},
{"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options",
OPEN_FRM_ONLY},
- {"TABLE_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment", OPEN_FRM_ONLY},
+ {"TABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
+ "Comment", OPEN_FRM_ONLY},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};
ST_FIELD_INFO columns_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY},
+ {"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",
@@ -6321,7 +6864,8 @@ ST_FIELD_INFO columns_fields_info[]=
{"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key", OPEN_FRM_ONLY},
{"EXTRA", 27, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY},
{"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges", OPEN_FRM_ONLY},
- {"COLUMN_COMMENT", 255, MYSQL_TYPE_STRING, 0, 0, "Comment", OPEN_FRM_ONLY},
+ {"COLUMN_COMMENT", COLUMN_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
+ "Comment", OPEN_FRM_ONLY},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};
@@ -6368,7 +6912,7 @@ ST_FIELD_INFO engines_fields_info[]=
ST_FIELD_INFO events_fields_info[]=
{
- {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
+ {"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",
@@ -6417,13 +6961,20 @@ ST_FIELD_INFO coll_charset_app_fields_info[]=
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, 1, 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", 9, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
- {"DTD_IDENTIFIER", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, 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},
+ {"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},
@@ -6439,7 +6990,7 @@ ST_FIELD_INFO proc_fields_info[]=
{"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", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Comment",
+ {"ROUTINE_COMMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Comment",
SKIP_OPEN_TABLE},
{"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
{"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
@@ -6454,7 +7005,7 @@ ST_FIELD_INFO proc_fields_info[]=
ST_FIELD_INFO stat_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY},
+ {"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},
@@ -6472,24 +7023,26 @@ ST_FIELD_INFO stat_fields_info[]=
{"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}
};
ST_FIELD_INFO view_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY},
+ {"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_FULL_TABLE},
- {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
+ {"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", 77, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
+ {"DEFINER", 77, 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_FULL_TABLE},
+ OPEN_FRM_ONLY},
{"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
+ OPEN_FRM_ONLY},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};
@@ -6497,7 +7050,7 @@ ST_FIELD_INFO view_fields_info[]=
ST_FIELD_INFO user_privileges_fields_info[]=
{
{"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 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}
@@ -6507,7 +7060,7 @@ ST_FIELD_INFO user_privileges_fields_info[]=
ST_FIELD_INFO schema_privileges_fields_info[]=
{
{"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 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},
@@ -6518,7 +7071,7 @@ ST_FIELD_INFO schema_privileges_fields_info[]=
ST_FIELD_INFO table_privileges_fields_info[]=
{
{"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 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},
@@ -6530,7 +7083,7 @@ ST_FIELD_INFO table_privileges_fields_info[]=
ST_FIELD_INFO column_privileges_fields_info[]=
{
{"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 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},
@@ -6542,7 +7095,7 @@ ST_FIELD_INFO column_privileges_fields_info[]=
ST_FIELD_INFO table_constraints_fields_info[]=
{
- {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
+ {"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,
@@ -6557,12 +7110,12 @@ ST_FIELD_INFO table_constraints_fields_info[]=
ST_FIELD_INFO key_column_usage_fields_info[]=
{
- {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
+ {"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, 1, 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},
@@ -6581,7 +7134,7 @@ ST_FIELD_INFO key_column_usage_fields_info[]=
ST_FIELD_INFO table_names_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 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, "Tables_in_",
SKIP_OPEN_TABLE},
@@ -6604,45 +7157,45 @@ ST_FIELD_INFO open_tables_fields_info[]=
ST_FIELD_INFO triggers_fields_info[]=
{
- {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"TRIGGER_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
+ {"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_FULL_TABLE},
- {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event", OPEN_FULL_TABLE},
- {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
+ 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_FULL_TABLE},
+ OPEN_FRM_ONLY},
{"EVENT_OBJECT_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table",
- OPEN_FULL_TABLE},
- {"ACTION_ORDER", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FULL_TABLE},
- {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_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_FULL_TABLE},
- {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing", OPEN_FULL_TABLE},
+ 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_FULL_TABLE},
+ OPEN_FRM_ONLY},
{"ACTION_REFERENCE_NEW_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FULL_TABLE},
- {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, "sql_mode", OPEN_FULL_TABLE},
- {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer", OPEN_FULL_TABLE},
+ 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},
+ {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FRM_ONLY},
+ {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, "sql_mode", OPEN_FRM_ONLY},
+ {"DEFINER", 77, 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_FULL_TABLE},
+ "character_set_client", OPEN_FRM_ONLY},
{"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "collation_connection", OPEN_FULL_TABLE},
+ "collation_connection", OPEN_FRM_ONLY},
{"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "Database Collation", OPEN_FULL_TABLE},
+ "Database Collation", OPEN_FRM_ONLY},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};
ST_FIELD_INFO partitions_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 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},
{"PARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
@@ -6652,7 +7205,7 @@ ST_FIELD_INFO partitions_fields_info[]=
(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", 12, MYSQL_TYPE_STRING, 0, 1, 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,
@@ -6722,6 +7275,7 @@ ST_FIELD_INFO plugin_fields_info[]=
{"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, 1, "License", SKIP_OPEN_TABLE},
+ {"LOAD_OPTION", 64, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};
@@ -6732,7 +7286,7 @@ ST_FIELD_INFO files_fields_info[]=
{"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, 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,
@@ -6793,12 +7347,12 @@ void init_fill_schema_files_row(TABLE* table)
ST_FIELD_INFO referential_constraints_fields_info[]=
{
- {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
+ {"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, 1, 0,
+ {"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},
@@ -6814,6 +7368,51 @@ ST_FIELD_INFO referential_constraints_fields_info[]=
};
+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},
+ {"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}
+};
+
+
+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}
+};
+
+
/*
Description of ST_FIELD_INFO in table.h
@@ -6844,18 +7443,21 @@ ST_SCHEMA_TABLE schema_tables[]=
0, make_old_format, 0, -1, -1, 0, 0},
#endif
{"FILES", files_fields_info, create_schema_table,
- fill_schema_files, 0, 0, -1, -1, 0, 0},
+ hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
{"GLOBAL_STATUS", variables_fields_info, create_schema_table,
fill_status, make_old_format, 0, 0, -1, 0, 0},
{"GLOBAL_VARIABLES", variables_fields_info, create_schema_table,
fill_variables, make_old_format, 0, 0, -1, 0, 0},
{"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0,
- OPEN_TABLE_ONLY},
+ OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
{"OPEN_TABLES", open_tables_fields_info, create_schema_table,
fill_open_tables, make_old_format, 0, -1, -1, 1, 0},
+ {"PARAMETERS", parameters_fields_info, create_schema_table,
+ fill_schema_proc, 0, 0, -1, -1, 0, 0},
{"PARTITIONS", partitions_fields_info, create_schema_table,
- get_all_tables, 0, get_schema_partitions_record, 1, 2, 0, OPEN_TABLE_ONLY},
+ get_all_tables, 0, get_schema_partitions_record, 1, 2, 0,
+ OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
{"PLUGINS", plugin_fields_info, create_schema_table,
fill_plugins, make_old_format, 0, -1, -1, 0, 0},
{"PROCESSLIST", processlist_fields_info, create_schema_table,
@@ -6865,7 +7467,7 @@ ST_SCHEMA_TABLE schema_tables[]=
NULL, -1, -1, false, 0},
{"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info,
create_schema_table, get_all_tables, 0, get_referential_constraints_record,
- 1, 9, 0, OPEN_TABLE_ONLY},
+ 1, 9, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
{"ROUTINES", proc_fields_info, create_schema_table,
fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0},
{"SCHEMATA", schema_fields_info, create_schema_table,
@@ -6884,15 +7486,18 @@ ST_SCHEMA_TABLE schema_tables[]=
{"TABLES", tables_fields_info, create_schema_table,
get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0,
OPTIMIZE_I_S_TABLE},
+ {"TABLESPACES", tablespaces_fields_info, create_schema_table,
+ hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
{"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table,
- get_all_tables, 0, get_schema_constraints_record, 3, 4, 0, OPEN_TABLE_ONLY},
+ get_all_tables, 0, get_schema_constraints_record, 3, 4, 0,
+ OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
{"TABLE_NAMES", table_names_fields_info, create_schema_table,
get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0},
{"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
{"TRIGGERS", triggers_fields_info, create_schema_table,
get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
- OPEN_TABLE_ONLY},
+ OPEN_TRIGGER_ONLY|OPTIMIZE_I_S_TABLE},
{"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table,
fill_schema_user_privileges, 0, 0, -1, -1, 0, 0},
{"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
@@ -6934,7 +7539,7 @@ int initialize_schema_table(st_plugin_int *plugin)
sql_print_error("Plugin '%s' init function returned error.",
plugin->name.str);
plugin->data= NULL;
- my_free(schema_table, MYF(0));
+ my_free(schema_table);
DBUG_RETURN(1);
}
@@ -6960,7 +7565,7 @@ int finalize_schema_table(st_plugin_int *plugin)
plugin->name.str));
}
}
- my_free(schema_table, MYF(0));
+ my_free(schema_table);
}
DBUG_RETURN(0);
}
@@ -7018,9 +7623,7 @@ static bool show_create_trigger_impl(THD *thd,
&trg_connection_cl_name,
&trg_db_cl_name);
- sys_var_thd_sql_mode::symbolic_mode_representation(thd,
- trg_sql_mode,
- &trg_sql_mode_str);
+ sql_mode_string_representation(thd, trg_sql_mode, &trg_sql_mode_str);
/* Resolve trigger client character set. */
@@ -7056,7 +7659,7 @@ static bool show_create_trigger_impl(THD *thd,
fields.push_back(new Item_empty_string("Database Collation",
MY_CS_NAME_SIZE));
- if (p->send_fields(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ if (p->send_result_set_metadata(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
return TRUE;
/* Send data. */
@@ -7120,14 +7723,14 @@ static bool show_create_trigger_impl(THD *thd,
- do not update Lex::query_tables in add_table_to_list().
*/
-static TABLE_LIST *get_trigger_table_impl(
- THD *thd,
- const sp_name *trg_name)
+static
+TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
{
char trn_path_buff[FN_REFLEN];
-
LEX_STRING trn_path= { trn_path_buff, 0 };
+ LEX_STRING db;
LEX_STRING tbl_name;
+ TABLE_LIST *table;
build_trn_path(thd, trg_name, &trn_path);
@@ -7141,61 +7744,23 @@ static TABLE_LIST *get_trigger_table_impl(
return NULL;
/* We need to reset statement table list to be PS/SP friendly. */
-
- TABLE_LIST *table;
-
- if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST))))
- {
- my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST));
+ if (!(table= (TABLE_LIST*) thd->alloc(sizeof(TABLE_LIST))))
return NULL;
- }
- table->db_length= trg_name->m_db.length;
- table->db= thd->strmake(trg_name->m_db.str, trg_name->m_db.length);
+ db= trg_name->m_db;
- table->table_name_length= tbl_name.length;
- table->table_name= thd->strmake(tbl_name.str, tbl_name.length);
+ db.str= thd->strmake(db.str, db.length);
+ tbl_name.str= thd->strmake(tbl_name.str, tbl_name.length);
- table->alias= thd->strmake(tbl_name.str, tbl_name.length);
+ if (db.str == NULL || tbl_name.str == NULL)
+ return NULL;
- table->lock_type= TL_IGNORE;
- table->cacheable_table= 0;
+ table->init_one_table(db.str, db.length, tbl_name.str, tbl_name.length,
+ tbl_name.str, TL_IGNORE);
return table;
}
-/**
- Read TRN and TRG files to obtain base table name for the specified
- trigger name and construct TABE_LIST object for the base table. Acquire
- LOCK_open when doing this.
-
- @param thd Thread context.
- @param trg_name Trigger name.
-
- @return TABLE_LIST object corresponding to the base table.
-*/
-
-static TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
-{
- /* Acquire LOCK_open (stop the server). */
-
- pthread_mutex_lock(&LOCK_open);
-
- /*
- Load base table name from the TRN-file and create TABLE_LIST object.
- */
-
- TABLE_LIST *lst= get_trigger_table_impl(thd, trg_name);
-
- /* Release LOCK_open (continue the server). */
-
- pthread_mutex_unlock(&LOCK_open);
-
- /* That's it. */
-
- return lst;
-}
-
/**
SHOW CREATE TRIGGER high-level implementation.
@@ -7211,46 +7776,50 @@ static TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
bool show_create_trigger(THD *thd, const sp_name *trg_name)
{
TABLE_LIST *lst= get_trigger_table(thd, trg_name);
+ uint num_tables; /* NOTE: unused, only to pass to open_tables(). */
+ Table_triggers_list *triggers;
+ int trigger_idx;
+ bool error= TRUE;
if (!lst)
return TRUE;
- if (check_table_access(thd, TRIGGER_ACL, lst, 1, TRUE))
+ if (check_table_access(thd, TRIGGER_ACL, lst, FALSE, 1, TRUE))
{
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "TRIGGER");
return TRUE;
}
/*
- Open the table by name in order to load Table_triggers_list object.
-
- NOTE: there is race condition here -- the table can be dropped after
- LOCK_open is released. It will be fixed later by introducing
- acquire-shared-table-name-lock functionality.
+ Metadata locks taken during SHOW CREATE TRIGGER should be released when
+ the statement completes as it is an information statement.
*/
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
- uint num_tables; /* NOTE: unused, only to pass to open_tables(). */
-
- if (open_tables(thd, &lst, &num_tables, 0))
+ /*
+ Open the table by name in order to load Table_triggers_list object.
+ */
+ if (open_tables(thd, &lst, &num_tables,
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
{
my_error(ER_TRG_CANT_OPEN_TABLE, MYF(0),
(const char *) trg_name->m_db.str,
(const char *) lst->table_name);
- return TRUE;
+ goto exit;
/* Perform closing actions and return error status. */
}
- Table_triggers_list *triggers= lst->table->triggers;
+ triggers= lst->table->triggers;
if (!triggers)
{
my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
- return TRUE;
+ goto exit;
}
- int trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name);
+ trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name);
if (trigger_idx < 0)
{
@@ -7258,14 +7827,164 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name)
(const char *) trg_name->m_db.str,
(const char *) lst->table_name);
- return TRUE;
+ goto exit;
}
- return show_create_trigger_impl(thd, triggers, trigger_idx);
+ error= show_create_trigger_impl(thd, triggers, trigger_idx);
/*
NOTE: if show_create_trigger_impl() failed, that means we could not
send data to the client. In this case we simply raise the error
status and client connection will be closed.
*/
+
+exit:
+ close_thread_tables(thd);
+ /* Release any metadata locks taken during SHOW CREATE TRIGGER. */
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+ return error;
+}
+
+class IS_internal_schema_access : public ACL_internal_schema_access
+{
+public:
+ IS_internal_schema_access()
+ {}
+
+ ~IS_internal_schema_access()
+ {}
+
+ ACL_internal_access_result check(ulong want_access,
+ ulong *save_priv) const;
+
+ const ACL_internal_table_access *lookup(const char *name) const;
+};
+
+ACL_internal_access_result
+IS_internal_schema_access::check(ulong want_access,
+ ulong *save_priv) const
+{
+ want_access &= ~SELECT_ACL;
+
+ /*
+ We don't allow any simple privileges but SELECT_ACL on
+ the information_schema database.
+ */
+ if (unlikely(want_access & DB_ACLS))
+ return ACL_INTERNAL_ACCESS_DENIED;
+
+ /* Always grant SELECT for the information schema. */
+ *save_priv|= SELECT_ACL;
+
+ return want_access ? ACL_INTERNAL_ACCESS_CHECK_GRANT :
+ ACL_INTERNAL_ACCESS_GRANTED;
+}
+
+const ACL_internal_table_access *
+IS_internal_schema_access::lookup(const char *name) const
+{
+ /* There are no per table rules for the information schema. */
+ return NULL;
}
+
+static IS_internal_schema_access is_internal_schema_access;
+
+void initialize_information_schema_acl()
+{
+ ACL_internal_schema_registry::register_schema(&INFORMATION_SCHEMA_NAME,
+ &is_internal_schema_access);
+}
+
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+/*
+ Convert a string in character set in column character set format
+ to utf8 character set if possible, the utf8 character set string
+ will later possibly be converted to character set used by client.
+ Thus we attempt conversion from column character set to both
+ utf8 and to character set client.
+
+ Examples of strings that should fail conversion to utf8 are unassigned
+ characters as e.g. 0x81 in cp1250 (Windows character set for for countries
+ like Czech and Poland). Example of string that should fail conversion to
+ character set on client (e.g. if this is latin1) is 0x2020 (daggger) in
+ ucs2.
+
+ If the conversion fails we will as a fall back convert the string to
+ hex encoded format. The caller of the function can also ask for hex
+ encoded format of output string unconditionally.
+
+ SYNOPSIS
+ get_cs_converted_string_value()
+ thd Thread object
+ input_str Input string in cs character set
+ output_str Output string to be produced in utf8
+ cs Character set of input string
+ use_hex Use hex string unconditionally
+
+
+ RETURN VALUES
+ No return value
+*/
+
+static void get_cs_converted_string_value(THD *thd,
+ String *input_str,
+ String *output_str,
+ CHARSET_INFO *cs,
+ bool use_hex)
+{
+
+ output_str->length(0);
+ if (input_str->length() == 0)
+ {
+ output_str->append("''");
+ return;
+ }
+ if (!use_hex)
+ {
+ String try_val;
+ uint try_conv_error= 0;
+
+ try_val.copy(input_str->ptr(), input_str->length(), cs,
+ thd->variables.character_set_client, &try_conv_error);
+ if (!try_conv_error)
+ {
+ String val;
+ uint conv_error= 0;
+
+ val.copy(input_str->ptr(), input_str->length(), cs,
+ system_charset_info, &conv_error);
+ if (!conv_error)
+ {
+ append_unescaped(output_str, val.ptr(), val.length());
+ return;
+ }
+ }
+ /* We had a conversion error, use hex encoded string for safety */
+ }
+ {
+ const uchar *ptr;
+ uint i, len;
+ char buf[3];
+
+ output_str->append("_");
+ output_str->append(cs->csname);
+ output_str->append(" ");
+ output_str->append("0x");
+ len= input_str->length();
+ ptr= (uchar*)input_str->ptr();
+ for (i= 0; i < len; i++)
+ {
+ uint high, low;
+
+ high= (*ptr) >> 4;
+ low= (*ptr) & 0x0F;
+ buf[0]= _dig_vec_upper[high];
+ buf[1]= _dig_vec_upper[low];
+ buf[2]= 0;
+ output_str->append((const char*)buf);
+ ptr++;
+ }
+ }
+ return;
+}
+#endif
diff --git a/sql/sql_show.h b/sql/sql_show.h
index fa067a46033..de8f2525baa 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -16,12 +16,24 @@
#ifndef SQL_SHOW_H
#define SQL_SHOW_H
+#include "sql_list.h" /* List */
+#include "handler.h" /* enum_schema_tables */
+#include "table.h" /* enum_schema_table_state */
+
/* Forward declarations */
+class JOIN;
class String;
class THD;
+class sp_name;
+struct TABLE_LIST;
struct st_ha_create_information;
+typedef class st_select_lex SELECT_LEX;
typedef st_ha_create_information HA_CREATE_INFO;
-struct TABLE_LIST;
+struct LEX;
+typedef struct st_mysql_show_var SHOW_VAR;
+typedef struct st_schema_table ST_SCHEMA_TABLE;
+struct TABLE;
+typedef struct system_status_var STATUS_VAR;
enum find_files_result {
FIND_FILES_OK,
@@ -29,6 +41,46 @@ enum find_files_result {
FIND_FILES_DIR
};
+/* Used by handlers to store things in schema tables */
+#define IS_FILES_FILE_ID 0
+#define IS_FILES_FILE_NAME 1
+#define IS_FILES_FILE_TYPE 2
+#define IS_FILES_TABLESPACE_NAME 3
+#define IS_FILES_TABLE_CATALOG 4
+#define IS_FILES_TABLE_SCHEMA 5
+#define IS_FILES_TABLE_NAME 6
+#define IS_FILES_LOGFILE_GROUP_NAME 7
+#define IS_FILES_LOGFILE_GROUP_NUMBER 8
+#define IS_FILES_ENGINE 9
+#define IS_FILES_FULLTEXT_KEYS 10
+#define IS_FILES_DELETED_ROWS 11
+#define IS_FILES_UPDATE_COUNT 12
+#define IS_FILES_FREE_EXTENTS 13
+#define IS_FILES_TOTAL_EXTENTS 14
+#define IS_FILES_EXTENT_SIZE 15
+#define IS_FILES_INITIAL_SIZE 16
+#define IS_FILES_MAXIMUM_SIZE 17
+#define IS_FILES_AUTOEXTEND_SIZE 18
+#define IS_FILES_CREATION_TIME 19
+#define IS_FILES_LAST_UPDATE_TIME 20
+#define IS_FILES_LAST_ACCESS_TIME 21
+#define IS_FILES_RECOVER_TIME 22
+#define IS_FILES_TRANSACTION_COUNTER 23
+#define IS_FILES_VERSION 24
+#define IS_FILES_ROW_FORMAT 25
+#define IS_FILES_TABLE_ROWS 26
+#define IS_FILES_AVG_ROW_LENGTH 27
+#define IS_FILES_DATA_LENGTH 28
+#define IS_FILES_MAX_DATA_LENGTH 29
+#define IS_FILES_INDEX_LENGTH 30
+#define IS_FILES_DATA_FREE 31
+#define IS_FILES_CREATE_TIME 32
+#define IS_FILES_UPDATE_TIME 33
+#define IS_FILES_CHECK_TIME 34
+#define IS_FILES_CHECKSUM 35
+#define IS_FILES_STATUS 36
+#define IS_FILES_EXTRA 37
+
find_files_result find_files(THD *thd, List<LEX_STRING> *files, const char *db,
const char *path, const char *wild, bool dir);
@@ -38,4 +90,46 @@ int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff);
int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table);
+void append_identifier(THD *thd, String *packet, const char *name,
+ uint length);
+void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
+int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
+bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
+bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
+
+void mysqld_list_processes(THD *thd,const char *user,bool verbose);
+int mysqld_show_status(THD *thd);
+int mysqld_show_variables(THD *thd,const char *wild);
+bool mysqld_show_storage_engines(THD *thd);
+bool mysqld_show_authors(THD *thd);
+bool mysqld_show_contributors(THD *thd);
+bool mysqld_show_privileges(THD *thd);
+char *make_backup_log_name(char *buff, const char *name, const char* log_ext);
+void calc_sum_of_all_status(STATUS_VAR *to);
+void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
+ const LEX_STRING *definer_host);
+int add_status_vars(SHOW_VAR *list);
+void remove_status_vars(SHOW_VAR *list);
+void init_status_vars();
+void free_status_vars();
+void reset_status_vars();
+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();
+
+ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name);
+ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx);
+int make_schema_select(THD *thd, SELECT_LEX *sel,
+ enum enum_schema_tables schema_table_idx);
+int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list);
+bool get_schema_tables_result(JOIN *join,
+ enum enum_schema_table_state executed_place);
+enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table);
+
+/* These functions were under INNODB_COMPATIBILITY_HOOKS */
+int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
+
#endif /* SQL_SHOW_H */
diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc
new file mode 100644
index 00000000000..09e9a828fa1
--- /dev/null
+++ b/sql/sql_signal.cc
@@ -0,0 +1,506 @@
+/* Copyright (C) 2008 Sun Microsystems, Inc
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "sql_priv.h"
+#include "sp_head.h"
+#include "sp_pcontext.h"
+#include "sp_rcontext.h"
+#include "sql_signal.h"
+
+/*
+ The parser accepts any error code (desired)
+ The runtime internally supports any error code (desired)
+ The client server protocol is limited to 16 bits error codes (restriction)
+ Enforcing the 65535 limit in the runtime until the protocol can change.
+*/
+#define MAX_MYSQL_ERRNO UINT_MAX16
+
+const LEX_STRING Diag_condition_item_names[]=
+{
+ { C_STRING_WITH_LEN("CLASS_ORIGIN") },
+ { C_STRING_WITH_LEN("SUBCLASS_ORIGIN") },
+ { C_STRING_WITH_LEN("CONSTRAINT_CATALOG") },
+ { C_STRING_WITH_LEN("CONSTRAINT_SCHEMA") },
+ { C_STRING_WITH_LEN("CONSTRAINT_NAME") },
+ { C_STRING_WITH_LEN("CATALOG_NAME") },
+ { C_STRING_WITH_LEN("SCHEMA_NAME") },
+ { C_STRING_WITH_LEN("TABLE_NAME") },
+ { C_STRING_WITH_LEN("COLUMN_NAME") },
+ { C_STRING_WITH_LEN("CURSOR_NAME") },
+ { C_STRING_WITH_LEN("MESSAGE_TEXT") },
+ { C_STRING_WITH_LEN("MYSQL_ERRNO") },
+
+ { C_STRING_WITH_LEN("CONDITION_IDENTIFIER") },
+ { C_STRING_WITH_LEN("CONDITION_NUMBER") },
+ { C_STRING_WITH_LEN("CONNECTION_NAME") },
+ { C_STRING_WITH_LEN("MESSAGE_LENGTH") },
+ { C_STRING_WITH_LEN("MESSAGE_OCTET_LENGTH") },
+ { C_STRING_WITH_LEN("PARAMETER_MODE") },
+ { C_STRING_WITH_LEN("PARAMETER_NAME") },
+ { C_STRING_WITH_LEN("PARAMETER_ORDINAL_POSITION") },
+ { C_STRING_WITH_LEN("RETURNED_SQLSTATE") },
+ { C_STRING_WITH_LEN("ROUTINE_CATALOG") },
+ { C_STRING_WITH_LEN("ROUTINE_NAME") },
+ { C_STRING_WITH_LEN("ROUTINE_SCHEMA") },
+ { C_STRING_WITH_LEN("SERVER_NAME") },
+ { C_STRING_WITH_LEN("SPECIFIC_NAME") },
+ { C_STRING_WITH_LEN("TRIGGER_CATALOG") },
+ { C_STRING_WITH_LEN("TRIGGER_NAME") },
+ { C_STRING_WITH_LEN("TRIGGER_SCHEMA") }
+};
+
+const LEX_STRING Diag_statement_item_names[]=
+{
+ { C_STRING_WITH_LEN("NUMBER") },
+ { C_STRING_WITH_LEN("MORE") },
+ { C_STRING_WITH_LEN("COMMAND_FUNCTION") },
+ { C_STRING_WITH_LEN("COMMAND_FUNCTION_CODE") },
+ { C_STRING_WITH_LEN("DYNAMIC_FUNCTION") },
+ { C_STRING_WITH_LEN("DYNAMIC_FUNCTION_CODE") },
+ { C_STRING_WITH_LEN("ROW_COUNT") },
+ { C_STRING_WITH_LEN("TRANSACTIONS_COMMITTED") },
+ { C_STRING_WITH_LEN("TRANSACTIONS_ROLLED_BACK") },
+ { C_STRING_WITH_LEN("TRANSACTION_ACTIVE") }
+};
+
+
+Set_signal_information::Set_signal_information(
+ const Set_signal_information& set)
+{
+ memcpy(m_item, set.m_item, sizeof(m_item));
+}
+
+void Set_signal_information::clear()
+{
+ memset(m_item, 0, sizeof(m_item));
+}
+
+void Signal_common::assign_defaults(MYSQL_ERROR *cond,
+ bool set_level_code,
+ MYSQL_ERROR::enum_warning_level level,
+ int sqlcode)
+{
+ if (set_level_code)
+ {
+ cond->m_level= level;
+ cond->m_sql_errno= sqlcode;
+ }
+ if (! cond->get_message_text())
+ cond->set_builtin_message_text(ER(sqlcode));
+}
+
+void Signal_common::eval_defaults(THD *thd, MYSQL_ERROR *cond)
+{
+ DBUG_ASSERT(cond);
+
+ const char* sqlstate;
+ bool set_defaults= (m_cond != 0);
+
+ if (set_defaults)
+ {
+ /*
+ SIGNAL is restricted in sql_yacc.yy to only signal SQLSTATE conditions.
+ */
+ DBUG_ASSERT(m_cond->type == sp_cond_type::state);
+ sqlstate= m_cond->sqlstate;
+ cond->set_sqlstate(sqlstate);
+ }
+ else
+ sqlstate= cond->get_sqlstate();
+
+ DBUG_ASSERT(sqlstate);
+ /* SQLSTATE class "00": illegal, rejected in the parser. */
+ DBUG_ASSERT((sqlstate[0] != '0') || (sqlstate[1] != '0'));
+
+ if ((sqlstate[0] == '0') && (sqlstate[1] == '1'))
+ {
+ /* SQLSTATE class "01": warning. */
+ assign_defaults(cond, set_defaults,
+ MYSQL_ERROR::WARN_LEVEL_WARN, ER_SIGNAL_WARN);
+ }
+ else if ((sqlstate[0] == '0') && (sqlstate[1] == '2'))
+ {
+ /* SQLSTATE class "02": not found. */
+ assign_defaults(cond, set_defaults,
+ MYSQL_ERROR::WARN_LEVEL_ERROR, ER_SIGNAL_NOT_FOUND);
+ }
+ else
+ {
+ /* other SQLSTATE classes : error. */
+ assign_defaults(cond, set_defaults,
+ MYSQL_ERROR::WARN_LEVEL_ERROR, ER_SIGNAL_EXCEPTION);
+ }
+}
+
+static bool assign_fixed_string(MEM_ROOT *mem_root,
+ CHARSET_INFO *dst_cs,
+ size_t max_char,
+ String *dst,
+ const String* src)
+{
+ bool truncated;
+ size_t numchars;
+ CHARSET_INFO *src_cs;
+ const char* src_str;
+ const char* src_end;
+ size_t src_len;
+ size_t to_copy;
+ char* dst_str;
+ size_t dst_len;
+ size_t dst_copied;
+ uint32 dummy_offset;
+
+ src_str= src->ptr();
+ if (src_str == NULL)
+ {
+ dst->set((const char*) NULL, 0, dst_cs);
+ return false;
+ }
+
+ src_cs= src->charset();
+ src_len= src->length();
+ src_end= src_str + src_len;
+ numchars= src_cs->cset->numchars(src_cs, src_str, src_end);
+
+ if (numchars <= max_char)
+ {
+ to_copy= src->length();
+ truncated= false;
+ }
+ else
+ {
+ numchars= max_char;
+ to_copy= dst_cs->cset->charpos(dst_cs, src_str, src_end, numchars);
+ truncated= true;
+ }
+
+ if (String::needs_conversion(to_copy, src_cs, dst_cs, & dummy_offset))
+ {
+ dst_len= numchars * dst_cs->mbmaxlen;
+ dst_str= (char*) alloc_root(mem_root, dst_len + 1);
+ if (dst_str)
+ {
+ const char* well_formed_error_pos;
+ const char* cannot_convert_error_pos;
+ const char* from_end_pos;
+
+ dst_copied= well_formed_copy_nchars(dst_cs, dst_str, dst_len,
+ src_cs, src_str, src_len,
+ numchars,
+ & well_formed_error_pos,
+ & cannot_convert_error_pos,
+ & from_end_pos);
+ DBUG_ASSERT(dst_copied <= dst_len);
+ dst_len= dst_copied; /* In case the copy truncated the data */
+ dst_str[dst_copied]= '\0';
+ }
+ }
+ else
+ {
+ dst_len= to_copy;
+ dst_str= (char*) alloc_root(mem_root, dst_len + 1);
+ if (dst_str)
+ {
+ memcpy(dst_str, src_str, to_copy);
+ dst_str[to_copy]= '\0';
+ }
+ }
+ dst->set(dst_str, dst_len, dst_cs);
+
+ return truncated;
+}
+
+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;
+ bool truncated;
+
+ DBUG_ENTER("assign_condition_item");
+
+ if (set->is_null())
+ {
+ thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR, name, "NULL");
+ DBUG_RETURN(1);
+ }
+
+ str= set->val_str(& str_value);
+ truncated= assign_fixed_string(mem_root, & my_charset_utf8_bin, 64, ci, str);
+ if (truncated)
+ {
+ if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES))
+ {
+ thd->raise_error_printf(ER_COND_ITEM_TOO_LONG, name);
+ DBUG_RETURN(1);
+ }
+
+ thd->raise_warning_printf(WARN_COND_ITEM_TRUNCATED, name);
+ }
+
+ DBUG_RETURN(0);
+}
+
+
+int Signal_common::eval_signal_informations(THD *thd, MYSQL_ERROR *cond)
+{
+ struct cond_item_map
+ {
+ enum enum_diag_condition_item_name m_item;
+ String MYSQL_ERROR::*m_member;
+ };
+
+ static cond_item_map map[]=
+ {
+ { DIAG_CLASS_ORIGIN, & MYSQL_ERROR::m_class_origin },
+ { DIAG_SUBCLASS_ORIGIN, & MYSQL_ERROR::m_subclass_origin },
+ { DIAG_CONSTRAINT_CATALOG, & MYSQL_ERROR::m_constraint_catalog },
+ { DIAG_CONSTRAINT_SCHEMA, & MYSQL_ERROR::m_constraint_schema },
+ { DIAG_CONSTRAINT_NAME, & MYSQL_ERROR::m_constraint_name },
+ { DIAG_CATALOG_NAME, & MYSQL_ERROR::m_catalog_name },
+ { DIAG_SCHEMA_NAME, & MYSQL_ERROR::m_schema_name },
+ { DIAG_TABLE_NAME, & MYSQL_ERROR::m_table_name },
+ { DIAG_COLUMN_NAME, & MYSQL_ERROR::m_column_name },
+ { DIAG_CURSOR_NAME, & MYSQL_ERROR::m_cursor_name }
+ };
+
+ Item *set;
+ String str_value;
+ String *str;
+ int i;
+ uint j;
+ int result= 1;
+ enum enum_diag_condition_item_name item_enum;
+ String *member;
+ const LEX_STRING *name;
+
+ DBUG_ENTER("Signal_common::eval_signal_informations");
+
+ for (i= FIRST_DIAG_SET_PROPERTY;
+ i <= LAST_DIAG_SET_PROPERTY;
+ i++)
+ {
+ set= m_set_signal_information.m_item[i];
+ if (set)
+ {
+ if (! set->fixed)
+ {
+ if (set->fix_fields(thd, & set))
+ goto end;
+ m_set_signal_information.m_item[i]= set;
+ }
+ }
+ }
+
+ /*
+ Generically assign all the UTF8 String 64 condition items
+ described in the map.
+ */
+ for (j= 0; j < array_elements(map); j++)
+ {
+ item_enum= map[j].m_item;
+ set= m_set_signal_information.m_item[item_enum];
+ if (set != NULL)
+ {
+ member= & (cond->* map[j].m_member);
+ name= & Diag_condition_item_names[item_enum];
+ if (assign_condition_item(cond->m_mem_root, name->str, thd, set, member))
+ goto end;
+ }
+ }
+
+ /*
+ Assign the remaining attributes.
+ */
+
+ set= m_set_signal_information.m_item[DIAG_MESSAGE_TEXT];
+ if (set != NULL)
+ {
+ if (set->is_null())
+ {
+ thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
+ "MESSAGE_TEXT", "NULL");
+ goto end;
+ }
+ /*
+ Enforce that SET MESSAGE_TEXT = <value> evaluates the value
+ as VARCHAR(128) CHARACTER SET UTF8.
+ */
+ bool truncated;
+ String utf8_text;
+ str= set->val_str(& str_value);
+ truncated= assign_fixed_string(thd->mem_root, & my_charset_utf8_bin, 128,
+ & utf8_text, str);
+ if (truncated)
+ {
+ if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES))
+ {
+ thd->raise_error_printf(ER_COND_ITEM_TOO_LONG,
+ "MESSAGE_TEXT");
+ goto end;
+ }
+
+ thd->raise_warning_printf(WARN_COND_ITEM_TRUNCATED,
+ "MESSAGE_TEXT");
+ }
+
+ /*
+ See the comments
+ "Design notes about MYSQL_ERROR::m_message_text."
+ in file sql_error.cc
+ */
+ String converted_text;
+ converted_text.set_charset(error_message_charset_info);
+ converted_text.append(utf8_text.ptr(), utf8_text.length(),
+ utf8_text.charset());
+ cond->set_builtin_message_text(converted_text.c_ptr_safe());
+ }
+
+ set= m_set_signal_information.m_item[DIAG_MYSQL_ERRNO];
+ if (set != NULL)
+ {
+ if (set->is_null())
+ {
+ thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
+ "MYSQL_ERRNO", "NULL");
+ goto end;
+ }
+ longlong code= set->val_int();
+ if ((code <= 0) || (code > MAX_MYSQL_ERRNO))
+ {
+ str= set->val_str(& str_value);
+ thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
+ "MYSQL_ERRNO", str->c_ptr_safe());
+ goto end;
+ }
+ cond->m_sql_errno= (int) code;
+ }
+
+ /*
+ The various item->val_xxx() methods don't return an error code,
+ but flag thd in case of failure.
+ */
+ if (! thd->is_error())
+ result= 0;
+
+end:
+ for (i= FIRST_DIAG_SET_PROPERTY;
+ i <= LAST_DIAG_SET_PROPERTY;
+ i++)
+ {
+ set= m_set_signal_information.m_item[i];
+ if (set)
+ {
+ if (set->fixed)
+ set->cleanup();
+ }
+ }
+
+ DBUG_RETURN(result);
+}
+
+bool Signal_common::raise_condition(THD *thd, MYSQL_ERROR *cond)
+{
+ bool result= TRUE;
+
+ DBUG_ENTER("Signal_common::raise_condition");
+
+ DBUG_ASSERT(m_lex->query_tables == NULL);
+
+ eval_defaults(thd, cond);
+ if (eval_signal_informations(thd, cond))
+ DBUG_RETURN(result);
+
+ /* SIGNAL should not signal WARN_LEVEL_NOTE */
+ DBUG_ASSERT((cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN) ||
+ (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR));
+
+ MYSQL_ERROR *raised= NULL;
+ raised= thd->raise_condition(cond->get_sql_errno(),
+ cond->get_sqlstate(),
+ cond->get_level(),
+ cond->get_message_text());
+ if (raised)
+ raised->copy_opt_attributes(cond);
+
+ if (cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN)
+ {
+ my_ok(thd);
+ result= FALSE;
+ }
+
+ DBUG_RETURN(result);
+}
+
+bool Signal_statement::execute(THD *thd)
+{
+ bool result= TRUE;
+ MYSQL_ERROR cond(thd->mem_root);
+
+ DBUG_ENTER("Signal_statement::execute");
+
+ /*
+ WL#2110 SIGNAL specification says:
+
+ When SIGNAL is executed, it has five effects, in the following order:
+
+ (1) First, the diagnostics area is completely cleared. So if the
+ SIGNAL is in a DECLARE HANDLER then any pending errors or warnings
+ are gone. So is 'row count'.
+
+ This has roots in the SQL standard specification for SIGNAL.
+ */
+
+ thd->stmt_da->reset_diagnostics_area();
+ thd->set_row_count_func(0);
+ thd->warning_info->clear_warning_info(thd->query_id);
+
+ result= raise_condition(thd, &cond);
+
+ DBUG_RETURN(result);
+}
+
+
+bool Resignal_statement::execute(THD *thd)
+{
+ MYSQL_ERROR *signaled;
+ int result= TRUE;
+
+ DBUG_ENTER("Resignal_statement::execute");
+
+ thd->warning_info->m_warn_id= thd->query_id;
+
+ if (! thd->spcont || ! (signaled= thd->spcont->raised_condition()))
+ {
+ thd->raise_error(ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER);
+ DBUG_RETURN(result);
+ }
+
+ if (m_cond == NULL)
+ {
+ /* RESIGNAL without signal_value */
+ result= raise_condition(thd, signaled);
+ DBUG_RETURN(result);
+ }
+
+ /* RESIGNAL with signal_value */
+ result= raise_condition(thd, signaled);
+
+ DBUG_RETURN(result);
+}
+
diff --git a/sql/sql_signal.h b/sql/sql_signal.h
new file mode 100644
index 00000000000..c9c1517f4ad
--- /dev/null
+++ b/sql/sql_signal.h
@@ -0,0 +1,152 @@
+/* Copyright (C) 2008 Sun Microsystems, Inc
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef SQL_SIGNAL_H
+#define SQL_SIGNAL_H
+
+/**
+ Signal_common represents the common properties of the SIGNAL and RESIGNAL
+ statements.
+*/
+class Signal_common : public Sql_statement
+{
+protected:
+ /**
+ Constructor.
+ @param lex the LEX structure for this statement.
+ @param cond the condition signaled if any, or NULL.
+ @param set collection of signal condition item assignments.
+ */
+ Signal_common(LEX *lex,
+ const sp_cond_type_t *cond,
+ const Set_signal_information& set)
+ : Sql_statement(lex),
+ m_cond(cond),
+ m_set_signal_information(set)
+ {}
+
+ virtual ~Signal_common()
+ {}
+
+ /**
+ Assign the condition items 'MYSQL_ERRNO', 'level' and 'MESSAGE_TEXT'
+ default values of a condition.
+ @param cond the condition to update.
+ @param set_level_code true if 'level' and 'MYSQL_ERRNO' needs to be overwritten
+ @param level the level to assign
+ @param sqlcode the sql code to assign
+ */
+ static void assign_defaults(MYSQL_ERROR *cond,
+ bool set_level_code,
+ MYSQL_ERROR::enum_warning_level level,
+ int sqlcode);
+
+ /**
+ Evaluate the condition items 'SQLSTATE', 'MYSQL_ERRNO', 'level' and 'MESSAGE_TEXT'
+ default values for this statement.
+ @param thd the current thread.
+ @param cond the condition to update.
+ */
+ void eval_defaults(THD *thd, MYSQL_ERROR *cond);
+
+ /**
+ Evaluate each signal condition items for this statement.
+ @param thd the current thread.
+ @param cond the condition to update.
+ @return 0 on success.
+ */
+ int eval_signal_informations(THD *thd, MYSQL_ERROR *cond);
+
+ /**
+ Raise a SQL condition.
+ @param thd the current thread.
+ @param cond the condition to raise.
+ @return false on success.
+ */
+ bool raise_condition(THD *thd, MYSQL_ERROR *cond);
+
+ /**
+ The condition to signal or resignal.
+ This member is optional and can be NULL (RESIGNAL).
+ */
+ const sp_cond_type_t *m_cond;
+
+ /**
+ Collection of 'SET item = value' assignments in the
+ SIGNAL/RESIGNAL statement.
+ */
+ Set_signal_information m_set_signal_information;
+};
+
+/**
+ Signal_statement represents a SIGNAL statement.
+*/
+class Signal_statement : public Signal_common
+{
+public:
+ /**
+ Constructor, used to represent a SIGNAL statement.
+ @param lex the LEX structure for this statement.
+ @param cond the SQL condition to signal (required).
+ @param set the collection of signal informations to signal.
+ */
+ Signal_statement(LEX *lex,
+ const sp_cond_type_t *cond,
+ const Set_signal_information& set)
+ : Signal_common(lex, cond, set)
+ {}
+
+ virtual ~Signal_statement()
+ {}
+
+ /**
+ Execute a SIGNAL statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ virtual bool execute(THD *thd);
+};
+
+/**
+ Resignal_statement represents a RESIGNAL statement.
+*/
+class Resignal_statement : public Signal_common
+{
+public:
+ /**
+ Constructor, used to represent a RESIGNAL statement.
+ @param lex the LEX structure for this statement.
+ @param cond the SQL condition to resignal (optional, may be NULL).
+ @param set the collection of signal informations to resignal.
+ */
+ Resignal_statement(LEX *lex,
+ const sp_cond_type_t *cond,
+ const Set_signal_information& set)
+ : Signal_common(lex, cond, set)
+ {}
+
+ virtual ~Resignal_statement()
+ {}
+
+ /**
+ Execute a RESIGNAL statement at runtime.
+ @param thd the current thread.
+ @return 0 on success.
+ */
+ virtual bool execute(THD *thd);
+};
+
+#endif
+
diff --git a/sql/sql_sort.h b/sql/sql_sort.h
index 1e9322f7f5b..45ef14c1319 100644
--- a/sql/sql_sort.h
+++ b/sql/sql_sort.h
@@ -1,3 +1,6 @@
+#ifndef SQL_SORT_INCLUDED
+#define SQL_SORT_INCLUDED
+
/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -13,6 +16,18 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "my_global.h" /* uchar */
+#include "my_base.h" /* ha_rows */
+#include "my_sys.h" /* qsort2_cmp */
+
+typedef struct st_buffpek BUFFPEK;
+typedef struct st_queue QUEUE;
+typedef struct st_sort_field SORT_FIELD;
+
+class Field;
+struct TABLE;
+
+
/* Defines used by filesort and uniques */
#define MERGEBUFF 7
@@ -87,3 +102,5 @@ int merge_buffers(SORTPARAM *param,IO_CACHE *from_file,
BUFFPEK *lastbuff,BUFFPEK *Fb,
BUFFPEK *Tb,int flag);
void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length);
+
+#endif /* SQL_SORT_INCLUDED */
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index a41f4d52101..4b7dab243d2 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -23,17 +23,7 @@
#include <my_sys.h>
#include <m_string.h>
#include <m_ctype.h>
-#ifdef HAVE_FCONVERT
-#include <floatingpoint.h>
-#endif
-
-/*
- The following extern declarations are ok as these are interface functions
- required by the string function
-*/
-
-extern uchar* sql_alloc(unsigned size);
-extern void sql_element_free(void *ptr);
+#include <mysql_com.h>
#include "sql_string.h"
@@ -41,9 +31,12 @@ extern void sql_element_free(void *ptr);
** String functions
*****************************************************************************/
-bool String::real_alloc(uint32 arg_length)
+bool String::real_alloc(uint32 length)
{
- arg_length=ALIGN_SIZE(arg_length+1);
+ uint32 arg_length= ALIGN_SIZE(length + 1);
+ DBUG_ASSERT(arg_length > length);
+ if (arg_length <= length)
+ return TRUE; /* Overflow */
str_length=0;
if (Alloced_length < arg_length)
{
@@ -66,6 +59,9 @@ bool String::real_alloc(uint32 arg_length)
bool String::realloc(uint32 alloc_length)
{
uint32 len=ALIGN_SIZE(alloc_length+1);
+ DBUG_ASSERT(len > alloc_length);
+ if (len <= alloc_length)
+ return TRUE; /* Overflow */
if (Alloced_length < len)
{
char *new_ptr;
@@ -106,83 +102,19 @@ bool String::set_int(longlong num, bool unsigned_flag, CHARSET_INFO *cs)
bool String::set_real(double num,uint decimals, CHARSET_INFO *cs)
{
- char buff[331];
+ char buff[FLOATING_POINT_BUFFER];
uint dummy_errors;
+ size_t len;
str_charset=cs;
if (decimals >= NOT_FIXED_DEC)
{
- // Enough for a DATETIME
- uint32 len= sprintf(buff, "%.15g", num);
+ len= my_gcvt(num, MY_GCVT_ARG_DOUBLE, sizeof(buff) - 1, buff, NULL);
return copy(buff, len, &my_charset_latin1, cs, &dummy_errors);
}
-#ifdef HAVE_FCONVERT
- int decpt,sign;
- char *pos,*to;
-
- VOID(fconvert(num,(int) decimals,&decpt,&sign,buff+1));
- if (!my_isdigit(&my_charset_latin1, buff[1]))
- { // Nan or Inf
- pos=buff+1;
- if (sign)
- {
- buff[0]='-';
- pos=buff;
- }
- uint dummy_errors;
- return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs, &dummy_errors);
- }
- if (alloc((uint32) ((uint32) decpt+3+decimals)))
- return TRUE;
- to=Ptr;
- if (sign)
- *to++='-';
-
- pos=buff+1;
- if (decpt < 0)
- { /* value is < 0 */
- *to++='0';
- if (!decimals)
- goto end;
- *to++='.';
- if ((uint32) -decpt > decimals)
- decpt= - (int) decimals;
- decimals=(uint32) ((int) decimals+decpt);
- while (decpt++ < 0)
- *to++='0';
- }
- else if (decpt == 0)
- {
- *to++= '0';
- if (!decimals)
- goto end;
- *to++='.';
- }
- else
- {
- while (decpt-- > 0)
- *to++= *pos++;
- if (!decimals)
- goto end;
- *to++='.';
- }
- while (decimals--)
- *to++= *pos++;
-
-end:
- *to=0;
- str_length=(uint32) (to-Ptr);
- return FALSE;
-#else
-#ifdef HAVE_SNPRINTF
- buff[sizeof(buff)-1]=0; // Safety
- snprintf(buff,sizeof(buff)-1, "%.*f",(int) decimals,num);
-#else
- sprintf(buff,"%.*f",(int) decimals,num);
-#endif
- return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs,
+ len= my_fcvt(num, decimals, buff, NULL);
+ return copy(buff, (uint32) len, &my_charset_latin1, cs,
&dummy_errors);
-#endif
}
@@ -472,6 +404,16 @@ bool String::append(const char *s)
}
+
+bool String::append_ulonglong(ulonglong val)
+{
+ if (realloc(str_length+MAX_BIGINT_WIDTH+2))
+ return TRUE;
+ char *end= (char*) longlong10_to_str(val, (char*) Ptr + str_length, 10);
+ str_length= end - Ptr;
+ return FALSE;
+}
+
/*
Append a string in the given charset to the string
with character set recoding
@@ -479,11 +421,25 @@ bool String::append(const char *s)
bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs)
{
- uint32 dummy_offset;
+ uint32 offset;
- if (needs_conversion(arg_length, cs, str_charset, &dummy_offset))
+ if (needs_conversion(arg_length, cs, str_charset, &offset))
{
- uint32 add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen;
+ uint32 add_length;
+ if ((cs == &my_charset_bin) && offset)
+ {
+ DBUG_ASSERT(str_charset->mbminlen > offset);
+ offset= str_charset->mbminlen - offset; // How many characters to pad
+ add_length= arg_length + offset;
+ if (realloc(str_length + add_length))
+ return TRUE;
+ bzero((char*) Ptr + str_length, offset);
+ memcpy(Ptr + str_length + offset, s, arg_length);
+ str_length+= add_length;
+ return FALSE;
+ }
+
+ add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen;
uint dummy_errors;
if (realloc(str_length + add_length))
return TRUE;
@@ -500,22 +456,6 @@ bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs)
return FALSE;
}
-
-#ifdef TO_BE_REMOVED
-bool String::append(FILE* file, uint32 arg_length, myf my_flags)
-{
- if (realloc(str_length+arg_length))
- return TRUE;
- if (my_fread(file, (uchar*) Ptr + str_length, arg_length, my_flags))
- {
- shrink(str_length);
- return TRUE;
- }
- str_length+=arg_length;
- return FALSE;
-}
-#endif
-
bool String::append(IO_CACHE* file, uint32 arg_length)
{
if (realloc(str_length+arg_length))
@@ -677,7 +617,8 @@ void String::qs_append(const char *str, uint32 len)
void String::qs_append(double d)
{
char *buff = Ptr + str_length;
- str_length+= sprintf(buff, "%.15g", d);
+ str_length+= my_gcvt(d, MY_GCVT_ARG_DOUBLE, FLOATING_POINT_BUFFER - 1, buff,
+ NULL);
}
void String::qs_append(double *d)
@@ -795,10 +736,11 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
*/
-uint32
-copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
- const char *from, uint32 from_length, CHARSET_INFO *from_cs,
- uint *errors)
+static uint32
+copy_and_convert_extended(char *to, uint32 to_length, CHARSET_INFO *to_cs,
+ const char *from, uint32 from_length,
+ CHARSET_INFO *from_cs,
+ uint *errors)
{
int cnvres;
my_wc_t wc;
@@ -850,6 +792,65 @@ outp:
}
+/*
+ Optimized for quick copying of ASCII characters in the range 0x00..0x7F.
+*/
+uint32
+copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
+ const char *from, uint32 from_length, CHARSET_INFO *from_cs,
+ uint *errors)
+{
+ /*
+ If any of the character sets is not ASCII compatible,
+ immediately switch to slow mb_wc->wc_mb method.
+ */
+ if ((to_cs->state | from_cs->state) & MY_CS_NONASCII)
+ return copy_and_convert_extended(to, to_length, to_cs,
+ from, from_length, from_cs, errors);
+
+ uint32 length= min(to_length, from_length), length2= length;
+
+#if defined(__i386__)
+ /*
+ Special loop for i386, it allows to refer to a
+ non-aligned memory block as UINT32, which makes
+ it possible to copy four bytes at once. This
+ gives about 10% performance improvement comparing
+ to byte-by-byte loop.
+ */
+ for ( ; length >= 4; length-= 4, from+= 4, to+= 4)
+ {
+ if ((*(uint32*)from) & 0x80808080)
+ break;
+ *((uint32*) to)= *((const uint32*) from);
+ }
+#endif
+
+ for (; ; *to++= *from++, length--)
+ {
+ if (!length)
+ {
+ *errors= 0;
+ return length2;
+ }
+ if (*((unsigned char*) from) > 0x7F) /* A non-ASCII character */
+ {
+ uint32 copied_length= length2 - length;
+ to_length-= copied_length;
+ from_length-= copied_length;
+ return copied_length + copy_and_convert_extended(to, to_length,
+ to_cs,
+ from, from_length,
+ from_cs,
+ errors);
+ }
+ }
+
+ DBUG_ASSERT(FALSE); // Should never get to here
+ return 0; // Make compiler happy
+}
+
+
/**
Copy string with HEX-encoding of "bad" characters.
@@ -988,6 +989,24 @@ well_formed_copy_nchars(CHARSET_INFO *to_cs,
uint pad_length= to_cs->mbminlen - from_offset;
bzero(to, pad_length);
memmove(to + pad_length, from, from_offset);
+ /*
+ In some cases left zero-padding can create an incorrect character.
+ For example:
+ INSERT INTO t1 (utf32_column) VALUES (0x110000);
+ We'll pad the value to 0x00110000, which is a wrong UTF32 sequence!
+ The valid characters range is limited to 0x00000000..0x0010FFFF.
+
+ Make sure we didn't pad to an incorrect character.
+ */
+ if (to_cs->cset->well_formed_len(to_cs,
+ to, to + to_cs->mbminlen, 1,
+ &well_formed_error) !=
+ to_cs->mbminlen)
+ {
+ *from_end_pos= *well_formed_error_pos= from;
+ *cannot_convert_error_pos= NULL;
+ return 0;
+ }
nchars--;
from+= from_offset;
from_length-= from_offset;
diff --git a/sql/sql_string.h b/sql/sql_string.h
index b15179bcbe5..3642a96de35 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -1,3 +1,6 @@
+#ifndef SQL_STRING_INCLUDED
+#define SQL_STRING_INCLUDED
+
/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -19,11 +22,15 @@
#pragma interface /* gcc class implementation */
#endif
-#ifndef NOT_FIXED_DEC
-#define NOT_FIXED_DEC 31
-#endif
+#include "m_ctype.h" /* my_charset_bin */
+#include "my_sys.h" /* alloc_root, my_free, my_realloc */
+#include "m_string.h" /* TRASH */
class String;
+typedef struct charset_info_st CHARSET_INFO;
+typedef struct st_io_cache IO_CACHE;
+typedef struct st_mem_root MEM_ROOT;
+
int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
@@ -124,6 +131,11 @@ public:
(void) realloc(str_length);
return Ptr;
}
+ LEX_STRING lex_string() const
+ {
+ LEX_STRING lex_string = { (char*) ptr(), length() };
+ return lex_string;
+ }
void set(String &str,uint32 offset,uint32 arg_length)
{
@@ -197,7 +209,7 @@ public:
{
alloced=0;
Alloced_length=0;
- my_free(Ptr,MYF(0));
+ my_free(Ptr);
Ptr=0;
str_length=0; /* Safety */
}
@@ -257,8 +269,13 @@ public:
CHARSET_INFO *csto, uint *errors);
bool append(const String &s);
bool append(const char *s);
- bool append(const char *s,uint32 arg_length);
- bool append(const char *s,uint32 arg_length, CHARSET_INFO *cs);
+ bool append(LEX_STRING *ls)
+ {
+ return append(ls->str, ls->length);
+ }
+ bool append(const char *s, uint32 arg_length);
+ bool append(const char *s, uint32 arg_length, CHARSET_INFO *cs);
+ bool append_ulonglong(ulonglong val);
bool append(IO_CACHE* file, uint32 arg_length);
bool append_with_prefill(const char *s, uint32 arg_length,
uint32 full_length, char fill_char);
@@ -393,3 +410,5 @@ static inline bool check_if_only_end_space(CHARSET_INFO *cs, char *str,
{
return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end;
}
+
+#endif /* SQL_STRING_INCLUDED */
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index b919ea9eae7..772496a10d5 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -15,21 +15,46 @@
/* drop and alter of tables */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "debug_sync.h"
+#include "sql_table.h"
+#include "sql_rename.h" // do_rename
+#include "sql_parse.h" // test_if_data_home_dir
+#include "sql_cache.h" // query_cache_*
+#include "sql_base.h" // open_table_uncached, lock_table_names
+#include "lock.h" // mysql_unlock_tables
+#include "strfunc.h" // find_type2, find_set
+#include "sql_view.h" // view_checksum
+#include "sql_truncate.h" // regenerate_locked_table
+#include "sql_partition.h" // mem_alloc_error,
+ // generate_partition_syntax,
+ // partition_info
+#include "sql_db.h" // load_db_opt_by_name
+#include "sql_time.h" // make_truncated_value_warning
+#include "records.h" // init_read_record, end_read_record
+#include "filesort.h" // filesort_free_buffers
+#include "sql_select.h" // setup_order,
+ // make_unireg_sortorder
+#include "sql_handler.h" // mysql_ha_rm_tables
+#include "discover.h" // readfrm
+#include "my_pthread.h" // pthread_mutex_t
+#include "log_event.h" // Query_log_event
#include <hash.h>
#include <myisam.h>
#include <my_dir.h>
#include "sp_head.h"
+#include "sp.h"
#include "sql_trigger.h"
+#include "sql_parse.h"
#include "sql_show.h"
-#include "debug_sync.h"
+#include "transaction.h"
+#include "datadict.h" // dd_frm_type()
#ifdef __WIN__
#include <io.h>
#endif
-int creating_table= 0; // How many mysql_create_table are running
-
const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
@@ -50,23 +75,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
uint *db_options,
handler *file, KEY **key_info_buffer,
uint *key_count, int select_field_count);
-static bool
-mysql_prepare_alter_table(THD *thd, TABLE *table,
- HA_CREATE_INFO *create_info,
- Alter_info *alter_info);
-
-#ifndef DBUG_OFF
-
-/* Wait until we get a 'mysql_kill' signal */
-
-static void wait_for_kill_signal(THD *thd)
-{
- while (thd->killed == 0)
- sleep(1);
- // Reset signal and continue as if nothing happend
- thd->killed= THD::NOT_KILLED;
-}
-#endif
/**
@@ -292,7 +300,8 @@ uint explain_filename(THD* thd,
{
if (explain_mode == EXPLAIN_ALL_VERBOSE)
{
- to_p= strnmov(to_p, ER(ER_DATABASE_NAME), end_p - to_p);
+ to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_DATABASE_NAME),
+ end_p - to_p);
*(to_p++)= ' ';
to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len);
to_p= strnmov(to_p, ", ", end_p - to_p);
@@ -305,7 +314,7 @@ uint explain_filename(THD* thd,
}
if (explain_mode == EXPLAIN_ALL_VERBOSE)
{
- to_p= strnmov(to_p, ER(ER_TABLE_NAME), end_p - to_p);
+ to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TABLE_NAME), end_p - to_p);
*(to_p++)= ' ';
to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len);
}
@@ -322,18 +331,22 @@ uint explain_filename(THD* thd,
if (name_type != NORMAL)
{
if (name_type == TEMP)
- to_p= strnmov(to_p, ER(ER_TEMPORARY_NAME), end_p - to_p);
+ to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TEMPORARY_NAME),
+ end_p - to_p);
else
- to_p= strnmov(to_p, ER(ER_RENAMED_NAME), end_p - to_p);
+ to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_RENAMED_NAME),
+ end_p - to_p);
to_p= strnmov(to_p, " ", end_p - to_p);
}
- to_p= strnmov(to_p, ER(ER_PARTITION_NAME), end_p - to_p);
+ to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_PARTITION_NAME),
+ end_p - to_p);
*(to_p++)= ' ';
to_p= add_identifier(thd, to_p, end_p, part_name, part_name_len);
if (subpart_name)
{
to_p= strnmov(to_p, ", ", end_p - to_p);
- to_p= strnmov(to_p, ER(ER_SUBPARTITION_NAME), end_p - to_p);
+ to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_SUBPARTITION_NAME),
+ end_p - to_p);
*(to_p++)= ' ';
to_p= add_identifier(thd, to_p, end_p, subpart_name, subpart_name_len);
}
@@ -525,9 +538,9 @@ uint build_table_filename(char *buff, size_t bufflen, const char *db,
if (flags & FN_IS_TMP) // FN_FROM_IS_TMP | FN_TO_IS_TMP
strnmov(tbbuff, table_name, sizeof(tbbuff));
else
- VOID(tablename_to_filename(table_name, tbbuff, sizeof(tbbuff)));
+ (void) tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
- VOID(tablename_to_filename(db, dbbuff, sizeof(dbbuff)));
+ (void) tablename_to_filename(db, dbbuff, sizeof(dbbuff));
char *end = buff + bufflen;
/* Don't add FN_ROOTDIR if mysql_data_home already includes it */
@@ -638,7 +651,7 @@ struct st_global_ddl_log
st_global_ddl_log global_ddl_log;
-pthread_mutex_t LOCK_gdl;
+mysql_mutex_t LOCK_gdl;
#define DDL_LOG_ENTRY_TYPE_POS 0
#define DDL_LOG_ACTION_TYPE_POS 1
@@ -668,8 +681,8 @@ static bool read_ddl_log_file_entry(uint entry_no)
uint io_size= global_ddl_log.io_size;
DBUG_ENTER("read_ddl_log_file_entry");
- if (my_pread(file_id, file_entry_buf, io_size, io_size * entry_no,
- MYF(MY_WME)) != io_size)
+ if (mysql_file_pread(file_id, file_entry_buf, io_size, io_size * entry_no,
+ MYF(MY_WME)) != io_size)
error= TRUE;
DBUG_RETURN(error);
}
@@ -692,8 +705,8 @@ static bool write_ddl_log_file_entry(uint entry_no)
char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
DBUG_ENTER("write_ddl_log_file_entry");
- if (my_pwrite(file_id, (uchar*)file_entry_buf,
- IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE)
+ if (mysql_file_pwrite(file_id, (uchar*)file_entry_buf,
+ IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE)
error= TRUE;
DBUG_RETURN(error);
}
@@ -727,7 +740,7 @@ static bool write_ddl_log_header()
sql_print_error("Error writing ddl log header");
DBUG_RETURN(TRUE);
}
- VOID(sync_ddl_log());
+ (void) sync_ddl_log();
DBUG_RETURN(error);
}
@@ -769,8 +782,9 @@ static uint read_ddl_log_header()
DBUG_ENTER("read_ddl_log_header");
create_ddl_log_file_name(file_name);
- if ((global_ddl_log.file_id= my_open(file_name,
- O_RDWR | O_BINARY, MYF(0))) >= 0)
+ if ((global_ddl_log.file_id= mysql_file_open(key_file_global_ddl_log,
+ file_name,
+ O_RDWR | O_BINARY, MYF(0))) >= 0)
{
if (read_ddl_log_file_entry(0UL))
{
@@ -795,7 +809,7 @@ static uint read_ddl_log_header()
global_ddl_log.first_free= NULL;
global_ddl_log.first_used= NULL;
global_ddl_log.num_entries= 0;
- VOID(pthread_mutex_init(&LOCK_gdl, MY_MUTEX_INIT_FAST));
+ mysql_mutex_init(key_LOCK_gdl, &LOCK_gdl, MY_MUTEX_INIT_FAST);
global_ddl_log.do_release= true;
DBUG_RETURN(entry_no);
}
@@ -866,10 +880,10 @@ static bool init_ddl_log()
global_ddl_log.io_size= IO_SIZE;
global_ddl_log.name_len= FN_LEN;
create_ddl_log_file_name(file_name);
- if ((global_ddl_log.file_id= my_create(file_name,
- CREATE_MODE,
- O_RDWR | O_TRUNC | O_BINARY,
- MYF(MY_WME))) < 0)
+ if ((global_ddl_log.file_id= mysql_file_create(key_file_global_ddl_log,
+ file_name, CREATE_MODE,
+ O_RDWR | O_TRUNC | O_BINARY,
+ MYF(MY_WME))) < 0)
{
/* Couldn't create ddl log file, this is serious error */
sql_print_error("Failed to open ddl log file");
@@ -878,7 +892,7 @@ static bool init_ddl_log()
global_ddl_log.inited= TRUE;
if (write_ddl_log_header())
{
- VOID(my_close(global_ddl_log.file_id, MYF(MY_WME)));
+ (void) mysql_file_close(global_ddl_log.file_id, MYF(MY_WME));
global_ddl_log.inited= FALSE;
DBUG_RETURN(TRUE);
}
@@ -955,14 +969,14 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
if (frm_action)
{
strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
- if ((error= my_delete(to_path, MYF(MY_WME))))
+ if ((error= mysql_file_delete(key_file_frm, to_path, MYF(MY_WME))))
{
if (my_errno != ENOENT)
break;
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
strxmov(to_path, ddl_log_entry->name, par_ext, NullS);
- VOID(my_delete(to_path, MYF(MY_WME)));
+ (void) mysql_file_delete(key_file_partition, to_path, MYF(MY_WME));
#endif
}
else
@@ -975,7 +989,7 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
}
if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos)))
break;
- VOID(sync_ddl_log());
+ (void) sync_ddl_log();
error= FALSE;
if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION)
break;
@@ -994,12 +1008,12 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
{
strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS);
- if (my_rename(from_path, to_path, MYF(MY_WME)))
+ if (mysql_file_rename(key_file_frm, from_path, to_path, MYF(MY_WME)))
break;
#ifdef WITH_PARTITION_STORAGE_ENGINE
strxmov(to_path, ddl_log_entry->name, par_ext, NullS);
strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS);
- VOID(my_rename(from_path, to_path, MYF(MY_WME)));
+ (void) mysql_file_rename(key_file_partition, from_path, to_path, MYF(MY_WME));
#endif
}
else
@@ -1010,7 +1024,7 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
}
if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos)))
break;
- VOID(sync_ddl_log());
+ (void) sync_ddl_log();
error= FALSE;
break;
}
@@ -1065,6 +1079,7 @@ static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry,
*/
used_entry->next_log_entry= first_used;
used_entry->prev_log_entry= NULL;
+ used_entry->next_active_log_entry= NULL;
global_ddl_log.first_used= used_entry;
if (first_used)
first_used->prev_log_entry= used_entry;
@@ -1148,7 +1163,7 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry,
}
if (write_header && !error)
{
- VOID(sync_ddl_log());
+ (void) sync_ddl_log();
if (write_ddl_log_header())
error= TRUE;
}
@@ -1205,7 +1220,7 @@ bool write_execute_ddl_log_entry(uint first_entry,
any log entries before, we are only here to write the execute
entry to indicate it is done.
*/
- VOID(sync_ddl_log());
+ (void) sync_ddl_log();
file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_EXECUTE_CODE;
}
else
@@ -1229,7 +1244,7 @@ bool write_execute_ddl_log_entry(uint first_entry,
release_ddl_log_memory_entry(*active_entry);
DBUG_RETURN(TRUE);
}
- VOID(sync_ddl_log());
+ (void) sync_ddl_log();
if (write_header)
{
if (write_ddl_log_header())
@@ -1325,7 +1340,7 @@ bool sync_ddl_log()
{
DBUG_RETURN(TRUE);
}
- if (my_sync(global_ddl_log.file_id, MYF(0)))
+ if (mysql_file_sync(global_ddl_log.file_id, MYF(0)))
{
/* Write to error log */
sql_print_error("Failed to sync ddl log");
@@ -1381,7 +1396,7 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry)
uint read_entry= first_entry;
DBUG_ENTER("execute_ddl_log_entry");
- pthread_mutex_lock(&LOCK_gdl);
+ mysql_mutex_lock(&LOCK_gdl);
do
{
if (read_ddl_log_entry(read_entry, &ddl_log_entry))
@@ -1403,7 +1418,7 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry)
}
read_entry= ddl_log_entry.next_entry;
} while (read_entry);
- pthread_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(FALSE);
}
@@ -1421,7 +1436,7 @@ static void close_ddl_log()
DBUG_ENTER("close_ddl_log");
if (global_ddl_log.file_id >= 0)
{
- VOID(my_close(global_ddl_log.file_id, MYF(MY_WME)));
+ (void) mysql_file_close(global_ddl_log.file_id, MYF(MY_WME));
global_ddl_log.file_id= (File) -1;
}
DBUG_VOID_RETURN;
@@ -1481,7 +1496,7 @@ void execute_ddl_log_recovery()
}
close_ddl_log();
create_ddl_log_file_name(file_name);
- VOID(my_delete(file_name, MYF(0)));
+ (void) mysql_file_delete(key_file_global_ddl_log, file_name, MYF(0));
global_ddl_log.recovery_phase= FALSE;
delete thd;
/* Remember that we don't have a THD */
@@ -1507,23 +1522,23 @@ void release_ddl_log()
if (!global_ddl_log.do_release)
DBUG_VOID_RETURN;
- pthread_mutex_lock(&LOCK_gdl);
+ mysql_mutex_lock(&LOCK_gdl);
while (used_list)
{
DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry;
- my_free(used_list, MYF(0));
+ my_free(used_list);
used_list= tmp;
}
while (free_list)
{
DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry;
- my_free(free_list, MYF(0));
+ my_free(free_list);
free_list= tmp;
}
close_ddl_log();
global_ddl_log.inited= 0;
- pthread_mutex_unlock(&LOCK_gdl);
- VOID(pthread_mutex_destroy(&LOCK_gdl));
+ mysql_mutex_unlock(&LOCK_gdl);
+ mysql_mutex_destroy(&LOCK_gdl);
global_ddl_log.do_release= false;
DBUG_VOID_RETURN;
}
@@ -1634,7 +1649,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
{
if (!(part_syntax_buf= generate_partition_syntax(part_info,
&syntax_len,
- TRUE, TRUE)))
+ TRUE, TRUE,
+ lpt->create_info,
+ lpt->alter_info)))
{
DBUG_RETURN(TRUE);
}
@@ -1653,7 +1670,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
CHF_CREATE_FLAG,
lpt->create_info))
{
- my_delete(shadow_frm_name, MYF(0));
+ mysql_file_delete(key_file_frm, shadow_frm_name, MYF(0));
error= 1;
goto end;
}
@@ -1671,13 +1688,13 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
if (readfrm(shadow_path, &data, &length) ||
packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len))
{
- my_free(data, MYF(MY_ALLOW_ZERO_PTR));
- my_free(lpt->pack_frm_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(data);
+ my_free(lpt->pack_frm_data);
mem_alloc_error(length);
error= 1;
goto end;
}
- error= my_delete(shadow_frm_name, MYF(MY_WME));
+ error= mysql_file_delete(key_file_frm, shadow_frm_name, MYF(MY_WME));
}
if (flags & WFRM_INSTALL_SHADOW)
{
@@ -1700,20 +1717,19 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
completing this we write a new phase to the log entry that will
deactivate it.
*/
- VOID(pthread_mutex_lock(&LOCK_open));
- if (my_delete(frm_name, MYF(MY_WME)) ||
+ if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
#ifdef WITH_PARTITION_STORAGE_ENGINE
lpt->table->file->ha_create_handler_files(path, shadow_path,
CHF_DELETE_FLAG, NULL) ||
deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) ||
(sync_ddl_log(), FALSE) ||
-#endif
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) ||
+ mysql_file_rename(key_file_frm,
+ shadow_frm_name, frm_name, MYF(MY_WME)) ||
lpt->table->file->ha_create_handler_files(path, shadow_path,
CHF_RENAME_FLAG, NULL))
#else
- my_rename(shadow_frm_name, frm_name, MYF(MY_WME)))
+ mysql_file_rename(key_file_frm,
+ shadow_frm_name, frm_name, MYF(MY_WME)))
#endif
{
error= 1;
@@ -1726,7 +1742,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
char *tmp_part_syntax_str;
if (!(part_syntax_buf= generate_partition_syntax(part_info,
&syntax_len,
- TRUE, TRUE)))
+ TRUE, TRUE,
+ lpt->create_info,
+ lpt->alter_info)))
{
error= 1;
goto err;
@@ -1741,22 +1759,23 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
error= 1;
goto err;
}
- share->partition_info= tmp_part_syntax_str;
+ share->partition_info_str= tmp_part_syntax_str;
}
else
- memcpy((char*) share->partition_info, part_syntax_buf, syntax_len + 1);
- share->partition_info_len= part_info->part_info_len= syntax_len;
+ memcpy((char*) share->partition_info_str, part_syntax_buf,
+ syntax_len + 1);
+ share->partition_info_str_len= part_info->part_info_len= syntax_len;
part_info->part_info_string= part_syntax_buf;
}
#endif
err:
- VOID(pthread_mutex_unlock(&LOCK_open));
#ifdef WITH_PARTITION_STORAGE_ENGINE
deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos);
part_info->frm_log_entry= NULL;
- VOID(sync_ddl_log());
+ (void) sync_ddl_log();
#endif
+ ;
}
end:
@@ -1771,6 +1790,8 @@ end:
clear_error is clear_error to be called
query Query to log
query_length Length of query
+ is_trans if the event changes either
+ a trans or non-trans engine.
RETURN VALUES
NONE
@@ -1781,7 +1802,7 @@ end:
*/
int write_bin_log(THD *thd, bool clear_error,
- char const *query, ulong query_length)
+ char const *query, ulong query_length, bool is_trans)
{
int error= 0;
if (mysql_bin_log.is_open())
@@ -1792,7 +1813,8 @@ int write_bin_log(THD *thd, bool clear_error,
else
errcode= query_error_code(thd, TRUE);
error= thd->binlog_query(THD::STMT_QUERY_TYPE,
- query, query_length, FALSE, FALSE, errcode);
+ query, query_length, is_trans, FALSE, FALSE,
+ errcode);
}
return error;
}
@@ -1813,7 +1835,8 @@ int write_bin_log(THD *thd, bool clear_error,
If a table is in use, we will wait for all users to free the table
before dropping it
- Wait if global_read_lock (FLUSH TABLES WITH READ LOCK) is set.
+ Wait if global_read_lock (FLUSH TABLES WITH READ LOCK) is set, but
+ not if under LOCK TABLES.
RETURN
FALSE OK. In this case ok packet is sent to user
@@ -1824,123 +1847,189 @@ int write_bin_log(THD *thd, bool clear_error,
bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
my_bool drop_temporary)
{
- bool error= FALSE, need_start_waiters= FALSE;
- Drop_table_error_handler err_handler(thd->get_internal_handler());
+ bool error;
+ Drop_table_error_handler err_handler;
+ TABLE_LIST *table;
+
DBUG_ENTER("mysql_rm_table");
- /* mark for close and remove all cached entries */
+ /* Disable drop of enabled log tables, must be done before name locking */
+ for (table= tables; table; table= table->next_local)
+ {
+ if (check_if_log_table(table->db_length, table->db,
+ table->table_name_length, table->table_name, true))
+ {
+ my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
+ DBUG_RETURN(true);
+ }
+ }
+
+ mysql_ha_rm_tables(thd, tables);
if (!drop_temporary)
{
- if ((error= wait_if_global_read_lock(thd, 0, 1)))
+ if (!thd->locked_tables_mode)
{
- my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), tables->table_name);
- DBUG_RETURN(TRUE);
+ if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
+ MYSQL_OPEN_SKIP_TEMPORARY))
+ DBUG_RETURN(true);
+ for (table= tables; table; table= table->next_local)
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
+ false);
}
else
- need_start_waiters= TRUE;
+ {
+ for (table= tables; table; table= table->next_local)
+ if (table->open_type != OT_BASE_ONLY &&
+ find_temporary_table(thd, table))
+ {
+ /*
+ A temporary table.
+
+ Don't try to find a corresponding MDL lock or assign it
+ to table->mdl_request.ticket. There can't be metadata
+ locks for temporary tables: they are local to the session.
+
+ Later in this function we release the MDL lock only if
+ table->mdl_requeset.ticket is not NULL. Thus here we
+ ensure that we won't release the metadata lock on the base
+ table locked with LOCK TABLES as a side effect of temporary
+ table drop.
+ */
+ DBUG_ASSERT(table->mdl_request.ticket == NULL);
+ }
+ else
+ {
+ /*
+ Not a temporary table.
+
+ Since 'tables' list can't contain duplicates (this is ensured
+ by parser) it is safe to cache pointer to the TABLE instances
+ in its elements.
+ */
+ table->table= find_table_for_mdl_upgrade(thd->open_tables, table->db,
+ table->table_name, false);
+ if (!table->table)
+ DBUG_RETURN(true);
+ table->mdl_request.ticket= table->table->mdl_ticket;
+ }
+ }
}
- /*
- Acquire LOCK_open after wait_if_global_read_lock(). If we would hold
- LOCK_open during wait_if_global_read_lock(), other threads could not
- close their tables. This would make a pretty deadlock.
- */
+ /* mark for close and remove all cached entries */
thd->push_internal_handler(&err_handler);
- error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0);
+ error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary,
+ false, false);
thd->pop_internal_handler();
-
- if (need_start_waiters)
- start_waiting_global_read_lock(thd);
-
if (error)
DBUG_RETURN(TRUE);
my_ok(thd);
DBUG_RETURN(FALSE);
}
-/*
- Execute the drop of a normal or temporary table
-
- SYNOPSIS
- mysql_rm_table_part2()
- thd Thread handler
- tables Tables to drop
- if_exists If set, don't give an error if table doesn't exists.
- In this case we give an warning of level 'NOTE'
- drop_temporary Only drop temporary tables
- drop_view Allow to delete VIEW .frm
- dont_log_query Don't write query to log files. This will also not
- generate warnings if the handler files doesn't exists
-
- TODO:
- When logging to the binary log, we should log
- tmp_tables and transactional tables as separate statements if we
- are in a transaction; This is needed to get these tables into the
- cached binary log that is only written on COMMIT.
-
- The current code only writes DROP statements that only uses temporary
- tables to the cache binary log. This should be ok on most cases, but
- not all.
- RETURN
- 0 ok
- 1 Error
- -1 Thread was killed
+/**
+ Execute the drop of a normal or temporary table.
+
+ @param thd Thread handler
+ @param tables Tables to drop
+ @param if_exists If set, don't give an error if table doesn't exists.
+ In this case we give an warning of level 'NOTE'
+ @param drop_temporary Only drop temporary tables
+ @param drop_view Allow to delete VIEW .frm
+ @param dont_log_query Don't write query to log files. This will also not
+ generate warnings if the handler files doesn't exists
+
+ @retval 0 ok
+ @retval 1 Error
+ @retval -1 Thread was killed
+
+ @note This function assumes that metadata locks have already been taken.
+ It is also assumed that the tables have been removed from TDC.
+
+ @todo When logging to the binary log, we should log
+ tmp_tables and transactional tables as separate statements if we
+ are in a transaction; This is needed to get these tables into the
+ cached binary log that is only written on COMMIT.
+ The current code only writes DROP statements that only uses temporary
+ tables to the cache binary log. This should be ok on most cases, but
+ not all.
*/
-int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
- bool drop_temporary, bool drop_view,
- bool dont_log_query)
+int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
+ bool drop_temporary, bool drop_view,
+ bool dont_log_query)
{
TABLE_LIST *table;
- char path[FN_REFLEN + 1], *alias;
- uint path_length;
+ char path[FN_REFLEN + 1], *alias= NULL;
+ uint path_length= 0;
String wrong_tables;
int error= 0;
int non_temp_tables_count= 0;
- bool some_tables_deleted=0, tmp_table_deleted=0, foreign_key_error=0;
+ bool foreign_key_error=0;
+ bool non_tmp_error= 0;
+ bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
+ bool non_tmp_table_deleted= 0;
String built_query;
- String built_tmp_query;
- DBUG_ENTER("mysql_rm_table_part2");
+ String built_trans_tmp_query, built_non_trans_tmp_query;
+ DBUG_ENTER("mysql_rm_table_no_locks");
- LINT_INIT(alias);
- LINT_INIT(path_length);
+ /*
+ Prepares the drop statements that will be written into the binary
+ log as follows:
- if (thd->current_stmt_binlog_row_based && !dont_log_query)
- {
- built_query.set_charset(system_charset_info);
- if (if_exists)
- built_query.append("DROP TABLE IF EXISTS ");
- else
- built_query.append("DROP TABLE ");
- }
+ 1 - If we are not processing a "DROP TEMPORARY" it prepares a
+ "DROP".
- mysql_ha_rm_tables(thd, tables, FALSE);
+ 2 - A "DROP" may result in a "DROP TEMPORARY" but the opposite is
+ not true.
- pthread_mutex_lock(&LOCK_open);
+ 3 - If the current format is row, the IF EXISTS token needs to be
+ appended because one does not know if CREATE TEMPORARY was previously
+ written to the binary log.
- /* Disable drop of enabled log tables, must be done before name locking */
- for (table= tables; table; table= table->next_local)
+ 4 - Add the IF_EXISTS token if necessary, i.e. if_exists is TRUE.
+
+ 5 - For temporary tables, there is a need to differentiate tables
+ in transactional and non-transactional storage engines. For that,
+ reason, two types of drop statements are prepared.
+
+ The need to different the type of tables when dropping a temporary
+ table stems from the fact that such drop does not commit an ongoing
+ transaction and changes to non-transactional tables must be written
+ ahead of the transaction in some circumstances.
+ */
+ if (!dont_log_query)
{
- if (check_if_log_table(table->db_length, table->db,
- table->table_name_length, table->table_name, 1))
+ if (!drop_temporary)
{
- my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(1);
+ built_query.set_charset(system_charset_info);
+ if (if_exists)
+ built_query.append("DROP TABLE IF EXISTS ");
+ else
+ built_query.append("DROP TABLE ");
}
- }
- if (!drop_temporary && lock_table_names_exclusively(thd, tables))
- {
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(1);
+ if (thd->is_current_stmt_binlog_format_row() || if_exists)
+ {
+ built_trans_tmp_query.set_charset(system_charset_info);
+ built_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
+ built_non_trans_tmp_query.set_charset(system_charset_info);
+ built_non_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
+ }
+ else
+ {
+ built_trans_tmp_query.set_charset(system_charset_info);
+ built_trans_tmp_query.append("DROP TEMPORARY TABLE ");
+ built_non_trans_tmp_query.set_charset(system_charset_info);
+ built_non_trans_tmp_query.append("DROP TEMPORARY TABLE ");
+ }
}
for (table= tables; table; table= table->next_local)
{
+ bool is_trans;
char *db=table->db;
handlerton *table_type;
enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN;
@@ -1949,83 +2038,99 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
table->db, table->table_name, (long) table->table,
table->table ? (long) table->table->s : (long) -1));
- error= drop_temporary_table(thd, table);
+ /*
+ If we are in locked tables mode and are dropping a temporary table,
+ the ticket should be NULL to ensure that we don't release a lock
+ on a base table later.
+ */
+ DBUG_ASSERT(!(thd->locked_tables_mode &&
+ table->open_type != OT_BASE_ONLY &&
+ find_temporary_table(thd, table) &&
+ table->mdl_request.ticket != NULL));
+
+ /*
+ drop_temporary_table may return one of the following error codes:
+ . 0 - a temporary table was successfully dropped.
+ . 1 - a temporary table was not found.
+ . -1 - a temporary table is used by an outer statement.
+ */
+ if (table->open_type == OT_BASE_ONLY)
+ error= 1;
+ else if ((error= drop_temporary_table(thd, table, &is_trans)) == -1)
+ {
+ DBUG_ASSERT(thd->in_sub_stmt);
+ goto err;
+ }
+
+ if ((drop_temporary && if_exists) || !error)
+ {
+ /*
+ This handles the case of temporary tables. We have the following cases:
- switch (error) {
- case 0:
- // removed temporary table
- tmp_table_deleted= 1;
- if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED &&
- thd->current_stmt_binlog_row_based)
+ . "DROP TEMPORARY" was executed and a temporary table was affected
+ (i.e. drop_temporary && !error) or the if_exists was specified (i.e.
+ drop_temporary && if_exists).
+
+ . "DROP" was executed but a temporary table was affected (.i.e
+ !error).
+ */
+ if (!dont_log_query)
{
- if (built_tmp_query.is_empty())
- {
- built_tmp_query.set_charset(system_charset_info);
- built_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
- }
+ /*
+ If there is an error, we don't know the type of the engine
+ at this point. So, we keep it in the trx-cache.
+ */
+ is_trans= error ? TRUE : is_trans;
+ if (is_trans)
+ trans_tmp_table_deleted= TRUE;
+ else
+ non_trans_tmp_table_deleted= TRUE;
- built_tmp_query.append("`");
+ String *built_ptr_query=
+ (is_trans ? &built_trans_tmp_query : &built_non_trans_tmp_query);
+ /*
+ Don't write the database name if it is the current one (or if
+ thd->db is NULL).
+ */
+ built_ptr_query->append("`");
if (thd->db == NULL || strcmp(db,thd->db) != 0)
{
- built_tmp_query.append(db);
- built_tmp_query.append("`.`");
+ built_ptr_query->append(db);
+ built_ptr_query->append("`.`");
}
- built_tmp_query.append(table->table_name);
- built_tmp_query.append("`,");
+ built_ptr_query->append(table->table_name);
+ built_ptr_query->append("`,");
}
-
- continue;
- case -1:
- DBUG_ASSERT(thd->in_sub_stmt);
- error= 1;
- goto err_with_placeholders;
- default:
- // temporary table not found
- error= 0;
- }
-
- /*
- If row-based replication is used and the table is not a
- temporary table, we add the table name to the drop statement
- being built. The string always end in a comma and the comma
- will be chopped off before being written to the binary log.
+ /*
+ This means that a temporary table was droped and as such there
+ is no need to proceed with the code that tries to drop a regular
+ table.
*/
- if (!drop_temporary && thd->current_stmt_binlog_row_based && !dont_log_query)
+ if (!error) continue;
+ }
+ else if (!drop_temporary)
{
non_temp_tables_count++;
- /*
- Don't write the database name if it is the current one (or if
- thd->db is NULL).
- */
- built_query.append("`");
- if (thd->db == NULL || strcmp(db,thd->db) != 0)
+
+ if (thd->locked_tables_mode)
{
- built_query.append(db);
- built_query.append("`.`");
+ if (wait_while_table_is_used(thd, table->table, HA_EXTRA_FORCE_REOPEN))
+ {
+ error= -1;
+ goto err;
+ }
+ close_all_tables_for_name(thd, table->table->s, TRUE);
+ table->table= 0;
}
- built_query.append(table->table_name);
- built_query.append("`,");
- }
-
- if (!drop_temporary)
- {
- TABLE *locked_table;
- abort_locked_tables(thd, db, table->table_name);
- remove_table_from_cache(thd, db, table->table_name,
- RTFC_WAIT_OTHER_THREAD_FLAG |
- RTFC_CHECK_KILLED_FLAG);
- /*
- If the table was used in lock tables, remember it so that
- unlock_table_names can free it
- */
- if ((locked_table= drop_locked_tables(thd, db, table->table_name)))
- table->table= locked_table;
-
+ /* Check that we have an exclusive lock on the table to be dropped. */
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
+ table->table_name,
+ MDL_EXCLUSIVE));
if (thd->killed)
{
error= -1;
- goto err_with_placeholders;
+ goto err;
}
alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
/* remove .frm file and engine files */
@@ -2033,33 +2138,74 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
reg_ext,
table->internal_tmp_table ?
FN_IS_TMP : 0);
+
+ /*
+ This handles the case where a "DROP" was executed and a regular
+ table "may be" dropped as drop_temporary is FALSE and error is
+ TRUE. If the error was FALSE a temporary table was dropped and
+ regardless of the status of drop_tempoary a "DROP TEMPORARY"
+ must be used.
+ */
+ if (!dont_log_query)
+ {
+ /*
+ Note that unless if_exists is TRUE or a temporary table was deleted,
+ there is no means to know if the statement should be written to the
+ binary log. See further information on this variable in what follows.
+ */
+ non_tmp_table_deleted= (if_exists ? TRUE : non_tmp_table_deleted);
+ /*
+ Don't write the database name if it is the current one (or if
+ thd->db is NULL).
+ */
+ built_query.append("`");
+ if (thd->db == NULL || strcmp(db,thd->db) != 0)
+ {
+ built_query.append(db);
+ built_query.append("`.`");
+ }
+
+ built_query.append(table->table_name);
+ built_query.append("`,");
+ }
}
- DEBUG_SYNC(thd, "rm_table_part2_before_delete_table");
+ DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
+ DBUG_EXECUTE_IF("sleep_before_no_locks_delete_table",
+ my_sleep(100000););
+ error= 0;
if (drop_temporary ||
((access(path, F_OK) &&
ha_create_table_from_engine(thd, db, alias)) ||
(!drop_view &&
- mysql_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
+ dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
{
- // Table was not found on disk and table can't be created from engine
+ /*
+ One of the following cases happened:
+ . "DROP TEMPORARY" but a temporary table was not found.
+ . "DROP" but table was not found on disk and table can't be
+ created from engine.
+ . ./sql/datadict.cc +32 /Alfranio - TODO: We need to test this.
+ */
if (if_exists)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
table->table_name);
else
+ {
+ non_tmp_error = (drop_temporary ? non_tmp_error : TRUE);
error= 1;
+ }
}
else
{
char *end;
/*
Cannot use the db_type from the table, since that might have changed
- while waiting for the exclusive name lock. We are under LOCK_open,
- so reading from the frm-file is safe.
+ while waiting for the exclusive name lock.
*/
if (frm_db_type == DB_TYPE_UNKNOWN)
{
- mysql_frm_type(thd, path, &frm_db_type);
+ dd_frm_type(thd, path, &frm_db_type);
DBUG_PRINT("info", ("frm_db_type %d from %s", frm_db_type, path));
}
table_type= ha_resolve_by_legacy_type(thd, frm_db_type);
@@ -2080,21 +2226,22 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
if (error == HA_ERR_ROW_IS_REFERENCED)
{
/* the table is referenced by a foreign key constraint */
- foreign_key_error=1;
+ foreign_key_error= 1;
}
if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE)
{
int new_error;
/* Delete the table definition file */
strmov(end,reg_ext);
- if (!(new_error=my_delete(path,MYF(MY_WME))))
+ if (!(new_error= mysql_file_delete(key_file_frm, path, MYF(MY_WME))))
{
- some_tables_deleted=1;
+ non_tmp_table_deleted= TRUE;
new_error= Table_triggers_list::drop_all_triggers(thd, db,
table->table_name);
}
error|= new_error;
}
+ non_tmp_error= error ? TRUE : non_tmp_error;
}
if (error)
{
@@ -2104,15 +2251,17 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
}
DBUG_PRINT("table", ("table: 0x%lx s: 0x%lx", (long) table->table,
table->table ? (long) table->table->s : (long) -1));
+
+ DBUG_EXECUTE_IF("bug43138",
+ my_printf_error(ER_BAD_TABLE_ERROR,
+ ER(ER_BAD_TABLE_ERROR), MYF(0),
+ table->table_name););
}
- /*
- It's safe to unlock LOCK_open: we have an exclusive lock
- on the table name.
- */
- pthread_mutex_unlock(&LOCK_open);
- DEBUG_SYNC(thd, "rm_table_part2_before_binlog");
- thd->thread_specific_used|= tmp_table_deleted;
+ DEBUG_SYNC(thd, "rm_table_no_locks_before_binlog");
+ thd->thread_specific_used|= (trans_tmp_table_deleted ||
+ non_trans_tmp_table_deleted);
error= 0;
+err:
if (wrong_tables.length())
{
if (!foreign_key_error)
@@ -2123,80 +2272,86 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
error= 1;
}
- if (some_tables_deleted || tmp_table_deleted || !error)
+ if (non_trans_tmp_table_deleted ||
+ trans_tmp_table_deleted || non_tmp_table_deleted)
{
query_cache_invalidate3(thd, tables, 0);
- if (!dont_log_query)
+ if (!dont_log_query && mysql_bin_log.is_open())
{
- if (!thd->current_stmt_binlog_row_based ||
- (non_temp_tables_count > 0 && !tmp_table_deleted))
+ if (non_trans_tmp_table_deleted)
{
- /*
- In this case, we are either using statement-based
- replication or using row-based replication but have only
- deleted one or more non-temporary tables (and no temporary
- tables). In this case, we can write the original query into
- the binary log.
- */
- error |= write_bin_log(thd, !error, thd->query(), thd->query_length());
+ /* Chop of the last comma */
+ built_non_trans_tmp_query.chop();
+ built_non_trans_tmp_query.append(" /* generated by server */");
+ error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
+ built_non_trans_tmp_query.ptr(),
+ built_non_trans_tmp_query.length(),
+ FALSE, FALSE, FALSE, 0);
}
- else if (thd->current_stmt_binlog_row_based &&
- tmp_table_deleted)
+ if (trans_tmp_table_deleted)
{
- if (non_temp_tables_count > 0)
- {
- /*
- In this case we have deleted both temporary and
- non-temporary tables, so:
- - since we have deleted a non-temporary table we have to
- binlog the statement, but
- - since we have deleted a temporary table we cannot binlog
- the statement (since the table may have not been created on the
- slave - check "if" branch below, this might cause the slave to
- stop).
-
- Instead, we write a built statement, only containing the
- non-temporary tables, to the binary log
- */
- built_query.chop(); // Chop of the last comma
+ /* Chop of the last comma */
+ built_trans_tmp_query.chop();
+ built_trans_tmp_query.append(" /* generated by server */");
+ error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
+ built_trans_tmp_query.ptr(),
+ built_trans_tmp_query.length(),
+ TRUE, FALSE, FALSE, 0);
+ }
+ if (non_tmp_table_deleted)
+ {
+ /* Chop of the last comma */
+ built_query.chop();
built_query.append(" /* generated by server */");
- error|= write_bin_log(thd, !error, built_query.ptr(), built_query.length());
- }
+ int error_code = (non_tmp_error ?
+ (foreign_key_error ? ER_ROW_IS_REFERENCED : ER_BAD_TABLE_ERROR) : 0);
+ error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
+ built_query.ptr(),
+ built_query.length(),
+ TRUE, FALSE, FALSE,
+ error_code);
+ }
+ }
+ }
- /*
- One needs to always log any temporary table drop, if:
- 1. thread logging format is mixed mode; AND
- 2. current statement logging format is set to row.
- */
- if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED)
+ if (!drop_temporary)
+ {
+ /*
+ Under LOCK TABLES we should release meta-data locks on the tables
+ which were dropped.
+
+ Leave LOCK TABLES mode if we managed to drop all tables which were
+ locked. Additional check for 'non_temp_tables_count' is to avoid
+ leaving LOCK TABLES mode if we have dropped only temporary tables.
+ */
+ if (thd->locked_tables_mode)
+ {
+ if (thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0)
+ {
+ thd->locked_tables_list.unlock_locked_tables(thd);
+ goto end;
+ }
+ for (table= tables; table; table= table->next_local)
+ {
+ /* Drop locks for all successfully dropped tables. */
+ if (table->table == NULL && table->mdl_request.ticket)
{
/*
- In this case we have deleted some temporary tables but we are using
- row based logging for the statement. However, thread uses mixed mode
- format, thence we need to log the dropping as we cannot tell for
- sure whether the create was logged as statement previously or not, ie,
- before switching to row mode.
+ Under LOCK TABLES we may have several instances of table open
+ and locked and therefore have to remove several metadata lock
+ requests associated with them.
*/
- built_tmp_query.chop(); // Chop of the last comma
- built_tmp_query.append(" /* generated by server */");
- error|= write_bin_log(thd, !error, built_tmp_query.ptr(), built_tmp_query.length());
+ thd->mdl_context.release_all_locks_for_name(table->mdl_request.ticket);
}
}
-
- /*
- The remaining cases are:
- - no tables were deleted and
- - only temporary tables were deleted and row-based
- replication is used.
- In both these cases, nothing should be written to the binary
- log.
- */
}
+ /*
+ Rely on the caller to implicitly commit the transaction
+ and release metadata locks.
+ */
}
- pthread_mutex_lock(&LOCK_open);
-err_with_placeholders:
- unlock_table_names(thd, tables, (TABLE_LIST*) 0);
- pthread_mutex_unlock(&LOCK_open);
+
+end:
DBUG_RETURN(error);
}
@@ -2225,7 +2380,7 @@ bool quick_rm_table(handlerton *base,const char *db,
uint path_length= build_table_filename(path, sizeof(path) - 1,
db, table_name, reg_ext, flags);
- if (my_delete(path,MYF(0)))
+ 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 & FRM_ONLY))
@@ -2254,10 +2409,10 @@ static int sort_keys(KEY *a, KEY *b)
{
if (!(b_flags & HA_NOSAME))
return -1;
- if ((a_flags ^ b_flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY))
+ if ((a_flags ^ b_flags) & HA_NULL_PART_KEY)
{
/* Sort NOT NULL keys before other keys */
- return (a_flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1;
+ return (a_flags & HA_NULL_PART_KEY) ? 1 : -1;
}
if (a->name == primary_key_name)
return -1;
@@ -2318,17 +2473,19 @@ bool check_duplicates_in_interval(const char *set_or_name,
tmp.count--;
if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
{
+ THD *thd= current_thd;
+ ErrConvString err(*cur_value, *cur_length, cs);
if ((current_thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
{
my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
- name,*cur_value,set_or_name);
+ name, err.ptr(), set_or_name);
return 1;
}
- push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_DUPLICATED_VALUE_IN_TYPE,
- ER(ER_DUPLICATED_VALUE_IN_TYPE),
- name,*cur_value,set_or_name);
+ push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_DUPLICATED_VALUE_IN_TYPE,
+ ER(ER_DUPLICATED_VALUE_IN_TYPE),
+ name, err.ptr(), set_or_name);
(*dup_val_count)++;
}
}
@@ -2545,6 +2702,54 @@ int prepare_create_field(Create_field *sql_field,
DBUG_RETURN(0);
}
+
+/*
+ Get character set from field object generated by parser using
+ default values when not set.
+
+ SYNOPSIS
+ get_sql_field_charset()
+ sql_field The sql_field object
+ create_info Info generated by parser
+
+ RETURN VALUES
+ cs Character set
+*/
+
+CHARSET_INFO* get_sql_field_charset(Create_field *sql_field,
+ HA_CREATE_INFO *create_info)
+{
+ CHARSET_INFO *cs= sql_field->charset;
+
+ if (!cs)
+ cs= create_info->default_table_charset;
+ /*
+ table_charset is set only in ALTER TABLE t1 CONVERT TO CHARACTER SET csname
+ if we want change character set for all varchar/char columns.
+ But the table charset must not affect the BLOB fields, so don't
+ allow to change my_charset_bin to somethig else.
+ */
+ if (create_info->table_charset && cs != &my_charset_bin)
+ cs= create_info->table_charset;
+ return cs;
+}
+
+
+bool check_duplicate_warning(THD *thd, char *msg, ulong length)
+{
+ List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
+ MYSQL_ERROR *err;
+ while ((err= it++))
+ {
+ if (strncmp(msg, err->get_message_text(), length) == 0)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
/*
Preparation for table creation
@@ -2608,18 +2813,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
executing a prepared statement for the second time.
*/
sql_field->length= sql_field->char_length;
- if (!sql_field->charset)
- sql_field->charset= create_info->default_table_charset;
- /*
- table_charset is set in ALTER TABLE if we want change character set
- for all varchar/char columns.
- But the table charset must not affect the BLOB fields, so don't
- allow to change my_charset_bin to somethig else.
- */
- if (create_info->table_charset && sql_field->charset != &my_charset_bin)
- sql_field->charset= create_info->table_charset;
-
- save_cs= sql_field->charset;
+ save_cs= sql_field->charset= get_sql_field_charset(sql_field,
+ create_info);
if ((sql_field->flags & BINCMP_FLAG) &&
!(sql_field->charset= get_charset_by_csname(sql_field->charset->csname,
MY_CS_BINSORT,MYF(0))))
@@ -2685,7 +2880,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
sql_field->interval_list);
List_iterator<String> int_it(sql_field->interval_list);
String conv, *tmp;
- char comma_buf[2];
+ char comma_buf[4]; /* 4 bytes for utf32 */
int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf,
(uchar*) comma_buf +
sizeof(comma_buf));
@@ -2714,7 +2909,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
interval->type_lengths[i],
comma_buf, comma_length, NULL, 0))
{
- my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", tmp->ptr());
+ ErrConvString err(tmp->ptr(), tmp->length(), cs);
+ my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", err.ptr());
DBUG_RETURN(TRUE);
}
}
@@ -2928,9 +3124,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
while ((key=key_iterator++))
{
- DBUG_PRINT("info", ("key name: '%s' type: %d", key->name ? key->name :
+ DBUG_PRINT("info", ("key name: '%s' type: %d", key->name.str ? key->name.str :
"(none)" , key->type));
- LEX_STRING key_name_str;
if (key->type == Key::FOREIGN_KEY)
{
fk_key_count++;
@@ -2939,7 +3134,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
fk_key->ref_columns.elements != fk_key->columns.elements)
{
my_error(ER_WRONG_FK_DEF, MYF(0),
- (fk_key->name ? fk_key->name : "foreign key without name"),
+ (fk_key->name.str ? fk_key->name.str :
+ "foreign key without name"),
ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
DBUG_RETURN(TRUE);
}
@@ -2952,12 +3148,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
DBUG_RETURN(TRUE);
}
- key_name_str.str= (char*) key->name;
- key_name_str.length= key->name ? strlen(key->name) : 0;
- if (check_string_char_length(&key_name_str, "", NAME_CHAR_LEN,
+ if (check_string_char_length(&key->name, "", NAME_CHAR_LEN,
system_charset_info, 1))
{
- my_error(ER_TOO_LONG_IDENT, MYF(0), key->name);
+ my_error(ER_TOO_LONG_IDENT, MYF(0), key->name.str);
DBUG_RETURN(TRUE);
}
key_iterator2.rewind ();
@@ -2971,7 +3165,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
Then we do not need the generated shorter key.
*/
if ((key2->type != Key::FOREIGN_KEY &&
- key2->name != ignore_key &&
+ key2->name.str != ignore_key &&
!foreign_key_prefix(key, key2)))
{
/* TODO: issue warning message */
@@ -2979,10 +3173,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (!key2->generated ||
(key->generated && key->columns.elements <
key2->columns.elements))
- key->name= ignore_key;
+ key->name.str= ignore_key;
else
{
- key2->name= ignore_key;
+ key2->name.str= ignore_key;
key_parts-= key2->columns.elements;
(*key_count)--;
}
@@ -2990,14 +3184,14 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
}
- if (key->name != ignore_key)
+ if (key->name.str != ignore_key)
key_parts+=key->columns.elements;
else
(*key_count)--;
- if (key->name && !tmp_table && (key->type != Key::PRIMARY) &&
- !my_strcasecmp(system_charset_info,key->name,primary_key_name))
+ if (key->name.str && !tmp_table && (key->type != Key::PRIMARY) &&
+ !my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
{
- my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name);
+ my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
DBUG_RETURN(TRUE);
}
}
@@ -3020,12 +3214,12 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
uint key_length=0;
Key_part_spec *column;
- if (key->name == ignore_key)
+ if (key->name.str == ignore_key)
{
/* ignore redundant keys */
do
key=key_iterator++;
- while (key && key->name == ignore_key);
+ while (key && key->name.str == ignore_key);
if (!key)
break;
}
@@ -3138,22 +3332,22 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
field=0;
while ((sql_field=it++) &&
my_strcasecmp(system_charset_info,
- column->field_name,
+ column->field_name.str,
sql_field->field_name))
field++;
if (!sql_field)
{
- my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name);
+ my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
}
while ((dup_column= cols2++) != column)
{
if (!my_strcasecmp(system_charset_info,
- column->field_name, dup_column->field_name))
+ column->field_name.str, dup_column->field_name.str))
{
my_printf_error(ER_DUP_FIELDNAME,
ER(ER_DUP_FIELDNAME),MYF(0),
- column->field_name);
+ column->field_name.str);
DBUG_RETURN(TRUE);
}
}
@@ -3167,7 +3361,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
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);
+ my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name.str);
DBUG_RETURN(-1);
}
ft_key_charset=sql_field->charset;
@@ -3184,18 +3378,26 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
{
column->length*= sql_field->charset->mbmaxlen;
- if (key->type == Key::SPATIAL && column->length)
+ if (key->type == Key::SPATIAL)
{
- my_error(ER_WRONG_SUB_KEY, MYF(0));
- DBUG_RETURN(TRUE);
- }
+ 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_SPATIAL_MUST_HAVE_GEOM_COL, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ }
if (f_is_blob(sql_field->pack_flag) ||
(f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
{
if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
{
- my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name);
+ my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
}
if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
@@ -3203,7 +3405,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
column->length= 25;
if (!column->length)
{
- my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name);
+ my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
}
}
@@ -3234,7 +3436,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
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);
+ my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
}
if (key->type == Key::SPATIAL)
@@ -3283,14 +3485,21 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
}
+ // Catch invalid use of partial keys
else if (!f_is_geom(sql_field->pack_flag) &&
- (column->length > length ||
- !Field::type_can_have_key_part (sql_field->sql_type) ||
- ((f_is_packed(sql_field->pack_flag) ||
- ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
- (key_info->flags & HA_NOSAME))) &&
- column->length != length)))
- {
+ // is the key partial?
+ column->length != length &&
+ // is prefix length bigger than field length?
+ (column->length > length ||
+ // can the field have a partial key?
+ !Field::type_can_have_key_part (sql_field->sql_type) ||
+ // a packed field can't be used in a partial key
+ f_is_packed(sql_field->pack_flag) ||
+ // does the storage engine allow prefixed search?
+ ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
+ // and is this a 'unique' key?
+ (key_info->flags & HA_NOSAME))))
+ {
my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
DBUG_RETURN(TRUE);
}
@@ -3299,7 +3508,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
else if (length == 0)
{
- my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name);
+ my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
}
if (length > file->max_key_part_length() && key->type != Key::FULLTEXT)
@@ -3358,7 +3567,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
key_name=primary_key_name;
primary_key=1;
}
- else if (!(key_name = key->name))
+ else if (!(key_name= key->name.str))
key_name=make_unique_key_name(sql_field->field_name,
*key_info_buffer, key_info);
if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
@@ -3382,6 +3591,40 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
DBUG_RETURN(TRUE);
}
+
+ uint tmp_len= system_charset_info->cset->charpos(system_charset_info,
+ key->key_create_info.comment.str,
+ key->key_create_info.comment.str +
+ key->key_create_info.comment.length,
+ INDEX_COMMENT_MAXLEN);
+
+ if (tmp_len < key->key_create_info.comment.length)
+ {
+ if ((thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
+ {
+ my_error(ER_TOO_LONG_INDEX_COMMENT, MYF(0),
+ key_info->name, (uint) INDEX_COMMENT_MAXLEN);
+ DBUG_RETURN(-1);
+ }
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_INDEX_COMMENT),
+ key_info->name, (uint) INDEX_COMMENT_MAXLEN);
+ /* do not push duplicate warnings */
+ if (!check_duplicate_warning(thd, warn_buff, strlen(warn_buff)))
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TOO_LONG_INDEX_COMMENT, warn_buff);
+
+ key->key_create_info.comment.length= tmp_len;
+ }
+
+ key_info->comment.length= key->key_create_info.comment.length;
+ if (key_info->comment.length > 0)
+ {
+ key_info->flags|= HA_USES_COMMENT;
+ key_info->comment.str= key->key_create_info.comment.str;
+ }
+
key_info++;
}
if (!unique_key && !primary_key &&
@@ -3573,39 +3816,42 @@ void sp_prepare_create_field(THD *thd, Create_field *sql_field)
}
-/*
- Write CREATE TABLE binlog
-
- SYNOPSIS
- write_create_table_bin_log()
- thd Thread object
- create_info Create information
- internal_tmp_table Set to 1 if this is an internal temporary table
+/**
+ Auxiliary function which allows to check if freshly created .FRM
+ file for table can be opened.
- DESCRIPTION
- This function only is called in mysql_create_table_no_lock and
- mysql_create_table
+ @retval FALSE - Success.
+ @retval TRUE - Failure.
+*/
- RETURN VALUES
- NONE
- */
-static inline int write_create_table_bin_log(THD *thd,
- const HA_CREATE_INFO *create_info,
- bool internal_tmp_table)
+static bool check_if_created_table_can_be_opened(THD *thd,
+ const char *path,
+ const char *db,
+ const char *table_name,
+ HA_CREATE_INFO *create_info,
+ handler *file)
{
+ TABLE table;
+ TABLE_SHARE share;
+ bool result;
+
/*
- Don't write statement if:
- - It is an internal temporary table,
- - Row-based logging is used and it we are creating a temporary table, or
- - The binary log is not open.
- Otherwise, the statement shall be binlogged.
- */
- if (!internal_tmp_table &&
- (!thd->current_stmt_binlog_row_based ||
- (thd->current_stmt_binlog_row_based &&
- !(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
- return write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- return 0;
+ It is impossible to open definition of partitioned table without .par file.
+ */
+ if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info))
+ return TRUE;
+
+ init_tmp_table_share(thd, &share, db, 0, table_name, path);
+
+ result= (open_table_def(thd, &share, 0) ||
+ open_table_from_share(thd, &share, "", 0, (uint) READ_ALL,
+ 0, &table, TRUE));
+ if (! result)
+ (void) closefrm(&table, 0);
+
+ free_table_share(&share);
+ (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info);
+ return result;
}
@@ -3623,14 +3869,16 @@ static inline int write_create_table_bin_log(THD *thd,
internal_tmp_table Set to 1 if this is an internal temporary table
(From ALTER TABLE)
select_field_count
+ is_trans identifies the type of engine where the table
+ was created: either trans or non-trans.
DESCRIPTION
If one creates a temporary table, this is automatically opened
Note that this function assumes that caller already have taken
- name-lock on table being created or used some other way to ensure
- that concurrent operations won't intervene. mysql_create_table()
- is a wrapper that can be used for this.
+ exclusive metadata lock on table being created or used some other
+ way to ensure that concurrent operations won't intervene.
+ mysql_create_table() is a wrapper that can be used for this.
no_log is needed for the case of CREATE ... SELECT,
as the logging will be done later in sql_insert.cc
@@ -3647,7 +3895,8 @@ bool mysql_create_table_no_lock(THD *thd,
HA_CREATE_INFO *create_info,
Alter_info *alter_info,
bool internal_tmp_table,
- uint select_field_count)
+ uint select_field_count,
+ bool *is_trans)
{
char path[FN_REFLEN + 1];
uint path_length;
@@ -3670,6 +3919,9 @@ bool mysql_create_table_no_lock(THD *thd,
}
if (check_engine(thd, table_name, create_info))
DBUG_RETURN(TRUE);
+
+ set_table_default_charset(thd, create_info, (char*) db);
+
db_options= create_info->table_options;
if (create_info->row_type == ROW_TYPE_DYNAMIC)
db_options|=HA_OPTION_PACK_RECORD;
@@ -3763,7 +4015,7 @@ bool mysql_create_table_no_lock(THD *thd,
ha_resolve_storage_engine_name(part_info->default_engine_type),
ha_resolve_storage_engine_name(create_info->db_type)));
if (part_info->check_partition_info(thd, &engine_type, file,
- create_info, TRUE))
+ create_info, FALSE))
goto err;
part_info->default_engine_type= engine_type;
@@ -3773,7 +4025,9 @@ bool mysql_create_table_no_lock(THD *thd,
*/
if (!(part_syntax_buf= generate_partition_syntax(part_info,
&syntax_len,
- TRUE, TRUE)))
+ TRUE, TRUE,
+ create_info,
+ alter_info)))
goto err;
part_info->part_info_string= part_syntax_buf;
part_info->part_info_len= syntax_len;
@@ -3799,9 +4053,9 @@ bool mysql_create_table_no_lock(THD *thd,
creates a proper .par file. The current part_info object is
only used to create the frm-file and .par-file.
*/
- if (part_info->use_default_no_partitions &&
- part_info->no_parts &&
- (int)part_info->no_parts !=
+ if (part_info->use_default_num_partitions &&
+ part_info->num_parts &&
+ (int)part_info->num_parts !=
file->get_default_no_partitions(create_info))
{
uint i;
@@ -3812,13 +4066,13 @@ bool mysql_create_table_no_lock(THD *thd,
(part_it++)->part_state= PART_TO_BE_DROPPED;
}
else if (part_info->is_sub_partitioned() &&
- part_info->use_default_no_subpartitions &&
- part_info->no_subparts &&
- (int)part_info->no_subparts !=
+ part_info->use_default_num_subpartitions &&
+ part_info->num_subparts &&
+ (int)part_info->num_subparts !=
file->get_default_no_partitions(create_info))
{
DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE);
- part_info->no_subparts= file->get_default_no_partitions(create_info);
+ part_info->num_subparts= file->get_default_no_partitions(create_info);
}
}
else if (create_info->db_type != engine_type)
@@ -3840,8 +4094,6 @@ bool mysql_create_table_no_lock(THD *thd,
}
#endif
- set_table_default_charset(thd, create_info, (char*) db);
-
if (mysql_prepare_create_table(thd, create_info, alter_info,
internal_tmp_table,
&db_options, file,
@@ -3867,18 +4119,16 @@ bool mysql_create_table_no_lock(THD *thd,
{
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
{
- create_info->table_existed= 1; // Mark that table existed
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
alias);
- error= write_create_table_bin_log(thd, create_info, internal_tmp_table);
+ error= 0;
goto err;
}
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
goto err;
}
- VOID(pthread_mutex_lock(&LOCK_open));
if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
{
if (!access(path,F_OK))
@@ -3886,7 +4136,7 @@ bool mysql_create_table_no_lock(THD *thd,
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
goto warn;
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
- goto unlock_and_end;
+ goto err;
}
/*
We don't assert here, but check the result, because the table could be
@@ -3896,11 +4146,14 @@ bool mysql_create_table_no_lock(THD *thd,
Then she could create the table. This case is pretty obscure and
therefore we don't introduce a new error message only for it.
*/
+ mysql_mutex_lock(&LOCK_open);
if (get_cached_table_share(db, table_name))
{
+ mysql_mutex_unlock(&LOCK_open);
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
- goto unlock_and_end;
+ goto err;
}
+ mysql_mutex_unlock(&LOCK_open);
}
/*
@@ -3908,7 +4161,7 @@ bool mysql_create_table_no_lock(THD *thd,
exist in any storage engine. In such a case it should
be discovered and the error ER_TABLE_EXISTS_ERROR be returned
unless user specified CREATE TABLE IF EXISTS
- The LOCK_open mutex has been locked to make sure no
+ An exclusive metadata lock ensures that no
one else is attempting to discover the table. Since
it's not on disk as a frm file, no one could be using it!
*/
@@ -3929,34 +4182,61 @@ bool mysql_create_table_no_lock(THD *thd,
if (create_if_not_exists)
goto warn;
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
- goto unlock_and_end;
+ goto err;
break;
default:
DBUG_PRINT("info", ("error: %u from storage engine", retcode));
my_error(retcode, MYF(0),table_name);
- goto unlock_and_end;
+ goto err;
}
}
thd_proc_info(thd, "creating table");
- create_info->table_existed= 0; // Mark that table is created
#ifdef HAVE_READLINK
- if (test_if_data_home_dir(create_info->data_file_name))
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY");
- goto unlock_and_end;
- }
- if (test_if_data_home_dir(create_info->index_file_name))
{
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY");
- goto unlock_and_end;
+ size_t dirlen;
+ char dirpath[FN_REFLEN];
+
+ /*
+ data_file_name and index_file_name include the table name without
+ extension. Mostly this does not refer to an existing file. When
+ comparing data_file_name or index_file_name against the data
+ directory, we try to resolve all symbolic links. On some systems,
+ we use realpath(3) for the resolution. This returns ENOENT if the
+ resolved path does not refer to an existing file. my_realpath()
+ does then copy the requested path verbatim, without symlink
+ resolution. Thereafter the comparison can fail even if the
+ requested path is within the data directory. E.g. if symlinks to
+ another file system are used. To make realpath(3) return the
+ resolved path, we strip the table name and compare the directory
+ path only. If the directory doesn't exist either, table creation
+ will fail anyway.
+ */
+ if (create_info->data_file_name)
+ {
+ dirname_part(dirpath, create_info->data_file_name, &dirlen);
+ if (test_if_data_home_dir(dirpath))
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY");
+ goto err;
+ }
+ }
+ if (create_info->index_file_name)
+ {
+ dirname_part(dirpath, create_info->index_file_name, &dirlen);
+ if (test_if_data_home_dir(dirpath))
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY");
+ goto err;
+ }
+ }
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (check_partition_dirs(thd->lex->part_info))
{
- goto unlock_and_end;
+ goto err;
}
#endif /* WITH_PARTITION_STORAGE_ENGINE */
@@ -3979,23 +4259,53 @@ bool mysql_create_table_no_lock(THD *thd,
if (rea_create_table(thd, path, db, table_name,
create_info, alter_info->create_list,
key_count, key_info_buffer, file))
- goto unlock_and_end;
+ goto err;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
- /* Open table and put in temporary table list */
- if (!(open_temporary_table(thd, path, db, table_name, 1)))
+ /*
+ Open a table (skipping table cache) and add it into
+ THD::temporary_tables list.
+ */
+
+ TABLE *table= open_table_uncached(thd, path, db, table_name, TRUE);
+
+ if (!table)
{
(void) rm_temporary_table(create_info->db_type, path);
- goto unlock_and_end;
+ goto err;
}
+
+ if (is_trans != NULL)
+ *is_trans= table->file->has_transactions();
+
thd->thread_specific_used= TRUE;
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ else if (part_info && create_info->frm_only)
+ {
+ /*
+ For partitioned tables we can't find some problems with table
+ until table is opened. Therefore in order to disallow creation
+ of corrupted tables we have to try to open table as the part
+ of its creation process.
+ In cases when both .FRM and SE part of table are created table
+ is implicitly open in ha_create_table() call.
+ In cases when we create .FRM without SE part we have to open
+ table explicitly.
+ */
+ if (check_if_created_table_can_be_opened(thd, path, db, table_name,
+ create_info, file))
+ {
+ char frm_name[FN_REFLEN];
+ strxmov(frm_name, path, reg_ext, NullS);
+ (void) mysql_file_delete(key_file_frm, frm_name, MYF(0));
+ goto err;
+ }
+ }
+#endif
- error= write_create_table_bin_log(thd, create_info, internal_tmp_table);
-unlock_and_end:
- VOID(pthread_mutex_unlock(&LOCK_open));
-
+ error= FALSE;
err:
thd_proc_info(thd, "After create");
delete file;
@@ -4006,86 +4316,57 @@ warn:
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
alias);
- create_info->table_existed= 1; // Mark that table existed
- error= write_create_table_bin_log(thd, create_info, internal_tmp_table);
- goto unlock_and_end;
+ goto err;
}
-/*
- Database and name-locking aware wrapper for mysql_create_table_no_lock(),
+/**
+ Implementation of SQLCOM_CREATE_TABLE.
+
+ Take the metadata locks (including a shared lock on the affected
+ schema) and create the table. Is written to be called from
+ mysql_execute_command(), to which it delegates the common parts
+ with other commands (i.e. implicit commit before and after,
+ close of thread tables.
*/
-bool mysql_create_table(THD *thd, const char *db, const char *table_name,
+bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
HA_CREATE_INFO *create_info,
- Alter_info *alter_info,
- bool internal_tmp_table,
- uint select_field_count)
+ Alter_info *alter_info)
{
- TABLE *name_lock= 0;
bool result;
+ bool is_trans= FALSE;
DBUG_ENTER("mysql_create_table");
- /* Wait for any database locks */
- pthread_mutex_lock(&LOCK_lock_db);
- while (!thd->killed &&
- hash_search(&lock_db_cache,(uchar*) db, strlen(db)))
+ /*
+ Open or obtain an exclusive metadata lock on table being created.
+ */
+ if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0))
{
- wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
- pthread_mutex_lock(&LOCK_lock_db);
+ result= TRUE;
+ goto end;
}
- if (thd->killed)
- {
- pthread_mutex_unlock(&LOCK_lock_db);
- DBUG_RETURN(TRUE);
- }
- creating_table++;
- pthread_mutex_unlock(&LOCK_lock_db);
+ /* Got lock. */
+ DEBUG_SYNC(thd, "locked_table_name");
- if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
- {
- if (lock_table_name_if_not_cached(thd, db, table_name, &name_lock))
- {
- result= TRUE;
- goto unlock;
- }
- if (!name_lock)
- {
- if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
- table_name);
- create_info->table_existed= 1;
- result= FALSE;
- write_create_table_bin_log(thd, create_info, internal_tmp_table);
- }
- else
- {
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
- result= TRUE;
- }
- goto unlock;
- }
- }
+ result= mysql_create_table_no_lock(thd, create_table->db,
+ create_table->table_name, create_info,
+ alter_info, FALSE, 0, &is_trans);
- result= mysql_create_table_no_lock(thd, db, table_name, create_info,
- alter_info,
- internal_tmp_table,
- select_field_count);
+ /*
+ Don't write statement if:
+ - Table creation has failed
+ - Row-based logging is used and we are creating a temporary table
+ Otherwise, the statement shall be binlogged.
+ */
+ if (!result &&
+ (!thd->is_current_stmt_binlog_format_row() ||
+ (thd->is_current_stmt_binlog_format_row() &&
+ !(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
+ result= write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans);
-unlock:
- if (name_lock)
- {
- pthread_mutex_lock(&LOCK_open);
- unlink_open_table(thd, name_lock, FALSE);
- pthread_mutex_unlock(&LOCK_open);
- }
- pthread_mutex_lock(&LOCK_lock_db);
- if (!--creating_table && creating_database)
- pthread_cond_signal(&COND_refresh);
- pthread_mutex_unlock(&LOCK_lock_db);
+end:
DBUG_RETURN(result);
}
@@ -4220,1022 +4501,6 @@ mysql_rename_table(handlerton *base, const char *old_db,
/*
- Force all other threads to stop using the table
-
- SYNOPSIS
- wait_while_table_is_used()
- thd Thread handler
- table Table to remove from cache
- function HA_EXTRA_PREPARE_FOR_DROP if table is to be deleted
- HA_EXTRA_FORCE_REOPEN if table is not be used
- HA_EXTRA_PREPARE_FOR_RENAME if table is to be renamed
- NOTES
- When returning, the table will be unusable for other threads until
- the table is closed.
-
- PREREQUISITES
- Lock on LOCK_open
- Win32 clients must also have a WRITE LOCK on the table !
-*/
-
-void wait_while_table_is_used(THD *thd, TABLE *table,
- enum ha_extra_function function)
-{
- DBUG_ENTER("wait_while_table_is_used");
- DBUG_PRINT("enter", ("table: '%s' share: 0x%lx db_stat: %u version: %lu",
- table->s->table_name.str, (ulong) table->s,
- table->db_stat, table->s->version));
-
- safe_mutex_assert_owner(&LOCK_open);
-
- VOID(table->file->extra(function));
- /* Mark all tables that are in use as 'old' */
- mysql_lock_abort(thd, table, TRUE); /* end threads waiting on lock */
-
- /* Wait until all there are no other threads that has this table open */
- remove_table_from_cache(thd, table->s->db.str,
- table->s->table_name.str,
- RTFC_WAIT_OTHER_THREAD_FLAG);
- DBUG_VOID_RETURN;
-}
-
-/*
- Close a cached table
-
- SYNOPSIS
- close_cached_table()
- thd Thread handler
- table Table to remove from cache
-
- NOTES
- Function ends by signaling threads waiting for the table to try to
- reopen the table.
-
- PREREQUISITES
- Lock on LOCK_open
- Win32 clients must also have a WRITE LOCK on the table !
-*/
-
-void close_cached_table(THD *thd, TABLE *table)
-{
- DBUG_ENTER("close_cached_table");
-
- wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
- /* Close lock if this is not got with LOCK TABLES */
- if (thd->lock)
- {
- mysql_unlock_tables(thd, thd->lock);
- thd->lock=0; // Start locked threads
- }
- /* Close all copies of 'table'. This also frees all LOCK TABLES lock */
- unlink_open_table(thd, table, TRUE);
-
- /* When lock on LOCK_open is freed other threads can continue */
- broadcast_refresh();
- DBUG_VOID_RETURN;
-}
-
-static int send_check_errmsg(THD *thd, TABLE_LIST* table,
- const char* operator_name, const char* errmsg)
-
-{
- Protocol *protocol= thd->protocol;
- protocol->prepare_for_resend();
- protocol->store(table->alias, system_charset_info);
- protocol->store((char*) operator_name, system_charset_info);
- protocol->store(STRING_WITH_LEN("error"), system_charset_info);
- protocol->store(errmsg, system_charset_info);
- thd->clear_error();
- if (protocol->write())
- return -1;
- return 1;
-}
-
-
-static int prepare_for_restore(THD* thd, TABLE_LIST* table,
- HA_CHECK_OPT *check_opt)
-{
- DBUG_ENTER("prepare_for_restore");
-
- if (table->table) // do not overwrite existing tables on restore
- {
- DBUG_RETURN(send_check_errmsg(thd, table, "restore",
- "table exists, will not overwrite on restore"
- ));
- }
- else
- {
- char* backup_dir= thd->lex->backup_dir;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN + 1], uname[FN_REFLEN];
- char* table_name= table->table_name;
- char* db= table->db;
-
- VOID(tablename_to_filename(table->table_name, uname, sizeof(uname) - 1));
-
- if (fn_format_relative_to_data_home(src_path, uname, backup_dir, reg_ext))
- DBUG_RETURN(-1); // protect buffer overflow
-
- build_table_filename(dst_path, sizeof(dst_path) - 1,
- db, table_name, reg_ext, 0);
-
- if (lock_and_wait_for_table_name(thd,table))
- DBUG_RETURN(-1);
-
- if (my_copy(src_path, dst_path, MYF(MY_WME)))
- {
- pthread_mutex_lock(&LOCK_open);
- unlock_table_name(thd, table);
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(send_check_errmsg(thd, table, "restore",
- "Failed copying .frm file"));
- }
- if (mysql_truncate(thd, table, 1))
- {
- pthread_mutex_lock(&LOCK_open);
- unlock_table_name(thd, table);
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(send_check_errmsg(thd, table, "restore",
- "Failed generating table from .frm file"));
- }
- }
-
- /*
- Now we should be able to open the partially restored table
- to finish the restore in the handler later on
- */
- pthread_mutex_lock(&LOCK_open);
- if (reopen_name_locked_table(thd, table, TRUE))
- {
- unlock_table_name(thd, table);
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(send_check_errmsg(thd, table, "restore",
- "Failed to open partially restored table"));
- }
- /* A MERGE table must not come here. */
- DBUG_ASSERT(!table->table || !table->table->child_l);
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0);
-}
-
-
-static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
- HA_CHECK_OPT *check_opt)
-{
- int error= 0;
- TABLE tmp_table, *table;
- TABLE_SHARE *share;
- char from[FN_REFLEN],tmp[FN_REFLEN+32];
- const char **ext;
- MY_STAT stat_info;
- DBUG_ENTER("prepare_for_repair");
-
- if (!(check_opt->sql_flags & TT_USEFRM))
- DBUG_RETURN(0);
-
- if (!(table= table_list->table)) /* if open_ltable failed */
- {
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
-
- key_length= create_table_def_key(thd, key, table_list, 0);
- pthread_mutex_lock(&LOCK_open);
- if (!(share= (get_table_share(thd, table_list, key, key_length, 0,
- &error))))
- {
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0); // Can't open frm file
- }
-
- if (open_table_from_share(thd, share, "", 0, 0, 0, &tmp_table, FALSE))
- {
- release_table_share(share, RELEASE_NORMAL);
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0); // Out of memory
- }
- table= &tmp_table;
- pthread_mutex_unlock(&LOCK_open);
- }
-
- /*
- REPAIR TABLE ... USE_FRM for temporary tables makes little sense.
- */
- if (table->s->tmp_table)
- {
- error= send_check_errmsg(thd, table_list, "repair",
- "Cannot repair temporary table from .frm file");
- goto end;
- }
-
- /*
- User gave us USE_FRM which means that the header in the index file is
- trashed.
- In this case we will try to fix the table the following way:
- - Rename the data file to a temporary name
- - Truncate the table
- - Replace the new data file with the old one
- - Run a normal repair using the new index file and the old data file
- */
-
- if (table->s->frm_version != FRM_VER_TRUE_VARCHAR)
- {
- error= send_check_errmsg(thd, table_list, "repair",
- "Failed repairing incompatible .frm file");
- goto end;
- }
-
- /*
- Check if this is a table type that stores index and data separately,
- like ISAM or MyISAM. We assume fixed order of engine file name
- extentions array. First element of engine file name extentions array
- is meta/index file extention. Second element - data file extention.
- */
- ext= table->file->bas_ext();
- if (!ext[0] || !ext[1])
- goto end; // No data file
-
- // Name of data file
- strxmov(from, table->s->normalized_path.str, ext[1], NullS);
- if (!my_stat(from, &stat_info, MYF(0)))
- goto end; // Can't use USE_FRM flag
-
- my_snprintf(tmp, sizeof(tmp), "%s-%lx_%lx",
- from, current_pid, thd->thread_id);
-
- /* If we could open the table, close it */
- if (table_list->table)
- {
- pthread_mutex_lock(&LOCK_open);
- close_cached_table(thd, table);
- pthread_mutex_unlock(&LOCK_open);
- }
- if (lock_and_wait_for_table_name(thd,table_list))
- {
- error= -1;
- goto end;
- }
- if (my_rename(from, tmp, MYF(MY_WME)))
- {
- pthread_mutex_lock(&LOCK_open);
- unlock_table_name(thd, table_list);
- pthread_mutex_unlock(&LOCK_open);
- error= send_check_errmsg(thd, table_list, "repair",
- "Failed renaming data file");
- goto end;
- }
- if (mysql_truncate(thd, table_list, 1))
- {
- pthread_mutex_lock(&LOCK_open);
- unlock_table_name(thd, table_list);
- pthread_mutex_unlock(&LOCK_open);
- error= send_check_errmsg(thd, table_list, "repair",
- "Failed generating table from .frm file");
- goto end;
- }
- if (my_rename(tmp, from, MYF(MY_WME)))
- {
- pthread_mutex_lock(&LOCK_open);
- unlock_table_name(thd, table_list);
- pthread_mutex_unlock(&LOCK_open);
- error= send_check_errmsg(thd, table_list, "repair",
- "Failed restoring .MYD file");
- goto end;
- }
-
- /*
- Now we should be able to open the partially repaired table
- to finish the repair in the handler later on.
- */
- pthread_mutex_lock(&LOCK_open);
- if (reopen_name_locked_table(thd, table_list, TRUE))
- {
- unlock_table_name(thd, table_list);
- pthread_mutex_unlock(&LOCK_open);
- error= send_check_errmsg(thd, table_list, "repair",
- "Failed to open partially repaired table");
- goto end;
- }
- pthread_mutex_unlock(&LOCK_open);
-
-end:
- if (table == &tmp_table)
- {
- pthread_mutex_lock(&LOCK_open);
- closefrm(table, 1); // Free allocated memory
- pthread_mutex_unlock(&LOCK_open);
- }
- DBUG_RETURN(error);
-}
-
-
-
-/*
- RETURN VALUES
- FALSE Message sent to net (admin operation went ok)
- TRUE Message should be sent by caller
- (admin operation or network communication failed)
-*/
-static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
- HA_CHECK_OPT* check_opt,
- const char *operator_name,
- thr_lock_type lock_type,
- bool open_for_modify,
- bool no_warnings_for_error,
- uint extra_open_options,
- int (*prepare_func)(THD *, TABLE_LIST *,
- HA_CHECK_OPT *),
- int (handler::*operator_func)(THD *,
- HA_CHECK_OPT *),
- int (view_operator_func)(THD *, TABLE_LIST*))
-{
- TABLE_LIST *table;
- SELECT_LEX *select= &thd->lex->select_lex;
- List<Item> field_list;
- Item *item;
- Protocol *protocol= thd->protocol;
- LEX *lex= thd->lex;
- int result_code;
- DBUG_ENTER("mysql_admin_table");
-
- if (end_active_trans(thd))
- DBUG_RETURN(1);
- field_list.push_back(item = new Item_empty_string("Table", NAME_CHAR_LEN*2));
- item->maybe_null = 1;
- field_list.push_back(item = new Item_empty_string("Op", 10));
- item->maybe_null = 1;
- field_list.push_back(item = new Item_empty_string("Msg_type", 10));
- item->maybe_null = 1;
- field_list.push_back(item = new Item_empty_string("Msg_text", 255));
- item->maybe_null = 1;
- if (protocol->send_fields(&field_list,
- Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
- DBUG_RETURN(TRUE);
-
- mysql_ha_rm_tables(thd, tables, FALSE);
-
- for (table= tables; table; table= table->next_local)
- {
- char table_name[NAME_LEN*2+2];
- char* db = table->db;
- bool fatal_error=0;
-
- DBUG_PRINT("admin", ("table: '%s'.'%s'", table->db, table->table_name));
- DBUG_PRINT("admin", ("extra_open_options: %u", extra_open_options));
- strxmov(table_name, db, ".", table->table_name, NullS);
- thd->open_options|= extra_open_options;
- table->lock_type= lock_type;
- /* open only one table from local list of command */
- {
- TABLE_LIST *save_next_global, *save_next_local;
- save_next_global= table->next_global;
- table->next_global= 0;
- save_next_local= table->next_local;
- table->next_local= 0;
- select->table_list.first= table;
- /*
- Time zone tables and SP tables can be add to lex->query_tables list,
- so it have to be prepared.
- TODO: Investigate if we can put extra tables into argument instead of
- using lex->query_tables
- */
- lex->query_tables= table;
- lex->query_tables_last= &table->next_global;
- lex->query_tables_own_last= 0;
- thd->no_warnings_for_error= no_warnings_for_error;
- if (view_operator_func == NULL)
- table->required_type=FRMTYPE_TABLE;
-
- open_and_lock_tables(thd, table);
- thd->no_warnings_for_error= 0;
- table->next_global= save_next_global;
- table->next_local= save_next_local;
- thd->open_options&= ~extra_open_options;
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (table->table)
- {
- /*
- Set up which partitions that should be processed
- if ALTER TABLE t ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION ..
- */
- Alter_info *alter_info= &lex->alter_info;
-
- if (alter_info->flags & ALTER_ADMIN_PARTITION)
- {
- if (!table->table->part_info)
- {
- my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
- DBUG_RETURN(TRUE);
- }
- uint no_parts_found;
- uint no_parts_opt= alter_info->partition_names.elements;
- no_parts_found= set_part_state(alter_info, table->table->part_info,
- PART_CHANGED);
- if (no_parts_found != no_parts_opt &&
- (!(alter_info->flags & ALTER_ALL_PARTITION)))
- {
- char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE];
- size_t length;
- DBUG_PRINT("admin", ("sending non existent partition error"));
- protocol->prepare_for_resend();
- protocol->store(table_name, system_charset_info);
- protocol->store(operator_name, system_charset_info);
- protocol->store(STRING_WITH_LEN("error"), system_charset_info);
- length= my_snprintf(buff, sizeof(buff),
- ER(ER_DROP_PARTITION_NON_EXISTENT),
- table_name);
- protocol->store(buff, length, system_charset_info);
- if(protocol->write())
- goto err;
- my_eof(thd);
- goto err;
- }
- }
- }
-#endif
- }
- DBUG_PRINT("admin", ("table: 0x%lx", (long) table->table));
-
- if (prepare_func)
- {
- DBUG_PRINT("admin", ("calling prepare_func"));
- switch ((*prepare_func)(thd, table, check_opt)) {
- case 1: // error, message written to net
- ha_autocommit_or_rollback(thd, 1);
- end_trans(thd, ROLLBACK);
- close_thread_tables(thd);
- DBUG_PRINT("admin", ("simple error, admin next table"));
- continue;
- case -1: // error, message could be written to net
- /* purecov: begin inspected */
- DBUG_PRINT("admin", ("severe error, stop"));
- goto err;
- /* purecov: end */
- default: // should be 0 otherwise
- DBUG_PRINT("admin", ("prepare_func succeeded"));
- ;
- }
- }
-
- /*
- CHECK TABLE command is only command where VIEW allowed here and this
- command use only temporary teble method for VIEWs resolving => there
- can't be VIEW tree substitition of join view => if opening table
- succeed then table->table will have real TABLE pointer as value (in
- case of join view substitution table->table can be 0, but here it is
- impossible)
- */
- if (!table->table)
- {
- DBUG_PRINT("admin", ("open table failed"));
- if (!thd->warn_list.elements)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
- ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE));
- /* if it was a view will check md5 sum */
- if (table->view &&
- view_checksum(thd, table) == HA_ADMIN_WRONG_CHECKSUM)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
- ER_VIEW_CHECKSUM, ER(ER_VIEW_CHECKSUM));
- if (thd->main_da.is_error() &&
- (thd->main_da.sql_errno() == ER_NO_SUCH_TABLE ||
- thd->main_da.sql_errno() == ER_FILE_NOT_FOUND))
- /* A missing table is just issued as a failed command */
- result_code= HA_ADMIN_FAILED;
- else
- /* Default failure code is corrupt table */
- result_code= HA_ADMIN_CORRUPT;
- goto send_result;
- }
-
- if (table->view)
- {
- DBUG_PRINT("admin", ("calling view_operator_func"));
- result_code= (*view_operator_func)(thd, table);
- goto send_result;
- }
-
- if (table->schema_table)
- {
- result_code= HA_ADMIN_NOT_IMPLEMENTED;
- goto send_result;
- }
-
- if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify)
- {
- /* purecov: begin inspected */
- char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE];
- size_t length;
- DBUG_PRINT("admin", ("sending error message"));
- protocol->prepare_for_resend();
- protocol->store(table_name, system_charset_info);
- protocol->store(operator_name, system_charset_info);
- protocol->store(STRING_WITH_LEN("error"), system_charset_info);
- length= my_snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
- table_name);
- protocol->store(buff, length, system_charset_info);
- ha_autocommit_or_rollback(thd, 0);
- end_trans(thd, COMMIT);
- close_thread_tables(thd);
- lex->reset_query_tables_list(FALSE);
- table->table=0; // For query cache
- if (protocol->write())
- goto err;
- thd->main_da.reset_diagnostics_area();
- continue;
- /* purecov: end */
- }
-
- /* Close all instances of the table to allow repair to rename files */
- if (lock_type == TL_WRITE && table->table->s->version)
- {
- DBUG_PRINT("admin", ("removing table from cache"));
- pthread_mutex_lock(&LOCK_open);
- const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open,
- "Waiting to get writelock");
- mysql_lock_abort(thd,table->table, TRUE);
- remove_table_from_cache(thd, table->table->s->db.str,
- table->table->s->table_name.str,
- RTFC_WAIT_OTHER_THREAD_FLAG |
- RTFC_CHECK_KILLED_FLAG);
- thd->exit_cond(old_message);
- DBUG_EXECUTE_IF("wait_in_mysql_admin_table", wait_for_kill_signal(thd););
- if (thd->killed)
- goto err;
- /* Flush entries in the query cache involving this table. */
- query_cache_invalidate3(thd, table->table, 0);
- open_for_modify= 0;
- }
-
- if (table->table->s->crashed && operator_func == &handler::ha_check)
- {
- /* purecov: begin inspected */
- DBUG_PRINT("admin", ("sending crashed warning"));
- protocol->prepare_for_resend();
- protocol->store(table_name, system_charset_info);
- protocol->store(operator_name, system_charset_info);
- protocol->store(STRING_WITH_LEN("warning"), system_charset_info);
- protocol->store(STRING_WITH_LEN("Table is marked as crashed"),
- system_charset_info);
- if (protocol->write())
- goto err;
- /* purecov: end */
- }
-
- if (operator_func == &handler::ha_repair &&
- !(check_opt->sql_flags & TT_USEFRM))
- {
- if ((table->table->file->check_old_types() == HA_ADMIN_NEEDS_ALTER) ||
- (table->table->file->ha_check_for_upgrade(check_opt) ==
- HA_ADMIN_NEEDS_ALTER))
- {
- DBUG_PRINT("admin", ("recreating table"));
- ha_autocommit_or_rollback(thd, 1);
- close_thread_tables(thd);
- tmp_disable_binlog(thd); // binlogging is done by caller if wanted
- result_code= mysql_recreate_table(thd, table);
- reenable_binlog(thd);
- /*
- mysql_recreate_table() can push OK or ERROR.
- Clear 'OK' status. If there is an error, keep it:
- we will store the error message in a result set row
- and then clear.
- */
- if (thd->main_da.is_ok())
- thd->main_da.reset_diagnostics_area();
- goto send_result;
- }
- }
-
- DBUG_PRINT("admin", ("calling operator_func '%s'", operator_name));
- result_code = (table->table->file->*operator_func)(thd, check_opt);
- DBUG_PRINT("admin", ("operator_func returned: %d", result_code));
-
-send_result:
-
- lex->cleanup_after_one_table_open();
- thd->clear_error(); // these errors shouldn't get client
- {
- List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
- MYSQL_ERROR *err;
- while ((err= it++))
- {
- protocol->prepare_for_resend();
- protocol->store(table_name, system_charset_info);
- protocol->store((char*) operator_name, system_charset_info);
- protocol->store(warning_level_names[err->level].str,
- warning_level_names[err->level].length,
- system_charset_info);
- protocol->store(err->msg, system_charset_info);
- if (protocol->write())
- goto err;
- }
- mysql_reset_errors(thd, true);
- }
- protocol->prepare_for_resend();
- protocol->store(table_name, system_charset_info);
- protocol->store(operator_name, system_charset_info);
-
-send_result_message:
-
- DBUG_PRINT("info", ("result_code: %d", result_code));
- switch (result_code) {
- case HA_ADMIN_NOT_IMPLEMENTED:
- {
- char buf[MYSQL_ERRMSG_SIZE];
- size_t length=my_snprintf(buf, sizeof(buf),
- ER(ER_CHECK_NOT_IMPLEMENTED), operator_name);
- protocol->store(STRING_WITH_LEN("note"), system_charset_info);
- protocol->store(buf, length, system_charset_info);
- }
- break;
-
- case HA_ADMIN_NOT_BASE_TABLE:
- {
- char buf[MYSQL_ERRMSG_SIZE];
- size_t length= my_snprintf(buf, sizeof(buf),
- ER(ER_BAD_TABLE_ERROR), table_name);
- protocol->store(STRING_WITH_LEN("note"), system_charset_info);
- protocol->store(buf, length, system_charset_info);
- }
- break;
-
- case HA_ADMIN_OK:
- protocol->store(STRING_WITH_LEN("status"), system_charset_info);
- protocol->store(STRING_WITH_LEN("OK"), system_charset_info);
- break;
-
- case HA_ADMIN_FAILED:
- protocol->store(STRING_WITH_LEN("status"), system_charset_info);
- protocol->store(STRING_WITH_LEN("Operation failed"),
- system_charset_info);
- break;
-
- case HA_ADMIN_REJECT:
- protocol->store(STRING_WITH_LEN("status"), system_charset_info);
- protocol->store(STRING_WITH_LEN("Operation need committed state"),
- system_charset_info);
- open_for_modify= FALSE;
- break;
-
- case HA_ADMIN_ALREADY_DONE:
- protocol->store(STRING_WITH_LEN("status"), system_charset_info);
- protocol->store(STRING_WITH_LEN("Table is already up to date"),
- system_charset_info);
- break;
-
- case HA_ADMIN_CORRUPT:
- protocol->store(STRING_WITH_LEN("error"), system_charset_info);
- protocol->store(STRING_WITH_LEN("Corrupt"), system_charset_info);
- fatal_error=1;
- break;
-
- case HA_ADMIN_INVALID:
- protocol->store(STRING_WITH_LEN("error"), system_charset_info);
- protocol->store(STRING_WITH_LEN("Invalid argument"),
- system_charset_info);
- break;
-
- case HA_ADMIN_TRY_ALTER:
- {
- /*
- This is currently used only by InnoDB. ha_innobase::optimize() answers
- "try with alter", so here we close the table, do an ALTER TABLE,
- reopen the table and do ha_innobase::analyze() on it.
- We have to end the row, so analyze could return more rows.
- */
- protocol->store(STRING_WITH_LEN("note"), system_charset_info);
- protocol->store(STRING_WITH_LEN(
- "Table does not support optimize, doing recreate + analyze instead"),
- system_charset_info);
- if (protocol->write())
- goto err;
- ha_autocommit_or_rollback(thd, 0);
- close_thread_tables(thd);
- DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze..."));
- TABLE_LIST *save_next_local= table->next_local,
- *save_next_global= table->next_global;
- table->next_local= table->next_global= 0;
- tmp_disable_binlog(thd); // binlogging is done by caller if wanted
- result_code= mysql_recreate_table(thd, table);
- reenable_binlog(thd);
- /*
- mysql_recreate_table() can push OK or ERROR.
- Clear 'OK' status. If there is an error, keep it:
- we will store the error message in a result set row
- and then clear.
- */
- if (thd->main_da.is_ok())
- thd->main_da.reset_diagnostics_area();
- ha_autocommit_or_rollback(thd, 0);
- close_thread_tables(thd);
- if (!result_code) // recreation went ok
- {
- if ((table->table= open_ltable(thd, table, lock_type, 0)) &&
- ((result_code= table->table->file->ha_analyze(thd, check_opt)) > 0))
- result_code= 0; // analyze went ok
- }
- /* Start a new row for the final status row */
- protocol->prepare_for_resend();
- protocol->store(table_name, system_charset_info);
- protocol->store(operator_name, system_charset_info);
- if (result_code) // either mysql_recreate_table or analyze failed
- {
- DBUG_ASSERT(thd->is_error());
- if (thd->is_error())
- {
- const char *err_msg= thd->main_da.message();
- if (!thd->vio_ok())
- {
- sql_print_error("%s", err_msg);
- }
- else
- {
- /* Hijack the row already in-progress. */
- protocol->store(STRING_WITH_LEN("error"), system_charset_info);
- protocol->store(err_msg, system_charset_info);
- if (protocol->write())
- goto err;
- /* Start off another row for HA_ADMIN_FAILED */
- protocol->prepare_for_resend();
- protocol->store(table_name, system_charset_info);
- protocol->store(operator_name, system_charset_info);
- }
- thd->clear_error();
- }
- }
- result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK;
- table->next_local= save_next_local;
- table->next_global= save_next_global;
- goto send_result_message;
- }
- case HA_ADMIN_WRONG_CHECKSUM:
- {
- protocol->store(STRING_WITH_LEN("note"), system_charset_info);
- protocol->store(ER(ER_VIEW_CHECKSUM), strlen(ER(ER_VIEW_CHECKSUM)),
- system_charset_info);
- break;
- }
-
- case HA_ADMIN_NEEDS_UPGRADE:
- case HA_ADMIN_NEEDS_ALTER:
- {
- char buf[MYSQL_ERRMSG_SIZE];
- size_t length;
-
- protocol->store(STRING_WITH_LEN("error"), system_charset_info);
- length=my_snprintf(buf, sizeof(buf), ER(ER_TABLE_NEEDS_UPGRADE),
- table->table_name);
- protocol->store(buf, length, system_charset_info);
- fatal_error=1;
- break;
- }
-
- default: // Probably HA_ADMIN_INTERNAL_ERROR
- {
- char buf[MYSQL_ERRMSG_SIZE];
- size_t length=my_snprintf(buf, sizeof(buf),
- "Unknown - internal error %d during operation",
- result_code);
- protocol->store(STRING_WITH_LEN("error"), system_charset_info);
- protocol->store(buf, length, system_charset_info);
- fatal_error=1;
- break;
- }
- }
- if (table->table)
- {
- if (fatal_error)
- table->table->s->version=0; // Force close of table
- else if (open_for_modify)
- {
- if (table->table->s->tmp_table)
- table->table->file->info(HA_STATUS_CONST);
- else
- {
- pthread_mutex_lock(&LOCK_open);
- remove_table_from_cache(thd, table->table->s->db.str,
- table->table->s->table_name.str, RTFC_NO_FLAG);
- pthread_mutex_unlock(&LOCK_open);
- }
- /* May be something modified consequently we have to invalidate cache */
- query_cache_invalidate3(thd, table->table, 0);
- }
- }
- ha_autocommit_or_rollback(thd, 0);
- end_trans(thd, COMMIT);
- close_thread_tables(thd);
- table->table=0; // For query cache
- if (protocol->write())
- goto err;
- }
-
- my_eof(thd);
- DBUG_RETURN(FALSE);
-
-err:
- ha_autocommit_or_rollback(thd, 1);
- end_trans(thd, ROLLBACK);
- close_thread_tables(thd); // Shouldn't be needed
- if (table)
- table->table=0;
- DBUG_RETURN(TRUE);
-}
-
-
-bool mysql_backup_table(THD* thd, TABLE_LIST* table_list)
-{
- DBUG_ENTER("mysql_backup_table");
- WARN_DEPRECATED(thd, "6.0", "BACKUP TABLE",
- "MySQL Administrator (mysqldump, mysql)");
- DBUG_RETURN(mysql_admin_table(thd, table_list, 0,
- "backup", TL_READ, 0, 0, 0, 0,
- &handler::ha_backup, 0));
-}
-
-
-bool mysql_restore_table(THD* thd, TABLE_LIST* table_list)
-{
- DBUG_ENTER("mysql_restore_table");
- WARN_DEPRECATED(thd, "6.0", "RESTORE TABLE",
- "MySQL Administrator (mysqldump, mysql)");
- DBUG_RETURN(mysql_admin_table(thd, table_list, 0,
- "restore", TL_WRITE, 1, 1, 0,
- &prepare_for_restore,
- &handler::ha_restore, 0));
-}
-
-
-bool mysql_repair_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
-{
- DBUG_ENTER("mysql_repair_table");
- DBUG_RETURN(mysql_admin_table(thd, tables, check_opt,
- "repair", TL_WRITE, 1,
- test(check_opt->sql_flags & TT_USEFRM),
- HA_OPEN_FOR_REPAIR,
- &prepare_for_repair,
- &handler::ha_repair, 0));
-}
-
-
-bool mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
-{
- DBUG_ENTER("mysql_optimize_table");
- DBUG_RETURN(mysql_admin_table(thd, tables, check_opt,
- "optimize", TL_WRITE, 1,0,0,0,
- &handler::ha_optimize, 0));
-}
-
-
-/*
- Assigned specified indexes for a table into key cache
-
- SYNOPSIS
- mysql_assign_to_keycache()
- thd Thread object
- tables Table list (one table only)
-
- RETURN VALUES
- FALSE ok
- TRUE error
-*/
-
-bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables,
- LEX_STRING *key_cache_name)
-{
- HA_CHECK_OPT check_opt;
- KEY_CACHE *key_cache;
- DBUG_ENTER("mysql_assign_to_keycache");
-
- check_opt.init();
- pthread_mutex_lock(&LOCK_global_system_variables);
- if (!(key_cache= get_key_cache(key_cache_name)))
- {
- pthread_mutex_unlock(&LOCK_global_system_variables);
- my_error(ER_UNKNOWN_KEY_CACHE, MYF(0), key_cache_name->str);
- DBUG_RETURN(TRUE);
- }
- pthread_mutex_unlock(&LOCK_global_system_variables);
- check_opt.key_cache= key_cache;
- DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt,
- "assign_to_keycache", TL_READ_NO_INSERT, 0, 0,
- 0, 0, &handler::assign_to_keycache, 0));
-}
-
-
-/*
- Reassign all tables assigned to a key cache to another key cache
-
- SYNOPSIS
- reassign_keycache_tables()
- thd Thread object
- src_cache Reference to the key cache to clean up
- dest_cache New key cache
-
- NOTES
- This is called when one sets a key cache size to zero, in which
- case we have to move the tables associated to this key cache to
- the "default" one.
-
- One has to ensure that one never calls this function while
- some other thread is changing the key cache. This is assured by
- the caller setting src_cache->in_init before calling this function.
-
- We don't delete the old key cache as there may still be pointers pointing
- to it for a while after this function returns.
-
- RETURN VALUES
- 0 ok
-*/
-
-int reassign_keycache_tables(THD *thd, KEY_CACHE *src_cache,
- KEY_CACHE *dst_cache)
-{
- DBUG_ENTER("reassign_keycache_tables");
-
- DBUG_ASSERT(src_cache != dst_cache);
- DBUG_ASSERT(src_cache->in_init);
- src_cache->param_buff_size= 0; // Free key cache
- ha_resize_key_cache(src_cache);
- ha_change_key_cache(src_cache, dst_cache);
- DBUG_RETURN(0);
-}
-
-
-/*
- Preload specified indexes for a table into key cache
-
- SYNOPSIS
- mysql_preload_keys()
- thd Thread object
- tables Table list (one table only)
-
- RETURN VALUES
- FALSE ok
- TRUE error
-*/
-
-bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
-{
- DBUG_ENTER("mysql_preload_keys");
- /*
- We cannot allow concurrent inserts. The storage engine reads
- directly from the index file, bypassing the cache. It could read
- outdated information if parallel inserts into cache blocks happen.
- */
- DBUG_RETURN(mysql_admin_table(thd, tables, 0,
- "preload_keys", TL_READ_NO_INSERT, 0, 0, 0, 0,
- &handler::preload_keys, 0));
-}
-
-
-
-/**
- @brief Create frm file based on I_S table
-
- @param[in] thd thread handler
- @param[in] schema_table I_S table
- @param[in] dst_path path where frm should be created
- @param[in] create_info Create info
-
- @return Operation status
- @retval 0 success
- @retval 1 error
-*/
-
-
-bool mysql_create_like_schema_frm(THD* thd, TABLE_LIST* schema_table,
- char *dst_path, HA_CREATE_INFO *create_info)
-{
- HA_CREATE_INFO local_create_info;
- Alter_info alter_info;
- bool tmp_table= (create_info->options & HA_LEX_CREATE_TMP_TABLE);
- uint keys= schema_table->table->s->keys;
- uint db_options= 0;
- DBUG_ENTER("mysql_create_like_schema_frm");
-
- bzero((char*) &local_create_info, sizeof(local_create_info));
- local_create_info.db_type= schema_table->table->s->db_type();
- local_create_info.row_type= schema_table->table->s->row_type;
- local_create_info.default_table_charset=default_charset_info;
- alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
- schema_table->table->use_all_columns();
- if (mysql_prepare_alter_table(thd, schema_table->table,
- &local_create_info, &alter_info))
- DBUG_RETURN(1);
- if (mysql_prepare_create_table(thd, &local_create_info, &alter_info,
- tmp_table, &db_options,
- schema_table->table->file,
- &schema_table->table->s->key_info, &keys, 0))
- DBUG_RETURN(1);
- local_create_info.max_rows= 0;
- if (mysql_create_frm(thd, dst_path, NullS, NullS,
- &local_create_info, alter_info.create_list,
- keys, schema_table->table->s->key_info,
- schema_table->table->file))
- DBUG_RETURN(1);
- DBUG_RETURN(0);
-}
-
-
-/*
Create a table identical to the specified table
SYNOPSIS
@@ -5253,185 +4518,76 @@ bool mysql_create_like_schema_frm(THD* thd, TABLE_LIST* schema_table,
bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
HA_CREATE_INFO *create_info)
{
- TABLE *name_lock= 0;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN + 1];
- uint dst_path_length;
- char *db= table->db;
- char *table_name= table->table_name;
- int err;
+ HA_CREATE_INFO local_create_info;
+ Alter_info local_alter_info;
bool res= TRUE;
+ bool is_trans= FALSE;
uint not_used;
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- char tmp_path[FN_REFLEN];
-#endif
- char ts_name[FN_LEN + 1];
- myf flags= MY_DONT_OVERWRITE_FILE;
DBUG_ENTER("mysql_create_like_table");
/*
- By opening source table we guarantee that it exists and no concurrent
- DDL operation will mess with it. Later we also take an exclusive
- name-lock on target table name, which makes copying of .frm file,
- call to ha_create_table() and binlogging atomic against concurrent DML
- and DDL operations on target table. Thus by holding both these "locks"
- we ensure that our statement is properly isolated from all concurrent
- operations which matter.
+ We the open source table to get its description in HA_CREATE_INFO
+ and Alter_info objects. This also acquires a shared metadata lock
+ on this table which ensures that no concurrent DDL operation will
+ mess with it.
+ Also in case when we create non-temporary table open_tables()
+ call obtains an exclusive metadata lock on target table ensuring
+ that we can safely perform table creation.
+ Thus by holding both these locks we ensure that our statement is
+ properly isolated from all concurrent operations which matter.
*/
- if (open_tables(thd, &src_table, &not_used, 0))
- DBUG_RETURN(TRUE);
-
- /*
- For bug#25875, Newly created table through CREATE TABLE .. LIKE
- has no ndb_dd attributes;
- Add something to get possible tablespace info from src table,
- it can get valid tablespace name only for disk-base ndb table
- */
- if ((src_table->table->file->get_tablespace_name(thd, ts_name, FN_LEN)))
- {
- create_info->tablespace= ts_name;
- create_info->storage_media= HA_SM_DISK;
- }
-
- strxmov(src_path, src_table->table->s->path.str, reg_ext, NullS);
+ if (open_tables(thd, &thd->lex->query_tables, &not_used, 0))
+ goto err;
+ src_table->table->use_all_columns();
- DBUG_EXECUTE_IF("sleep_create_like_before_check_if_exists", my_sleep(6000000););
+ /* Fill HA_CREATE_INFO and Alter_info with description of source table. */
+ bzero((char*) &local_create_info, sizeof(local_create_info));
+ local_create_info.db_type= src_table->table->s->db_type();
+ local_create_info.row_type= src_table->table->s->row_type;
+ if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
+ &local_alter_info))
+ goto err;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ /* Partition info is not handled by mysql_prepare_alter_table() call. */
+ if (src_table->table->part_info)
+ thd->work_part_info= src_table->table->part_info->get_clone();
+#endif
/*
- Check that destination tables does not exist. Note that its name
- was already checked when it was added to the table list.
- */
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
- {
- if (src_table->table->file->ht == partition_hton)
- {
- my_error(ER_PARTITION_NO_TEMPORARY, MYF(0));
- goto err;
- }
- if (find_temporary_table(thd, db, table_name))
- goto table_exists;
- dst_path_length= build_tmptable_filename(thd, dst_path, sizeof(dst_path));
- create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
- }
- else
- {
- if (lock_table_name_if_not_cached(thd, db, table_name, &name_lock))
- goto err;
- if (!name_lock)
- goto table_exists;
- dst_path_length= build_table_filename(dst_path, sizeof(dst_path) - 1,
- db, table_name, reg_ext, 0);
- if (!access(dst_path, F_OK))
- goto table_exists;
- }
+ Adjust description of source table before using it for creation of
+ target table.
- DBUG_EXECUTE_IF("sleep_create_like_before_copy", my_sleep(6000000););
-
- if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
- flags|= MY_SYNC;
-
- /*
- Create a new table by copying from source table
- and sync the new table if the flag MY_SYNC is set
-
- Altough exclusive name-lock on target table protects us from concurrent
- DML and DDL operations on it we still want to wrap .FRM creation and call
- to ha_create_table() in critical section protected by LOCK_open in order
- to provide minimal atomicity against operations which disregard name-locks,
- like I_S implementation, for example. This is a temporary and should not
- be copied. Instead we should fix our code to always honor name-locks.
-
- Also some engines (e.g. NDB cluster) require that LOCK_open should be held
- during the call to ha_create_table(). See bug #28614 for more info.
+ Similarly to SHOW CREATE TABLE we ignore MAX_ROWS attribute of
+ temporary table which represents I_S table.
*/
- VOID(pthread_mutex_lock(&LOCK_open));
if (src_table->schema_table)
- {
- if (mysql_create_like_schema_frm(thd, src_table, dst_path, create_info))
- {
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
- }
- else if (my_copy(src_path, dst_path, flags))
- {
- if (my_errno == ENOENT)
- my_error(ER_BAD_DB_ERROR,MYF(0),db);
- else
- my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno);
- VOID(pthread_mutex_unlock(&LOCK_open));
+ local_create_info.max_rows= 0;
+ /* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */
+ local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS;
+ /* Replace type of source table with one specified in the statement. */
+ local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
+ local_create_info.options|= create_info->options & HA_LEX_CREATE_TMP_TABLE;
+ /* Reset auto-increment counter for the new table. */
+ local_create_info.auto_increment_value= 0;
+
+ if ((res= mysql_create_table_no_lock(thd, table->db, table->table_name,
+ &local_create_info, &local_alter_info,
+ FALSE, 0, &is_trans)))
goto err;
- }
/*
- As mysql_truncate don't work on a new table at this stage of
- creation, instead create the table directly (for both normal
- and temporary tables).
+ Ensure that we have an exclusive lock on target table if we are creating
+ non-temporary table.
*/
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- /*
- For partitioned tables we need to copy the .par file as well since
- it is used in open_table_def to even be able to create a new handler.
- */
- if (src_table->table->file->ht == partition_hton)
- {
- fn_format(tmp_path, dst_path, reg_ext, ".par", MYF(MY_REPLACE_EXT));
- strmov(dst_path, tmp_path);
- fn_format(tmp_path, src_path, reg_ext, ".par", MYF(MY_REPLACE_EXT));
- strmov(src_path, tmp_path);
- my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE));
- }
-#endif
-
- DBUG_EXECUTE_IF("sleep_create_like_before_ha_create", my_sleep(6000000););
-
- dst_path[dst_path_length - reg_ext_length]= '\0'; // Remove .frm
- if (thd->variables.keep_files_on_create)
- create_info->options|= HA_CREATE_KEEP_FILES;
- err= ha_create_table(thd, dst_path, db, table_name, create_info, 1);
- VOID(pthread_mutex_unlock(&LOCK_open));
-
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
- {
- if (err || !open_temporary_table(thd, dst_path, db, table_name, 1))
- {
- (void) rm_temporary_table(create_info->db_type,
- dst_path); /* purecov: inspected */
- goto err; /* purecov: inspected */
- }
- thd->thread_specific_used= TRUE;
- }
- else if (err)
- {
- (void) quick_rm_table(create_info->db_type, db,
- table_name, 0); /* purecov: inspected */
- goto err; /* purecov: inspected */
- }
-
-goto binlog;
-
-table_exists:
- if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
- {
- char warn_buff[MYSQL_ERRMSG_SIZE];
- my_snprintf(warn_buff, sizeof(warn_buff),
- ER(ER_TABLE_EXISTS_ERROR), table_name);
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_TABLE_EXISTS_ERROR,warn_buff);
- }
- else
- {
- my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
- goto err;
- }
-
-binlog:
- DBUG_EXECUTE_IF("sleep_create_like_before_binlogging", my_sleep(6000000););
-
+ DBUG_ASSERT((create_info->options & HA_LEX_CREATE_TMP_TABLE) ||
+ thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
+ table->table_name,
+ MDL_EXCLUSIVE));
/*
We have to write the query before we unlock the tables.
*/
- if (thd->current_stmt_binlog_row_based)
+ if (thd->is_current_stmt_binlog_format_row())
{
/*
Since temporary tables are not replicated under row-based
@@ -5455,36 +4611,39 @@ binlog:
char buf[2048];
String query(buf, sizeof(buf), system_charset_info);
query.length(0); // Have to zero it since constructor doesn't
+ Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
/*
- Here we open the destination table, on which we already have
- name-lock. This is needed for store_create_info() to work.
- The table will be closed by unlink_open_table() at the end
- of this function.
+ The condition avoids a crash as described in BUG#48506. Other
+ binlogging problems related to CREATE TABLE IF NOT EXISTS LIKE
+ when the existing object is a view will be solved by BUG 47442.
*/
- table->table= name_lock;
- VOID(pthread_mutex_lock(&LOCK_open));
- if (reopen_name_locked_table(thd, table, FALSE))
- {
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
- VOID(pthread_mutex_unlock(&LOCK_open));
-
- /*
- The condition avoids a crash as described in BUG#48506. Other
- binlogging problems related to CREATE TABLE IF NOT EXISTS LIKE
- when the existing object is a view will be solved by BUG 47442.
- */
if (!table->view)
{
- IF_DBUG(int result=)
+ /*
+ Here we open the destination table, on which we already have
+ exclusive metadata lock. This is needed for store_create_info()
+ to work. The table will be closed by close_thread_table() at
+ the end of this branch.
+ */
+ if (open_table(thd, table, thd->mem_root, &ot_ctx))
+ goto err;
+
+ int result __attribute__((unused))=
store_create_info(thd, table, &query,
create_info, FALSE /* show_database */);
DBUG_ASSERT(result == 0); // store_create_info() always return 0
if (write_bin_log(thd, TRUE, query.ptr(), query.length()))
goto err;
+
+ DBUG_ASSERT(thd->open_tables == table->table);
+ /*
+ When opening the table, we ignored the locked tables
+ (MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table without
+ risking to close some locked table.
+ */
+ close_thread_table(thd, &thd->open_tables);
}
}
else // Case 1
@@ -5495,45 +4654,14 @@ binlog:
Case 3 and 4 does nothing under RBR
*/
}
- else if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
+ else if (write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans))
goto err;
- res= FALSE;
-
err:
- if (name_lock)
- {
- pthread_mutex_lock(&LOCK_open);
- unlink_open_table(thd, name_lock, FALSE);
- pthread_mutex_unlock(&LOCK_open);
- }
DBUG_RETURN(res);
}
-bool mysql_analyze_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
-{
- thr_lock_type lock_type = TL_READ_NO_INSERT;
-
- DBUG_ENTER("mysql_analyze_table");
- DBUG_RETURN(mysql_admin_table(thd, tables, check_opt,
- "analyze", lock_type, 1, 0, 0, 0,
- &handler::ha_analyze, 0));
-}
-
-
-bool mysql_check_table(THD* thd, TABLE_LIST* tables,HA_CHECK_OPT* check_opt)
-{
- thr_lock_type lock_type = TL_READ_NO_INSERT;
-
- DBUG_ENTER("mysql_check_table");
- DBUG_RETURN(mysql_admin_table(thd, tables, check_opt,
- "check", lock_type,
- 0, 0, HA_OPEN_FOR_REPAIR, 0,
- &handler::ha_check, &view_checksum));
-}
-
-
/* table_list should contain just one table */
static int
mysql_discard_or_import_tablespace(THD *thd,
@@ -5559,6 +4687,7 @@ mysql_discard_or_import_tablespace(THD *thd,
not complain when we lock the table
*/
thd->tablespace_op= TRUE;
+ table_list->mdl_request.set_type(MDL_SHARED_WRITE);
if (!(table=open_ltable(thd, table_list, TL_WRITE, 0)))
{
thd->tablespace_op=FALSE;
@@ -5579,17 +4708,17 @@ mysql_discard_or_import_tablespace(THD *thd,
query_cache_invalidate3(thd, table_list, 0);
/* The ALTER TABLE is always in its own transaction */
- error = ha_autocommit_or_rollback(thd, 0);
- if (end_active_trans(thd))
+ error= trans_commit_stmt(thd);
+ if (trans_commit_implicit(thd))
error=1;
if (error)
goto err;
error= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
err:
- ha_autocommit_or_rollback(thd, error);
+ trans_rollback_stmt(thd);
thd->tablespace_op=FALSE;
-
+
if (error == 0)
{
my_ok(thd);
@@ -5597,7 +4726,7 @@ err:
}
table->file->print_error(error, MYF(0));
-
+
DBUG_RETURN(-1);
}
@@ -5624,7 +4753,7 @@ is_index_maintenance_unique (TABLE *table, Alter_info *alter_info)
while ((key= key_it++))
{
- if (key->name)
+ if (key->name.str)
{
Alter_drop *drop;
@@ -5632,7 +4761,7 @@ is_index_maintenance_unique (TABLE *table, Alter_info *alter_info)
while ((drop= drop_it++))
{
if (drop->type == Alter_drop::KEY &&
- !my_strcasecmp(system_charset_info, key->name, drop->name))
+ !my_strcasecmp(system_charset_info, key->name.str, drop->name))
return TRUE;
}
}
@@ -5643,7 +4772,7 @@ is_index_maintenance_unique (TABLE *table, Alter_info *alter_info)
/*
SYNOPSIS
- compare_tables()
+ mysql_compare_tables()
table The original table.
alter_info Alter options, fields and keys for the new
table.
@@ -5683,17 +4812,16 @@ is_index_maintenance_unique (TABLE *table, Alter_info *alter_info)
FALSE success
*/
-static
bool
-compare_tables(TABLE *table,
- Alter_info *alter_info,
- HA_CREATE_INFO *create_info,
- uint order_num,
- enum_alter_table_change_level *need_copy_table,
- KEY **key_info_buffer,
- uint **index_drop_buffer, uint *index_drop_count,
- uint **index_add_buffer, uint *index_add_count,
- uint *candidate_key_count)
+mysql_compare_tables(TABLE *table,
+ Alter_info *alter_info,
+ HA_CREATE_INFO *create_info,
+ uint order_num,
+ enum_alter_table_change_level *need_copy_table,
+ KEY **key_info_buffer,
+ uint **index_drop_buffer, uint *index_drop_count,
+ uint **index_add_buffer, uint *index_add_count,
+ uint *candidate_key_count)
{
Field **f_ptr, *field;
uint changes= 0, tmp;
@@ -5709,7 +4837,7 @@ compare_tables(TABLE *table,
*/
bool varchar= create_info->varchar;
bool not_nullable= true;
- DBUG_ENTER("compare_tables");
+ DBUG_ENTER("mysql_compare_tables");
/*
Create a copy of alter_info.
@@ -5720,7 +4848,7 @@ compare_tables(TABLE *table,
mysql_prepare_create_table. Unfortunately,
mysql_prepare_create_table performs its transformations
"in-place", that is, modifies the argument. Since we would
- like to keep compare_tables() idempotent (not altering any
+ like to keep mysql_compare_tables() idempotent (not altering any
of the arguments) we create a copy of alter_info here and
pass it to mysql_prepare_create_table, then use the result
to evaluate possibility of fast ALTER TABLE, and then
@@ -6030,6 +5158,34 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
DBUG_RETURN(error);
}
+/**
+ maximum possible length for certain blob types.
+
+ @param[in] type Blob type (e.g. MYSQL_TYPE_TINY_BLOB)
+
+ @return
+ length
+*/
+
+static uint
+blob_length_by_type(enum_field_types type)
+{
+ switch (type)
+ {
+ case MYSQL_TYPE_TINY_BLOB:
+ return 255;
+ case MYSQL_TYPE_BLOB:
+ return 65535;
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ return 16777215;
+ case MYSQL_TYPE_LONG_BLOB:
+ return 4294967295U;
+ default:
+ DBUG_ASSERT(0); // we should never go here
+ return 0;
+ }
+}
+
/**
Prepare column and key definitions for CREATE TABLE in ALTER TABLE.
@@ -6072,7 +5228,7 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
@retval FALSE success
*/
-static bool
+bool
mysql_prepare_alter_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info,
Alter_info *alter_info)
@@ -6326,6 +5482,14 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
BLOBs may have cfield->length == 0, which is why we test it before
checking whether cfield->length < key_part_length (in chars).
+
+ In case of TEXTs we check the data type maximum length *in bytes*
+ to key part length measured *in characters* (i.e. key_part_length
+ devided to mbmaxlen). This is because it's OK to have:
+ CREATE TABLE t1 (a tinytext, key(a(254)) character set utf8);
+ In case of this example:
+ - data type maximum length is 255.
+ - key_part_length is 1016 (=254*4, where 4 is mbmaxlen)
*/
if (!Field::type_can_have_key_part(cfield->field->type()) ||
!Field::type_can_have_key_part(cfield->sql_type) ||
@@ -6333,12 +5497,16 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
(key_info->flags & HA_SPATIAL) ||
(cfield->field->field_length == key_part_length &&
!f_is_blob(key_part->key_type)) ||
- (cfield->length && (cfield->length < key_part_length /
- key_part->field->charset()->mbmaxlen)))
+ (cfield->length && (((cfield->sql_type >= MYSQL_TYPE_TINY_BLOB &&
+ cfield->sql_type <= MYSQL_TYPE_BLOB) ?
+ blob_length_by_type(cfield->sql_type) :
+ cfield->length) <
+ key_part_length / key_part->field->charset()->mbmaxlen)))
key_part_length= 0; // Use whole field
}
key_part_length /= key_part->field->charset()->mbmaxlen;
key_parts.push_back(new Key_part_spec(cfield->field_name,
+ strlen(cfield->field_name),
key_part_length));
}
if (key_parts.elements)
@@ -6353,6 +5521,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
key_create_info.block_size= key_info->block_size;
if (key_info->flags & HA_USES_PARSER)
key_create_info.parser_name= *plugin_name(key_info->parser);
+ if (key_info->flags & HA_USES_COMMENT)
+ key_create_info.comment= key_info->comment;
if (key_info->flags & HA_SPATIAL)
key_type= Key::SPATIAL;
@@ -6368,7 +5538,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
else
key_type= Key::MULTIPLE;
- key= new Key(key_type, key_name,
+ key= new Key(key_type, key_name, strlen(key_name),
&key_create_info,
test(key_info->flags & HA_GENERATED_KEY),
key_parts);
@@ -6381,10 +5551,10 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
{
if (key->type != Key::FOREIGN_KEY)
new_key_list.push_back(key);
- if (key->name &&
- !my_strcasecmp(system_charset_info,key->name,primary_key_name))
+ if (key->name.str &&
+ !my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
{
- my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name);
+ my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
goto err;
}
}
@@ -6467,7 +5637,7 @@ err:
Important is the fact, that this function tries to do as little work as
possible, by finding out whether a intermediate table is needed to copy
data into and when finishing the altering to use it as the original table.
- For this reason the function compare_tables() is called, which decides
+ For this reason the function mysql_compare_tables() is called, which decides
based on all kind of data how similar are the new and the original
tables.
@@ -6482,7 +5652,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Alter_info *alter_info,
uint order_num, ORDER *order, bool ignore)
{
- TABLE *table, *new_table= 0, *name_lock= 0;
+ TABLE *table, *new_table= 0;
+ MDL_ticket *mdl_ticket;
+ MDL_request target_mdl_request;
int error= 0;
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN + 1];
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
@@ -6491,11 +5663,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
char reg_path[FN_REFLEN+1];
ha_rows copied,deleted;
handlerton *old_db_type, *new_db_type, *save_old_db_type;
- legacy_db_type table_type;
- frm_type_enum frm_type;
enum_alter_table_change_level need_copy_table= ALTER_TABLE_METADATA_ONLY;
#ifdef WITH_PARTITION_STORAGE_ENGINE
- uint fast_alter_partition= 0;
+ TABLE *table_for_fast_alter_partition= NULL;
bool partition_changed= FALSE;
#endif
bool need_lock_for_indexes= TRUE;
@@ -6564,94 +5734,35 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
build_table_filename(reg_path, sizeof(reg_path) - 1, db, table_name, reg_ext, 0);
build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
- mysql_ha_rm_tables(thd, table_list, FALSE);
+ mysql_ha_rm_tables(thd, table_list);
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
/* Conditionally writes to binlog. */
DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
alter_info->tablespace_op));
- strxnmov(new_name_buff, sizeof (new_name_buff) - 1, mysql_data_home, "/", db,
- "/", table_name, reg_ext, NullS);
- (void) unpack_filename(new_name_buff, new_name_buff);
+
/*
- If this is just a rename of a view, short cut to the
- following scenario: 1) lock LOCK_open 2) do a RENAME
- 2) unlock LOCK_open.
- This is a copy-paste added to make sure
- ALTER (sic:) TABLE .. RENAME works for views. ALTER VIEW is handled
- as an independent branch in mysql_execute_command. The need
- for a copy-paste arose because the main code flow of ALTER TABLE
- ... RENAME tries to use open_ltable, which does not work for views
- (open_ltable was never modified to merge table lists of child tables
- into the main table list, like open_tables does).
- This code is wrong and will be removed, please do not copy.
+ Code below can handle only base tables so ensure that we won't open a view.
+ Note that RENAME TABLE the only ALTER clause which is supported for views
+ has been already processed.
*/
- frm_type= mysql_frm_type(thd, new_name_buff, &table_type);
- /* Rename a view */
- /* Sic: there is a race here */
- if (frm_type == FRMTYPE_VIEW && !(alter_info->flags & ~ALTER_RENAME))
- {
- /*
- The following branch handles "ALTER VIEW v1 /no arguments/;"
- This feature is not documented one.
- However, before "OPTIMIZE TABLE t1;" was implemented,
- ALTER TABLE with no alter_specifications was used to force-rebuild
- the table. That's why this grammar is allowed. That's why we ignore
- it for views. So just do nothing in such a case.
- */
- if (!new_name)
- {
- my_ok(thd);
- DBUG_RETURN(FALSE);
- }
+ table_list->required_type= FRMTYPE_TABLE;
- /*
- Avoid problems with a rename on a table that we have locked or
- if the user is trying to to do this in a transcation context
- */
+ Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info);
- if (thd->locked_tables || thd->active_transaction())
- {
- my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
- ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
- DBUG_RETURN(TRUE);
- }
+ DEBUG_SYNC(thd, "alter_table_before_open_tables");
+ error= open_and_lock_tables(thd, table_list, FALSE, 0,
+ &alter_prelocking_strategy);
- if (wait_if_global_read_lock(thd,0,1))
- DBUG_RETURN(TRUE);
- VOID(pthread_mutex_lock(&LOCK_open));
- if (lock_table_names(thd, table_list))
- {
- error= 1;
- goto view_err;
- }
-
- if (!do_rename(thd, table_list, new_db, new_name, new_name, 1))
- {
- if (mysql_bin_log.is_open())
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query(), thd->query_length(),
- 0, FALSE, 0);
- if ((error= mysql_bin_log.write(&qinfo)))
- goto view_err_unlock;
- }
- my_ok(thd);
- }
-
-view_err_unlock:
- unlock_table_names(thd, table_list, (TABLE_LIST*) 0);
-
-view_err:
- pthread_mutex_unlock(&LOCK_open);
- start_waiting_global_read_lock(thd);
- DBUG_RETURN(error);
+ if (error)
+ {
+ DBUG_RETURN(TRUE);
}
- if (!(table= open_n_lock_single_table(thd, table_list, TL_WRITE_ALLOW_READ)))
- DBUG_RETURN(TRUE);
+ table= table_list->table;
table->use_all_columns();
+ mdl_ticket= table->mdl_ticket;
/*
Prohibit changing of the UNION list of a non-temporary MERGE table
@@ -6659,7 +5770,8 @@ view_err:
set of tables from the old table or to open a new TABLE object for
an extended list and verify that they belong to locked tables.
*/
- if (thd->locked_tables &&
+ if ((thd->locked_tables_mode == LTM_LOCK_TABLES ||
+ thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) &&
(create_info->used_fields & HA_CREATE_USED_UNION) &&
(table->s->tmp_table == NO_TMP_TABLE))
{
@@ -6703,14 +5815,29 @@ view_err:
}
else
{
- if (lock_table_name_if_not_cached(thd, new_db, new_name, &name_lock))
+ target_mdl_request.init(MDL_key::TABLE, new_db, new_name,
+ MDL_EXCLUSIVE, MDL_TRANSACTION);
+ /*
+ Global intention exclusive lock must have been already acquired when
+ table to be altered was open, so there is no need to do it here.
+ */
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::GLOBAL,
+ "", "",
+ MDL_INTENTION_EXCLUSIVE));
+
+ if (thd->mdl_context.try_acquire_lock(&target_mdl_request))
DBUG_RETURN(TRUE);
- if (!name_lock)
+ if (target_mdl_request.ticket == NULL)
{
+ /* Table exists and is locked by some thread. */
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
DBUG_RETURN(TRUE);
}
-
+ DEBUG_SYNC(thd, "locked_table_name");
+ /*
+ Table maybe does not exist, but we got an exclusive lock
+ on the name, now we can safely try to find out for sure.
+ */
build_table_filename(new_name_buff, sizeof(new_name_buff) - 1,
new_db, new_name_buff, reg_ext, 0);
if (!access(new_name_buff, F_OK))
@@ -6796,28 +5923,15 @@ view_err:
case LEAVE_AS_IS:
break;
case ENABLE:
- /*
- wait_while_table_is_used() ensures that table being altered is
- opened only by this thread and that TABLE::TABLE_SHARE::version
- of TABLE object corresponding to this table is 0.
- The latter guarantees that no DML statement will open this table
- until ALTER TABLE finishes (i.e. until close_thread_tables())
- while the fact that the table is still open gives us protection
- from concurrent DDL statements.
- */
- VOID(pthread_mutex_lock(&LOCK_open));
- wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
- VOID(pthread_mutex_unlock(&LOCK_open));
+ if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ goto err;
DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000););
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
- /* COND_refresh will be signaled in close_thread_tables() */
break;
case DISABLE:
- VOID(pthread_mutex_lock(&LOCK_open));
- wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
- VOID(pthread_mutex_unlock(&LOCK_open));
+ if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ goto err;
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
- /* COND_refresh will be signaled in close_thread_tables() */
break;
default:
DBUG_ASSERT(FALSE);
@@ -6828,72 +5942,59 @@ view_err:
{
error= 0;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
- table->alias);
+ ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
+ table->alias);
}
- /*
- Unlike to the above case close_cached_table() below will remove ALL
- instances of TABLE from table cache (it will also remove table lock
- held by this thread). So to make actual table renaming and writing
- to binlog atomic we have to put them into the same critical section
- protected by LOCK_open mutex. This also removes gap for races between
- access() and mysql_rename_table() calls.
- */
-
if (!error && (new_name != table_name || new_db != db))
{
thd_proc_info(thd, "rename");
-
- /*
- Workaround InnoDB ending the transaction when the table instance
- is unlocked/closed (close_cached_table below), otherwise the trx
- state will differ between the server and storage engine layers.
- */
- ha_autocommit_or_rollback(thd, 0);
-
- VOID(pthread_mutex_lock(&LOCK_open));
/*
Then do a 'simple' rename of the table. First we need to close all
instances of 'source' table.
+ Note that if wait_while_table_is_used() returns error here (i.e. if
+ this thread was killed) then it must be that previous step of
+ simple rename did nothing and therefore we can safely return
+ without additional clean-up.
*/
- close_cached_table(thd, table);
+ if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ goto err;
+ close_all_tables_for_name(thd, table->s, TRUE);
/*
Then, we want check once again that target table does not exist.
Actually the order of these two steps does not matter since
- earlier we took name-lock on the target table, so we do them
- in this particular order only to be consistent with 5.0, in which
- we don't take this name-lock and where this order really matters.
+ earlier we took exclusive metadata lock on the target table, so
+ we do them in this particular order only to be consistent with 5.0,
+ in which we don't take this lock and where this order really matters.
TODO: Investigate if we need this access() check at all.
*/
if (!access(new_name_buff,F_OK))
{
- my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
- error= -1;
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
+ error= -1;
}
else
{
- *fn_ext(new_name)=0;
- if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
- error= -1;
- else if (Table_triggers_list::change_table_name(thd, db, table_name,
+ *fn_ext(new_name)=0;
+ if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
+ error= -1;
+ else if (Table_triggers_list::change_table_name(thd, db,
+ alias, table_name,
new_db, new_alias))
{
- VOID(mysql_rename_table(old_db_type, new_db, new_alias, db,
- table_name, 0));
+ (void) mysql_rename_table(old_db_type, new_db, new_alias, db,
+ table_name, 0);
error= -1;
}
}
}
- else
- VOID(pthread_mutex_lock(&LOCK_open));
if (error == HA_ERR_WRONG_COMMAND)
{
error= 0;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
- table->alias);
+ ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
+ table->alias);
}
if (!error)
@@ -6907,11 +6008,22 @@ view_err:
table->file->print_error(error, MYF(0));
error= -1;
}
- if (name_lock)
- unlink_open_table(thd, name_lock, FALSE);
- VOID(pthread_mutex_unlock(&LOCK_open));
table_list->table= NULL; // For query cache
query_cache_invalidate3(thd, table_list, 0);
+
+ if ((thd->locked_tables_mode == LTM_LOCK_TABLES ||
+ thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES))
+ {
+ /*
+ Under LOCK TABLES we should adjust meta-data locks before finishing
+ statement. Otherwise we can rely on them being released
+ along with the implicit commit.
+ */
+ if (new_name != table_name || new_db != db)
+ thd->mdl_context.release_all_locks_for_name(mdl_ticket);
+ else
+ mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
+ }
DBUG_RETURN(error);
}
@@ -6919,7 +6031,9 @@ view_err:
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (prep_alter_part_table(thd, table, alter_info, create_info, old_db_type,
- &partition_changed, &fast_alter_partition))
+ &partition_changed,
+ db, table_name, path,
+ &table_for_fast_alter_partition))
goto err;
#endif
/*
@@ -6957,13 +6071,13 @@ view_err:
{
enum_alter_table_change_level need_copy_table_res;
/* Check how much the tables differ. */
- if (compare_tables(table, alter_info,
- create_info, order_num,
- &need_copy_table_res,
- &key_info_buffer,
- &index_drop_buffer, &index_drop_count,
- &index_add_buffer, &index_add_count,
- &candidate_key_count))
+ if (mysql_compare_tables(table, alter_info,
+ create_info, order_num,
+ &need_copy_table_res,
+ &key_info_buffer,
+ &index_drop_buffer, &index_drop_count,
+ &index_add_buffer, &index_add_count,
+ &candidate_key_count))
goto err;
DBUG_EXECUTE_IF("alter_table_only_metadata_change", {
@@ -7152,13 +6266,12 @@ view_err:
create_info->frm_only= 1;
#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (fast_alter_partition)
+ if (table_for_fast_alter_partition)
{
- DBUG_ASSERT(!name_lock);
DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info,
create_info, table_list,
db, table_name,
- fast_alter_partition));
+ table_for_fast_alter_partition));
}
#endif
@@ -7215,6 +6328,8 @@ view_err:
create_info->data_file_name=create_info->index_file_name=0;
DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock");
+ DBUG_EXECUTE_IF("sleep_before_create_table_no_lock",
+ my_sleep(100000););
/*
Create a table with a temporary name.
With create_info->frm_only == 1 this creates a .frm file only.
@@ -7224,7 +6339,7 @@ view_err:
error= mysql_create_table_no_lock(thd, new_db, tmp_name,
create_info,
alter_info,
- 1, 0);
+ 1, 0, NULL);
reenable_binlog(thd);
if (error)
goto err;
@@ -7235,13 +6350,15 @@ view_err:
{
if (table->s->tmp_table)
{
+ Open_table_context ot_ctx(thd, (MYSQL_OPEN_IGNORE_FLUSH |
+ MYSQL_LOCK_IGNORE_TIMEOUT));
TABLE_LIST tbl;
bzero((void*) &tbl, sizeof(tbl));
tbl.db= new_db;
tbl.table_name= tbl.alias= tmp_name;
/* Table is in thd->temporary_tables */
- new_table= open_table(thd, &tbl, thd->mem_root, (bool*) 0,
- MYSQL_LOCK_IGNORE_FLUSH);
+ (void) open_table(thd, &tbl, thd->mem_root, &ot_ctx);
+ new_table= tbl.table;
}
else
{
@@ -7249,11 +6366,11 @@ view_err:
/* table is a normal table: Create temporary table in same directory */
build_table_filename(path, sizeof(path) - 1, new_db, tmp_name, "",
FN_IS_TMP);
- /* Open our intermediate table */
- new_table=open_temporary_table(thd, path, new_db, tmp_name,0);
+ /* Open our intermediate table. */
+ new_table= open_table_uncached(thd, path, new_db, tmp_name, TRUE);
}
if (!new_table)
- goto err1;
+ goto err_new_table_cleanup;
/*
Note: In case of MERGE table, we do not attach children. We do not
copy data for MERGE tables. Only the children have data.
@@ -7274,6 +6391,10 @@ view_err:
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
new_table->next_number_field=new_table->found_next_number_field;
thd_proc_info(thd, "copy to tmp table");
+ DBUG_EXECUTE_IF("abort_copy_table", {
+ my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
+ goto err_new_table_cleanup;
+ });
error= copy_data_between_tables(table, new_table,
alter_info->create_list, ignore,
order_num, order, &copied, &deleted,
@@ -7282,14 +6403,14 @@ view_err:
}
else
{
- VOID(pthread_mutex_lock(&LOCK_open));
- wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
- VOID(pthread_mutex_unlock(&LOCK_open));
+ if (!table->s->tmp_table &&
+ wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ goto err_new_table_cleanup;
thd_proc_info(thd, "manage keys");
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
alter_info->keys_onoff);
- error= ha_autocommit_or_rollback(thd, 0);
- if (end_active_trans(thd))
+ error= trans_commit_stmt(thd);
+ if (trans_commit_implicit(thd))
error= 1;
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -7335,7 +6456,7 @@ view_err:
table->key_info= key_info;
table->file->print_error(error, MYF(0));
table->key_info= save_key_info;
- goto err1;
+ goto err_new_table_cleanup;
}
}
/*end of if (index_add_count)*/
@@ -7358,14 +6479,14 @@ view_err:
index_drop_count)))
{
table->file->print_error(error, MYF(0));
- goto err1;
+ goto err_new_table_cleanup;
}
/* Tell the handler to finally drop the indexes. */
if ((error= table->file->final_drop_index(table)))
{
table->file->print_error(error, MYF(0));
- goto err1;
+ goto err_new_table_cleanup;
}
}
/*end of if (index_drop_count)*/
@@ -7377,71 +6498,73 @@ view_err:
/* Need to commit before a table is unlocked (NDB requirement). */
DBUG_PRINT("info", ("Committing before unlocking table"));
- if (ha_autocommit_or_rollback(thd, 0) || end_active_trans(thd))
- goto err1;
+ if (trans_commit_stmt(thd) || trans_commit_implicit(thd))
+ goto err_new_table_cleanup;
}
/*end of if (! new_table) for add/drop index*/
+ if (error)
+ goto err_new_table_cleanup;
+
if (table->s->tmp_table != NO_TMP_TABLE)
{
- /* We changed a temporary table */
- if (error)
- goto err1;
/* Close lock if this is a transactional table */
if (thd->lock)
{
- mysql_unlock_tables(thd, thd->lock);
- thd->lock=0;
+ if (thd->locked_tables_mode != LTM_LOCK_TABLES &&
+ thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES)
+ {
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock=0;
+ }
+ else
+ {
+ /*
+ If LOCK TABLES list is not empty and contains this table,
+ unlock the table and remove the table from this list.
+ */
+ mysql_lock_remove(thd, thd->lock, table);
+ }
}
- /*
- If LOCK TABLES list is not empty and contains this table,
- unlock the table and remove the table from this list.
- */
- mysql_lock_remove(thd, thd->locked_tables, table, FALSE);
/* Remove link to old table and rename the new one */
close_temporary_table(thd, table, 1, 1);
/* Should pass the 'new_name' as we store table name in the cache */
if (rename_temporary_table(thd, new_table, new_db, new_name))
- goto err1;
+ goto err_new_table_cleanup;
/* We don't replicate alter table statement on temporary tables */
- if (!thd->current_stmt_binlog_row_based &&
+ if (!thd->is_current_stmt_binlog_format_row() &&
write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
DBUG_RETURN(TRUE);
goto end_temporary;
}
+ /*
+ Close the intermediate table that will be the new table, but do
+ not delete it! Even altough MERGE tables do not have their children
+ attached here it is safe to call close_temporary_table().
+ */
if (new_table)
{
- /*
- Close the intermediate table that will be the new table.
- Note that MERGE tables do not have their children attached here.
- */
- intern_close_table(new_table);
- my_free(new_table,MYF(0));
+ close_temporary_table(thd, new_table, 1, 0);
+ new_table= 0;
}
DEBUG_SYNC(thd, "alter_table_before_rename_result_table");
- VOID(pthread_mutex_lock(&LOCK_open));
- if (error)
- {
- VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
/*
Data is copied. Now we:
- 1) Wait until all other threads close old version of table.
+ 1) Wait until all other threads will stop using old version of table
+ by upgrading shared metadata lock to exclusive one.
2) Close instances of table open by this thread and replace them
- with exclusive name-locks.
+ with placeholders to simplify reopen process.
3) Rename the old table to a temp name, rename the new one to the
old name.
4) If we are under LOCK TABLES and don't do ALTER TABLE ... RENAME
we reopen new version of table.
5) Write statement to the binary log.
6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we
- remove name-locks from list of open tables and table cache.
- 7) If we are not not under LOCK TABLES we rely on close_thread_tables()
- call to remove name-locks from table cache and list of open table.
+ remove placeholders and release metadata locks.
+ 7) If we are not not under LOCK TABLES we rely on the caller
+ (mysql_execute_command()) to release metadata locks.
*/
thd_proc_info(thd, "rename result table");
@@ -7450,10 +6573,15 @@ view_err:
if (lower_case_table_names)
my_casedn_str(files_charset_info, old_name);
- wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME);
- close_data_files_and_morph_locks(thd, db, table_name);
+ if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME))
+ goto err_new_table_cleanup;
+
+
+ close_all_tables_for_name(thd, table->s,
+ new_name != table_name || new_db != db);
error=0;
+ table_list->table= table= 0; /* Safety */
save_old_db_type= old_db_type;
/*
@@ -7463,7 +6591,7 @@ view_err:
it should become the actual table. Later, we will recycle the old table.
However, in case of ALTER TABLE RENAME there might be no intermediate
table. This is when the old and new tables are compatible, according to
- compare_table(). Then, we need one additional call to
+ mysql_compare_table(). Then, we need one additional call to
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
actual rename in the SE and the FRM is not touched. Note that, if the
table is renamed and the SE is also changed, then an intermediate table
@@ -7479,7 +6607,7 @@ view_err:
FN_TO_IS_TMP))
{
error=1;
- VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
+ (void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
}
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
new_alias, FN_FROM_IS_TMP) ||
@@ -7487,21 +6615,24 @@ view_err:
(need_copy_table != ALTER_TABLE_METADATA_ONLY ||
mysql_rename_table(save_old_db_type, db, table_name, new_db,
new_alias, NO_FRM_RENAME)) &&
- Table_triggers_list::change_table_name(thd, db, table_name,
+ Table_triggers_list::change_table_name(thd, db, alias, table_name,
new_db, new_alias)))
{
/* Try to get everything back. */
error=1;
- VOID(quick_rm_table(new_db_type,new_db,new_alias, 0));
- VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
- VOID(mysql_rename_table(old_db_type, db, old_name, db, alias,
- FN_FROM_IS_TMP));
+ (void) quick_rm_table(new_db_type,new_db,new_alias, 0);
+ (void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
+ (void) mysql_rename_table(old_db_type, db, old_name, db, alias,
+ FN_FROM_IS_TMP);
}
+ if (! error)
+ (void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
+
if (error)
{
/* This shouldn't happen. But let us play it safe. */
- goto err_with_placeholders;
+ goto err_with_mdl;
}
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
@@ -7511,6 +6642,7 @@ view_err:
To do this we need to obtain a handler object for it.
NO need to tamper with MERGE tables. The real open is done later.
*/
+ Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
TABLE *t_table;
if (new_name != table_name || new_db != db)
{
@@ -7519,45 +6651,36 @@ view_err:
table_list->table_name_length= strlen(new_name);
table_list->db= new_db;
table_list->db_length= strlen(new_db);
- table_list->table= name_lock;
- if (reopen_name_locked_table(thd, table_list, FALSE))
- goto err_with_placeholders;
- t_table= table_list->table;
+ table_list->mdl_request.ticket= target_mdl_request.ticket;
}
else
{
- if (reopen_table(table))
- goto err_with_placeholders;
- t_table= table;
- }
- /* Tell the handler that a new frm file is in place. */
- if (t_table->file->ha_create_handler_files(path, NULL, CHF_INDEX_FLAG,
- create_info))
- goto err_with_placeholders;
- if (thd->locked_tables && new_name == table_name && new_db == db)
- {
/*
- We are 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 suitable for reopening.
+ Under LOCK TABLES, we have a different mdl_lock_ticket
+ points to a different instance than the one set initially
+ to request the lock.
*/
- DBUG_ASSERT(t_table == table);
- table->open_placeholder= 1;
- close_handle_and_leave_table_as_lock(table);
+ table_list->mdl_request.ticket= mdl_ticket;
}
- }
+ if (open_table(thd, table_list, thd->mem_root, &ot_ctx))
+ {
+ goto err_with_mdl;
+ }
+ t_table= table_list->table;
+
+ /* Tell the handler that a new frm file is in place. */
+ error= t_table->file->ha_create_handler_files(path, NULL, CHF_INDEX_FLAG,
+ create_info);
- VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
+ DBUG_ASSERT(thd->open_tables == t_table);
+ close_thread_table(thd, &thd->open_tables);
+ table_list->table= 0;
- if (thd->locked_tables && new_name == table_name && new_db == db)
- {
- thd->in_lock_tables= 1;
- error= reopen_tables(thd, 1, 1);
- thd->in_lock_tables= 0;
if (error)
- goto err_with_placeholders;
+ goto err_with_mdl;
}
- VOID(pthread_mutex_unlock(&LOCK_open));
+ if (thd->locked_tables_list.reopen_tables(thd))
+ goto err_with_mdl;
thd_proc_info(thd, "end");
@@ -7569,7 +6692,7 @@ view_err:
db, table_name);
DBUG_ASSERT(!(mysql_bin_log.is_open() &&
- thd->current_stmt_binlog_row_based &&
+ thd->is_current_stmt_binlog_format_row() &&
(create_info->options & HA_LEX_CREATE_TMP_TABLE)));
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
DBUG_RETURN(TRUE);
@@ -7584,11 +6707,11 @@ view_err:
char path[FN_REFLEN];
TABLE *t_table;
build_table_filename(path + 1, sizeof(path) - 1, new_db, table_name, "", 0);
- t_table= open_temporary_table(thd, path, new_db, tmp_name, 0);
+ t_table= open_table_uncached(thd, path, new_db, tmp_name, FALSE);
if (t_table)
{
intern_close_table(t_table);
- my_free(t_table, MYF(0));
+ my_free(t_table);
}
else
sql_print_warning("Could not open table %s.%s after rename\n",
@@ -7598,48 +6721,46 @@ view_err:
table_list->table=0; // For query cache
query_cache_invalidate3(thd, table_list, 0);
- if (thd->locked_tables && (new_name != table_name || new_db != db))
+ if (thd->locked_tables_mode == LTM_LOCK_TABLES ||
+ thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
{
- /*
- If are we under LOCK TABLES and did ALTER TABLE with RENAME we need
- to remove placeholders for the old table and for the target table
- from the list of open tables and table cache. If we are not under
- LOCK TABLES we can rely on close_thread_tables() doing this job.
- */
- pthread_mutex_lock(&LOCK_open);
- unlink_open_table(thd, table, FALSE);
- unlink_open_table(thd, name_lock, FALSE);
- pthread_mutex_unlock(&LOCK_open);
+ if ((new_name != table_name || new_db != db))
+ thd->mdl_context.release_all_locks_for_name(mdl_ticket);
+ else
+ mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
}
end_temporary:
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
(ulong) (copied + deleted), (ulong) deleted,
- (ulong) thd->cuted_fields);
+ (ulong) thd->warning_info->statement_warn_count());
my_ok(thd, copied + deleted, 0L, tmp_name);
- thd->some_tables_deleted=0;
DBUG_RETURN(FALSE);
-err1:
+err_new_table_cleanup:
if (new_table)
{
/* close_temporary_table() frees the new_table pointer. */
close_temporary_table(thd, new_table, 1, 1);
}
else
- VOID(quick_rm_table(new_db_type, new_db, tmp_name,
- create_info->frm_only
- ? FN_IS_TMP | FRM_ONLY
- : FN_IS_TMP));
+ (void) quick_rm_table(new_db_type, new_db, tmp_name,
+ create_info->frm_only ? FN_IS_TMP | FRM_ONLY : FN_IS_TMP);
err:
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ /* If prep_alter_part_table created an intermediate table, destroy it. */
+ if (table_for_fast_alter_partition)
+ close_temporary(table_for_fast_alter_partition, 1, 0);
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
/*
No default value was provided for a DATE/DATETIME field, the
current sql_mode doesn't allow the '0000-00-00' value and
the table to be altered isn't empty.
Report error here.
*/
- if (alter_info->error_if_not_empty && thd->row_count)
+ if (alter_info->error_if_not_empty &&
+ thd->warning_info->current_row_for_warning())
{
const char *f_val= 0;
enum enum_mysql_timestamp_type t_type= MYSQL_TIMESTAMP_DATE;
@@ -7660,33 +6781,75 @@ err:
}
bool save_abort_on_warning= thd->abort_on_warning;
thd->abort_on_warning= TRUE;
- make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
f_val, strlength(f_val), t_type,
alter_info->datetime_field->field_name);
thd->abort_on_warning= save_abort_on_warning;
}
- if (name_lock)
- {
- pthread_mutex_lock(&LOCK_open);
- unlink_open_table(thd, name_lock, FALSE);
- pthread_mutex_unlock(&LOCK_open);
- }
+
DBUG_RETURN(TRUE);
-err_with_placeholders:
+err_with_mdl:
/*
- An error happened while we were holding exclusive name-lock on table
- being altered. To be safe under LOCK TABLES we should remove placeholders
- from list of open tables list and table cache.
+ An error happened while we were holding exclusive name metadata lock
+ on table being altered. To be safe under LOCK TABLES we should
+ remove all references to the altered table from the list of locked
+ tables and release the exclusive metadata lock.
*/
- unlink_open_table(thd, table, FALSE);
- if (name_lock)
- unlink_open_table(thd, name_lock, FALSE);
- VOID(pthread_mutex_unlock(&LOCK_open));
+ thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
+ thd->mdl_context.release_all_locks_for_name(mdl_ticket);
DBUG_RETURN(TRUE);
}
/* mysql_alter_table */
+
+
+/**
+ Prepare the transaction for the alter table's copy phase.
+*/
+
+bool mysql_trans_prepare_alter_copy_data(THD *thd)
+{
+ DBUG_ENTER("mysql_prepare_alter_copy_data");
+ /*
+ Turn off recovery logging since rollback of an alter table is to
+ delete the new table so there is no need to log the changes to it.
+
+ This needs to be done before external_lock.
+ */
+ if (ha_enable_transaction(thd, FALSE))
+ DBUG_RETURN(TRUE);
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ Commit the copy phase of the alter table.
+*/
+
+bool mysql_trans_commit_alter_copy_data(THD *thd)
+{
+ bool error= FALSE;
+ DBUG_ENTER("mysql_commit_alter_copy_data");
+
+ if (ha_enable_transaction(thd, TRUE))
+ DBUG_RETURN(TRUE);
+
+ /*
+ Ensure that the new table is saved properly to disk before installing
+ the new .frm.
+ And that InnoDB's internal latches are released, to avoid deadlock
+ when waiting on other instances of the table before rename (Bug#54747).
+ */
+ if (trans_commit_stmt(thd))
+ error= TRUE;
+ if (trans_commit_implicit(thd))
+ error= TRUE;
+
+ DBUG_RETURN(error);
+}
+
+
static int
copy_data_between_tables(TABLE *from,TABLE *to,
List<Create_field> &create,
@@ -7713,14 +6876,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
ulonglong prev_insert_id;
DBUG_ENTER("copy_data_between_tables");
- /*
- Turn off recovery logging since rollback of an alter table is to
- delete the new table so there is no need to log the changes to it.
-
- This needs to be done before external_lock
- */
- error= ha_enable_transaction(thd, FALSE);
- if (error)
+ if (mysql_trans_prepare_alter_copy_data(thd))
DBUG_RETURN(-1);
if (!(copy= new Copy_field[to->s->fields]))
@@ -7807,7 +6963,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE);
if (ignore)
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- thd->row_count= 0;
+ thd->warning_info->reset_current_row_for_warning();
restore_record(to, s->default_values); // Create empty record
while (!(error=info.read_record(&info)))
{
@@ -7817,7 +6973,6 @@ copy_data_between_tables(TABLE *from,TABLE *to,
error= 1;
break;
}
- thd->row_count++;
/* Return error if source table isn't empty. */
if (error_if_not_empty)
{
@@ -7867,6 +7022,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
}
else
found_count++;
+ thd->warning_info->inc_current_row_for_warning();
}
end_read_record(&info);
free_io_cache(from);
@@ -7875,24 +7031,12 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (to->file->ha_end_bulk_insert() && error <= 0)
{
to->file->print_error(my_errno,MYF(0));
- error=1;
+ error= 1;
}
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
- if (ha_enable_transaction(thd, TRUE))
- {
+ if (mysql_trans_commit_alter_copy_data(thd))
error= 1;
- goto err;
- }
-
- /*
- Ensure that the new table is saved properly to disk so that we
- can do a rename
- */
- if (ha_autocommit_or_rollback(thd, 0))
- error=1;
- if (end_active_trans(thd))
- error=1;
err:
thd->variables.sql_mode= save_sql_mode;
@@ -7903,6 +7047,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
to->file->ha_release_auto_increment();
if (to->file->ha_external_lock(thd,F_UNLCK))
error=1;
+ if (error < 0 && to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME))
+ error= 1;
DBUG_RETURN(error > 0 ? -1 : 0);
}
@@ -7930,6 +7076,12 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
uninitialized data. open_tables() could fail.
*/
table_list->table= NULL;
+ /* Same applies to MDL ticket. */
+ table_list->mdl_request.ticket= NULL;
+ /* Set lock type which is appropriate for ALTER TABLE. */
+ table_list->lock_type= TL_READ_NO_INSERT;
+ /* Same applies to MDL request. */
+ table_list->mdl_request.set_type(MDL_SHARED_NO_WRITE);
bzero((char*) &create_info, sizeof(create_info));
create_info.row_type=ROW_TYPE_NOT_USED;
@@ -7956,7 +7108,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
field_list.push_back(item= new Item_int("Checksum", (longlong) 1,
MY_INT64_NUM_DECIMAL_DIGITS));
item->maybe_null= 1;
- if (protocol->send_fields(&field_list,
+ if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
@@ -7968,7 +7120,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
strxmov(table_name, table->db ,".", table->table_name, NullS);
- t= table->table= open_n_lock_single_table(thd, table, TL_READ);
+ t= table->table= open_n_lock_single_table(thd, table, TL_READ, 0);
thd->clear_error(); // these errors shouldn't get client
protocol->prepare_for_resend();
@@ -8064,7 +7216,13 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
}
}
thd->clear_error();
+ if (! thd->in_sub_stmt)
+ trans_rollback_stmt(thd);
close_thread_tables(thd);
+ /*
+ Don't release metadata locks, this will be done at
+ statement end.
+ */
table->table=0; // For query cache
}
if (protocol->write())
@@ -8074,10 +7232,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
my_eof(thd);
DBUG_RETURN(FALSE);
- err:
- close_thread_tables(thd); // Shouldn't be needed
- if (table)
- table->table=0;
+err:
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_table.h b/sql/sql_table.h
new file mode 100644
index 00000000000..aa5738fd4c9
--- /dev/null
+++ b/sql/sql_table.h
@@ -0,0 +1,217 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_TABLE_INCLUDED
+#define SQL_TABLE_INCLUDED
+
+#include "my_global.h" /* my_bool */
+#include "my_sys.h" // pthread_mutex_t
+
+class Alter_info;
+class Create_field;
+struct TABLE_LIST;
+class THD;
+struct TABLE;
+struct handlerton;
+typedef struct st_ha_check_opt HA_CHECK_OPT;
+typedef struct st_ha_create_information HA_CREATE_INFO;
+typedef struct st_key KEY;
+typedef struct st_key_cache KEY_CACHE;
+typedef struct st_lock_param_type ALTER_PARTITION_PARAM_TYPE;
+typedef struct st_mysql_lex_string LEX_STRING;
+typedef struct st_order ORDER;
+class Alter_table_change_level;
+
+enum ddl_log_entry_code
+{
+ /*
+ DDL_LOG_EXECUTE_CODE:
+ This is a code that indicates that this is a log entry to
+ be executed, from this entry a linked list of log entries
+ can be found and executed.
+ DDL_LOG_ENTRY_CODE:
+ An entry to be executed in a linked list from an execute log
+ entry.
+ DDL_IGNORE_LOG_ENTRY_CODE:
+ An entry that is to be ignored
+ */
+ DDL_LOG_EXECUTE_CODE = 'e',
+ DDL_LOG_ENTRY_CODE = 'l',
+ DDL_IGNORE_LOG_ENTRY_CODE = 'i'
+};
+
+enum ddl_log_action_code
+{
+ /*
+ The type of action that a DDL_LOG_ENTRY_CODE entry is to
+ perform.
+ DDL_LOG_DELETE_ACTION:
+ Delete an entity
+ DDL_LOG_RENAME_ACTION:
+ Rename an entity
+ DDL_LOG_REPLACE_ACTION:
+ Rename an entity after removing the previous entry with the
+ new name, that is replace this entry.
+ */
+ DDL_LOG_DELETE_ACTION = 'd',
+ DDL_LOG_RENAME_ACTION = 'r',
+ DDL_LOG_REPLACE_ACTION = 's'
+};
+
+
+typedef struct st_ddl_log_entry
+{
+ const char *name;
+ const char *from_name;
+ const char *handler_name;
+ uint next_entry;
+ uint entry_pos;
+ enum ddl_log_entry_code entry_type;
+ enum ddl_log_action_code action_type;
+ /*
+ Most actions have only one phase. REPLACE does however have two
+ phases. The first phase removes the file with the new name if
+ there was one there before and the second phase renames the
+ old name to the new name.
+ */
+ char phase;
+} DDL_LOG_ENTRY;
+
+typedef struct st_ddl_log_memory_entry
+{
+ uint entry_pos;
+ struct st_ddl_log_memory_entry *next_log_entry;
+ struct st_ddl_log_memory_entry *prev_log_entry;
+ struct st_ddl_log_memory_entry *next_active_log_entry;
+} DDL_LOG_MEMORY_ENTRY;
+
+
+enum enum_explain_filename_mode
+{
+ EXPLAIN_ALL_VERBOSE= 0,
+ EXPLAIN_PARTITIONS_VERBOSE,
+ EXPLAIN_PARTITIONS_AS_COMMENT
+};
+
+/* depends on errmsg.txt Database `db`, Table `t` ... */
+#define EXPLAIN_FILENAME_MAX_EXTRA_LENGTH 63
+
+#define MYSQL50_TABLE_NAME_PREFIX "#mysql50#"
+#define MYSQL50_TABLE_NAME_PREFIX_LENGTH 9
+
+#define WFRM_WRITE_SHADOW 1
+#define WFRM_INSTALL_SHADOW 2
+#define WFRM_PACK_FRM 4
+#define WFRM_KEEP_SHARE 8
+
+/* Flags for conversion functions. */
+#define FN_FROM_IS_TMP (1 << 0)
+#define FN_TO_IS_TMP (1 << 1)
+#define FN_IS_TMP (FN_FROM_IS_TMP | FN_TO_IS_TMP)
+#define NO_FRM_RENAME (1 << 2)
+#define FRM_ONLY (1 << 3)
+
+uint filename_to_tablename(const char *from, char *to, uint to_length);
+uint tablename_to_filename(const char *from, char *to, uint to_length);
+uint check_n_cut_mysql50_prefix(const char *from, char *to, uint to_length);
+bool check_mysql50_prefix(const char *name);
+uint build_table_filename(char *buff, size_t bufflen, const char *db,
+ const char *table, const char *ext, uint flags);
+uint build_table_shadow_filename(char *buff, size_t bufflen,
+ ALTER_PARTITION_PARAM_TYPE *lpt);
+bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info);
+bool mysql_create_table_no_lock(THD *thd, const char *db,
+ const char *table_name,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info,
+ bool tmp_table, uint select_field_count,
+ bool *is_trans);
+bool mysql_prepare_alter_table(THD *thd, TABLE *table,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info);
+bool mysql_trans_prepare_alter_copy_data(THD *thd);
+bool mysql_trans_commit_alter_copy_data(THD *thd);
+bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
+ HA_CREATE_INFO *create_info,
+ TABLE_LIST *table_list,
+ Alter_info *alter_info,
+ uint order_num, ORDER *order, bool ignore);
+bool mysql_compare_tables(TABLE *table,
+ Alter_info *alter_info,
+ HA_CREATE_INFO *create_info,
+ uint order_num,
+ Alter_table_change_level *need_copy_table,
+ KEY **key_info_buffer,
+ uint **index_drop_buffer, uint *index_drop_count,
+ uint **index_add_buffer, uint *index_add_count,
+ uint *candidate_key_count);
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list);
+bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
+ TABLE_LIST *src_table,
+ HA_CREATE_INFO *create_info);
+bool mysql_rename_table(handlerton *base, const char *old_db,
+ const char * old_name, const char *new_db,
+ const char * new_name, uint flags);
+
+bool mysql_backup_table(THD* thd, TABLE_LIST* table_list);
+bool mysql_restore_table(THD* thd, TABLE_LIST* table_list);
+
+bool mysql_checksum_table(THD* thd, TABLE_LIST* table_list,
+ HA_CHECK_OPT* check_opt);
+bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
+ my_bool drop_temporary);
+int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
+ bool drop_temporary, bool drop_view,
+ bool log_query);
+bool quick_rm_table(handlerton *base,const char *db,
+ const char *table_name, uint flags);
+void close_cached_table(THD *thd, TABLE *table);
+void sp_prepare_create_field(THD *thd, Create_field *sql_field);
+int prepare_create_field(Create_field *sql_field,
+ uint *blob_columns,
+ int *timestamps, int *timestamps_with_niladic,
+ longlong table_flags);
+CHARSET_INFO* get_sql_field_charset(Create_field *sql_field,
+ HA_CREATE_INFO *create_info);
+bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags);
+int write_bin_log(THD *thd, bool clear_error,
+ char const *query, ulong query_length,
+ bool is_trans= FALSE);
+bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry,
+ DDL_LOG_MEMORY_ENTRY **active_entry);
+bool write_execute_ddl_log_entry(uint first_entry,
+ bool complete,
+ DDL_LOG_MEMORY_ENTRY **active_entry);
+bool deactivate_ddl_log_entry(uint entry_no);
+void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry);
+bool sync_ddl_log();
+void release_ddl_log();
+void execute_ddl_log_recovery();
+bool execute_ddl_log_entry(THD *thd, uint first_entry);
+bool check_duplicate_warning(THD *thd, char *msg, ulong length);
+
+/*
+ These prototypes where under INNODB_COMPATIBILITY_HOOKS.
+*/
+uint explain_filename(THD* thd, const char *from, char *to, uint to_length,
+ enum_explain_filename_mode explain_mode);
+
+
+extern MYSQL_PLUGIN_IMPORT const char *primary_key_name;
+extern mysql_mutex_t LOCK_gdl;
+
+#endif /* SQL_TABLE_INCLUDED */
diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc
index 65107f8679e..18650c11c09 100644
--- a/sql/sql_tablespace.cc
+++ b/sql/sql_tablespace.cc
@@ -15,7 +15,11 @@
/* drop and alter of tablespaces */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_tablespace.h"
+#include "sql_table.h" // write_bin_log
+#include "sql_class.h" // THD
int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
{
@@ -31,7 +35,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
{
hton= ha_default_handlerton(thd);
if (ts_info->storage_engine != 0)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_USING_OTHER_HANDLER,
ER(ER_WARN_USING_OTHER_HANDLER),
ha_resolve_storage_engine_name(hton),
@@ -60,7 +64,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
}
else
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
ER(ER_ILLEGAL_HA_CREATE_OPTION),
ha_resolve_storage_engine_name(hton),
diff --git a/sql/sql_tablespace.h b/sql/sql_tablespace.h
new file mode 100644
index 00000000000..93544dea4af
--- /dev/null
+++ b/sql/sql_tablespace.h
@@ -0,0 +1,24 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_TABLESPACE_INCLUDED
+#define SQL_TABLESPACE_INCLUDED
+
+class THD;
+class st_alter_tablespace;
+
+int mysql_alter_tablespace(THD* thd, st_alter_tablespace *ts_info);
+
+#endif /* SQL_TABLESPACE_INCLUDED */
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 5de8301fd05..9d0614f8529 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2006 MySQL AB
+/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -17,8 +17,13 @@
/* Write some debug info */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_test.h"
+#include "sql_base.h" // table_def_cache, table_cache_count, unused_tables
+#include "sql_show.h" // calc_sum_of_all_status
#include "sql_select.h"
+#include "keycaches.h"
#include <hash.h>
#include <thr_alarm.h>
#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
@@ -40,7 +45,6 @@ static const char *lock_descriptions[] =
/* TL_READ_HIGH_PRIORITY */ "High priority read lock",
/* TL_READ_NO_INSERT */ "Read lock without concurrent inserts",
/* TL_WRITE_ALLOW_WRITE */ "Write lock that allows other writers",
- /* TL_WRITE_ALLOW_READ */ "Write lock, but allow reading",
/* TL_WRITE_CONCURRENT_INSERT */ "Concurrent insert lock",
/* TL_WRITE_DELAYED */ "Lock used by delayed insert",
/* TL_WRITE_DEFAULT */ NULL,
@@ -55,44 +59,54 @@ static const char *lock_descriptions[] =
void
print_where(COND *cond,const char *info, enum_query_type query_type)
{
+ char buff[256];
+ String str(buff,(uint32) sizeof(buff), system_charset_info);
+ str.length(0);
if (cond)
- {
- char buff[256];
- String str(buff,(uint32) sizeof(buff), system_charset_info);
- str.length(0);
cond->print(&str, query_type);
- str.append('\0');
- DBUG_LOCK_FILE;
- (void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info);
- (void) fputs(str.ptr(),DBUG_FILE);
- (void) fputc('\n',DBUG_FILE);
- DBUG_UNLOCK_FILE;
- }
+ str.append('\0');
+
+ DBUG_LOCK_FILE;
+ (void) fprintf(DBUG_FILE,"\nWHERE:(%s) %p ", info, cond);
+ (void) fputs(str.ptr(),DBUG_FILE);
+ (void) fputc('\n',DBUG_FILE);
+ DBUG_UNLOCK_FILE;
}
/* This is for debugging purposes */
-void print_cached_tables(void)
+static void print_cached_tables(void)
{
uint idx,count,unused;
- TABLE *start_link,*lnk;
+ TABLE_SHARE *share;
+ TABLE *start_link, *lnk, *entry;
compile_time_assert(TL_WRITE_ONLY+1 == array_elements(lock_descriptions));
/* purecov: begin tested */
- VOID(pthread_mutex_lock(&LOCK_open));
+ mysql_mutex_lock(&LOCK_open);
puts("DB Table Version Thread Open Lock");
- for (idx=unused=0 ; idx < open_cache.records ; idx++)
+ for (idx=unused=0 ; idx < table_def_cache.records ; idx++)
{
- TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
- printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
- entry->s->db.str, entry->s->table_name.str, entry->s->version,
- entry->in_use ? entry->in_use->thread_id : 0L,
- entry->db_stat ? 1 : 0,
- entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
- if (!entry->in_use)
+ share= (TABLE_SHARE*) my_hash_element(&table_def_cache, idx);
+
+ I_P_List_iterator<TABLE, TABLE_share> it(share->used_tables);
+ while ((entry= it++))
+ {
+ printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
+ entry->s->db.str, entry->s->table_name.str, entry->s->version,
+ entry->in_use->thread_id, entry->db_stat ? 1 : 0,
+ lock_descriptions[(int)entry->reginfo.lock_type]);
+ }
+ it.init(share->free_tables);
+ while ((entry= it++))
+ {
unused++;
+ printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
+ entry->s->db.str, entry->s->table_name.str, entry->s->version,
+ 0L, entry->db_stat ? 1 : 0, "Not in use");
+ }
}
count=0;
if ((start_link=lnk=unused_tables))
@@ -104,19 +118,20 @@ void print_cached_tables(void)
printf("unused_links isn't linked properly\n");
return;
}
- } while (count++ < open_cache.records && (lnk=lnk->next) != start_link);
+ } while (count++ < cached_open_tables() && (lnk=lnk->next) != start_link);
if (lnk != start_link)
{
printf("Unused_links aren't connected\n");
}
}
if (count != unused)
- printf("Unused_links (%d) doesn't match open_cache: %d\n", count,unused);
+ printf("Unused_links (%d) doesn't match table_def_cache: %d\n", count,
+ unused);
printf("\nCurrent refresh version: %ld\n",refresh_version);
- if (hash_check(&open_cache))
- printf("Error: File hash table is corrupted\n");
+ if (my_hash_check(&table_def_cache))
+ printf("Error: Table definition hash table is corrupted\n");
fflush(stdout);
- VOID(pthread_mutex_unlock(&LOCK_open));
+ mysql_mutex_unlock(&LOCK_open);
/* purecov: end */
return;
}
@@ -155,7 +170,7 @@ void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
}
out.append('\0'); // Purify doesn't like c_ptr()
DBUG_LOCK_FILE;
- VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE));
+ (void) fputs("\nInfo about FILESORT\n",DBUG_FILE);
fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr());
DBUG_UNLOCK_FILE;
DBUG_VOID_RETURN;
@@ -184,7 +199,7 @@ TEST_join(JOIN *join)
}
DBUG_LOCK_FILE;
- VOID(fputs("\nInfo about JOIN\n",DBUG_FILE));
+ (void) fputs("\nInfo about JOIN\n",DBUG_FILE);
for (i=0 ; i < join->tables ; i++)
{
JOIN_TAB *tab=join->join_tab+i;
@@ -210,7 +225,7 @@ TEST_join(JOIN *join)
tab->select->quick->dbug_dump(18, FALSE);
}
else
- VOID(fputs(" select used\n",DBUG_FILE));
+ (void) fputs(" select used\n",DBUG_FILE);
}
if (tab->ref.key_parts)
{
@@ -325,6 +340,11 @@ print_plan(JOIN* join, uint idx, double record_count, double read_time,
#endif
+C_MODE_START
+static int dl_compare(const void *p1, const void *p2);
+static int print_key_cache_status(const char *name, KEY_CACHE *key_cache);
+C_MODE_END
+
typedef struct st_debug_lock
{
ulong thread_id;
@@ -334,8 +354,13 @@ typedef struct st_debug_lock
enum thr_lock_type type;
} TABLE_LOCK_INFO;
-static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b)
+static int dl_compare(const void *p1, const void *p2)
{
+ TABLE_LOCK_INFO *a, *b;
+
+ a= (TABLE_LOCK_INFO *) p1;
+ b= (TABLE_LOCK_INFO *) p2;
+
if (a->thread_id > b->thread_id)
return 1;
if (a->thread_id < b->thread_id)
@@ -365,7 +390,7 @@ static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data,
table_lock_info.lock_text=text;
// lock_type is also obtainable from THR_LOCK_DATA
table_lock_info.type=table->reginfo.lock_type;
- VOID(push_dynamic(ar,(uchar*) &table_lock_info));
+ (void) push_dynamic(ar,(uchar*) &table_lock_info);
}
}
}
@@ -385,18 +410,19 @@ static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data,
function so that we can easily add this if we ever need this.
*/
-static void display_table_locks(void)
+static void display_table_locks(void)
{
LIST *list;
+ void *saved_base;
DYNAMIC_ARRAY saved_table_locks;
- VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50));
- VOID(pthread_mutex_lock(&THR_LOCK_lock));
+ (void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO), cached_open_tables() + 20,50);
+ mysql_mutex_lock(&THR_LOCK_lock);
for (list= thr_lock_thread_list; list; list= list_rest(list))
{
THR_LOCK *lock=(THR_LOCK*) list->data;
- VOID(pthread_mutex_lock(&lock->mutex));
+ mysql_mutex_lock(&lock->mutex);
push_locks_into_array(&saved_table_locks, lock->write.data, FALSE,
"Locked - write");
push_locks_into_array(&saved_table_locks, lock->write_wait.data, TRUE,
@@ -405,16 +431,20 @@ static void display_table_locks(void)
"Locked - read");
push_locks_into_array(&saved_table_locks, lock->read_wait.data, TRUE,
"Waiting - read");
- VOID(pthread_mutex_unlock(&lock->mutex));
+ mysql_mutex_unlock(&lock->mutex);
}
- VOID(pthread_mutex_unlock(&THR_LOCK_lock));
- if (!saved_table_locks.elements) goto end;
-
- qsort((uchar*) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare);
+ mysql_mutex_unlock(&THR_LOCK_lock);
+
+ if (!saved_table_locks.elements)
+ goto end;
+
+ saved_base= dynamic_element(&saved_table_locks, 0, TABLE_LOCK_INFO *);
+ my_qsort(saved_base, saved_table_locks.elements, sizeof(TABLE_LOCK_INFO),
+ dl_compare);
freeze_size(&saved_table_locks);
puts("\nThread database.table_name Locked/Waiting Lock_type\n");
-
+
unsigned int i;
for (i=0 ; i < saved_table_locks.elements ; i++)
{
@@ -453,8 +483,10 @@ writes: %10s\n\
r_requests: %10s\n\
reads: %10s\n\n",
name,
- (ulong) key_cache->param_buff_size, key_cache->param_block_size,
- key_cache->param_division_limit, key_cache->param_age_threshold,
+ (ulong) key_cache->param_buff_size,
+ (ulong)key_cache->param_block_size,
+ (ulong)key_cache->param_division_limit,
+ (ulong)key_cache->param_age_threshold,
key_cache->blocks_used,key_cache->global_blocks_changed,
llstr(key_cache->global_cache_w_requests,llbuff1),
llstr(key_cache->global_cache_write,llbuff2),
@@ -472,7 +504,7 @@ void mysql_print_status()
calc_sum_of_all_status(&tmp);
printf("\nStatus information:\n\n");
- VOID(my_getwd(current_dir, sizeof(current_dir),MYF(0)));
+ (void) my_getwd(current_dir, sizeof(current_dir),MYF(0));
printf("Current dir: %s\n", current_dir);
printf("Running threads: %d Stack size: %ld\n", thread_count,
(long) my_thread_stack_size);
@@ -483,7 +515,7 @@ void mysql_print_status()
/* Print key cache status */
puts("\nKey caches:");
process_key_caches(print_key_cache_status);
- pthread_mutex_lock(&LOCK_status);
+ mysql_mutex_lock(&LOCK_status);
printf("\nhandler status:\n\
read_key: %10lu\n\
read_next: %10lu\n\
@@ -499,7 +531,7 @@ update: %10lu\n",
tmp.ha_write_count,
tmp.ha_delete_count,
tmp.ha_update_count);
- pthread_mutex_unlock(&LOCK_status);
+ mysql_mutex_unlock(&LOCK_status);
printf("\nTable status:\n\
Opened tables: %10lu\n\
Open tables: %10lu\n\
@@ -523,11 +555,6 @@ Next alarm time: %lu\n",
#endif
display_table_locks();
fflush(stdout);
- my_checkmalloc();
- fprintf(stdout,"\nBegin safemalloc memory dump:\n"); // tag needed for test suite
- TERMINATE(stdout, 1); // Write malloc information
- fprintf(stdout,"\nEnd safemalloc memory dump.\n");
- fflush(stdout);
#ifdef HAVE_MALLINFO
struct mallinfo info= mallinfo();
printf("\nMemory status:\n\
diff --git a/sql/sql_test.h b/sql/sql_test.h
new file mode 100644
index 00000000000..d7fcc126cb2
--- /dev/null
+++ b/sql/sql_test.h
@@ -0,0 +1,37 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_TEST_INCLUDED
+#define SQL_TEST_INCLUDED
+
+#include "mysqld.h"
+
+class JOIN;
+struct TABLE_LIST;
+typedef class Item COND;
+typedef class st_select_lex SELECT_LEX;
+typedef struct st_sort_field SORT_FIELD;
+
+#ifndef DBUG_OFF
+void print_where(COND *cond,const char *info, enum_query_type query_type);
+void TEST_filesort(SORT_FIELD *sortorder,uint s_length);
+void TEST_join(JOIN *join);
+void print_plan(JOIN* join,uint idx, double record_count, double read_time,
+ double current_read_time, const char *info);
+void dump_TABLE_LIST_graph(SELECT_LEX *select_lex, TABLE_LIST* tl);
+#endif
+void mysql_print_status();
+
+#endif /* SQL_TEST_INCLUDED */
diff --git a/sql/time.cc b/sql/sql_time.cc
index 8b554beb94b..9606304ea16 100644
--- a/sql/time.cc
+++ b/sql/sql_time.cc
@@ -16,7 +16,11 @@
/* Functions to handle date and time */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED by other includes
+#include "sql_time.h"
+#include "tztime.h" // struct Time_zone
+#include "sql_class.h" // THD, MODE_INVALID_DATES, MODE_NO_ZERO_DATE
#include <m_ctype.h>
@@ -214,6 +218,69 @@ ulong convert_month_to_period(ulong month)
/*
+ Convert a string to 8-bit representation,
+ for use in str_to_time/str_to_date/str_to_date.
+
+ In the future to_ascii() can be extended to convert
+ non-ASCII digits to ASCII digits
+ (for example, ARABIC-INDIC, DEVANAGARI, BENGALI, and so on)
+ so DATE/TIME/DATETIME values understand digits in the
+ respected scripts.
+*/
+static uint
+to_ascii(CHARSET_INFO *cs,
+ const char *src, uint src_length,
+ char *dst, uint dst_length)
+
+{
+ int cnvres;
+ my_wc_t wc;
+ const char *srcend= src + src_length;
+ char *dst0= dst, *dstend= dst + dst_length - 1;
+ while (dst < dstend &&
+ (cnvres= (cs->cset->mb_wc)(cs, &wc,
+ (const uchar*) src,
+ (const uchar*) srcend)) > 0 &&
+ wc < 128)
+ {
+ src+= cnvres;
+ *dst++= wc;
+ }
+ *dst= '\0';
+ return dst - dst0;
+}
+
+
+/* Character set-aware version of str_to_time() */
+bool str_to_time(CHARSET_INFO *cs, const char *str,uint length,
+ MYSQL_TIME *l_time, int *warning)
+{
+ char cnv[32];
+ if ((cs->state & MY_CS_NONASCII) != 0)
+ {
+ length= to_ascii(cs, str, length, cnv, sizeof(cnv));
+ str= cnv;
+ }
+ return str_to_time(str, length, l_time, warning);
+}
+
+
+/* Character set-aware version of str_to_datetime() */
+timestamp_type str_to_datetime(CHARSET_INFO *cs,
+ const char *str, uint length,
+ MYSQL_TIME *l_time, uint flags, int *was_cut)
+{
+ char cnv[32];
+ if ((cs->state & MY_CS_NONASCII) != 0)
+ {
+ length= to_ascii(cs, str, length, cnv, sizeof(cnv));
+ str= cnv;
+ }
+ return str_to_datetime(str, length, l_time, flags, was_cut);
+}
+
+
+/*
Convert a timestamp string to a MYSQL_TIME value and produce a warning
if string was truncated during conversion.
@@ -222,14 +289,15 @@ ulong convert_month_to_period(ulong month)
*/
timestamp_type
-str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
+str_to_datetime_with_warn(CHARSET_INFO *cs,
+ const char *str, uint length, MYSQL_TIME *l_time,
uint flags)
{
int was_cut;
THD *thd= current_thd;
timestamp_type ts_type;
- ts_type= str_to_datetime(str, length, l_time,
+ ts_type= str_to_datetime(cs, str, length, l_time,
(flags | (thd->variables.sql_mode &
(MODE_INVALID_DATES |
MODE_NO_ZERO_DATE))),
@@ -284,7 +352,8 @@ my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *in_dst_time_
See str_to_time() for more info.
*/
bool
-str_to_time_with_warn(const char *str, uint length, MYSQL_TIME *l_time)
+str_to_time_with_warn(CHARSET_INFO *cs,
+ const char *str, uint length, MYSQL_TIME *l_time)
{
int warning;
bool ret_val= str_to_time(str, length, l_time, &warning);
@@ -697,7 +766,7 @@ void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
{
uint length= (uint) my_time_to_str(l_time, (char*) str->ptr());
str->length(length);
- str->set_charset(&my_charset_bin);
+ str->set_charset(&my_charset_numeric);
}
@@ -706,7 +775,7 @@ void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
{
uint length= (uint) my_date_to_str(l_time, (char*) str->ptr());
str->length(length);
- str->set_charset(&my_charset_bin);
+ str->set_charset(&my_charset_numeric);
}
@@ -715,7 +784,7 @@ void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
{
uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr());
str->length(length);
- str->set_charset(&my_charset_bin);
+ str->set_charset(&my_charset_numeric);
}
@@ -748,7 +817,7 @@ void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level leve
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
type_str, str.c_ptr(), field_name,
- (ulong) thd->row_count);
+ (ulong) thd->warning_info->current_row_for_warning());
else
{
if (time_type > MYSQL_TIMESTAMP_ERROR)
diff --git a/sql/sql_time.h b/sql/sql_time.h
new file mode 100644
index 00000000000..47e1a2b4843
--- /dev/null
+++ b/sql/sql_time.h
@@ -0,0 +1,101 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_TIME_INCLUDED
+#define SQL_TIME_INCLUDED
+
+#include "my_global.h" /* ulong */
+#include "my_time.h"
+#include "mysql_time.h" /* timestamp_type */
+#include "sql_error.h" /* MYSQL_ERROR */
+#include "structs.h" /* INTERVAL */
+
+typedef enum enum_mysql_timestamp_type timestamp_type;
+typedef struct st_date_time_format DATE_TIME_FORMAT;
+typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT;
+
+/* Flags for calc_week() function. */
+#define WEEK_MONDAY_FIRST 1
+#define WEEK_YEAR 2
+#define WEEK_FIRST_WEEKDAY 4
+
+ulong convert_period_to_month(ulong period);
+ulong convert_month_to_period(ulong month);
+void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
+my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
+bool str_to_time_with_warn(CHARSET_INFO *cs, const char *str, uint length,
+ MYSQL_TIME *l_time);
+timestamp_type str_to_datetime_with_warn(CHARSET_INFO *cs, const char *str,
+ uint length, MYSQL_TIME *l_time,
+ uint flags);
+void make_truncated_value_warning(THD *thd,
+ MYSQL_ERROR::enum_warning_level level,
+ const char *str_val, uint str_length,
+ timestamp_type time_type,
+ const char *field_name);
+extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
+ const char *format_str,
+ uint format_length);
+extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd,
+ DATE_TIME_FORMAT *format);
+const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
+ timestamp_type type);
+void make_date(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
+ String *str);
+void make_time(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
+ String *str);
+void make_datetime(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
+ String *str);
+
+/* MYSQL_TIME operations */
+bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
+ INTERVAL interval);
+bool calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign,
+ longlong *seconds_out, long *microseconds_out);
+int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b);
+void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
+void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
+uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
+
+int calc_weekday(long daynr,bool sunday_first_day_of_week);
+bool parse_date_time_format(timestamp_type format_type,
+ const char *format, uint format_length,
+ DATE_TIME_FORMAT *date_time_format);
+/* Character set-aware version of str_to_time() */
+bool str_to_time(CHARSET_INFO *cs, const char *str,uint length,
+ MYSQL_TIME *l_time, int *warning);
+/* Character set-aware version of str_to_datetime() */
+timestamp_type str_to_datetime(CHARSET_INFO *cs,
+ const char *str, uint length,
+ MYSQL_TIME *l_time, uint flags, int *was_cut);
+
+/* convenience wrapper */
+inline bool parse_date_time_format(timestamp_type format_type,
+ DATE_TIME_FORMAT *date_time_format)
+{
+ return parse_date_time_format(format_type,
+ date_time_format->format.str,
+ date_time_format->format.length,
+ date_time_format);
+}
+
+
+extern DATE_TIME_FORMAT global_date_format;
+extern DATE_TIME_FORMAT global_datetime_format;
+extern DATE_TIME_FORMAT global_time_format;
+extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
+extern LEX_STRING interval_type_to_name[];
+
+#endif /* SQL_TIME_INCLUDED */
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 9348feaa22a..c2e3cd9944a 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2005 MySQL AB
+/* Copyright (C) 2004-2005 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -15,10 +15,21 @@
#define MYSQL_LEX 1
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h"
#include "sp_head.h"
#include "sql_trigger.h"
+#include "sql_parse.h" // parse_sql
#include "parse_file.h"
+#include "sp.h"
+#include "sql_base.h" // find_temporary_table
+#include "sql_show.h" // append_definer, append_identifier
+#include "sql_table.h" // build_table_filename,
+ // check_n_cut_mysql50_prefix
+#include "sql_db.h" // get_default_db_collation
+#include "sql_acl.h" // *_ACL, is_acl_user
+#include "sql_handler.h" // mysql_ha_rm_tables
/*************************************************************************/
@@ -327,8 +338,9 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
TABLE *table;
bool result= TRUE;
String stmt_query;
+ bool lock_upgrade_done= FALSE;
+ MDL_ticket *mdl_ticket= NULL;
Query_tables_list backup;
- bool need_start_waiting= FALSE;
DBUG_ENTER("mysql_create_or_drop_trigger");
@@ -377,19 +389,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(TRUE);
}
- /*
- We don't want perform our operations while global read lock is held
- so we have to wait until its end and then prevent it from occurring
- again until we are done, unless we are under lock tables. (Acquiring
- LOCK_open is not enough because global read lock is held without holding
- LOCK_open).
- */
- if (!thd->locked_tables &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- DBUG_RETURN(TRUE);
-
- VOID(pthread_mutex_lock(&LOCK_open));
-
if (!create)
{
bool if_exists= thd->lex->drop_if_exists;
@@ -399,6 +398,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
destructive changes necessary to open the trigger's table.
*/
thd->lex->reset_n_backup_query_tables_list(&backup);
+ /*
+ Restore Query_tables_list::sql_command, which was
+ reset above, as the code that writes the query to the
+ binary log assumes that this value corresponds to the
+ statement that is being executed.
+ */
+ thd->lex->sql_command= backup.sql_command;
if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables))
goto end;
@@ -429,7 +435,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
thd->lex->query_tables_own_last= 0;
- err_status= check_table_access(thd, TRIGGER_ACL, tables, 1, FALSE);
+ err_status= check_table_access(thd, TRIGGER_ACL, tables, FALSE, 1, FALSE);
thd->lex->query_tables_own_last= save_query_tables_own_last;
@@ -441,7 +447,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_ASSERT(tables->next_global == 0);
/* We do not allow creation of triggers on temporary tables. */
- if (create && find_temporary_table(thd, tables->db, tables->table_name))
+ if (create && find_temporary_table(thd, tables))
{
my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
goto end;
@@ -449,31 +455,42 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
/* We also don't allow creation of triggers on views. */
tables->required_type= FRMTYPE_TABLE;
+ /*
+ Also prevent DROP TRIGGER from opening temporary table which might
+ shadow base table on which trigger to be dropped is defined.
+ */
+ tables->open_type= OT_BASE_ONLY;
/* Keep consistent with respect to other DDL statements */
- mysql_ha_rm_tables(thd, tables, TRUE);
+ mysql_ha_rm_tables(thd, tables);
- if (thd->locked_tables)
+ if (thd->locked_tables_mode)
{
- /* Table must be write locked */
- if (name_lock_locked_table(thd, tables))
+ /* Under LOCK TABLES we must only accept write locked tables. */
+ if (!(tables->table= find_table_for_mdl_upgrade(thd->open_tables,
+ tables->db,
+ tables->table_name,
+ FALSE)))
goto end;
}
else
{
- /* Grab the name lock and insert the placeholder*/
- if (lock_table_names(thd, tables))
+ tables->table= open_n_lock_single_table(thd, tables,
+ TL_READ_NO_INSERT, 0);
+ if (! tables->table)
goto end;
-
- /* Convert the placeholder to a real table */
- if (reopen_name_locked_table(thd, tables, TRUE))
- {
- unlock_table_name(thd, tables);
- goto end;
- }
+ tables->table->use_all_columns();
}
table= tables->table;
+ /* Later on we will need it to downgrade the lock */
+ mdl_ticket= table->mdl_ticket;
+
+ if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ goto end;
+
+ lock_upgrade_done= TRUE;
+
if (!table->triggers)
{
if (!create)
@@ -490,42 +507,35 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
table->triggers->create_trigger(thd, tables, &stmt_query):
table->triggers->drop_trigger(thd, tables, &stmt_query));
- /* Under LOCK TABLES we must reopen the table to activate the trigger. */
- if (!result && thd->locked_tables)
- {
- /* Make table suitable for reopening */
- close_data_files_and_morph_locks(thd, tables->db, tables->table_name);
- thd->in_lock_tables= 1;
- if (reopen_tables(thd, 1, 1))
- {
- /* To be safe remove this table from the set of LOCKED TABLES */
- unlink_open_table(thd, tables->table, FALSE);
+ if (result)
+ goto end;
- /*
- Ignore reopen_tables errors for now. It's better not leave master/slave
- in a inconsistent state.
- */
- thd->clear_error();
- }
- thd->in_lock_tables= 0;
- }
+ close_all_tables_for_name(thd, table->s, FALSE);
+ /*
+ Reopen the table if we were under LOCK TABLES.
+ Ignore the return value for now. It's better to
+ keep master/slave in consistent state.
+ */
+ thd->locked_tables_list.reopen_tables(thd);
end:
-
if (!result)
{
result= write_bin_log(thd, TRUE, stmt_query.ptr(), stmt_query.length());
}
- VOID(pthread_mutex_unlock(&LOCK_open));
+ /*
+ If we are under LOCK TABLES we should restore original state of
+ meta-data locks. Otherwise all locks will be released along
+ with the implicit commit.
+ */
+ if (thd->locked_tables_mode && tables && lock_upgrade_done)
+ mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
/* Restore the query table list. Used only for drop trigger. */
if (!create)
thd->lex->restore_backup_query_tables_list(&backup);
- if (need_start_waiting)
- start_waiting_global_read_lock(thd);
-
if (!result)
my_ok(thd);
@@ -815,7 +825,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
return 0;
err_with_cleanup:
- my_delete(trigname_buff, MYF(MY_WME));
+ mysql_file_delete(key_file_trn, trigname_buff, MYF(MY_WME));
return 1;
}
@@ -838,7 +848,7 @@ static bool rm_trigger_file(char *path, const char *db,
const char *table_name)
{
build_table_filename(path, FN_REFLEN-1, db, table_name, TRG_EXT, 0);
- return my_delete(path, MYF(MY_WME));
+ return mysql_file_delete(key_file_trg, path, MYF(MY_WME));
}
@@ -860,7 +870,7 @@ static bool rm_trigname_file(char *path, const char *db,
const char *trigger_name)
{
build_table_filename(path, FN_REFLEN - 1, db, trigger_name, TRN_EXT, 0);
- return my_delete(path, MYF(MY_WME));
+ return mysql_file_delete(key_file_trn, path, MYF(MY_WME));
}
@@ -1209,12 +1219,13 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
DBUG_RETURN(1); // EOM
}
-
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRG_NO_CREATION_CTX,
- ER(ER_TRG_NO_CREATION_CTX),
- (const char*) db,
- (const char*) table_name);
+
+ if (!thd->no_warnings_for_error)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRG_NO_CREATION_CTX,
+ ER(ER_TRG_NO_CREATION_CTX),
+ (const char*) db,
+ (const char*) table_name);
if (!(trg_client_cs_name= alloc_lex_string(&table->mem_root)) ||
!(trg_connection_cl_name= alloc_lex_string(&table->mem_root)) ||
@@ -1292,6 +1303,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
thd->reset_db((char*) db, strlen(db));
while ((trg_create_str= it++))
{
+ sp_head *sp;
trg_sql_mode= itm++;
LEX_STRING *trg_definer= it_definer++;
@@ -1328,13 +1340,14 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
*/
lex.set_trg_event_type_for_tables();
- lex.sphead->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode);
-
int event= lex.trg_chistics.event;
int action_time= lex.trg_chistics.action_time;
- lex.sphead->set_creation_ctx(creation_ctx);
- triggers->bodies[event][action_time]= lex.sphead;
+ sp= triggers->bodies[event][action_time]= lex.sphead;
+ lex.sphead= NULL; /* Prevent double cleanup. */
+
+ sp->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode);
+ sp->set_creation_ctx(creation_ctx);
if (!trg_definer->length)
{
@@ -1343,31 +1356,30 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
MySQL, which does not support triggers definers. We should emit
warning here.
*/
-
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER),
- (const char*) db,
- (const char*) lex.sphead->m_name.str);
-
+ if (!thd->no_warnings_for_error)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER),
+ (const char*) db,
+ (const char*) sp->m_name.str);
+
/*
Set definer to the '' to correct displaying in the information
schema.
*/
- lex.sphead->set_definer((char*) "", 0);
+ sp->set_definer((char*) "", 0);
/*
Triggers without definer information are executed under the
authorization of the invoker.
*/
- lex.sphead->m_chistics->suid= SP_IS_NOT_SUID;
+ sp->m_chistics->suid= SP_IS_NOT_SUID;
}
else
- lex.sphead->set_definer(trg_definer->str, trg_definer->length);
+ sp->set_definer(trg_definer->str, trg_definer->length);
- if (triggers->names_list.push_back(&lex.sphead->m_name,
- &table->mem_root))
+ if (triggers->names_list.push_back(&sp->m_name, &table->mem_root))
goto err_with_lex_cleanup;
if (!(on_table_name= alloc_lex_string(&table->mem_root)))
@@ -1636,7 +1648,8 @@ bool add_table_for_trigger(THD *thd,
DBUG_RETURN(TRUE);
*table= sp_add_to_query_tables(thd, lex, trg_name->m_db.str,
- tbl_name.str, TL_IGNORE);
+ tbl_name.str, TL_IGNORE,
+ MDL_SHARED_NO_WRITE);
DBUG_RETURN(*table ? FALSE : TRUE);
}
@@ -1649,9 +1662,6 @@ bool add_table_for_trigger(THD *thd,
@param db schema for table
@param name name for table
- @note
- The calling thread should hold the LOCK_open mutex;
-
@retval
False success
@retval
@@ -1666,7 +1676,7 @@ bool Table_triggers_list::drop_all_triggers(THD *thd, char *db, char *name)
DBUG_ENTER("drop_all_triggers");
bzero(&table, sizeof(table));
- init_alloc_root(&table.mem_root, 8192, 0);
+ init_sql_alloc(&table.mem_root, 8192, 0);
if (Table_triggers_list::check_n_load(thd, db, name, &table, 1))
{
@@ -1850,6 +1860,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *old_db_name,
@param[in,out] thd Thread context
@param[in] db Old database of subject table
+ @param[in] old_alias Old alias of subject table
@param[in] old_table Old name of subject table
@param[in] new_db New database for subject table
@param[in] new_table New name of subject table
@@ -1859,13 +1870,14 @@ Table_triggers_list::change_table_name_in_trignames(const char *old_db_name,
i.e. it either will complete successfully, or will fail leaving files
in their initial state.
Also this method assumes that subject table is not renamed to itself.
- This method needs to be called under an exclusive table name lock.
+ This method needs to be called under an exclusive table metadata lock.
@retval FALSE Success
@retval TRUE Error
*/
bool Table_triggers_list::change_table_name(THD *thd, const char *db,
+ const char *old_alias,
const char *old_table,
const char *new_db,
const char *new_table)
@@ -1877,24 +1889,17 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
DBUG_ENTER("change_table_name");
bzero(&table, sizeof(table));
- init_alloc_root(&table.mem_root, 8192, 0);
+ init_sql_alloc(&table.mem_root, 8192, 0);
/*
This method interfaces the mysql server code protected by
- either LOCK_open mutex or with an exclusive table name lock.
- In the future, only an exclusive table name lock will be enough.
+ an exclusive metadata lock.
*/
-#ifndef DBUG_OFF
- uchar key[MAX_DBKEY_LENGTH];
- uint key_length= (uint) (strmov(strmov((char*)&key[0], db)+1,
- old_table)-(char*)&key[0])+1;
-
- if (!is_table_name_exclusively_locked_by_this_thread(thd, key, key_length))
- safe_mutex_assert_owner(&LOCK_open);
-#endif
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, old_table,
+ MDL_EXCLUSIVE));
DBUG_ASSERT(my_strcasecmp(table_alias_charset, db, new_db) ||
- my_strcasecmp(table_alias_charset, old_table, new_table));
+ my_strcasecmp(table_alias_charset, old_alias, new_table));
if (Table_triggers_list::check_n_load(thd, db, old_table, &table, TRUE))
{
@@ -1903,7 +1908,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
}
if (table.triggers)
{
- LEX_STRING old_table_name= { (char *) old_table, strlen(old_table) };
+ LEX_STRING old_table_name= { (char *) old_alias, strlen(old_alias) };
LEX_STRING new_table_name= { (char *) new_table, strlen(new_table) };
/*
Since triggers should be in the same schema as their subject tables
@@ -2034,6 +2039,61 @@ bool Table_triggers_list::process_triggers(THD *thd,
/**
+ Add triggers for table to the set of routines used by statement.
+ Add tables used by them to statement table list. Do the same for
+ routines used by triggers.
+
+ @param thd Thread context.
+ @param prelocking_ctx Prelocking context of the statement.
+ @param table_list Table list element for table with trigger.
+
+ @retval FALSE Success.
+ @retval TRUE Failure.
+*/
+
+bool
+Table_triggers_list::
+add_tables_and_routines_for_triggers(THD *thd,
+ Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list)
+{
+ DBUG_ASSERT(static_cast<int>(table_list->lock_type) >=
+ static_cast<int>(TL_WRITE_ALLOW_WRITE));
+
+ for (int i= 0; i < (int)TRG_EVENT_MAX; i++)
+ {
+ if (table_list->trg_event_map &
+ static_cast<uint8>(1 << static_cast<int>(i)))
+ {
+ for (int j= 0; j < (int)TRG_ACTION_MAX; j++)
+ {
+ /* We can have only one trigger per action type currently */
+ sp_head *trigger= table_list->table->triggers->bodies[i][j];
+
+ if (trigger)
+ {
+ MDL_key key(MDL_key::TRIGGER, trigger->m_db.str, trigger->m_name.str);
+
+ if (sp_add_used_routine(prelocking_ctx, thd->stmt_arena,
+ &key, table_list->belong_to_view))
+ {
+ trigger->add_used_tables_to_table_list(thd,
+ &prelocking_ctx->query_tables_last,
+ table_list->belong_to_view);
+ sp_update_stmt_used_routines(thd, prelocking_ctx,
+ &trigger->m_sroutines,
+ table_list->belong_to_view);
+ trigger->propagate_attributes(prelocking_ctx);
+ }
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+/**
Mark fields of subject table which we read/set in its triggers
as such.
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index f6754a75284..dd954957f07 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -1,3 +1,6 @@
+#ifndef SQL_TRIGGER_INCLUDED
+#define SQL_TRIGGER_INCLUDED
+
/* Copyright (C) 2004-2005 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -13,6 +16,38 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* Forward declarations */
+
+class Item_trigger_field;
+class sp_head;
+class sp_name;
+class Query_tables_list;
+struct TABLE_LIST;
+class Query_tables_list;
+
+/** Event on which trigger is invoked. */
+enum trg_event_type
+{
+ TRG_EVENT_INSERT= 0,
+ TRG_EVENT_UPDATE= 1,
+ TRG_EVENT_DELETE= 2,
+ TRG_EVENT_MAX
+};
+
+#include "table.h" /* GRANT_INFO */
+
+/*
+ We need this two enums here instead of sql_lex.h because
+ at least one of them is used by Item_trigger_field interface.
+
+ Time when trigger is invoked (i.e. before or after row actually
+ inserted/updated/deleted).
+*/
+enum trg_action_time_type
+{
+ TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX
+};
+
/**
This class holds all information about triggers of table.
@@ -122,6 +157,7 @@ public:
TABLE *table, bool names_only);
static bool drop_all_triggers(THD *thd, char *db, char *table_name);
static bool change_table_name(THD *thd, const char *db,
+ const char *old_alias,
const char *old_table,
const char *new_db,
const char *new_table);
@@ -141,8 +177,10 @@ public:
void mark_fields_used(trg_event_type event);
friend class Item_trigger_field;
- friend int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
- TABLE_LIST *table);
+
+ bool add_tables_and_routines_for_triggers(THD *thd,
+ Query_tables_list *prelocking_ctx,
+ TABLE_LIST *table_list);
private:
bool prepare_record1_accessors(TABLE *table);
@@ -173,4 +211,9 @@ bool load_table_name_for_trigger(THD *thd,
const sp_name *trg_name,
const LEX_STRING *trn_path,
LEX_STRING *tbl_name);
+bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);
+
+extern const char * const TRG_EXT;
+extern const char * const TRN_EXT;
+#endif /* SQL_TRIGGER_INCLUDED */
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
new file mode 100644
index 00000000000..0cff2875ac8
--- /dev/null
+++ b/sql/sql_truncate.cc
@@ -0,0 +1,516 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 */
+
+#include "debug_sync.h" // DEBUG_SYNC
+#include "table.h" // TABLE, FOREIGN_KEY_INFO
+#include "sql_class.h" // THD
+#include "sql_base.h" // open_and_lock_tables
+#include "sql_table.h" // write_bin_log
+#include "sql_handler.h" // mysql_ha_rm_tables
+#include "datadict.h" // dd_recreate_table()
+#include "lock.h" // MYSQL_OPEN_TEMPORARY_ONLY
+#include "sql_acl.h" // DROP_ACL
+#include "sql_parse.h" // check_one_table_access()
+#include "sql_truncate.h"
+
+
+/**
+ Append a list of field names to a string.
+
+ @param str The string.
+ @param fields The list of field names.
+
+ @return TRUE on failure, FALSE otherwise.
+*/
+
+static bool fk_info_append_fields(String *str, List<LEX_STRING> *fields)
+{
+ bool res= FALSE;
+ LEX_STRING *field;
+ List_iterator_fast<LEX_STRING> it(*fields);
+
+ while ((field= it++))
+ {
+ res|= str->append("`");
+ res|= str->append(field);
+ res|= str->append("`, ");
+ }
+
+ str->chop();
+ str->chop();
+
+ return res;
+}
+
+
+/**
+ Generate a foreign key description suitable for a error message.
+
+ @param thd Thread context.
+ @param fk_info The foreign key information.
+
+ @return A human-readable string describing the foreign key.
+*/
+
+static const char *fk_info_str(THD *thd, FOREIGN_KEY_INFO *fk_info)
+{
+ bool res= FALSE;
+ char buffer[STRING_BUFFER_USUAL_SIZE*2];
+ String str(buffer, sizeof(buffer), system_charset_info);
+
+ str.length(0);
+
+ /*
+ `db`.`tbl`, CONSTRAINT `id` FOREIGN KEY (`fk`) REFERENCES `db`.`tbl` (`fk`)
+ */
+
+ res|= str.append('`');
+ res|= str.append(fk_info->foreign_db);
+ res|= str.append("`.`");
+ res|= str.append(fk_info->foreign_table);
+ res|= str.append("`, CONSTRAINT `");
+ res|= str.append(fk_info->foreign_id);
+ res|= str.append("` FOREIGN KEY (");
+ res|= fk_info_append_fields(&str, &fk_info->foreign_fields);
+ res|= str.append(") REFERENCES `");
+ res|= str.append(fk_info->referenced_db);
+ res|= str.append("`.`");
+ res|= str.append(fk_info->referenced_table);
+ res|= str.append("` (");
+ res|= fk_info_append_fields(&str, &fk_info->referenced_fields);
+ res|= str.append(')');
+
+ return res ? NULL : thd->strmake(str.ptr(), str.length());
+}
+
+
+/**
+ Check and emit a fatal error if the table which is going to be
+ affected by TRUNCATE TABLE is a parent table in some non-self-
+ referencing foreign key.
+
+ @remark The intention is to allow truncate only for tables that
+ are not dependent on other tables.
+
+ @param thd Thread context.
+ @param table Table handle.
+
+ @retval FALSE This table is not parent in a non-self-referencing foreign
+ key. Statement can proceed.
+ @retval TRUE This table is parent in a non-self-referencing foreign key,
+ error was emitted.
+*/
+
+static bool
+fk_truncate_illegal_if_parent(THD *thd, TABLE *table)
+{
+ FOREIGN_KEY_INFO *fk_info;
+ List<FOREIGN_KEY_INFO> fk_list;
+ List_iterator_fast<FOREIGN_KEY_INFO> it;
+
+ /*
+ Bail out early if the table is not referenced by a foreign key.
+ In this case, the table could only be, if at all, a child table.
+ */
+ if (! table->file->referenced_by_foreign_key())
+ return FALSE;
+
+ /*
+ This table _is_ referenced by a foreign key. At this point, only
+ self-referencing keys are acceptable. For this reason, get the list
+ of foreign keys referencing this table in order to check the name
+ of the child (dependent) tables.
+ */
+ table->file->get_parent_foreign_key_list(thd, &fk_list);
+
+ /* Out of memory when building list. */
+ if (thd->is_error())
+ return TRUE;
+
+ it.init(fk_list);
+
+ /* Loop over the set of foreign keys for which this table is a parent. */
+ while ((fk_info= it++))
+ {
+ DBUG_ASSERT(!my_strcasecmp(system_charset_info,
+ fk_info->referenced_db->str,
+ table->s->db.str));
+
+ DBUG_ASSERT(!my_strcasecmp(system_charset_info,
+ fk_info->referenced_table->str,
+ table->s->table_name.str));
+
+ if (my_strcasecmp(system_charset_info, fk_info->foreign_db->str,
+ table->s->db.str) ||
+ my_strcasecmp(system_charset_info, fk_info->foreign_table->str,
+ table->s->table_name.str))
+ break;
+ }
+
+ /* Table is parent in a non-self-referencing foreign key. */
+ if (fk_info)
+ {
+ my_error(ER_TRUNCATE_ILLEGAL_FK, MYF(0), fk_info_str(thd, fk_info));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ Open and truncate a locked table.
+
+ @param thd Thread context.
+ @param table_ref Table list element for the table to be truncated.
+ @param is_tmp_table True if element refers to a temp table.
+
+ @retval 0 Success.
+ @retval > 0 Error code.
+*/
+
+int Truncate_statement::handler_truncate(THD *thd, TABLE_LIST *table_ref,
+ bool is_tmp_table)
+{
+ int error= 0;
+ uint flags;
+ DBUG_ENTER("Truncate_statement::handler_truncate");
+
+ /*
+ Can't recreate, the engine must mechanically delete all rows
+ in the table. Use open_and_lock_tables() to open a write cursor.
+ */
+
+ /* If it is a temporary table, no need to take locks. */
+ if (is_tmp_table)
+ flags= MYSQL_OPEN_TEMPORARY_ONLY;
+ else
+ {
+ /* We don't need to load triggers. */
+ DBUG_ASSERT(table_ref->trg_event_map == 0);
+ /*
+ Our metadata lock guarantees that no transaction is reading
+ or writing into the table. Yet, to open a write cursor we need
+ a thr_lock lock. Allow to open base tables only.
+ */
+ table_ref->required_type= FRMTYPE_TABLE;
+ /*
+ Ignore pending FLUSH TABLES since we don't want to release
+ the MDL lock taken above and otherwise there is no way to
+ wait for FLUSH TABLES in deadlock-free fashion.
+ */
+ flags= MYSQL_OPEN_IGNORE_FLUSH | MYSQL_OPEN_SKIP_TEMPORARY;
+ /*
+ Even though we have an MDL lock on the table here, we don't
+ pass MYSQL_OPEN_HAS_MDL_LOCK to open_and_lock_tables
+ since to truncate a MERGE table, we must open and lock
+ merge children, and on those we don't have an MDL lock.
+ Thus clear the ticket to satisfy MDL asserts.
+ */
+ table_ref->mdl_request.ticket= NULL;
+ }
+
+ /* Open the table as it will handle some required preparations. */
+ if (open_and_lock_tables(thd, table_ref, FALSE, flags))
+ DBUG_RETURN(1);
+
+ /* Whether to truncate regardless of foreign keys. */
+ if (! (thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS))
+ error= fk_truncate_illegal_if_parent(thd, table_ref->table);
+
+ if (!error && (error= table_ref->table->file->ha_truncate()))
+ table_ref->table->file->print_error(error, MYF(0));
+
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Close and recreate a temporary table. In case of success,
+ write truncate statement into the binary log if in statement
+ mode.
+
+ @param thd Thread context.
+ @param table The temporary table.
+
+ @retval FALSE Success.
+ @retval TRUE Error.
+*/
+
+static bool recreate_temporary_table(THD *thd, TABLE *table)
+{
+ bool error= TRUE;
+ TABLE_SHARE *share= table->s;
+ HA_CREATE_INFO create_info;
+ handlerton *table_type= table->s->db_type();
+ DBUG_ENTER("recreate_temporary_table");
+
+ memset(&create_info, 0, sizeof(create_info));
+
+ table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
+
+ /* Don't free share. */
+ close_temporary_table(thd, table, FALSE, FALSE);
+
+ /*
+ We must use share->normalized_path.str since for temporary tables it
+ differs from what dd_recreate_table() would generate based
+ on table and schema names.
+ */
+ ha_create_table(thd, share->normalized_path.str, share->db.str,
+ share->table_name.str, &create_info, 1);
+
+ if (open_table_uncached(thd, share->path.str, share->db.str,
+ share->table_name.str, TRUE))
+ {
+ error= FALSE;
+ thd->thread_specific_used= TRUE;
+ }
+ else
+ rm_temporary_table(table_type, share->path.str);
+
+ free_table_share(share);
+ my_free(table);
+
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Handle locking a base table for truncate.
+
+ @param[in] thd Thread context.
+ @param[in] table_ref Table list element for the table to
+ be truncated.
+ @param[out] hton_can_recreate Set to TRUE if table can be dropped
+ and recreated.
+
+ @retval FALSE Success.
+ @retval TRUE Error.
+*/
+
+bool Truncate_statement::lock_table(THD *thd, TABLE_LIST *table_ref,
+ bool *hton_can_recreate)
+{
+ TABLE *table= NULL;
+ DBUG_ENTER("Truncate_statement::lock_table");
+
+ /* Lock types are set in the parser. */
+ DBUG_ASSERT(table_ref->lock_type == TL_WRITE);
+ /* The handler truncate protocol dictates a exclusive lock. */
+ DBUG_ASSERT(table_ref->mdl_request.type == MDL_EXCLUSIVE);
+
+ /*
+ Before doing anything else, acquire a metadata lock on the table,
+ or ensure we have one. We don't use open_and_lock_tables()
+ right away because we want to be able to truncate (and recreate)
+ corrupted tables, those that we can't fully open.
+
+ MySQL manual documents that TRUNCATE can be used to repair a
+ damaged table, i.e. a table that can not be fully "opened".
+ In particular MySQL manual says: As long as the table format
+ file tbl_name.frm is valid, the table can be re-created as
+ an empty table with TRUNCATE TABLE, even if the data or index
+ files have become corrupted.
+ */
+ if (thd->locked_tables_mode)
+ {
+ if (!(table= find_table_for_mdl_upgrade(thd->open_tables, table_ref->db,
+ table_ref->table_name, FALSE)))
+ DBUG_RETURN(TRUE);
+
+ *hton_can_recreate= ha_check_storage_engine_flag(table->s->db_type(),
+ HTON_CAN_RECREATE);
+ table_ref->mdl_request.ticket= table->mdl_ticket;
+ }
+ else
+ {
+ /* Acquire an exclusive lock. */
+ DBUG_ASSERT(table_ref->next_global == NULL);
+ if (lock_table_names(thd, table_ref, NULL,
+ thd->variables.lock_wait_timeout,
+ MYSQL_OPEN_SKIP_TEMPORARY))
+ DBUG_RETURN(TRUE);
+
+ if (dd_check_storage_engine_flag(thd, table_ref->db, table_ref->table_name,
+ HTON_CAN_RECREATE, hton_can_recreate))
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ A storage engine can recreate or truncate the table only if there
+ are no references to it from anywhere, i.e. no cached TABLE in the
+ table cache.
+ */
+ if (thd->locked_tables_mode)
+ {
+ DEBUG_SYNC(thd, "upgrade_lock_for_truncate");
+ /* To remove the table from the cache we need an exclusive lock. */
+ if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ DBUG_RETURN(TRUE);
+ m_ticket_downgrade= table->mdl_ticket;
+ /* Close if table is going to be recreated. */
+ if (*hton_can_recreate)
+ close_all_tables_for_name(thd, table->s, FALSE);
+ }
+ else
+ {
+ /* Table is already locked exclusively. Remove cached instances. */
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_ref->db,
+ table_ref->table_name, FALSE);
+ }
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ Optimized delete of all rows by doing a full generate of the table.
+
+ @remark Will work even if the .MYI and .MYD files are destroyed.
+ In other words, it works as long as the .FRM is intact and
+ the engine supports re-create.
+
+ @param thd Thread context.
+ @param table_ref Table list element for the table to be truncated.
+
+ @retval FALSE Success.
+ @retval TRUE Error.
+*/
+
+bool Truncate_statement::truncate_table(THD *thd, TABLE_LIST *table_ref)
+{
+ int error;
+ TABLE *table;
+ bool binlog_stmt;
+ DBUG_ENTER("Truncate_statement::truncate_table");
+
+ /* Initialize, or reinitialize in case of reexecution (SP). */
+ m_ticket_downgrade= NULL;
+
+ /* Remove table from the HANDLER's hash. */
+ mysql_ha_rm_tables(thd, table_ref);
+
+ /* If it is a temporary table, no need to take locks. */
+ if ((table= find_temporary_table(thd, table_ref)))
+ {
+ /* In RBR, the statement is not binlogged if the table is temporary. */
+ binlog_stmt= !thd->is_current_stmt_binlog_format_row();
+
+ /* Note that a temporary table cannot be partitioned. */
+ if (ha_check_storage_engine_flag(table->s->db_type(), HTON_CAN_RECREATE))
+ {
+ if ((error= recreate_temporary_table(thd, table)))
+ binlog_stmt= FALSE; /* No need to binlog failed truncate-by-recreate. */
+
+ DBUG_ASSERT(! thd->transaction.stmt.modified_non_trans_table);
+ }
+ else
+ {
+ /*
+ The engine does not support truncate-by-recreate. Open the
+ table and invoke the handler truncate. In such a manner this
+ can in fact open several tables if it's a temporary MyISAMMRG
+ table.
+ */
+ error= handler_truncate(thd, table_ref, TRUE);
+ }
+
+ /*
+ No need to invalidate the query cache, queries with temporary
+ tables are not in the cache. No need to write to the binary
+ log a failed row-by-row delete even if under RBR as the table
+ might not exist on the slave.
+ */
+ }
+ else /* It's not a temporary table. */
+ {
+ bool hton_can_recreate;
+
+ if (lock_table(thd, table_ref, &hton_can_recreate))
+ DBUG_RETURN(TRUE);
+
+ if (hton_can_recreate)
+ {
+ /*
+ The storage engine can truncate the table by creating an
+ empty table with the same structure.
+ */
+ error= dd_recreate_table(thd, table_ref->db, table_ref->table_name);
+
+ if (thd->locked_tables_mode && thd->locked_tables_list.reopen_tables(thd))
+ thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
+
+ /* No need to binlog a failed truncate-by-recreate. */
+ binlog_stmt= !error;
+ }
+ else
+ {
+ /*
+ The engine does not support truncate-by-recreate.
+ Attempt to use the handler truncate method.
+ */
+ error= handler_truncate(thd, table_ref, FALSE);
+
+ /*
+ All effects of a TRUNCATE TABLE operation are committed even if
+ truncation fails. Thus, the query must be written to the binary
+ log. The only exception is a unimplemented truncate method.
+ */
+ binlog_stmt= !error || error != HA_ERR_WRONG_COMMAND;
+ }
+
+ query_cache_invalidate3(thd, table_ref, FALSE);
+ }
+
+ /* DDL is logged in statement format, regardless of binlog format. */
+ if (binlog_stmt)
+ error|= write_bin_log(thd, !error, thd->query(), thd->query_length());
+
+ /*
+ A locked table ticket was upgraded to a exclusive lock. After the
+ the query has been written to the binary log, downgrade the lock
+ to a shared one.
+ */
+ if (m_ticket_downgrade)
+ m_ticket_downgrade->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
+
+ DBUG_RETURN(error);
+}
+
+
+/**
+ Execute a TRUNCATE statement at runtime.
+
+ @param thd The current thread.
+
+ @return FALSE on success.
+*/
+
+bool Truncate_statement::execute(THD *thd)
+{
+ bool res= TRUE;
+ TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
+ DBUG_ENTER("Truncate_statement::execute");
+
+ if (check_one_table_access(thd, DROP_ACL, first_table))
+ DBUG_RETURN(res);
+
+ if (! (res= truncate_table(thd, first_table)))
+ my_ok(thd);
+
+ DBUG_RETURN(res);
+}
+
diff --git a/sql/sql_truncate.h b/sql/sql_truncate.h
new file mode 100644
index 00000000000..95a2f35df4f
--- /dev/null
+++ b/sql/sql_truncate.h
@@ -0,0 +1,64 @@
+#ifndef SQL_TRUNCATE_INCLUDED
+#define SQL_TRUNCATE_INCLUDED
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 */
+
+class THD;
+struct TABLE_LIST;
+
+/**
+ Truncate_statement represents the TRUNCATE statement.
+*/
+class Truncate_statement : public Sql_statement
+{
+private:
+ /* Set if a lock must be downgraded after truncate is done. */
+ MDL_ticket *m_ticket_downgrade;
+
+public:
+ /**
+ Constructor, used to represent a ALTER TABLE statement.
+ @param lex the LEX structure for this statement.
+ */
+ Truncate_statement(LEX *lex)
+ : Sql_statement(lex)
+ {}
+
+ virtual ~Truncate_statement()
+ {}
+
+ /**
+ Execute a TRUNCATE statement at runtime.
+ @param thd the current thread.
+ @return false on success.
+ */
+ bool execute(THD *thd);
+
+protected:
+ /** Handle locking a base table for truncate. */
+ bool lock_table(THD *, TABLE_LIST *, bool *);
+
+ /** Truncate table via the handler method. */
+ int handler_truncate(THD *, TABLE_LIST *, bool);
+
+ /**
+ Optimized delete of all rows by doing a full regenerate of the table.
+ Depending on the storage engine, it can be accomplished through a
+ drop and recreate or via the handler truncate method.
+ */
+ bool truncate_table(THD *, TABLE_LIST *);
+};
+
+#endif
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 1d5335f0652..94e2fe43f03 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB
+/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -31,8 +31,14 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_base.h" // close_mysql_tables
+#include "sql_parse.h" // check_identifier_name
+#include "sql_table.h" // write_bin_log
+#include "records.h" // init_read_record, end_read_record
#include <my_pthread.h>
+#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
#ifdef HAVE_DLOPEN
extern "C"
@@ -44,7 +50,7 @@ extern "C"
static bool initialized = 0;
static MEM_ROOT mem;
static HASH udf_hash;
-static rw_lock_t THR_LOCK_udf;
+static mysql_rwlock_t THR_LOCK_udf;
static udf_func *add_udf(LEX_STRING *name, Item_result ret,
@@ -100,6 +106,26 @@ extern "C" uchar* get_hash_key(const uchar *buff, size_t *length,
return (uchar*) udf->name.str;
}
+#ifdef HAVE_PSI_INTERFACE
+static PSI_rwlock_key key_rwlock_THR_LOCK_udf;
+
+static PSI_rwlock_info all_udf_rwlocks[]=
+{
+ { &key_rwlock_THR_LOCK_udf, "THR_LOCK_udf", PSI_FLAG_GLOBAL}
+};
+
+static void init_udf_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_udf_rwlocks);
+ PSI_server->register_rwlock(category, all_udf_rwlocks, count);
+}
+#endif
/*
Read all predeclared functions from mysql.func and accept all that
@@ -119,15 +145,19 @@ void udf_init()
if (initialized)
DBUG_VOID_RETURN;
- my_rwlock_init(&THR_LOCK_udf,NULL);
-
+#ifdef HAVE_PSI_INTERFACE
+ init_udf_psi_keys();
+#endif
+
+ mysql_rwlock_init(key_rwlock_THR_LOCK_udf, &THR_LOCK_udf);
+
init_sql_alloc(&mem, UDF_ALLOC_BLOCK_SIZE, 0);
THD *new_thd = new THD;
if (!new_thd ||
- hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
+ my_hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
{
sql_print_error("Can't allocate memory for udf structures");
- hash_free(&udf_hash);
+ my_hash_free(&udf_hash);
free_root(&mem,MYF(0));
delete new_thd;
DBUG_VOID_RETURN;
@@ -135,15 +165,11 @@ void udf_init()
initialized = 1;
new_thd->thread_stack= (char*) &new_thd;
new_thd->store_globals();
- lex_start(new_thd);
new_thd->set_db(db, sizeof(db)-1);
- bzero((uchar*) &tables,sizeof(tables));
- tables.alias= tables.table_name= (char*) "func";
- tables.lock_type = TL_READ;
- tables.db= db;
+ tables.init_one_table(db, sizeof(db)-1, "func", 4, "func", TL_READ);
- if (simple_open_n_lock_tables(new_thd, &tables))
+ if (open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{
DBUG_PRINT("error",("Can't open udf table"));
sql_print_error("Can't open the mysql.func table. Please "
@@ -219,10 +245,10 @@ void udf_init()
if (error > 0)
sql_print_error("Got unknown error: %d", my_errno);
end_read_record(&read_record_info);
- new_thd->version--; // Force close to free memory
+ table->m_needs_reopen= TRUE; // Force close to free memory
end:
- close_thread_tables(new_thd);
+ close_mysql_tables(new_thd);
delete new_thd;
/* Remember that we don't have a THD */
my_pthread_setspecific_ptr(THR_THD, 0);
@@ -236,25 +262,25 @@ void udf_free()
DBUG_ENTER("udf_free");
for (uint idx=0 ; idx < udf_hash.records ; idx++)
{
- udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
+ udf_func *udf=(udf_func*) my_hash_element(&udf_hash,idx);
if (udf->dlhandle) // Not closed before
{
/* Mark all versions using the same handler as closed */
for (uint j=idx+1 ; j < udf_hash.records ; j++)
{
- udf_func *tmp=(udf_func*) hash_element(&udf_hash,j);
+ udf_func *tmp=(udf_func*) my_hash_element(&udf_hash,j);
if (udf->dlhandle == tmp->dlhandle)
tmp->dlhandle=0; // Already closed
}
dlclose(udf->dlhandle);
}
}
- hash_free(&udf_hash);
+ my_hash_free(&udf_hash);
free_root(&mem,MYF(0));
if (initialized)
{
initialized= 0;
- rwlock_destroy(&THR_LOCK_udf);
+ mysql_rwlock_destroy(&THR_LOCK_udf);
}
DBUG_VOID_RETURN;
}
@@ -265,7 +291,7 @@ static void del_udf(udf_func *udf)
DBUG_ENTER("del_udf");
if (!--udf->usage_count)
{
- hash_delete(&udf_hash,(uchar*) udf);
+ my_hash_delete(&udf_hash,(uchar*) udf);
using_udf_functions=udf_hash.records != 0;
}
else
@@ -279,7 +305,7 @@ static void del_udf(udf_func *udf)
uint name_length=udf->name.length;
udf->name.str=(char*) "*";
udf->name.length=1;
- hash_update(&udf_hash,(uchar*) udf,(uchar*) name,name_length);
+ my_hash_update(&udf_hash,(uchar*) udf,(uchar*) name,name_length);
}
DBUG_VOID_RETURN;
}
@@ -292,19 +318,19 @@ void free_udf(udf_func *udf)
if (!initialized)
DBUG_VOID_RETURN;
- rw_wrlock(&THR_LOCK_udf);
+ mysql_rwlock_wrlock(&THR_LOCK_udf);
if (!--udf->usage_count)
{
/*
We come here when someone has deleted the udf function
while another thread still was using the udf
*/
- hash_delete(&udf_hash,(uchar*) udf);
+ my_hash_delete(&udf_hash,(uchar*) udf);
using_udf_functions=udf_hash.records != 0;
if (!find_udf_dl(udf->dl))
dlclose(udf->dlhandle);
}
- rw_unlock(&THR_LOCK_udf);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
DBUG_VOID_RETURN;
}
@@ -321,19 +347,19 @@ udf_func *find_udf(const char *name,uint length,bool mark_used)
/* TODO: This should be changed to reader locks someday! */
if (mark_used)
- rw_wrlock(&THR_LOCK_udf); /* Called during fix_fields */
+ mysql_rwlock_wrlock(&THR_LOCK_udf); /* Called during fix_fields */
else
- rw_rdlock(&THR_LOCK_udf); /* Called during parsing */
+ mysql_rwlock_rdlock(&THR_LOCK_udf); /* Called during parsing */
- if ((udf=(udf_func*) hash_search(&udf_hash,(uchar*) name,
- length ? length : (uint) strlen(name))))
+ if ((udf=(udf_func*) my_hash_search(&udf_hash,(uchar*) name,
+ length ? length : (uint) strlen(name))))
{
if (!udf->dlhandle)
udf=0; // Could not be opened
else if (mark_used)
udf->usage_count++;
}
- rw_unlock(&THR_LOCK_udf);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
DBUG_RETURN(udf);
}
@@ -348,7 +374,7 @@ static void *find_udf_dl(const char *dl)
*/
for (uint idx=0 ; idx < udf_hash.records ; idx++)
{
- udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
+ udf_func *udf=(udf_func*) my_hash_element(&udf_hash,idx);
if (!strcmp(dl, udf->dl) && udf->dlhandle != NULL)
DBUG_RETURN(udf->dlhandle);
}
@@ -430,11 +456,11 @@ int mysql_create_function(THD *thd,udf_func *udf)
Turn off row binlogging of this statement and use statement-based
so that all supporting tables are updated for CREATE FUNCTION command.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
- rw_wrlock(&THR_LOCK_udf);
- if ((hash_search(&udf_hash,(uchar*) udf->name.str, udf->name.length)))
+ mysql_rwlock_wrlock(&THR_LOCK_udf);
+ if ((my_hash_search(&udf_hash,(uchar*) udf->name.str, udf->name.length)))
{
my_error(ER_UDF_EXISTS, MYF(0), udf->name.str);
goto err;
@@ -475,11 +501,9 @@ int mysql_create_function(THD *thd,udf_func *udf)
/* create entry in mysql.func table */
- bzero((char*) &tables,sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*) "func";
+ tables.init_one_table("mysql", 5, "func", 4, "func", TL_WRITE);
/* Allow creation of functions even if we can't open func table */
- if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
+ if (!(table = open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
goto err;
table->use_all_columns();
restore_record(table, s->default_values); // Default values for fields
@@ -496,25 +520,31 @@ int mysql_create_function(THD *thd,udf_func *udf)
del_udf(u_d);
goto err;
}
- rw_unlock(&THR_LOCK_udf);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
/* Binlog the create function. */
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(1);
}
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(0);
err:
if (new_dl)
dlclose(dl);
- rw_unlock(&THR_LOCK_udf);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(1);
}
@@ -542,12 +572,12 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
Turn off row binlogging of this statement and use statement-based
so that all supporting tables are updated for DROP FUNCTION command.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
- rw_wrlock(&THR_LOCK_udf);
- if (!(udf=(udf_func*) hash_search(&udf_hash,(uchar*) udf_name->str,
- (uint) udf_name->length)))
+ mysql_rwlock_wrlock(&THR_LOCK_udf);
+ if (!(udf=(udf_func*) my_hash_search(&udf_hash,(uchar*) udf_name->str,
+ (uint) udf_name->length)))
{
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
goto err;
@@ -562,10 +592,9 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
if (udf->dlhandle && !find_udf_dl(udf->dl))
dlclose(udf->dlhandle);
- bzero((char*) &tables,sizeof(tables));
- tables.db=(char*) "mysql";
- tables.table_name= tables.alias= (char*) "func";
- if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
+ tables.init_one_table("mysql", 5, "func", 4, "func", TL_WRITE);
+
+ if (!(table = open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
goto err;
table->use_all_columns();
table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
@@ -578,24 +607,31 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
if ((error = table->file->ha_delete_row(table->record[0])))
table->file->print_error(error, MYF(0));
}
- close_thread_tables(thd);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
- rw_unlock(&THR_LOCK_udf);
-
- /* Binlog the drop function. */
+ /*
+ Binlog the drop function. Keep the table open and locked
+ while binlogging, to avoid binlog inconsistency.
+ */
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(1);
}
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(0);
- err:
- rw_unlock(&THR_LOCK_udf);
+err:
+ mysql_rwlock_unlock(&THR_LOCK_udf);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(1);
}
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index 4b8b492698e..95cb167869e 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.h
@@ -1,3 +1,6 @@
+#ifndef SQL_UDF_INCLUDED
+#define SQL_UDF_INCLUDED
+
/* Copyright (C) 2000-2001, 2003-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -140,3 +143,4 @@ void free_udf(udf_func *udf);
int mysql_create_function(THD *thd,udf_func *udf);
int mysql_drop_function(THD *thd,const LEX_STRING *name);
#endif
+#endif /* SQL_UDF_INCLUDED */
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 70598fbfcd4..1c0c48c0fec 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -20,9 +20,13 @@
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_union.h"
#include "sql_select.h"
#include "sql_cursor.h"
+#include "sql_base.h" // fill_record
+#include "filesort.h" // filesort_free_buffers
bool mysql_union(THD *thd, LEX *lex, select_result *result,
SELECT_LEX_UNIT *unit, ulong setup_tables_done_option)
@@ -32,8 +36,7 @@ bool mysql_union(THD *thd, LEX *lex, select_result *result,
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK |
setup_tables_done_option)))
res= unit->exec();
- if (res || !thd->cursor || !thd->cursor->is_open())
- res|= unit->cleanup();
+ res|= unit->cleanup();
DBUG_RETURN(res);
}
@@ -121,7 +124,7 @@ select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
(ORDER*) 0, is_union_distinct, 1,
- options, HA_POS_ERROR, (char*) alias)))
+ options, HA_POS_ERROR, alias)))
return TRUE;
table->file->extra(HA_EXTRA_WRITE_CACHE);
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
@@ -230,7 +233,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
bool can_skip_order_by;
sl->options|= SELECT_NO_UNLOCK;
JOIN *join= new JOIN(thd_arg, sl->item_list,
- sl->options | thd_arg->options | additional_options,
+ sl->options | thd_arg->variables.option_bits | additional_options,
tmp_result);
/*
setup_tables_done_option should be set only for very first SELECT,
@@ -354,7 +357,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
}
- create_options= (first_sl->options | thd_arg->options |
+ create_options= (first_sl->options | thd_arg->variables.option_bits |
TMP_TABLE_ALL_COLUMNS);
/*
Force the temporary table to be a MyISAM table if we're going to use
@@ -395,7 +398,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
init_prepare_fake_select_lex(thd);
/* Should be done only once (the only item_list per statement) */
DBUG_ASSERT(fake_select_lex->join == 0);
- if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
+ if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->variables.option_bits,
result)))
{
fake_select_lex->table_list.empty();
@@ -431,6 +434,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
err:
thd_arg->lex->current_select= lex_select_save;
+ (void) cleanup();
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_union.h b/sql/sql_union.h
new file mode 100644
index 00000000000..43e1b7a6910
--- /dev/null
+++ b/sql/sql_union.h
@@ -0,0 +1,31 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_UNION_INCLUDED
+#define SQL_UNION_INCLUDED
+
+#include "my_global.h" /* ulong */
+
+class THD;
+class select_result;
+struct LEX;
+
+typedef class st_select_lex_unit SELECT_LEX_UNIT;
+
+bool mysql_union(THD *thd, LEX *lex, select_result *result,
+ SELECT_LEX_UNIT *unit, ulong setup_tables_done_option);
+
+
+#endif /* SQL_UNION_INCLUDED */
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 01c70a7a268..b49ed2beafe 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -19,11 +19,28 @@
Multi-table updates were introduced by Sinisa & Monty
*/
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_update.h"
+#include "sql_cache.h" // query_cache_*
+#include "sql_base.h" // close_tables_for_reopen
+#include "sql_parse.h" // cleanup_items
+#include "sql_partition.h" // partition_key_modified
#include "sql_select.h"
+#include "sql_view.h" // check_key_in_view
#include "sp_head.h"
#include "sql_trigger.h"
+#include "probes_mysql.h"
#include "debug_sync.h"
+#include "key.h" // is_key_used
+#include "sql_acl.h" // *_ACL, check_grant
+#include "records.h" // init_read_record,
+ // end_read_record
+#include "filesort.h" // filesort
+#include "sql_derived.h" // mysql_derived_prepare,
+ // mysql_handle_derived,
+ // mysql_derived_filling
/**
@@ -238,15 +255,17 @@ int mysql_update(THD *thd,
COND *conds,
uint order_num, ORDER *order,
ha_rows limit,
- enum enum_duplicates handle_duplicates, bool ignore)
+ enum enum_duplicates handle_duplicates, bool ignore,
+ ha_rows *found_return, ha_rows *updated_return)
{
bool using_limit= limit != HA_POS_ERROR;
- bool safe_update= test(thd->options & OPTION_SAFE_UPDATES);
- bool used_key_is_modified, transactional_table, will_batch;
+ bool safe_update= test(thd->variables.option_bits & OPTION_SAFE_UPDATES);
+ bool used_key_is_modified= FALSE, transactional_table, will_batch;
int res;
int error, loc_error;
- uint used_index= MAX_KEY, dup_key_found;
+ uint used_index, dup_key_found;
bool need_sort= TRUE;
+ bool reverse= FALSE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege;
#endif
@@ -257,32 +276,25 @@ int mysql_update(THD *thd,
SQL_SELECT *select;
READ_RECORD info;
SELECT_LEX *select_lex= &thd->lex->select_lex;
- bool need_reopen;
ulonglong id;
List<Item> all_fields;
THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("mysql_update");
- for ( ; ; )
- {
- if (open_tables(thd, &table_list, &table_count, 0))
- DBUG_RETURN(1);
+ if (open_tables(thd, &table_list, &table_count, 0))
+ DBUG_RETURN(1);
- if (table_list->multitable_view)
- {
- DBUG_ASSERT(table_list->view != 0);
- DBUG_PRINT("info", ("Switch to multi-update"));
- /* pass counter value */
- thd->lex->table_count= table_count;
- /* convert to multiupdate */
- DBUG_RETURN(2);
- }
- if (!lock_tables(thd, table_list, table_count, &need_reopen))
- break;
- if (!need_reopen)
- DBUG_RETURN(1);
- close_tables_for_reopen(thd, &table_list);
+ if (table_list->multitable_view)
+ {
+ DBUG_ASSERT(table_list->view != 0);
+ DBUG_PRINT("info", ("Switch to multi-update"));
+ /* pass counter value */
+ thd->lex->table_count= table_count;
+ /* convert to multiupdate */
+ DBUG_RETURN(2);
}
+ if (lock_tables(thd, table_list, table_count, 0))
+ DBUG_RETURN(1);
if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
(thd->fill_derived_tables() &&
@@ -403,11 +415,7 @@ int mysql_update(THD *thd,
my_ok(thd); // No matching records
DBUG_RETURN(0);
}
- if (!select && limit != HA_POS_ERROR)
- {
- if ((used_index= get_index_for_order(table, order, limit)) != MAX_KEY)
- need_sort= FALSE;
- }
+
/* If running in safe sql mode, don't allow updates without keys */
if (table->quick_keys.is_clear_all())
{
@@ -423,24 +431,20 @@ int mysql_update(THD *thd,
table->mark_columns_needed_for_update();
- /* Check if we are modifying a key that we are used to search with */
-
- if (select && select->quick)
- {
- used_index= select->quick->index;
- used_key_is_modified= (!select->quick->unique_key_range() &&
- select->quick->is_keys_used(table->write_set));
+ table->update_const_key_parts(conds);
+ order= simple_remove_const(order, conds);
+
+ used_index= get_index_for_order(order, table, select, limit,
+ &need_sort, &reverse);
+ if (need_sort)
+ { // Assign table scan index to check below for modified key fields:
+ used_index= table->file->key_used_on_scan;
}
- else
- {
- used_key_is_modified= 0;
- if (used_index == MAX_KEY) // no index for sort order
- used_index= table->file->key_used_on_scan;
- if (used_index != MAX_KEY)
- used_key_is_modified= is_key_used(table, used_index, table->write_set);
+ if (used_index != MAX_KEY)
+ { // Check if we are modifying a key that we are used to search with:
+ used_key_is_modified= is_key_used(table, used_index, table->write_set);
}
-
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (used_key_is_modified || order ||
partition_key_modified(table, table->write_set))
@@ -459,7 +463,7 @@ int mysql_update(THD *thd,
table->use_all_columns();
}
- /* note: We avoid sorting avoid if we sort on the used index */
+ /* note: We avoid sorting if we sort on the used index */
if (order && (need_sort || used_key_is_modified))
{
/*
@@ -521,7 +525,7 @@ int mysql_update(THD *thd,
if (used_index == MAX_KEY || (select && select->quick))
init_read_record(&info, thd, table, select, 0, 1, FALSE);
else
- init_read_record_idx(&info, thd, table, 1, used_index);
+ init_read_record_idx(&info, thd, table, 1, used_index, reverse);
thd_proc_info(thd, "Searching rows for update");
ha_rows tmp_limit= limit;
@@ -716,11 +720,13 @@ int mysql_update(THD *thd,
If (ignore && error is ignorable) we don't have to
do anything; otherwise...
*/
+ myf flags= 0;
+
if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
- thd->fatal_error(); /* Other handler errors are fatal */
+ flags|= ME_FATALERROR; /* Other handler errors are fatal */
prepare_record_for_error_message(error, table);
- table->file->print_error(error,MYF(0));
+ table->file->print_error(error,MYF(flags));
error= 1;
break;
}
@@ -779,7 +785,7 @@ int mysql_update(THD *thd,
}
else
table->file->unlock_row();
- thd->row_count++;
+ thd->warning_info->inc_current_row_for_warning();
if (thd->is_error())
{
error= 1;
@@ -817,9 +823,8 @@ int mysql_update(THD *thd,
*/
{
/* purecov: begin inspected */
- thd->fatal_error();
prepare_record_for_error_message(loc_error, table);
- table->file->print_error(loc_error,MYF(0));
+ table->file->print_error(loc_error,MYF(ME_FATALERROR));
error= 1;
/* purecov: end */
}
@@ -835,7 +840,7 @@ int mysql_update(THD *thd,
end_read_record(&info);
delete select;
thd_proc_info(thd, "end");
- VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
+ (void) table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
/*
Invalidate the table in the query cache if something changed.
@@ -845,6 +850,9 @@ int mysql_update(THD *thd,
{
query_cache_invalidate3(thd, table_list, 1);
}
+
+ if (thd->transaction.stmt.modified_non_trans_table)
+ thd->transaction.all.modified_non_trans_table= TRUE;
/*
error < 0 means really no error at all: we processed all rows until the
@@ -867,13 +875,11 @@ int mysql_update(THD *thd,
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
- transactional_table, FALSE, errcode))
+ transactional_table, FALSE, FALSE, errcode))
{
error=1; // Rollback update
}
}
- if (thd->transaction.stmt.modified_non_trans_table)
- thd->transaction.all.modified_non_trans_table= TRUE;
}
DBUG_ASSERT(transactional_table || !updated || thd->transaction.stmt.modified_non_trans_table);
free_underlaid_joins(thd, select_lex);
@@ -885,15 +891,17 @@ int mysql_update(THD *thd,
if (error < 0)
{
char buff[MYSQL_ERRMSG_SIZE];
- my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
- (ulong) thd->cuted_fields);
- thd->row_count_func=
- (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
- my_ok(thd, (ulong) thd->row_count_func, id, buff);
+ my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), (ulong) found,
+ (ulong) updated,
+ (ulong) thd->warning_info->statement_warn_count());
+ my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
+ id, buff);
DBUG_PRINT("info",("%ld records updated", (long) updated));
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
thd->abort_on_warning= 0;
+ *found_return= found;
+ *updated_return= updated;
DBUG_RETURN((error >= 0 || thd->is_error()) ? 1 : 0);
err:
@@ -930,19 +938,6 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_update");
- /*
- Statement-based replication of UPDATE ... LIMIT is not safe as order of
- rows is not defined, so in mixed mode we go to row-based.
-
- Note that we may consider a statement as safe if ORDER BY primary_key
- is present. However it may confuse users to see very similiar statements
- replicated differently.
- */
- if (thd->lex->current_select->select_limit)
- {
- thd->lex->set_stmt_unsafe();
- thd->set_current_stmt_binlog_row_based_if_mixed();
- }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= table->grant.want_privilege=
(SELECT_ACL & ~table->grant.privilege);
@@ -969,7 +964,6 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
{
update_non_unique_table_error(table_list, "UPDATE", duplicate);
- my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
DBUG_RETURN(TRUE);
}
}
@@ -1025,19 +1019,24 @@ int mysql_multi_update_prepare(THD *thd)
count in open_tables()
*/
uint table_count= lex->table_count;
- const bool using_lock_tables= thd->locked_tables != 0;
+ const bool using_lock_tables= thd->locked_tables_mode != LTM_NONE;
bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
- bool need_reopen= FALSE;
DBUG_ENTER("mysql_multi_update_prepare");
/* following need for prepared statements, to run next time multi-update */
thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
-reopen_tables:
+ /*
+ Open tables and create derived ones, but do not lock and fill them yet.
- /* open tables and create derived ones, but do not lock and fill them */
- if (((original_multiupdate || need_reopen) &&
- open_tables(thd, &table_list, &table_count, 0)) ||
+ During prepare phase acquire only S metadata locks instead of SW locks to
+ keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE
+ and global read lock.
+ */
+ if ((original_multiupdate &&
+ open_tables(thd, &table_list, &table_count,
+ (thd->stmt_arena->is_stmt_prepare() ?
+ MYSQL_OPEN_FORCE_SHARED_MDL : 0))) ||
mysql_handle_derived(lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE);
/*
@@ -1107,6 +1106,11 @@ reopen_tables:
If we are using the binary log, we need TL_READ_NO_INSERT to get
correct order of statements. Otherwise, we use a TL_READ lock to
improve performance.
+ We don't downgrade metadata lock from SW to SR in this case as
+ there is no guarantee that the same ticket is not used by
+ another table instance used by this statement which is going to
+ be write-locked (for example, trigger to be invoked might try
+ to update this table).
*/
tl->lock_type= read_lock_type_for_table(thd, lex, tl);
tl->updating= 0;
@@ -1121,10 +1125,11 @@ reopen_tables:
if (!tl->derived)
{
uint want_privilege= tl->updating ? UPDATE_ACL : SELECT_ACL;
- if (check_access(thd, want_privilege,
- tl->db, &tl->grant.privilege, 0, 0,
- test(tl->schema_table)) ||
- check_grant(thd, want_privilege, tl, 0, 1, 0))
+ if (check_access(thd, want_privilege, tl->db,
+ &tl->grant.privilege,
+ &tl->grant.m_internal,
+ 0, 0) ||
+ check_grant(thd, want_privilege, tl, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
}
}
@@ -1146,62 +1151,11 @@ reopen_tables:
/* now lock and fill tables */
if (!thd->stmt_arena->is_stmt_prepare() &&
- lock_tables(thd, table_list, table_count, &need_reopen))
+ lock_tables(thd, table_list, table_count, 0))
{
- if (!need_reopen)
- DBUG_RETURN(TRUE);
-
- DBUG_PRINT("info", ("lock_tables failed, reopening"));
-
- /*
- We have to reopen tables since some of them were altered or dropped
- during lock_tables() or something was done with their triggers.
- Let us do some cleanups to be able do setup_table() and setup_fields()
- once again.
- */
- List_iterator_fast<Item> it(*fields);
- Item *item;
- while ((item= it++))
- item->cleanup();
-
- /* We have to cleanup translation tables of views. */
- for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global)
- tbl->cleanup_items();
-
- /*
- To not to hog memory (as a result of the
- unit->reinit_exec_mechanism() call below):
- */
- lex->unit.cleanup();
-
- for (SELECT_LEX *sl= lex->all_selects_list;
- sl;
- sl= sl->next_select_in_list())
- {
- SELECT_LEX_UNIT *unit= sl->master_unit();
- unit->reinit_exec_mechanism(); // reset unit->prepared flags
- /*
- Reset 'clean' flag back to force normal execution of
- unit->cleanup() in Prepared_statement::cleanup_stmt()
- (call to lex->unit.cleanup() above sets this flag to TRUE).
- */
- unit->unclean();
- }
-
- /*
- Also we need to cleanup Natural_join_column::table_field items.
- To not to traverse a join tree we will cleanup whole
- thd->free_list (in PS execution mode that list may not contain
- items from 'fields' list, so the cleanup above is necessary to.
- */
- cleanup_items(thd->free_list);
- cleanup_items(thd->stmt_arena->free_list);
- close_tables_for_reopen(thd, &table_list);
-
- DEBUG_SYNC(thd, "multi_update_reopen_tables");
-
- goto reopen_tables;
+ DBUG_RETURN(TRUE);
}
+ /* @todo: downgrade the metadata locks here. */
/*
Check that we are not using table that we are updating, but we should
@@ -1256,18 +1210,22 @@ bool mysql_multi_update(THD *thd,
List<Item> *values,
COND *conds,
ulonglong options,
- enum enum_duplicates handle_duplicates, bool ignore,
- SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
+ enum enum_duplicates handle_duplicates,
+ bool ignore,
+ SELECT_LEX_UNIT *unit,
+ SELECT_LEX *select_lex,
+ multi_update **result)
{
- multi_update *result;
bool res;
DBUG_ENTER("mysql_multi_update");
- if (!(result= new multi_update(table_list,
+ if (!(*result= new multi_update(table_list,
thd->lex->select_lex.leaf_tables,
fields, values,
handle_duplicates, ignore)))
+ {
DBUG_RETURN(TRUE);
+ }
thd->abort_on_warning= test(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
@@ -1282,19 +1240,18 @@ bool mysql_multi_update(THD *thd,
(ORDER *)NULL,
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE,
- result, unit, select_lex);
+ *result, unit, select_lex);
DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error()));
res|= thd->is_error();
if (unlikely(res))
{
/* If we had a another error reported earlier then this will be ignored */
- result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR));
- result->abort();
+ (*result)->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR));
+ (*result)->abort_result_set();
}
- delete result;
thd->abort_on_warning= 0;
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(res);
}
@@ -1551,7 +1508,7 @@ multi_update::initialize_tables(JOIN *join)
TABLE_LIST *table_ref;
DBUG_ENTER("initialize_tables");
- if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
+ if ((thd->variables.option_bits & OPTION_SAFE_UPDATES) && error_if_full_join(join))
DBUG_RETURN(1);
main_table=join->join_tab->table;
table_to_update= 0;
@@ -1675,13 +1632,14 @@ loop_end:
tmp_param->field_count=temp_fields.elements;
tmp_param->group_parts=1;
tmp_param->group_length= table->file->ref_length;
- if (!(tmp_tables[cnt]=create_tmp_table(thd,
- tmp_param,
- temp_fields,
- (ORDER*) &group, 0, 0,
- TMP_TABLE_ALL_COLUMNS,
- HA_POS_ERROR,
- (char *) "")))
+ /* small table, ignore SQL_BIG_TABLES */
+ my_bool save_big_tables= thd->variables.big_tables;
+ thd->variables.big_tables= FALSE;
+ tmp_tables[cnt]=create_tmp_table(thd, tmp_param, temp_fields,
+ (ORDER*) &group, 0, 0,
+ TMP_TABLE_ALL_COLUMNS, HA_POS_ERROR, "");
+ thd->variables.big_tables= save_big_tables;
+ if (!tmp_tables[cnt])
DBUG_RETURN(1);
tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
}
@@ -1791,11 +1749,13 @@ bool multi_update::send_data(List<Item> &not_used_values)
If (ignore && error == is ignorable) we don't have to
do anything; otherwise...
*/
+ myf flags= 0;
+
if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
- thd->fatal_error(); /* Other handler errors are fatal */
+ flags|= ME_FATALERROR; /* Other handler errors are fatal */
prepare_record_for_error_message(error, table);
- table->file->print_error(error,MYF(0));
+ table->file->print_error(error,MYF(flags));
DBUG_RETURN(1);
}
}
@@ -1809,10 +1769,10 @@ bool multi_update::send_data(List<Item> &not_used_values)
/* non-transactional or transactional table got modified */
/* either multi_update class' flag is raised in its branch */
if (table->file->has_transactions())
- transactional_tables= 1;
+ transactional_tables= TRUE;
else
{
- trans_safe= 0;
+ trans_safe= FALSE;
thd->transaction.stmt.modified_non_trans_table= TRUE;
}
}
@@ -1878,7 +1838,7 @@ void multi_update::send_error(uint errcode,const char *err)
}
-void multi_update::abort()
+void multi_update::abort_result_set()
{
/* the error was handled or nothing deleted and no side effects return */
if (error_handled ||
@@ -1903,7 +1863,7 @@ void multi_update::abort()
todo/fixme: do_update() is never called with the arg 1.
should it change the signature to become argless?
*/
- VOID(do_updates());
+ (void) do_updates();
}
}
if (thd->transaction.stmt.modified_non_trans_table)
@@ -1922,8 +1882,8 @@ void multi_update::abort()
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
/* the error of binary logging is ignored */
(void)thd->binlog_query(THD::ROW_QUERY_TYPE,
- thd->query(), thd->query_length(),
- transactional_tables, FALSE, errcode);
+ thd->query(), thd->query_length(),
+ transactional_tables, FALSE, FALSE, errcode);
}
thd->transaction.all.modified_non_trans_table= TRUE;
}
@@ -2055,10 +2015,10 @@ int multi_update::do_updates()
if (updated != org_updated)
{
if (table->file->has_transactions())
- transactional_tables= 1;
+ transactional_tables= TRUE;
else
{
- trans_safe= 0; // Can't do safe rollback
+ trans_safe= FALSE; // Can't do safe rollback
thd->transaction.stmt.modified_non_trans_table= TRUE;
}
}
@@ -2073,9 +2033,8 @@ int multi_update::do_updates()
err:
{
- thd->fatal_error();
prepare_record_for_error_message(local_error, table);
- table->file->print_error(local_error,MYF(0));
+ table->file->print_error(local_error,MYF(ME_FATALERROR));
}
err2:
@@ -2088,10 +2047,10 @@ err2:
if (updated != org_updated)
{
if (table->file->has_transactions())
- transactional_tables= 1;
+ transactional_tables= TRUE;
else
{
- trans_safe= 0;
+ trans_safe= FALSE;
thd->transaction.stmt.modified_non_trans_table= TRUE;
}
}
@@ -2113,7 +2072,9 @@ bool multi_update::send_eof()
Does updates for the last n - 1 tables, returns 0 if ok;
error takes into account killed status gained in do_updates()
*/
- int local_error = (table_count) ? do_updates() : 0;
+ int local_error= thd->is_error();
+ if (!local_error)
+ local_error = (table_count) ? do_updates() : 0;
/*
if local_error is not set ON until after do_updates() then
later carried out killing should not affect binlogging.
@@ -2137,8 +2098,9 @@ bool multi_update::send_eof()
either from the query's list or via a stored routine: bug#13270,23333
*/
- DBUG_ASSERT(trans_safe || !updated ||
- thd->transaction.stmt.modified_non_trans_table);
+ if (thd->transaction.stmt.modified_non_trans_table)
+ thd->transaction.all.modified_non_trans_table= TRUE;
+
if (local_error == 0 || thd->transaction.stmt.modified_non_trans_table)
{
if (mysql_bin_log.is_open())
@@ -2150,14 +2112,15 @@ bool multi_update::send_eof()
errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
- transactional_tables, FALSE, errcode))
+ transactional_tables, FALSE, FALSE, errcode))
{
local_error= 1; // Rollback update
}
}
- if (thd->transaction.stmt.modified_non_trans_table)
- thd->transaction.all.modified_non_trans_table= TRUE;
}
+ DBUG_ASSERT(trans_safe || !updated ||
+ thd->transaction.stmt.modified_non_trans_table);
+
if (local_error != 0)
error_handled= TRUE; // to force early leave from ::send_error()
@@ -2173,8 +2136,7 @@ bool multi_update::send_eof()
thd->first_successful_insert_id_in_prev_stmt : 0;
my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO),
(ulong) found, (ulong) updated, (ulong) thd->cuted_fields);
- thd->row_count_func=
- (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
- ::my_ok(thd, (ulong) thd->row_count_func, id, buff);
+ ::my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
+ id, buff);
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_update.h b/sql/sql_update.h
new file mode 100644
index 00000000000..50ff50f025d
--- /dev/null
+++ b/sql/sql_update.h
@@ -0,0 +1,44 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 SQL_UPDATE_INCLUDED
+#define SQL_UPDATE_INCLUDED
+
+#include "sql_class.h" /* enum_duplicates */
+
+class Item;
+struct TABLE_LIST;
+class THD;
+
+typedef class st_select_lex SELECT_LEX;
+typedef class st_select_lex_unit SELECT_LEX_UNIT;
+
+bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
+ Item **conds, uint order_num, ORDER *order);
+int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
+ List<Item> &values,COND *conds,
+ uint order_num, ORDER *order, ha_rows limit,
+ enum enum_duplicates handle_duplicates, bool ignore,
+ ha_rows *found_return, ha_rows *updated_return);
+bool mysql_multi_update(THD *thd, TABLE_LIST *table_list,
+ List<Item> *fields, List<Item> *values,
+ COND *conds, ulonglong options,
+ enum enum_duplicates handle_duplicates, bool ignore,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex,
+ multi_update **result);
+bool records_are_comparable(const TABLE *table);
+bool compare_records(const TABLE *table);
+
+#endif /* SQL_UPDATE_INCLUDED */
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 133574089aa..54b5eb43ab1 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004 MySQL AB
+/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -15,12 +15,24 @@
*/
#define MYSQL_LEX 1
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_view.h"
+#include "sql_base.h" // find_table_in_global_list, lock_table_names
+#include "sql_parse.h" // sql_parse
+#include "sql_cache.h" // query_cache_*
+#include "lock.h" // MYSQL_OPEN_SKIP_TEMPORARY
+#include "sql_show.h" // append_identifier
+#include "sql_table.h" // build_table_filename
+#include "sql_db.h" // mysql_opt_change_db, mysql_change_db
+#include "sql_acl.h" // *_ACL, check_grant
#include "sql_select.h"
#include "parse_file.h"
#include "sp.h"
#include "sp_head.h"
#include "sp_cache.h"
+#include "datadict.h" // dd_frm_type()
#define MD5_BUFF_LENGTH 33
@@ -29,15 +41,6 @@ const LEX_STRING view_type= { C_STRING_WITH_LEN("VIEW") };
static int mysql_register_view(THD *thd, TABLE_LIST *view,
enum_view_create_mode mode);
-const char *updatable_views_with_limit_names[]= { "NO", "YES", NullS };
-TYPELIB updatable_views_with_limit_typelib=
-{
- array_elements(updatable_views_with_limit_names)-1, "",
- updatable_views_with_limit_names,
- 0
-};
-
-
/*
Make a unique name for an anonymous view column
SYNOPSIS
@@ -207,40 +210,17 @@ static void make_valid_column_names(List<Item> &item_list)
static bool
fill_defined_view_parts (THD *thd, TABLE_LIST *view)
{
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
LEX *lex= thd->lex;
- bool not_used;
TABLE_LIST decoy;
memcpy (&decoy, view, sizeof (TABLE_LIST));
+ key_length= create_table_def_key(thd, key, view, 0);
- /*
- Let's reset decoy.view before calling open_table(): when we start
- supporting ALTER VIEW in PS/SP that may save us from a crash.
- */
-
- decoy.view= NULL;
-
- /*
- open_table() will return NULL if 'decoy' is idenitifying a view *and*
- there is no TABLE object for that view in the table cache. However,
- decoy.view will be set to 1.
-
- If there is a TABLE-instance for the oject identified by 'decoy',
- open_table() will return that instance no matter if it is a table or
- a view.
-
- Thus, there is no need to check for the return value of open_table(),
- since the return value itself does not mean anything.
- */
-
- open_table(thd, &decoy, thd->mem_root, &not_used, OPEN_VIEW_NO_PARSE);
-
- if (!decoy.view)
- {
- /* It's a table. */
- my_error(ER_WRONG_OBJECT, MYF(0), view->db, view->table_name, "VIEW");
+ if (tdc_open_view(thd, &decoy, decoy.alias, key, key_length,
+ thd->mem_root, OPEN_VIEW_NO_PARSE))
return TRUE;
- }
if (!lex->definer)
{
@@ -296,13 +276,17 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
checked that we have not more privileges on correspondent column of view
table (i.e. user will not get some privileges by view creation)
*/
- if ((check_access(thd, CREATE_VIEW_ACL, view->db, &view->grant.privilege,
- 0, 0, is_schema_db(view->db, view->db_length)) ||
- check_grant(thd, CREATE_VIEW_ACL, view, 0, 1, 0)) ||
+ if ((check_access(thd, CREATE_VIEW_ACL, view->db,
+ &view->grant.privilege,
+ &view->grant.m_internal,
+ 0, 0) ||
+ check_grant(thd, CREATE_VIEW_ACL, view, FALSE, 1, FALSE)) ||
(mode != VIEW_CREATE_NEW &&
- (check_access(thd, DROP_ACL, view->db, &view->grant.privilege,
- 0, 0, is_schema_db(view->db, view->db_length)) ||
- check_grant(thd, DROP_ACL, view, 0, 1, 0))))
+ (check_access(thd, DROP_ACL, view->db,
+ &view->grant.privilege,
+ &view->grant.m_internal,
+ 0, 0) ||
+ check_grant(thd, DROP_ACL, view, FALSE, 1, FALSE))))
goto err;
for (sl= select_lex; sl; sl= sl->next_select())
@@ -351,8 +335,10 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
if (!tbl->table_in_first_from_clause)
{
if (check_access(thd, SELECT_ACL, tbl->db,
- &tbl->grant.privilege, 0, 0, test(tbl->schema_table)) ||
- check_grant(thd, SELECT_ACL, tbl, 0, 1, 0))
+ &tbl->grant.privilege,
+ &tbl->grant.m_internal,
+ 0, 0) ||
+ check_grant(thd, SELECT_ACL, tbl, FALSE, 1, FALSE))
goto err;
}
}
@@ -429,6 +415,35 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
DBUG_ASSERT(!lex->proc_list.first && !lex->result &&
!lex->param_list.elements);
+ /*
+ We can't allow taking exclusive meta-data locks of unlocked view under
+ LOCK TABLES since this might lead to deadlock. Since at the moment we
+ can't really lock view with LOCK TABLES we simply prohibit creation/
+ alteration of views under LOCK TABLES.
+ */
+
+ if (thd->locked_tables_mode)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ res= TRUE;
+ goto err;
+ }
+
+ if ((res= create_view_precheck(thd, tables, view, mode)))
+ goto err;
+
+ lex->link_first_table_back(view, link_to_local);
+ view->open_type= OT_BASE_ONLY;
+
+ if (open_and_lock_tables(thd, lex->query_tables, TRUE, 0))
+ {
+ view= lex->unlink_first_table(&link_to_local);
+ res= TRUE;
+ goto err;
+ }
+
+ view= lex->unlink_first_table(&link_to_local);
+
if (mode == VIEW_ALTER && fill_defined_view_parts(thd, view))
{
res= TRUE;
@@ -490,16 +505,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
}
}
#endif
-
- if ((res= create_view_precheck(thd, tables, view, mode)))
- goto err;
-
- if (open_and_lock_tables(thd, tables))
- {
- res= TRUE;
- goto err;
- }
-
/*
check that tables are not temporary and this VIEW do not used in query
(it is possible with ALTERing VIEW).
@@ -644,12 +649,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
}
#endif
- if (wait_if_global_read_lock(thd, 0, 0))
- {
- res= TRUE;
- goto err;
- }
- VOID(pthread_mutex_lock(&LOCK_open));
res= mysql_register_view(thd, view, mode);
if (mysql_bin_log.is_open())
@@ -692,14 +691,12 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
int errcode= query_error_code(thd, TRUE);
if (thd->binlog_query(THD::STMT_QUERY_TYPE,
- buff.ptr(), buff.length(), FALSE, FALSE, errcode))
+ buff.ptr(), buff.length(), FALSE, FALSE, FALSE, errcode))
res= TRUE;
}
- VOID(pthread_mutex_unlock(&LOCK_open));
if (mode != VIEW_CREATE_NEW)
query_cache_invalidate3(thd, view, 0);
- start_waiting_global_read_lock(thd);
if (res)
goto err;
@@ -848,7 +845,8 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
thd->variables.sql_mode|= sql_mode;
}
- DBUG_PRINT("info", ("View: %s", view_query.ptr()));
+ DBUG_PRINT("info",
+ ("View: %*.s", (int) view_query.length(), view_query.ptr()));
/* fill structure */
view->source= thd->lex->create_view_select;
@@ -1154,8 +1152,18 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
table->db, table->table_name);
get_default_definer(thd, &table->definer);
}
+
+ /*
+ Initialize view definition context by character set names loaded from
+ the view definition file. Use UTF8 character set if view definition
+ file is of old version and does not contain the character set names.
+ */
+ table->view_creation_ctx= View_creation_ctx::create(thd, table);
+
if (flags & OPEN_VIEW_NO_PARSE)
{
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
DBUG_RETURN(FALSE);
}
@@ -1167,16 +1175,23 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
table->view_db.length= table->db_length;
table->view_name.str= table->table_name;
table->view_name.length= table->table_name_length;
-
- /*TODO: md5 test here and warning if it is differ */
-
/*
- Initialize view definition context by character set names loaded from
- the view definition file. Use UTF8 character set if view definition
- file is of old version and does not contain the character set names.
+ We don't invalidate a prepared statement when a view changes,
+ or when someone creates a temporary table.
+ Instead, the view is inlined into the body of the statement
+ upon the first execution. Below, make sure that on
+ re-execution of a prepared statement we don't prefer
+ a temporary table to the view, if the view name was shadowed
+ with a temporary table with the same name.
+ This assignment ensures that on re-execution open_table() will
+ not try to call find_temporary_table() for this TABLE_LIST,
+ but will invoke open_table_from_share(), which will
+ eventually call this function.
*/
+ table->open_type= OT_BASE_ONLY;
+
+ /*TODO: md5 test here and warning if it is differ */
- table->view_creation_ctx= View_creation_ctx::create(thd, table);
/*
TODO: TABLE mem root should be used here when VIEW will be stored in
@@ -1264,8 +1279,9 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
if (!table->prelocking_placeholder &&
(old_lex->sql_command == SQLCOM_SELECT && old_lex->describe))
{
- if (check_table_access(thd, SELECT_ACL, view_tables, UINT_MAX, TRUE) &&
- check_table_access(thd, SHOW_VIEW_ACL, table, UINT_MAX, TRUE))
+ if (check_table_access(thd, SELECT_ACL, view_tables, FALSE,
+ UINT_MAX, TRUE) &&
+ check_table_access(thd, SHOW_VIEW_ACL, table, FALSE, UINT_MAX, TRUE))
{
my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0));
goto err;
@@ -1275,7 +1291,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
(old_lex->sql_command == SQLCOM_SHOW_CREATE) &&
!table->belong_to_view)
{
- if (check_table_access(thd, SHOW_VIEW_ACL, table, UINT_MAX, FALSE))
+ if (check_table_access(thd, SHOW_VIEW_ACL, table, FALSE, UINT_MAX, FALSE))
goto err;
}
@@ -1290,7 +1306,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
tbl;
tbl= (view_tables_tail= tbl)->next_global)
{
- tbl->skip_temporary= 1;
+ tbl->open_type= OT_BASE_ONLY;
tbl->belong_to_view= top_view;
tbl->referencing_view= table;
tbl->prelocking_placeholder= table->prelocking_placeholder;
@@ -1337,8 +1353,8 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
If the view's body needs row-based binlogging (e.g. the VIEW is created
from SELECT UUID()), the top statement also needs it.
*/
- if (lex->is_stmt_unsafe())
- old_lex->set_stmt_unsafe();
+ old_lex->set_stmt_unsafe_flags(lex->get_stmt_unsafe_flags());
+
view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
lex->can_be_merged());
@@ -1360,7 +1376,11 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
anyway.
*/
for (tbl= view_main_select_tables; tbl; tbl= tbl->next_local)
+ {
tbl->lock_type= table->lock_type;
+ tbl->mdl_request.set_type((tbl->lock_type >= TL_WRITE_ALLOW_WRITE) ?
+ MDL_SHARED_WRITE : MDL_SHARED_READ);
+ }
/*
If the view is mergeable, we might want to
INSERT/UPDATE/DELETE into tables of this view. Preserve the
@@ -1608,16 +1628,30 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
bool something_wrong= FALSE;
DBUG_ENTER("mysql_drop_view");
- VOID(pthread_mutex_lock(&LOCK_open));
+ /*
+ We can't allow dropping of unlocked view under LOCK TABLES since this
+ might lead to deadlock. But since we can't really lock view with LOCK
+ TABLES we have to simply prohibit dropping of views.
+ */
+
+ if (thd->locked_tables_mode)
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
+ if (lock_table_names(thd, views, 0, thd->variables.lock_wait_timeout,
+ MYSQL_OPEN_SKIP_TEMPORARY))
+ DBUG_RETURN(TRUE);
+
for (view= views; view; view= view->next_local)
{
- TABLE_SHARE *share;
frm_type_enum type= FRMTYPE_ERROR;
build_table_filename(path, sizeof(path) - 1,
view->db, view->table_name, reg_ext, 0);
if (access(path, F_OK) ||
- FRMTYPE_VIEW != (type= mysql_frm_type(thd, path, &not_used)))
+ FRMTYPE_VIEW != (type= dd_frm_type(thd, path, &not_used)))
{
char name[FN_REFLEN];
my_snprintf(name, sizeof(name), "%s.%s", view->db, view->table_name);
@@ -1644,24 +1678,18 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
}
continue;
}
- if (my_delete(path, MYF(MY_WME)))
+ if (mysql_file_delete(key_file_frm, path, MYF(MY_WME)))
error= TRUE;
some_views_deleted= TRUE;
/*
- For a view, there is only one table_share object which should never
- be used outside of LOCK_open
+ For a view, there is a TABLE_SHARE object, but its
+ ref_count never goes above 1. Remove it from the table
+ definition cache, in case the view was cached.
*/
- if ((share= get_cached_table_share(view->db, view->table_name)))
- {
- DBUG_ASSERT(share->ref_count == 0);
- pthread_mutex_lock(&share->mutex);
- share->ref_count++;
- share->version= 0;
- pthread_mutex_unlock(&share->mutex);
- release_table_share(share, RELEASE_WAIT_FOR_DROP);
- }
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, view->db, view->table_name,
+ FALSE);
query_cache_invalidate3(thd, view, 0);
sp_cache_invalidate();
}
@@ -1686,8 +1714,6 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
something_wrong= 1;
}
- VOID(pthread_mutex_unlock(&LOCK_open));
-
if (something_wrong)
{
DBUG_RETURN(TRUE);
@@ -1698,53 +1724,6 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
/*
- Check type of .frm if we are not going to parse it
-
- SYNOPSIS
- mysql_frm_type()
- path path to file
-
- RETURN
- FRMTYPE_ERROR error
- FRMTYPE_TABLE table
- FRMTYPE_VIEW view
-*/
-
-frm_type_enum mysql_frm_type(THD *thd, char *path, enum legacy_db_type *dbt)
-{
- File file;
- uchar header[10]; //"TYPE=VIEW\n" it is 10 characters
- size_t error;
- DBUG_ENTER("mysql_frm_type");
-
- *dbt= DB_TYPE_UNKNOWN;
-
- if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)
- DBUG_RETURN(FRMTYPE_ERROR);
- error= my_read(file, (uchar*) header, sizeof(header), MYF(MY_NABP));
- my_close(file, MYF(MY_WME));
-
- if (error)
- DBUG_RETURN(FRMTYPE_ERROR);
- if (!strncmp((char*) header, "TYPE=VIEW\n", sizeof(header)))
- DBUG_RETURN(FRMTYPE_VIEW);
-
- /*
- This is just a check for DB_TYPE. We'll return default unknown type
- if the following test is true (arg #3). This should not have effect
- on return value from this function (default FRMTYPE_TABLE)
- */
- if (header[0] != (uchar) 254 || header[1] != 1 ||
- (header[2] != FRM_VER && header[2] != FRM_VER+1 &&
- (header[2] < FRM_VER+3 || header[2] > FRM_VER+4)))
- DBUG_RETURN(FRMTYPE_TABLE);
-
- *dbt= (enum legacy_db_type) (uint) *(header + 3);
- DBUG_RETURN(FRMTYPE_TABLE); // Is probably a .frm table
-}
-
-
-/*
check of key (primary or unique) presence in updatable view
SYNOPSIS
diff --git a/sql/sql_view.h b/sql/sql_view.h
index e08c2168e14..c15ecffccb8 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -1,3 +1,6 @@
+#ifndef SQL_VIEW_INCLUDED
+#define SQL_VIEW_INCLUDED
+
/* -*- C++ -*- */
/* Copyright (C) 2004 MySQL AB
@@ -15,6 +18,16 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "sql_class.h" /* Required by sql_lex.h */
+#include "sql_lex.h" /* enum_view_create_mode, enum_drop_mode */
+
+/* Forward declarations */
+
+class File_parser;
+
+
+/* Function declarations */
+
bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
enum_view_create_mode mode);
@@ -30,8 +43,6 @@ bool check_key_in_view(THD *thd, TABLE_LIST * view);
bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view);
-frm_type_enum mysql_frm_type(THD *thd, char *path, enum legacy_db_type *dbt);
-
int view_checksum(THD *thd, TABLE_LIST *view);
extern TYPELIB updatable_views_with_limit_typelib;
@@ -42,3 +53,6 @@ bool mysql_rename_view(THD *thd, const char *new_db, const char *new_name,
#define VIEW_ANY_ACL (SELECT_ACL | UPDATE_ACL | INSERT_ACL | DELETE_ACL)
+extern const LEX_STRING view_type;
+
+#endif /* SQL_VIEW_INCLUDED */
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 4e24e69af42..9aa938437b1 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -29,13 +29,21 @@
#define YYLEX_PARAM yythd
#define YYTHD ((THD *)yythd)
#define YYLIP (& YYTHD->m_parser_state->m_lip)
+#define YYPS (& YYTHD->m_parser_state->m_yacc)
#define MYSQL_YACC
#define YYINITDEPTH 100
#define YYMAXDEPTH 3200 /* Because of 64K stack */
#define Lex (YYTHD->lex)
#define Select Lex->current_select
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_parse.h" /* comp_*_creator */
+#include "sql_table.h" /* primary_key_name */
+#include "sql_partition.h" /* mem_alloc_error, partition_info, HASH_PARTITION */
+#include "sql_acl.h" /* *_ACL */
+#include "password.h" /* my_make_scrambled_password_323, my_make_scrambled_password */
+#include "sql_class.h" /* Key_part_spec, enum_filetype, Diag_condition_item_name */
#include "slave.h"
#include "lex_symbol.h"
#include "item_create.h"
@@ -43,9 +51,16 @@
#include "sp_pcontext.h"
#include "sp_rcontext.h"
#include "sp.h"
+#include "sql_alter.h" // Alter_table*_statement
+#include "sql_truncate.h" // Truncate_statement
+#include "sql_admin.h" // Analyze/Check..._table_stmt
+#include "sql_partition_admin.h" // Alter_table_*_partition_stmt
+#include "sql_signal.h"
#include "event_parse_data.h"
#include <myisam.h>
#include <myisammrg.h>
+#include "keycaches.h"
+#include "set_var.h"
/* this is to get the bison compilation windows warnings out */
#ifdef _MSC_VER
@@ -55,8 +70,6 @@
int yylex(void *yylval, void *yythd);
-const LEX_STRING null_lex_str= {0,0};
-
#define yyoverflow(A,B,C,D,E,F) \
{ \
ulong val= *(F); \
@@ -131,10 +144,13 @@ void my_parse_error(const char *s)
Lex_input_stream *lip= & thd->m_parser_state->m_lip;
const char *yytext= lip->get_tok_start();
+ if (!yytext)
+ yytext= "";
+
/* Push an error into the error stack */
+ ErrConvString err(yytext, thd->variables.character_set_client);
my_printf_error(ER_PARSE_ERROR, ER(ER_PARSE_ERROR), MYF(0), s,
- (yytext ? yytext : ""),
- lip->yylineno);
+ err.ptr(), lip->yylineno);
}
/**
@@ -424,7 +440,7 @@ set_system_variable(THD *thd, struct sys_var_with_base *tmp,
LEX *lex= thd->lex;
/* No AUTOCOMMIT from a stored function or trigger. */
- if (lex->spcont && tmp->var == &sys_autocommit)
+ if (lex->spcont && tmp->var == Sys_autocommit_ptr)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
if (! (var= new set_var(var_type, tmp->var, &tmp->base_name, val)))
@@ -595,12 +611,97 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
DBUG_RETURN(result);
}
+/**
+ @brief Creates a new SELECT_LEX for a UNION branch.
+
+ Sets up and initializes a SELECT_LEX structure for a query once the parser
+ discovers a UNION token. The current SELECT_LEX is pushed on the stack and
+ the new SELECT_LEX becomes the current one.
+
+ @param lex The parser state.
+
+ @param is_union_distinct True if the union preceding the new select statement
+ uses UNION DISTINCT.
+
+ @param is_top_level This should be @c TRUE if the newly created SELECT_LEX
+ is a non-nested statement.
+
+ @return <code>false</code> if successful, <code>true</code> if an error was
+ reported. In the latter case parsing should stop.
+ */
+bool add_select_to_union_list(LEX *lex, bool is_union_distinct,
+ bool is_top_level)
+{
+ /*
+ Only the last SELECT can have INTO. Since the grammar won't allow INTO in
+ a nested SELECT, we make this check only when creating a top-level SELECT.
+ */
+ if (is_top_level && lex->result)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO");
+ return TRUE;
+ }
+ if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
+ {
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ return TRUE;
+ }
+ /* This counter shouldn't be incremented for UNION parts */
+ lex->nest_level--;
+ if (mysql_new_select(lex, 0))
+ return TRUE;
+ mysql_init_select(lex);
+ lex->current_select->linkage=UNION_TYPE;
+ if (is_union_distinct) /* UNION DISTINCT - remember position */
+ lex->current_select->master_unit()->union_distinct=
+ lex->current_select;
+ return FALSE;
+}
+
+/**
+ @brief Initializes a SELECT_LEX for a query within parentheses (aka
+ braces).
+
+ @return false if successful, true if an error was reported. In the latter
+ case parsing should stop.
+ */
+bool setup_select_in_parentheses(LEX *lex)
+{
+ SELECT_LEX * sel= lex->current_select;
+ if (sel->set_braces(1))
+ {
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ return TRUE;
+ }
+ if (sel->linkage == UNION_TYPE &&
+ !sel->master_unit()->first_select()->braces &&
+ sel->master_unit()->first_select()->linkage ==
+ UNION_TYPE)
+ {
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ return TRUE;
+ }
+ if (sel->linkage == UNION_TYPE &&
+ sel->olap != UNSPECIFIED_OLAP_TYPE &&
+ sel->master_unit()->fake_select_lex)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "CUBE/ROLLUP", "ORDER BY");
+ return TRUE;
+ }
+ /* select in braces, can't contain global parameters */
+ if (sel->master_unit()->fake_select_lex)
+ sel->master_unit()->global_parameters=
+ sel->master_unit()->fake_select_lex;
+ return FALSE;
+}
static bool add_create_index_prepare (LEX *lex, Table_ident *table)
{
lex->sql_command= SQLCOM_CREATE_INDEX;
if (!lex->current_select->add_table_to_list(lex->thd, table, NULL,
- TL_OPTION_UPDATING))
+ TL_OPTION_UPDATING,
+ TL_READ_NO_INSERT,
+ MDL_SHARED_NO_WRITE))
return TRUE;
lex->alter_info.reset();
lex->alter_info.flags= ALTER_ADD_INDEX;
@@ -609,9 +710,9 @@ static bool add_create_index_prepare (LEX *lex, Table_ident *table)
return FALSE;
}
-
-static bool add_create_index (LEX *lex, Key::Keytype type, const char *name,
- KEY_CREATE_INFO *info= NULL, bool generated= 0)
+static bool add_create_index (LEX *lex, Key::Keytype type,
+ const LEX_STRING &name,
+ KEY_CREATE_INFO *info= NULL, bool generated= 0)
{
Key *key;
key= new Key(type, name, info ? info : &lex->key_create_info, generated,
@@ -663,10 +764,14 @@ static bool add_create_index (LEX *lex, Key::Keytype type, const char *name,
struct sp_cond_type *spcondtype;
struct { int vars, conds, hndlrs, curs; } spblock;
sp_name *spname;
- struct st_lex *lex;
+ LEX *lex;
sp_head *sphead;
struct p_elem_val *p_elem_value;
enum index_hint_type index_hint;
+ enum enum_filetype filetype;
+ enum Foreign_key::fk_option m_fk_option;
+ enum enum_yes_no_unknown m_yes_no_unk;
+ Diag_condition_item_name diag_condition_item_name;
}
%{
@@ -675,10 +780,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%pure_parser /* We have threads */
/*
- Currently there are 169 shift/reduce conflicts.
+ Currently there are 168 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 169
+%expect 168
/*
Comments for TOKENS.
@@ -748,6 +853,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CASCADED /* SQL-2003-R */
%token CASE_SYM /* SQL-2003-R */
%token CAST_SYM /* SQL-2003-R */
+%token CATALOG_NAME_SYM /* SQL-2003-N */
%token CHAIN_SYM /* SQL-2003-N */
%token CHANGE
%token CHANGED
@@ -756,6 +862,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CHECKSUM_SYM
%token CHECK_SYM /* SQL-2003-R */
%token CIPHER_SYM
+%token CLASS_ORIGIN_SYM /* SQL-2003-N */
%token CLIENT_SYM
%token CLOSE_SYM /* SQL-2003-R */
%token COALESCE /* SQL-2003-N */
@@ -764,6 +871,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token COLLATION_SYM /* SQL-2003-N */
%token COLUMNS
%token COLUMN_SYM /* SQL-2003-R */
+%token COLUMN_NAME_SYM /* SQL-2003-N */
%token COMMENT_SYM
%token COMMITTED_SYM /* SQL-2003-N */
%token COMMIT_SYM /* SQL-2003-R */
@@ -771,10 +879,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token COMPLETION_SYM
%token COMPRESSED_SYM
%token CONCURRENT
-%token CONDITION_SYM /* SQL-2003-N */
+%token CONDITION_SYM /* SQL-2003-R, SQL-2008-R */
%token CONNECTION_SYM
%token CONSISTENT_SYM
%token CONSTRAINT /* SQL-2003-R */
+%token CONSTRAINT_CATALOG_SYM /* SQL-2003-N */
+%token CONSTRAINT_NAME_SYM /* SQL-2003-N */
+%token CONSTRAINT_SCHEMA_SYM /* SQL-2003-N */
%token CONTAINS_SYM /* SQL-2003-N */
%token CONTEXT_SYM
%token CONTINUE_SYM /* SQL-2003-R */
@@ -788,6 +899,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CURDATE /* MYSQL-FUNC */
%token CURRENT_USER /* SQL-2003-R */
%token CURSOR_SYM /* SQL-2003-R */
+%token CURSOR_NAME_SYM /* SQL-2003-N */
%token CURTIME /* MYSQL-FUNC */
%token DATABASE
%token DATABASES
@@ -841,6 +953,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token ENUM
%token EQ /* OPERATOR */
%token EQUAL_SYM /* OPERATOR */
+%token ERROR_SYM
%token ERRORS
%token ESCAPED
%token ESCAPE_SYM /* SQL-2003-R */
@@ -868,12 +981,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token FOREIGN /* SQL-2003-R */
%token FOR_SYM /* SQL-2003-R */
%token FOUND_SYM /* SQL-2003-R */
-%token FRAC_SECOND_SYM
%token FROM
%token FULL /* SQL-2003-R */
%token FULLTEXT_SYM
%token FUNCTION_SYM /* SQL-2003-R */
%token GE
+%token GENERAL
%token GEOMETRYCOLLECTION
%token GEOMETRY_SYM
%token GET_FORMAT /* MYSQL-FUNC */
@@ -900,13 +1013,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token IDENT_QUOTED
%token IF
%token IGNORE_SYM
+%token IGNORE_SERVER_IDS_SYM
%token IMPORT
%token INDEXES
%token INDEX_SYM
%token INFILE
%token INITIAL_SIZE_SYM
%token INNER_SYM /* SQL-2003-R */
-%token INNOBASE_SYM
%token INOUT_SYM /* SQL-2003-R */
%token INSENSITIVE_SYM /* SQL-2003-R */
%token INSERT /* SQL-2003-R */
@@ -974,6 +1087,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token MASTER_SSL_VERIFY_SERVER_CERT_SYM
%token MASTER_SYM
%token MASTER_USER_SYM
+%token MASTER_HEARTBEAT_PERIOD_SYM
%token MATCH /* SQL-2003-R */
%token MAX_CONNECTIONS_PER_HOUR
%token MAX_QUERIES_PER_HOUR
@@ -989,6 +1103,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token MEDIUM_SYM
%token MEMORY_SYM
%token MERGE_SYM /* SQL-2003-R */
+%token MESSAGE_TEXT_SYM /* SQL-2003-N */
%token MICROSECOND_SYM /* MYSQL-FUNC */
%token MIGRATE_SYM
%token MINUTE_MICROSECOND_SYM
@@ -1005,6 +1120,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token MULTIPOINT
%token MULTIPOLYGON
%token MUTEX_SYM
+%token MYSQL_ERRNO_SYM
%token NAMES_SYM /* SQL-2003-N */
%token NAME_SYM /* SQL-2003-N */
%token NATIONAL_SYM /* SQL-2003-R */
@@ -1068,11 +1184,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PREV_SYM
%token PRIMARY_SYM /* SQL-2003-R */
%token PRIVILEGES /* SQL-2003-N */
-%token PROCEDURE /* SQL-2003-R */
+%token PROCEDURE_SYM /* SQL-2003-R */
%token PROCESS
%token PROCESSLIST_SYM
%token PROFILE_SYM
%token PROFILES_SYM
+%token PROXY_SYM
%token PURGE
%token QUARTER_SYM
%token QUERY_SYM
@@ -1090,6 +1207,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token REDUNDANT_SYM
%token REFERENCES /* SQL-2003-R */
%token REGEXP
+%token RELAY
+%token RELAYLOG_SYM
%token RELAY_LOG_FILE_SYM
%token RELAY_LOG_POS_SYM
%token RELAY_THREAD
@@ -1105,6 +1224,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token REPLICATION
%token REQUIRE_SYM
%token RESET_SYM
+%token RESIGNAL_SYM /* SQL-2003-R */
%token RESOURCES
%token RESTORE_SYM
%token RESTRICT
@@ -1122,6 +1242,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token RTREE_SYM
%token SAVEPOINT_SYM /* SQL-2003-R */
%token SCHEDULE_SYM
+%token SCHEMA_NAME_SYM /* SQL-2003-N */
%token SECOND_MICROSECOND_SYM
%token SECOND_SYM /* SQL-2003-R */
%token SECURITY_SYM /* SQL-2003-N */
@@ -1140,9 +1261,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SHIFT_RIGHT /* OPERATOR */
%token SHOW
%token SHUTDOWN
+%token SIGNAL_SYM /* SQL-2003-R */
%token SIGNED_SYM
%token SIMPLE_SYM /* SQL-2003-N */
%token SLAVE
+%token SLOW
%token SMALLINT /* SQL-2003-R */
%token SNAPSHOT_SYM
%token SOCKET_SYM
@@ -1173,6 +1296,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token STORAGE_SYM
%token STRAIGHT_JOIN
%token STRING_SYM
+%token SUBCLASS_ORIGIN_SYM /* SQL-2003-N */
%token SUBDATE_SYM
%token SUBJECT_SYM
%token SUBPARTITIONS_SYM
@@ -1189,6 +1313,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token TABLE_REF_PRIORITY
%token TABLE_SYM /* SQL-2003-R */
%token TABLE_CHECKSUM_SYM
+%token TABLE_NAME_SYM /* SQL-2003-N */
%token TEMPORARY /* SQL-2003-N */
%token TEMPTABLE_SYM
%token TERMINATED
@@ -1255,11 +1380,14 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token WHERE /* SQL-2003-R */
%token WHILE_SYM
%token WITH /* SQL-2003-R */
+%token WITH_CUBE_SYM /* INTERNAL */
+%token WITH_ROLLUP_SYM /* INTERNAL */
%token WORK_SYM /* SQL-2003-N */
%token WRAPPER_SYM
%token WRITE_SYM /* SQL-2003-N */
%token X509_SYM
%token XA_SYM
+%token XML_SYM
%token XOR
%token YEAR_MONTH_SYM
%token YEAR_SYM /* SQL-2003-R */
@@ -1291,6 +1419,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
NCHAR_STRING opt_component key_cache_name
sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
+ opt_constraint constraint opt_ident
%type <lex_str_ptr>
opt_table_alias
@@ -1300,39 +1429,41 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
table_ident_opt_wild
%type <simple_string>
- remember_name remember_end opt_ident opt_db text_or_password
- opt_constraint constraint
+ remember_name remember_end opt_db text_or_password
%type <string>
text_string opt_gconcat_separator
%type <num>
- type int_type real_type order_dir lock_option
+ type type_with_opt_collate int_type real_type order_dir lock_option
udf_type if_exists opt_local opt_table_options table_options
table_option opt_if_not_exists opt_no_write_to_binlog
- delete_option opt_temporary all_or_any opt_distinct
+ opt_temporary all_or_any opt_distinct
opt_ignore_leaves fulltext_options spatial_type union_option
- start_transaction_opts opt_chain opt_release
+ start_transaction_opts
union_opt select_derived_init option_type2
opt_natural_language_mode opt_query_expansion
opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
+%type <m_yes_no_unk>
+ opt_chain opt_release
+
+%type <m_fk_option>
+ delete_option
+
%type <ulong_num>
ulong_num real_ulong_num merge_insert_types
%type <ulonglong_number>
ulonglong_num real_ulonglong_num size_number
-%type <p_elem_value>
- part_bit_expr
-
%type <lock_type>
replace_lock_option opt_low_priority insert_lock_option load_data_lock
%type <item>
literal text_literal insert_ident order_ident
- simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
+ simple_ident expr opt_expr opt_else sum_expr in_sum_expr
variable variable_aux bool_pri
predicate bit_expr
table_wild simple_expr udf_expr
@@ -1347,6 +1478,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
function_call_nonkeyword
function_call_generic
function_call_conflict
+ signal_allowed_expr
%type <item_num>
NUM_literal
@@ -1374,12 +1506,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
join_table_list join_table
table_factor table_ref esc_table_ref
select_derived derived_table_list
+ select_derived_union
%type <date_time_type> date_time_type;
%type <interval> interval
-%type <interval_time_st> interval_time_st
-
%type <interval_time_st> interval_time_stamp
%type <db_type> storage_engines known_storage_engines
@@ -1409,8 +1540,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <variable> internal_variable_name
-%type <select_lex> subselect take_first_select
- get_select_lex
+%type <select_lex> subselect
+ get_select_lex query_specification
+ query_expression_body
%type <boolfunc2creator> comp_op
@@ -1420,17 +1552,19 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
show describe load alter optimize keycache preload flush
reset purge begin commit rollback savepoint release
slave master_def master_defs master_file_def slave_until_opts
- repair restore backup analyze check start checksum
+ repair analyze check start checksum
field_list field_list_item field_spec kill column_def key_def
- keycache_list assign_to_keycache preload_list preload_keys
+ keycache_list keycache_list_or_parts assign_to_keycache
+ assign_to_keycache_parts
+ preload_list preload_list_or_parts preload_keys preload_keys_parts
select_item_list select_item values_list no_braces
opt_limit_clause delete_limit_clause fields opt_values values
procedure_list procedure_list2 procedure_item
handler
opt_precision opt_ignore opt_column opt_restrict
grant revoke set lock unlock string_list field_options field_option
- field_opt_list opt_binary table_lock_list table_lock
- ref_list opt_on_delete opt_on_delete_list opt_on_delete_item use
+ field_opt_list opt_binary ascii unicode table_lock_list table_lock
+ ref_list opt_match_clause opt_on_update_delete use
opt_delete_options opt_delete_option varchar nchar nvarchar
opt_outer table_list table_name table_alias_ref_list table_alias_ref
opt_option opt_place
@@ -1438,6 +1572,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_column_list grant_privileges grant_ident grant_list grant_option
object_privilege object_privilege_list user_list rename_list
clear_privileges flush_options flush_option
+ opt_with_read_lock flush_options_list
equal optional_braces
opt_mi_check_type opt_to mi_check_types normal_join
table_to_table_list table_to_table opt_table_list opt_as
@@ -1451,7 +1586,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
prepare prepare_src execute deallocate
statement sp_suid
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
- load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
+ opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
view_replace_or_algorithm view_replace
view_algorithm view_or_trigger_or_sp_or_event
definer_tail no_definer_tail
@@ -1462,6 +1597,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
spatial_key_options fulltext_key_options normal_key_opt
fulltext_key_opt spatial_key_opt fulltext_key_opts spatial_key_opts
key_using_alg
+ part_column_list
server_def server_options_list server_option
definer_opt no_definer definer
END_OF_INPUT
@@ -1477,17 +1613,21 @@ END_OF_INPUT
%type <NONE> case_stmt_specification simple_case_stmt searched_case_stmt
%type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list
-%type <spcondtype> sp_cond sp_hcond
+%type <spcondtype> sp_cond sp_hcond sqlstate signal_value opt_signal_value
%type <spblock> sp_decls sp_decl
%type <lex> sp_cursor_stmt
%type <spname> sp_name
%type <index_hint> index_hint_type
%type <num> index_hint_clause
+%type <filetype> data_or_xml
+
+%type <NONE> signal_stmt resignal_stmt
+%type <diag_condition_item_name> signal_condition_information_item_name
%type <NONE>
'-' '+' '*' '/' '%' '(' ')'
',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_SYM BETWEEN_SYM CASE_SYM
- THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM
+ THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM DELETE_SYM
%%
/*
@@ -1529,7 +1669,7 @@ query:
Lex_input_stream *lip = YYLIP;
if ((YYTHD->client_capabilities & CLIENT_MULTI_QUERIES) &&
- ! lip->stmt_prepare_mode &&
+ lip->multi_statements &&
! lip->eof())
{
/*
@@ -1570,7 +1710,6 @@ verb_clause:
statement:
alter
| analyze
- | backup
| binlog_base64_event
| call
| change
@@ -1604,12 +1743,13 @@ statement:
| repair
| replace
| reset
- | restore
+ | resignal_stmt
| revoke
| rollback
| savepoint
| select
| set
+ | signal_stmt
| show
| slave
| start
@@ -1722,6 +1862,12 @@ change:
LEX *lex = Lex;
lex->sql_command = SQLCOM_CHANGE_MASTER;
bzero((char*) &lex->mi, sizeof(lex->mi));
+ /*
+ resetting flags that can left from the previous CHANGE MASTER
+ */
+ lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_UNCHANGED;
+ my_init_dynamic_array(&Lex->mi.repl_ignore_server_ids,
+ sizeof(::server_id), 16, 16);
}
master_defs
{}
@@ -1756,7 +1902,7 @@ master_def:
| MASTER_SSL_SYM EQ ulong_num
{
Lex->mi.ssl= $3 ?
- LEX_MASTER_INFO::SSL_ENABLE : LEX_MASTER_INFO::SSL_DISABLE;
+ LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE;
}
| MASTER_SSL_CA_SYM EQ TEXT_STRING_sys
{
@@ -1781,11 +1927,60 @@ master_def:
| MASTER_SSL_VERIFY_SERVER_CERT_SYM EQ ulong_num
{
Lex->mi.ssl_verify_server_cert= $3 ?
- LEX_MASTER_INFO::SSL_ENABLE : LEX_MASTER_INFO::SSL_DISABLE;
+ LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE;
}
- | master_file_def
+
+ | MASTER_HEARTBEAT_PERIOD_SYM EQ NUM_literal
+ {
+ Lex->mi.heartbeat_period= (float) $3->val_real();
+ if (Lex->mi.heartbeat_period > SLAVE_MAX_HEARTBEAT_PERIOD ||
+ Lex->mi.heartbeat_period < 0.0)
+ {
+ const char format[]= "%d";
+ char buf[4*sizeof(SLAVE_MAX_HEARTBEAT_PERIOD) + sizeof(format)];
+ sprintf(buf, format, SLAVE_MAX_HEARTBEAT_PERIOD);
+ my_error(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, MYF(0), buf);
+ MYSQL_YYABORT;
+ }
+ if (Lex->mi.heartbeat_period > slave_net_timeout)
+ {
+ push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX,
+ ER(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX));
+ }
+ if (Lex->mi.heartbeat_period < 0.001)
+ {
+ if (Lex->mi.heartbeat_period != 0.0)
+ {
+ push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN,
+ ER(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN));
+ Lex->mi.heartbeat_period= 0.0;
+ }
+ Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_DISABLE;
+ }
+ Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_ENABLE;
+ }
+ | IGNORE_SERVER_IDS_SYM EQ '(' ignore_server_id_list ')'
+ {
+ Lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE;
+ }
+ |
+ master_file_def
+ ;
+
+ignore_server_id_list:
+ /* Empty */
+ | ignore_server_id
+ | ignore_server_id_list ',' ignore_server_id
;
+ignore_server_id:
+ ulong_num
+ {
+ insert_dynamic(&Lex->mi.repl_ignore_server_ids, (uchar*) &($1));
+ }
+
master_file_def:
MASTER_LOG_FILE_SYM EQ TEXT_STRING_sys
{
@@ -1829,8 +2024,14 @@ create:
lex->sql_command= SQLCOM_CREATE_TABLE;
if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
TL_OPTION_UPDATING,
- TL_WRITE))
+ TL_WRITE, MDL_EXCLUSIVE))
MYSQL_YYABORT;
+ /*
+ For CREATE TABLE, an non-existing table is not an error.
+ Instruct open_tables() to just take an MDL lock if the
+ table does not exist.
+ */
+ lex->query_tables->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
lex->alter_info.reset();
lex->col_list.empty();
lex->change=NullS;
@@ -1840,6 +2041,7 @@ create:
lex->create_info.default_table_charset= NULL;
lex->name.str= 0;
lex->name.length= 0;
+ lex->create_last_non_select_table= lex->last_table();
}
create2
{
@@ -1854,6 +2056,7 @@ create:
ha_resolve_storage_engine_name(lex->create_info.db_type),
$5->table.str);
}
+ create_table_set_open_action_and_adjust_tables(lex);
}
| CREATE opt_unique INDEX_SYM ident key_alg ON table_ident
{
@@ -1862,7 +2065,7 @@ create:
}
'(' key_list ')' normal_key_options
{
- if (add_create_index(Lex, $2, $4.str))
+ if (add_create_index(Lex, $2, $4))
MYSQL_YYABORT;
}
| CREATE fulltext INDEX_SYM ident init_key_options ON
@@ -1873,7 +2076,7 @@ create:
}
'(' key_list ')' fulltext_key_options
{
- if (add_create_index(Lex, $2, $4.str))
+ if (add_create_index(Lex, $2, $4))
MYSQL_YYABORT;
}
| CREATE spatial INDEX_SYM ident init_key_options ON
@@ -1884,7 +2087,7 @@ create:
}
'(' key_list ')' spatial_key_options
{
- if (add_create_index(Lex, $2, $4.str))
+ if (add_create_index(Lex, $2, $4))
MYSQL_YYABORT;
}
| CREATE DATABASE opt_if_not_exists ident
@@ -2326,7 +2529,7 @@ sp_init_param:
;
sp_fdparam:
- ident sp_init_param type
+ ident sp_init_param type_with_opt_collate
{
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
@@ -2363,7 +2566,7 @@ sp_pdparams:
;
sp_pdparam:
- sp_opt_inout sp_init_param ident type
+ sp_opt_inout sp_init_param ident type_with_opt_collate
{
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
@@ -2443,7 +2646,7 @@ sp_decl:
lex->sphead->reset_lex(YYTHD);
lex->spcont->declare_var_boundary($2);
}
- type
+ type_with_opt_collate
sp_opt_default
{
THD *thd= YYTHD;
@@ -2506,12 +2709,12 @@ sp_decl:
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
- if (spc->find_cond(&$2, TRUE))
- {
- my_error(ER_SP_DUP_COND, MYF(0), $2.str);
- MYSQL_YYABORT;
- }
- if(YYTHD->lex->spcont->push_cond(&$2, $5))
+ if (spc->find_cond(&$2, TRUE))
+ {
+ my_error(ER_SP_DUP_COND, MYF(0), $2.str);
+ MYSQL_YYABORT;
+ }
+ if(YYTHD->lex->spcont->push_cond(&$2, $5))
MYSQL_YYABORT;
$$.vars= $$.hndlrs= $$.curs= 0;
$$.conds= 1;
@@ -2526,9 +2729,9 @@ sp_decl:
sp_pcontext *ctx= lex->spcont;
sp_instr_hpush_jump *i=
new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
- ctx->current_var_count());
+ ctx->current_var_count());
if (i == NULL ||
- sp->add_instr(i) ||
+ sp->add_instr(i) ||
sp->push_backpatch(i, ctx->push_label((char *)"", 0)))
MYSQL_YYABORT;
}
@@ -2545,15 +2748,15 @@ sp_decl:
i= new sp_instr_hreturn(sp->instructions(), ctx,
ctx->current_var_count());
if (i == NULL ||
- sp->add_instr(i))
+ sp->add_instr(i))
MYSQL_YYABORT;
}
else
{ /* EXIT or UNDO handler, just jump to the end of the block */
i= new sp_instr_hreturn(sp->instructions(), ctx, 0);
if (i == NULL ||
- sp->add_instr(i) ||
- sp->push_backpatch(i, lex->spcont->last_label())) /* Block end */
+ sp->add_instr(i) ||
+ sp->push_backpatch(i, lex->spcont->last_label())) /* Block end */
MYSQL_YYABORT;
}
lex->sphead->backpatch(hlab);
@@ -2580,9 +2783,9 @@ sp_decl:
}
i= new sp_instr_cpush(sp->instructions(), ctx, $5,
ctx->current_cursor_count());
- if (i == NULL ||
+ if (i == NULL ||
sp->add_instr(i) ||
- ctx->push_cursor(&$2))
+ ctx->push_cursor(&$2))
MYSQL_YYABORT;
$$.vars= $$.conds= $$.hndlrs= 0;
$$.curs= 1;
@@ -2651,13 +2854,22 @@ sp_hcond_element:
sp_cond:
ulong_num
{ /* mysql errno */
+ if ($1 == 0)
+ {
+ my_error(ER_WRONG_VALUE, MYF(0), "CONDITION", "0");
+ MYSQL_YYABORT;
+ }
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
if ($$ == NULL)
MYSQL_YYABORT;
$$->type= sp_cond_type_t::number;
$$->mysqlerr= $1;
}
- | SQLSTATE_SYM opt_value TEXT_STRING_literal
+ | sqlstate
+ ;
+
+sqlstate:
+ SQLSTATE_SYM opt_value TEXT_STRING_literal
{ /* SQLSTATE */
if (!sp_cond_check(&$3))
{
@@ -2668,8 +2880,8 @@ sp_cond:
if ($$ == NULL)
MYSQL_YYABORT;
$$->type= sp_cond_type_t::state;
- memcpy($$->sqlstate, $3.str, 5);
- $$->sqlstate[5]= '\0';
+ memcpy($$->sqlstate, $3.str, SQLSTATE_LENGTH);
+ $$->sqlstate[SQLSTATE_LENGTH]= '\0';
}
;
@@ -2715,6 +2927,160 @@ sp_hcond:
}
;
+signal_stmt:
+ SIGNAL_SYM signal_value opt_set_signal_information
+ {
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Yacc_state *state= & thd->m_parser_state->m_yacc;
+
+ lex->sql_command= SQLCOM_SIGNAL;
+ lex->m_stmt= new (thd->mem_root) Signal_statement(lex, $2,
+ state->m_set_signal_info);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
+ }
+ ;
+
+signal_value:
+ ident
+ {
+ LEX *lex= Lex;
+ sp_cond_type_t *cond;
+ if (lex->spcont == NULL)
+ {
+ /* SIGNAL foo cannot be used outside of stored programs */
+ my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
+ MYSQL_YYABORT;
+ }
+ cond= lex->spcont->find_cond(&$1);
+ if (cond == NULL)
+ {
+ my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
+ MYSQL_YYABORT;
+ }
+ if (cond->type != sp_cond_type_t::state)
+ {
+ my_error(ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0));
+ MYSQL_YYABORT;
+ }
+ $$= cond;
+ }
+ | sqlstate
+ { $$= $1; }
+ ;
+
+opt_signal_value:
+ /* empty */
+ { $$= NULL; }
+ | signal_value
+ { $$= $1; }
+ ;
+
+opt_set_signal_information:
+ /* empty */
+ {
+ YYTHD->m_parser_state->m_yacc.m_set_signal_info.clear();
+ }
+ | SET signal_information_item_list
+ ;
+
+signal_information_item_list:
+ signal_condition_information_item_name EQ signal_allowed_expr
+ {
+ Set_signal_information *info;
+ info= & YYTHD->m_parser_state->m_yacc.m_set_signal_info;
+ int index= (int) $1;
+ info->clear();
+ info->m_item[index]= $3;
+ }
+ | signal_information_item_list ','
+ signal_condition_information_item_name EQ signal_allowed_expr
+ {
+ Set_signal_information *info;
+ info= & YYTHD->m_parser_state->m_yacc.m_set_signal_info;
+ int index= (int) $3;
+ if (info->m_item[index] != NULL)
+ {
+ my_error(ER_DUP_SIGNAL_SET, MYF(0),
+ Diag_condition_item_names[index].str);
+ MYSQL_YYABORT;
+ }
+ info->m_item[index]= $5;
+ }
+ ;
+
+/*
+ Only a limited subset of <expr> are allowed in SIGNAL/RESIGNAL.
+*/
+signal_allowed_expr:
+ literal
+ { $$= $1; }
+ | variable
+ {
+ if ($1->type() == Item::FUNC_ITEM)
+ {
+ Item_func *item= (Item_func*) $1;
+ if (item->functype() == Item_func::SUSERVAR_FUNC)
+ {
+ /*
+ Don't allow the following syntax:
+ SIGNAL/RESIGNAL ...
+ SET <signal condition item name> = @foo := expr
+ */
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
+ }
+ }
+ $$= $1;
+ }
+ | simple_ident
+ { $$= $1; }
+ ;
+
+/* conditions that can be set in signal / resignal */
+signal_condition_information_item_name:
+ CLASS_ORIGIN_SYM
+ { $$= DIAG_CLASS_ORIGIN; }
+ | SUBCLASS_ORIGIN_SYM
+ { $$= DIAG_SUBCLASS_ORIGIN; }
+ | CONSTRAINT_CATALOG_SYM
+ { $$= DIAG_CONSTRAINT_CATALOG; }
+ | CONSTRAINT_SCHEMA_SYM
+ { $$= DIAG_CONSTRAINT_SCHEMA; }
+ | CONSTRAINT_NAME_SYM
+ { $$= DIAG_CONSTRAINT_NAME; }
+ | CATALOG_NAME_SYM
+ { $$= DIAG_CATALOG_NAME; }
+ | SCHEMA_NAME_SYM
+ { $$= DIAG_SCHEMA_NAME; }
+ | TABLE_NAME_SYM
+ { $$= DIAG_TABLE_NAME; }
+ | COLUMN_NAME_SYM
+ { $$= DIAG_COLUMN_NAME; }
+ | CURSOR_NAME_SYM
+ { $$= DIAG_CURSOR_NAME; }
+ | MESSAGE_TEXT_SYM
+ { $$= DIAG_MESSAGE_TEXT; }
+ | MYSQL_ERRNO_SYM
+ { $$= DIAG_MYSQL_ERRNO; }
+ ;
+
+resignal_stmt:
+ RESIGNAL_SYM opt_signal_value opt_set_signal_information
+ {
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Yacc_state *state= & thd->m_parser_state->m_yacc;
+
+ lex->sql_command= SQLCOM_RESIGNAL;
+ lex->m_stmt= new (thd->mem_root) Resignal_statement(lex, $2,
+ state->m_set_signal_info);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
+ }
+ ;
+
sp_decl_idents:
ident
{
@@ -2852,7 +3218,7 @@ sp_proc_stmt_return:
i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3,
sp->m_return_field_def.sql_type, lex);
if (i == NULL ||
- sp->add_instr(i))
+ sp->add_instr(i))
MYSQL_YYABORT;
sp->m_flags|= sp_head::HAS_RETURN;
}
@@ -3093,7 +3459,7 @@ sp_if:
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx,
$2, lex);
if (i == NULL ||
- sp->push_backpatch(i, ctx->push_label((char *)"", 0)) ||
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0)) ||
sp->add_cont_backpatch(i) ||
sp->add_instr(i))
MYSQL_YYABORT;
@@ -3382,7 +3748,7 @@ sp_unlabeled_control:
if (i == NULL ||
lex->sphead->add_instr(i))
MYSQL_YYABORT;
- }
+ }
| WHILE_SYM
{ Lex->sphead->reset_lex(YYTHD); }
expr DO_SYM
@@ -3393,7 +3759,7 @@ sp_unlabeled_control:
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
$3, lex);
if (i == NULL ||
- /* Jumping forward */
+ /* Jumping forward */
sp->push_backpatch(i, lex->spcont->last_label()) ||
sp->new_cont_backpatch(i) ||
sp->add_instr(i))
@@ -3844,7 +4210,7 @@ size_number:
create2:
'(' create2a {}
| opt_create_table_options
- opt_partitioning
+ opt_create_partitioning
create3 {}
| LIKE table_ident
{
@@ -3854,7 +4220,8 @@ create2:
lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
src_table= lex->select_lex.add_table_to_list(thd, $2, NULL, 0,
- TL_READ);
+ TL_READ,
+ MDL_SHARED_READ);
if (! src_table)
MYSQL_YYABORT;
/* CREATE TABLE ... LIKE is not allowed for views. */
@@ -3868,7 +4235,8 @@ create2:
lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
src_table= lex->select_lex.add_table_to_list(thd, $3, NULL, 0,
- TL_READ);
+ TL_READ,
+ MDL_SHARED_READ);
if (! src_table)
MYSQL_YYABORT;
/* CREATE TABLE ... LIKE is not allowed for views. */
@@ -3877,32 +4245,36 @@ create2:
;
create2a:
- field_list ')' opt_create_table_options
- opt_partitioning
+ create_field_list ')' opt_create_table_options
+ opt_create_partitioning
create3 {}
- | opt_partitioning
+ | opt_create_partitioning
create_select ')'
- {
- Select->set_braces(1);
- Lex->create_select_start_with_brace= TRUE;
- }
+ { Select->set_braces(1);}
union_opt {}
;
create3:
/* empty */ {}
| opt_duplicate opt_as create_select
- {
- Select->set_braces(0);
- Lex->create_select_start_with_brace= FALSE;
- }
+ { Select->set_braces(0);}
union_clause {}
| opt_duplicate opt_as '(' create_select ')'
+ { Select->set_braces(1);}
+ union_opt {}
+ ;
+
+opt_create_partitioning:
+ opt_partitioning
{
- Select->set_braces(1);
- Lex->create_select_start_with_brace= TRUE;
+ /*
+ Remove all tables used in PARTITION clause from the global table
+ list. Partitioning with subqueries is not allowed anyway.
+ */
+ TABLE_LIST *last_non_sel_table= Lex->create_last_non_select_table;
+ last_non_sel_table->next_global= 0;
+ Lex->query_tables_last= &last_non_sel_table->next_global;
}
- union_opt {}
;
/*
@@ -3935,17 +4307,9 @@ opt_partitioning:
;
partitioning:
- PARTITION_SYM
+ PARTITION_SYM have_partitioning
{
-#ifdef WITH_PARTITION_STORAGE_ENGINE
LEX *lex= Lex;
- LEX_STRING partition_name={C_STRING_WITH_LEN("partition")};
- if (!plugin_is_ready(&partition_name, MYSQL_STORAGE_ENGINE_PLUGIN))
- {
- my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
- "--skip-partition");
- MYSQL_YYABORT;
- }
lex->part_info= new partition_info();
if (!lex->part_info)
{
@@ -3956,14 +4320,27 @@ partitioning:
{
lex->alter_info.flags|= ALTER_PARTITION;
}
+ }
+ partition
+ ;
+
+have_partitioning:
+ /* empty */
+ {
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ LEX_STRING partition_name={C_STRING_WITH_LEN("partition")};
+ if (!plugin_is_ready(&partition_name, MYSQL_STORAGE_ENGINE_PLUGIN))
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
+ "--skip-partition");
+ MYSQL_YYABORT;
+ }
#else
- my_error(ER_FEATURE_DISABLED, MYF(0),
- "partitioning", "--with-partition");
+ my_error(ER_FEATURE_DISABLED, MYF(0), "partitioning",
+ "--with-plugin-partition");
MYSQL_YYABORT;
#endif
-
}
- partition
;
partition_entry:
@@ -3984,25 +4361,28 @@ partition_entry:
;
partition:
- BY part_type_def opt_no_parts opt_sub_part part_defs
+ BY part_type_def opt_num_parts opt_sub_part part_defs
;
part_type_def:
opt_linear KEY_SYM '(' part_field_list ')'
{
- LEX *lex= Lex;
- lex->part_info->list_of_part_fields= TRUE;
- lex->part_info->part_type= HASH_PARTITION;
+ partition_info *part_info= Lex->part_info;
+ part_info->list_of_part_fields= TRUE;
+ part_info->column_list= FALSE;
+ part_info->part_type= HASH_PARTITION;
}
| opt_linear HASH_SYM
{ Lex->part_info->part_type= HASH_PARTITION; }
part_func {}
- | RANGE_SYM
+ | RANGE_SYM part_func
{ Lex->part_info->part_type= RANGE_PARTITION; }
- part_func {}
- | LIST_SYM
+ | RANGE_SYM part_column_list
+ { Lex->part_info->part_type= RANGE_PARTITION; }
+ | LIST_SYM part_func
+ { Lex->part_info->part_type= LIST_PARTITION; }
+ | LIST_SYM part_column_list
{ Lex->part_info->part_type= LIST_PARTITION; }
- part_func {}
;
opt_linear:
@@ -4024,59 +4404,66 @@ part_field_item_list:
part_field_item:
ident
{
- if (Lex->part_info->part_field_list.push_back($1.str))
+ partition_info *part_info= Lex->part_info;
+ part_info->num_columns++;
+ if (part_info->part_field_list.push_back($1.str))
{
mem_alloc_error(1);
MYSQL_YYABORT;
}
+ if (part_info->num_columns > MAX_REF_PARTS)
+ {
+ my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0),
+ "list of partition fields");
+ MYSQL_YYABORT;
+ }
+ }
+ ;
+
+part_column_list:
+ COLUMNS '(' part_field_list ')'
+ {
+ partition_info *part_info= Lex->part_info;
+ part_info->column_list= TRUE;
+ part_info->list_of_part_fields= TRUE;
}
;
+
part_func:
'(' remember_name part_func_expr remember_end ')'
{
- LEX *lex= Lex;
- uint expr_len= (uint)($4 - $2) - 1;
- lex->part_info->list_of_part_fields= FALSE;
- lex->part_info->part_expr= $3;
- char *func_string= (char*) sql_memdup($2+1, expr_len);
- if (func_string == NULL)
- MYSQL_YYABORT;
- lex->part_info->part_func_string= func_string;
- lex->part_info->part_func_len= expr_len;
+ partition_info *part_info= Lex->part_info;
+ if (part_info->set_part_expr($2+1, $3, $4, FALSE))
+ { MYSQL_YYABORT; }
+ part_info->num_columns= 1;
+ part_info->column_list= FALSE;
}
;
sub_part_func:
'(' remember_name part_func_expr remember_end ')'
{
- LEX *lex= Lex;
- uint expr_len= (uint)($4 - $2) - 1;
- lex->part_info->list_of_subpart_fields= FALSE;
- lex->part_info->subpart_expr= $3;
- char *func_string= (char*) sql_memdup($2+1, expr_len);
- if (func_string == NULL)
- MYSQL_YYABORT;
- lex->part_info->subpart_func_string= func_string;
- lex->part_info->subpart_func_len= expr_len;
+ if (Lex->part_info->set_part_expr($2+1, $3, $4, TRUE))
+ { MYSQL_YYABORT; }
}
;
-opt_no_parts:
+opt_num_parts:
/* empty */ {}
| PARTITIONS_SYM real_ulong_num
{
- uint no_parts= $2;
- LEX *lex= Lex;
- if (no_parts == 0)
+ uint num_parts= $2;
+ partition_info *part_info= Lex->part_info;
+ if (num_parts == 0)
{
my_error(ER_NO_PARTS_ERROR, MYF(0), "partitions");
MYSQL_YYABORT;
}
- lex->part_info->no_parts= no_parts;
- lex->part_info->use_default_no_partitions= FALSE;
+ part_info->num_parts= num_parts;
+ part_info->use_default_num_partitions= FALSE;
}
;
@@ -4084,15 +4471,15 @@ opt_sub_part:
/* empty */ {}
| SUBPARTITION_SYM BY opt_linear HASH_SYM sub_part_func
{ Lex->part_info->subpart_type= HASH_PARTITION; }
- opt_no_subparts {}
+ opt_num_subparts {}
| SUBPARTITION_SYM BY opt_linear KEY_SYM
'(' sub_part_field_list ')'
{
- LEX *lex= Lex;
- lex->part_info->subpart_type= HASH_PARTITION;
- lex->part_info->list_of_subpart_fields= TRUE;
+ partition_info *part_info= Lex->part_info;
+ part_info->subpart_type= HASH_PARTITION;
+ part_info->list_of_subpart_fields= TRUE;
}
- opt_no_subparts {}
+ opt_num_subparts {}
;
sub_part_field_list:
@@ -4103,11 +4490,18 @@ sub_part_field_list:
sub_part_field_item:
ident
{
- if (Lex->part_info->subpart_field_list.push_back($1.str))
+ partition_info *part_info= Lex->part_info;
+ if (part_info->subpart_field_list.push_back($1.str))
{
mem_alloc_error(1);
MYSQL_YYABORT;
}
+ if (part_info->subpart_field_list.elements > MAX_REF_PARTS)
+ {
+ my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0),
+ "list of subpartition fields");
+ MYSQL_YYABORT;
+ }
}
;
@@ -4127,33 +4521,46 @@ part_func_expr:
}
;
-opt_no_subparts:
+opt_num_subparts:
/* empty */ {}
| SUBPARTITIONS_SYM real_ulong_num
{
- uint no_parts= $2;
+ uint num_parts= $2;
LEX *lex= Lex;
- if (no_parts == 0)
+ if (num_parts == 0)
{
my_error(ER_NO_PARTS_ERROR, MYF(0), "subpartitions");
MYSQL_YYABORT;
}
- lex->part_info->no_subparts= no_parts;
- lex->part_info->use_default_no_subpartitions= FALSE;
+ lex->part_info->num_subparts= num_parts;
+ lex->part_info->use_default_num_subpartitions= FALSE;
}
;
part_defs:
/* empty */
- {}
+ {
+ partition_info *part_info= Lex->part_info;
+ if (part_info->part_type == RANGE_PARTITION)
+ {
+ my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0),
+ "RANGE");
+ MYSQL_YYABORT;
+ }
+ else if (part_info->part_type == LIST_PARTITION)
+ {
+ my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0),
+ "LIST");
+ MYSQL_YYABORT;
+ }
+ }
| '(' part_def_list ')'
{
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
+ partition_info *part_info= Lex->part_info;
uint count_curr_parts= part_info->partitions.elements;
- if (part_info->no_parts != 0)
+ if (part_info->num_parts != 0)
{
- if (part_info->no_parts !=
+ if (part_info->num_parts !=
count_curr_parts)
{
my_parse_error(ER(ER_PARTITION_WRONG_NO_PART_ERROR));
@@ -4162,7 +4569,7 @@ part_defs:
}
else if (count_curr_parts > 0)
{
- part_info->no_parts= count_curr_parts;
+ part_info->num_parts= count_curr_parts;
}
part_info->count_curr_subparts= 0;
}
@@ -4176,8 +4583,7 @@ part_def_list:
part_definition:
PARTITION_SYM
{
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
+ partition_info *part_info= Lex->part_info;
partition_element *p_elem= new partition_element();
if (!p_elem || part_info->partitions.push_back(p_elem))
@@ -4189,7 +4595,7 @@ part_definition:
part_info->curr_part_elem= p_elem;
part_info->current_partition= p_elem;
part_info->use_default_partitions= FALSE;
- part_info->use_default_no_partitions= FALSE;
+ part_info->use_default_num_partitions= FALSE;
}
part_name
opt_part_values
@@ -4201,8 +4607,7 @@ part_definition:
part_name:
ident
{
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
+ partition_info *part_info= Lex->part_info;
partition_element *p_elem= part_info->curr_part_elem;
p_elem->partition_name= $1.str;
}
@@ -4212,15 +4617,16 @@ opt_part_values:
/* empty */
{
LEX *lex= Lex;
+ partition_info *part_info= lex->part_info;
if (! lex->is_partition_management())
{
- if (lex->part_info->part_type == RANGE_PARTITION)
+ if (part_info->part_type == RANGE_PARTITION)
{
my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
"RANGE", "LESS THAN");
MYSQL_YYABORT;
}
- if (lex->part_info->part_type == LIST_PARTITION)
+ if (part_info->part_type == LIST_PARTITION)
{
my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
"LIST", "IN");
@@ -4228,14 +4634,15 @@ opt_part_values:
}
}
else
- lex->part_info->part_type= HASH_PARTITION;
+ part_info->part_type= HASH_PARTITION;
}
- | VALUES LESS_SYM THAN_SYM part_func_max
+ | VALUES LESS_SYM THAN_SYM
{
LEX *lex= Lex;
+ partition_info *part_info= lex->part_info;
if (! lex->is_partition_management())
{
- if (Lex->part_info->part_type != RANGE_PARTITION)
+ if (part_info->part_type != RANGE_PARTITION)
{
my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
"RANGE", "LESS THAN");
@@ -4243,153 +4650,181 @@ opt_part_values:
}
}
else
- lex->part_info->part_type= RANGE_PARTITION;
+ part_info->part_type= RANGE_PARTITION;
}
- | VALUES IN_SYM '(' part_list_func ')'
+ part_func_max {}
+ | VALUES IN_SYM
{
LEX *lex= Lex;
+ partition_info *part_info= lex->part_info;
if (! lex->is_partition_management())
{
- if (Lex->part_info->part_type != LIST_PARTITION)
+ if (part_info->part_type != LIST_PARTITION)
{
my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
- "LIST", "IN");
+ "LIST", "IN");
MYSQL_YYABORT;
}
}
else
- lex->part_info->part_type= LIST_PARTITION;
+ part_info->part_type= LIST_PARTITION;
}
+ part_values_in {}
;
part_func_max:
- max_value_sym
+ MAX_VALUE_SYM
{
- LEX *lex= Lex;
- if (lex->part_info->defined_max_value)
+ partition_info *part_info= Lex->part_info;
+
+ if (part_info->num_columns &&
+ part_info->num_columns != 1U)
{
- my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR));
+ part_info->print_debug("Kilroy II", NULL);
+ my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR));
MYSQL_YYABORT;
}
- lex->part_info->defined_max_value= TRUE;
- lex->part_info->curr_part_elem->max_value= TRUE;
- lex->part_info->curr_part_elem->range_value= LONGLONG_MAX;
- }
- | part_range_func
- {
- if (Lex->part_info->defined_max_value)
+ else
+ part_info->num_columns= 1U;
+ if (part_info->init_column_part())
{
- my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR));
MYSQL_YYABORT;
}
- if (Lex->part_info->curr_part_elem->has_null_value)
+ if (part_info->add_max_value())
{
- my_parse_error(ER(ER_NULL_IN_VALUES_LESS_THAN));
MYSQL_YYABORT;
}
}
+ | part_value_item {}
;
-max_value_sym:
- MAX_VALUE_SYM
- | '(' MAX_VALUE_SYM ')'
- ;
-
-part_range_func:
- '(' part_bit_expr ')'
+part_values_in:
+ part_value_item
+ {
+ LEX *lex= Lex;
+ partition_info *part_info= lex->part_info;
+ part_info->print_debug("part_values_in: part_value_item", NULL);
+
+ if (part_info->num_columns != 1U)
+ {
+ if (!lex->is_partition_management() ||
+ part_info->num_columns == 0 ||
+ part_info->num_columns > MAX_REF_PARTS)
+ {
+ part_info->print_debug("Kilroy III", NULL);
+ my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR));
+ MYSQL_YYABORT;
+ }
+ /*
+ Reorganize the current large array into a list of small
+ arrays with one entry in each array. This can happen
+ in the first partition of an ALTER TABLE statement where
+ we ADD or REORGANIZE partitions. Also can only happen
+ for LIST partitions.
+ */
+ if (part_info->reorganize_into_single_field_col_val())
+ {
+ MYSQL_YYABORT;
+ }
+ }
+ }
+ | '(' part_value_list ')'
{
partition_info *part_info= Lex->part_info;
- if (!($2->unsigned_flag))
- part_info->curr_part_elem->signed_flag= TRUE;
- part_info->curr_part_elem->range_value= $2->value;
+ if (part_info->num_columns < 2U)
+ {
+ my_parse_error(ER(ER_ROW_SINGLE_PARTITION_FIELD_ERROR));
+ MYSQL_YYABORT;
+ }
}
;
-part_list_func:
- part_list_item {}
- | part_list_func ',' part_list_item {}
+part_value_list:
+ part_value_item {}
+ | part_value_list ',' part_value_item {}
;
-part_list_item:
- part_bit_expr
+part_value_item:
+ '('
{
- part_elem_value *value_ptr= $1;
partition_info *part_info= Lex->part_info;
- if (!value_ptr->unsigned_flag)
- part_info->curr_part_elem->signed_flag= TRUE;
- if (!value_ptr->null_value &&
- part_info->curr_part_elem->
- list_val_list.push_back(value_ptr))
+ part_info->print_debug("( part_value_item", NULL);
+ /* Initialisation code needed for each list of value expressions */
+ if (!(part_info->part_type == LIST_PARTITION &&
+ part_info->num_columns == 1U) &&
+ part_info->init_column_part())
{
- mem_alloc_error(sizeof(part_elem_value));
MYSQL_YYABORT;
}
}
- ;
-
-part_bit_expr:
- bit_expr
+ part_value_item_list {}
+ ')'
{
- Item *part_expr= $1;
- THD *thd= YYTHD;
- LEX *lex= thd->lex;
- Name_resolution_context *context= &lex->current_select->context;
- TABLE_LIST *save_list= context->table_list;
- const char *save_where= thd->where;
-
- context->table_list= 0;
- thd->where= "partition function";
-
- part_elem_value *value_ptr=
- (part_elem_value*)sql_alloc(sizeof(part_elem_value));
- if (!value_ptr)
+ partition_info *part_info= Lex->part_info;
+ part_info->print_debug(") part_value_item", NULL);
+ if (part_info->num_columns == 0)
+ part_info->num_columns= part_info->curr_list_object;
+ if (part_info->num_columns != part_info->curr_list_object)
{
- mem_alloc_error(sizeof(part_elem_value));
+ /*
+ All value items lists must be of equal length, in some cases
+ which is covered by the above if-statement we don't know yet
+ how many columns is in the partition so the assignment above
+ ensures that we only report errors when we know we have an
+ error.
+ */
+ part_info->print_debug("Kilroy I", NULL);
+ my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR));
MYSQL_YYABORT;
}
- if (part_expr->walk(&Item::check_partition_func_processor, 0,
- NULL))
+ part_info->curr_list_object= 0;
+ }
+ ;
+
+part_value_item_list:
+ part_value_expr_item {}
+ | part_value_item_list ',' part_value_expr_item {}
+ ;
+
+part_value_expr_item:
+ MAX_VALUE_SYM
+ {
+ partition_info *part_info= Lex->part_info;
+ if (part_info->part_type == LIST_PARTITION)
{
- my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+ my_parse_error(ER(ER_MAXVALUE_IN_VALUES_IN));
MYSQL_YYABORT;
}
- if (part_expr->fix_fields(YYTHD, (Item**)0) ||
- ((context->table_list= save_list), FALSE) ||
- (!part_expr->const_item()) ||
- (!lex->safe_to_cache_query))
+ if (part_info->add_max_value())
{
- my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0));
MYSQL_YYABORT;
}
- thd->where= save_where;
- value_ptr->value= part_expr->val_int();
- value_ptr->unsigned_flag= TRUE;
- if (!part_expr->unsigned_flag &&
- value_ptr->value < 0)
- value_ptr->unsigned_flag= FALSE;
- if ((value_ptr->null_value= part_expr->null_value))
+ }
+ | bit_expr
+ {
+ LEX *lex= Lex;
+ partition_info *part_info= lex->part_info;
+ Item *part_expr= $1;
+
+ if (!lex->safe_to_cache_query)
{
- if (Lex->part_info->curr_part_elem->has_null_value)
- {
- my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
- MYSQL_YYABORT;
- }
- Lex->part_info->curr_part_elem->has_null_value= TRUE;
+ my_parse_error(ER(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
+ MYSQL_YYABORT;
}
- else if (part_expr->result_type() != INT_RESULT)
+ if (part_info->add_column_list_value(YYTHD, part_expr))
{
- my_parse_error(ER(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR));
MYSQL_YYABORT;
}
- $$= value_ptr;
}
;
+
opt_sub_partition:
/* empty */
{
- if (Lex->part_info->no_subparts != 0 &&
- !Lex->part_info->use_default_subpartitions)
+ partition_info *part_info= Lex->part_info;
+ if (part_info->num_subparts != 0 &&
+ !part_info->use_default_subpartitions)
{
/*
We come here when we have defined subpartitions on the first
@@ -4401,11 +4836,10 @@ opt_sub_partition:
}
| '(' sub_part_list ')'
{
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
- if (part_info->no_subparts != 0)
+ partition_info *part_info= Lex->part_info;
+ if (part_info->num_subparts != 0)
{
- if (part_info->no_subparts !=
+ if (part_info->num_subparts !=
part_info->count_curr_subparts)
{
my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
@@ -4419,7 +4853,7 @@ opt_sub_partition:
my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
MYSQL_YYABORT;
}
- part_info->no_subparts= part_info->count_curr_subparts;
+ part_info->num_subparts= part_info->count_curr_subparts;
}
part_info->count_curr_subparts= 0;
}
@@ -4433,8 +4867,7 @@ sub_part_list:
sub_part_definition:
SUBPARTITION_SYM
{
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
+ partition_info *part_info= Lex->part_info;
partition_element *curr_part= part_info->current_partition;
partition_element *sub_p_elem= new partition_element(curr_part);
if (part_info->use_default_subpartitions &&
@@ -4462,7 +4895,7 @@ sub_part_definition:
}
part_info->curr_part_elem= sub_p_elem;
part_info->use_default_subpartitions= FALSE;
- part_info->use_default_no_subpartitions= FALSE;
+ part_info->use_default_num_subpartitions= FALSE;
part_info->count_curr_subparts++;
}
sub_name opt_part_options {}
@@ -4488,9 +4921,9 @@ opt_part_option:
{ Lex->part_info->curr_part_elem->tablespace_name= $3.str; }
| opt_storage ENGINE_SYM opt_equal storage_engines
{
- LEX *lex= Lex;
- lex->part_info->curr_part_elem->engine_type= $4;
- lex->part_info->default_engine_type= $4;
+ partition_info *part_info= Lex->part_info;
+ part_info->curr_part_elem->engine_type= $4;
+ part_info->default_engine_type= $4;
}
| NODEGROUP_SYM opt_equal real_ulong_num
{ Lex->part_info->curr_part_elem->nodegroup_id= (uint16) $3; }
@@ -4514,7 +4947,6 @@ create_select:
SELECT_SYM
{
LEX *lex=Lex;
- lex->lock_option= TL_READ_DEFAULT;
if (lex->sql_command == SQLCOM_INSERT)
lex->sql_command= SQLCOM_INSERT_SELECT;
else if (lex->sql_command == SQLCOM_REPLACE)
@@ -4526,19 +4958,6 @@ create_select:
lex->current_select->table_list.save_and_clear(&lex->save_list);
mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LIST;
-
- if (lex->sql_command == SQLCOM_CREATE_TABLE &&
- (lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS))
- {
- Lex_input_stream *lip= YYLIP;
-
- if (lex->spcont)
- lex->create_select_pos= lip->get_tok_start() -
- lex->sphead->m_tmp_query;
- else
- lex->create_select_pos= lip->get_tok_start() - lip->get_buf();
- lex->create_select_in_comment= (lip->in_comment == DISCARD_COMMENT);
- }
}
select_options select_item_list
{
@@ -4613,14 +5032,8 @@ create_table_option:
ENGINE_SYM opt_equal storage_engines
{
Lex->create_info.db_type= $3;
- Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE;
- }
- | TYPE_SYM opt_equal storage_engines
- {
- Lex->create_info.db_type= $3;
- WARN_DEPRECATED(yythd, "6.0", "TYPE=storage_engine",
- "'ENGINE=storage_engine'");
- Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE;
+ if ($3)
+ Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE;
}
| MAX_ROWS opt_equal ulonglong_num
{
@@ -4693,17 +5106,30 @@ create_table_option:
Lex->create_info.row_type= $3;
Lex->create_info.used_fields|= HA_CREATE_USED_ROW_FORMAT;
}
- | UNION_SYM opt_equal '(' opt_table_list ')'
+ | UNION_SYM opt_equal
+ {
+ Lex->select_lex.table_list.save_and_clear(&Lex->save_list);
+ }
+ '(' opt_table_list ')'
{
- /* Move the union list to the merge_list */
+ /*
+ Move the union list to the merge_list and exclude its tables
+ from the global list.
+ */
LEX *lex=Lex;
- TABLE_LIST *table_list= lex->select_lex.get_table_list();
lex->create_info.merge_list= lex->select_lex.table_list;
- lex->create_info.merge_list.elements--;
- lex->create_info.merge_list.first= table_list->next_local;
- lex->select_lex.table_list.elements=1;
- lex->select_lex.table_list.next= &(table_list->next_local);
- table_list->next_local= 0;
+ lex->select_lex.table_list= lex->save_list;
+ /*
+ When excluding union list from the global list we assume that
+ elements of the former immediately follow elements which represent
+ table being created/altered and parent tables.
+ */
+ TABLE_LIST *last_non_sel_table= lex->create_last_non_select_table;
+ DBUG_ASSERT(last_non_sel_table->next_global ==
+ lex->create_info.merge_list.first);
+ last_non_sel_table->next_global= 0;
+ Lex->query_tables_last= &last_non_sel_table->next_global;
+
lex->create_info.used_fields|= HA_CREATE_USED_UNION;
}
| default_charset
@@ -4766,14 +5192,14 @@ default_collation:
HA_CREATE_INFO *cinfo= &Lex->create_info;
if ((cinfo->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
cinfo->default_table_charset && $4 &&
- !my_charset_same(cinfo->default_table_charset,$4))
- {
- my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- $4->name, cinfo->default_table_charset->csname);
- MYSQL_YYABORT;
- }
- Lex->create_info.default_table_charset= $4;
- Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
+ !($4= merge_charset_and_collation(cinfo->default_table_charset,
+ $4)))
+ {
+ MYSQL_YYABORT;
+ }
+
+ Lex->create_info.default_table_charset= $4;
+ Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
}
;
@@ -4841,6 +5267,14 @@ udf_type:
| INT_SYM {$$ = (int) INT_RESULT; }
;
+
+create_field_list:
+ field_list
+ {
+ Lex->create_last_non_select_table= Lex->last_table();
+ }
+ ;
+
field_list:
field_list_item
| field_list ',' field_list_item
@@ -4880,15 +5314,13 @@ key_def:
| opt_constraint constraint_key_type opt_ident key_alg
'(' key_list ')' normal_key_options
{
- if (add_create_index (Lex, $2, $3 ? $3 : $1))
+ if (add_create_index (Lex, $2, $3.str ? $3 : $1))
MYSQL_YYABORT;
}
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
{
LEX *lex=Lex;
- const char *key_name= $1 ? $1 : $4;
- const char *fkey_name = $4 ? $4 : key_name;
- Key *key= new Foreign_key(fkey_name, lex->col_list,
+ Key *key= new Foreign_key($4.str ? $4 : $1, lex->col_list,
$8,
lex->ref_list,
lex->fk_delete_opt,
@@ -4897,16 +5329,12 @@ key_def:
if (key == NULL)
MYSQL_YYABORT;
lex->alter_info.key_list.push_back(key);
- if (add_create_index (lex, Key::MULTIPLE, key_name,
+ if (add_create_index (lex, Key::MULTIPLE, $1.str ? $1 : $4,
&default_key_create_info, 1))
MYSQL_YYABORT;
/* Only used for ALTER TABLE. Ignored otherwise. */
lex->alter_info.flags|= ALTER_FOREIGN_KEY;
}
- | constraint opt_check_constraint
- {
- Lex->col_list.empty(); /* Alloced by sql_alloc */
- }
| opt_constraint check_constraint
{
Lex->col_list.empty(); /* Alloced by sql_alloc */
@@ -4919,11 +5347,11 @@ opt_check_constraint:
;
check_constraint:
- CHECK_SYM expr
+ CHECK_SYM '(' expr ')'
;
opt_constraint:
- /* empty */ { $$=(char*) 0; }
+ /* empty */ { $$= null_lex_str; }
| constraint { $$= $1; }
;
@@ -5028,7 +5456,7 @@ type:
{ $$=MYSQL_TYPE_DATE; }
| TIME_SYM
{ $$=MYSQL_TYPE_TIME; }
- | TIMESTAMP opt_field_length
+ | TIMESTAMP
{
if (YYTHD->variables.sql_mode & MODE_MAXDB)
$$=MYSQL_TYPE_DATETIME;
@@ -5214,6 +5642,7 @@ field_length:
opt_field_length:
/* empty */ { Lex->length=(char*) 0; /* use default length */ }
| field_length { }
+ ;
opt_precision:
/* empty */ {}
@@ -5282,6 +5711,28 @@ attribute:
}
;
+
+type_with_opt_collate:
+ type opt_collate
+ {
+ $$= $1;
+
+ if (Lex->charset) /* Lex->charset is scanned in "type" */
+ {
+ if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2)))
+ MYSQL_YYABORT;
+ }
+ else if ($2)
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "COLLATE with no CHARACTER SET "
+ "in SP parameters, RETURNS, DECLARE");
+ MYSQL_YYABORT;
+ }
+ }
+ ;
+
+
now_or_signed_literal:
NOW_SYM optional_braces
{
@@ -5364,11 +5815,21 @@ opt_default:
| DEFAULT {}
;
-opt_binary:
- /* empty */ { Lex->charset=NULL; }
- | ASCII_SYM opt_bin_mod { Lex->charset=&my_charset_latin1; }
- | BYTE_SYM { Lex->charset=&my_charset_bin; }
- | UNICODE_SYM opt_bin_mod
+
+ascii:
+ ASCII_SYM { Lex->charset= &my_charset_latin1; }
+ | BINARY ASCII_SYM
+ {
+ Lex->charset= &my_charset_latin1_bin;
+ }
+ | ASCII_SYM BINARY
+ {
+ Lex->charset= &my_charset_latin1_bin;
+ }
+ ;
+
+unicode:
+ UNICODE_SYM
{
if (!(Lex->charset=get_charset_by_csname("ucs2",
MY_CS_PRIMARY,MYF(0))))
@@ -5377,8 +5838,40 @@ opt_binary:
MYSQL_YYABORT;
}
}
+ | UNICODE_SYM BINARY
+ {
+ if (!(Lex->charset=get_charset_by_name("ucs2_bin", MYF(0))))
+ {
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), "ucs2_bin");
+ MYSQL_YYABORT;
+ }
+ }
+ | BINARY UNICODE_SYM
+ {
+ if (!(Lex->charset=get_charset_by_name("ucs2_bin", MYF(0))))
+ {
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), "ucs2_bin");
+ MYSQL_YYABORT;
+ }
+ }
+ ;
+
+opt_binary:
+ /* empty */ { Lex->charset=NULL; }
+ | ascii
+ | unicode
+ | BYTE_SYM { Lex->charset=&my_charset_bin; }
| charset charset_name opt_bin_mod { Lex->charset=$2; }
- | BINARY opt_bin_charset { Lex->type|= BINCMP_FLAG; }
+ | BINARY
+ {
+ Lex->charset= NULL;
+ Lex->type|= BINCMP_FLAG;
+ }
+ | BINARY charset charset_name
+ {
+ Lex->charset= $3;
+ Lex->type|= BINCMP_FLAG;
+ }
;
opt_bin_mod:
@@ -5386,20 +5879,6 @@ opt_bin_mod:
| BINARY { Lex->type|= BINCMP_FLAG; }
;
-opt_bin_charset:
- /* empty */ { Lex->charset= NULL; }
- | ASCII_SYM { Lex->charset=&my_charset_latin1; }
- | UNICODE_SYM
- {
- if (!(Lex->charset=get_charset_by_csname("ucs2",
- MY_CS_PRIMARY,MYF(0))))
- {
- my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2");
- MYSQL_YYABORT;
- }
- }
- | charset charset_name { Lex->charset=$2; }
- ;
opt_primary:
/* empty */
@@ -5407,64 +5886,93 @@ opt_primary:
;
references:
- REFERENCES table_ident
- {
- LEX *lex=Lex;
- lex->fk_delete_opt= lex->fk_update_opt= lex->fk_match_option= 0;
- lex->ref_list.empty();
- }
+ REFERENCES
+ table_ident
opt_ref_list
+ opt_match_clause
+ opt_on_update_delete
{
$$=$2;
}
;
opt_ref_list:
- /* empty */ opt_on_delete {}
- | '(' ref_list ')' opt_on_delete {}
+ /* empty */
+ { Lex->ref_list.empty(); }
+ | '(' ref_list ')'
;
ref_list:
ref_list ',' ident
{
- Key_part_spec *key= new Key_part_spec($3.str);
+ Key_part_spec *key= new Key_part_spec($3, 0);
if (key == NULL)
MYSQL_YYABORT;
Lex->ref_list.push_back(key);
}
| ident
{
- Key_part_spec *key= new Key_part_spec($1.str);
+ Key_part_spec *key= new Key_part_spec($1, 0);
if (key == NULL)
MYSQL_YYABORT;
- Lex->ref_list.push_back(key);
+ LEX *lex= Lex;
+ lex->ref_list.empty();
+ lex->ref_list.push_back(key);
}
;
-opt_on_delete:
- /* empty */ {}
- | opt_on_delete_list {}
- ;
-
-opt_on_delete_list:
- opt_on_delete_list opt_on_delete_item {}
- | opt_on_delete_item {}
+opt_match_clause:
+ /* empty */
+ { Lex->fk_match_option= Foreign_key::FK_MATCH_UNDEF; }
+ | MATCH FULL
+ { Lex->fk_match_option= Foreign_key::FK_MATCH_FULL; }
+ | MATCH PARTIAL
+ { Lex->fk_match_option= Foreign_key::FK_MATCH_PARTIAL; }
+ | MATCH SIMPLE_SYM
+ { Lex->fk_match_option= Foreign_key::FK_MATCH_SIMPLE; }
;
-opt_on_delete_item:
- ON DELETE_SYM delete_option { Lex->fk_delete_opt= $3; }
- | ON UPDATE_SYM delete_option { Lex->fk_update_opt= $3; }
- | MATCH FULL { Lex->fk_match_option= Foreign_key::FK_MATCH_FULL; }
- | MATCH PARTIAL { Lex->fk_match_option= Foreign_key::FK_MATCH_PARTIAL; }
- | MATCH SIMPLE_SYM { Lex->fk_match_option= Foreign_key::FK_MATCH_SIMPLE; }
+opt_on_update_delete:
+ /* empty */
+ {
+ LEX *lex= Lex;
+ lex->fk_update_opt= Foreign_key::FK_OPTION_UNDEF;
+ lex->fk_delete_opt= Foreign_key::FK_OPTION_UNDEF;
+ }
+ | ON UPDATE_SYM delete_option
+ {
+ LEX *lex= Lex;
+ lex->fk_update_opt= $3;
+ lex->fk_delete_opt= Foreign_key::FK_OPTION_UNDEF;
+ }
+ | ON DELETE_SYM delete_option
+ {
+ LEX *lex= Lex;
+ lex->fk_update_opt= Foreign_key::FK_OPTION_UNDEF;
+ lex->fk_delete_opt= $3;
+ }
+ | ON UPDATE_SYM delete_option
+ ON DELETE_SYM delete_option
+ {
+ LEX *lex= Lex;
+ lex->fk_update_opt= $3;
+ lex->fk_delete_opt= $6;
+ }
+ | ON DELETE_SYM delete_option
+ ON UPDATE_SYM delete_option
+ {
+ LEX *lex= Lex;
+ lex->fk_update_opt= $6;
+ lex->fk_delete_opt= $3;
+ }
;
delete_option:
- RESTRICT { $$= (int) Foreign_key::FK_OPTION_RESTRICT; }
- | CASCADE { $$= (int) Foreign_key::FK_OPTION_CASCADE; }
- | SET NULL_SYM { $$= (int) Foreign_key::FK_OPTION_SET_NULL; }
- | NO_SYM ACTION { $$= (int) Foreign_key::FK_OPTION_NO_ACTION; }
- | SET DEFAULT { $$= (int) Foreign_key::FK_OPTION_DEFAULT; }
+ RESTRICT { $$= Foreign_key::FK_OPTION_RESTRICT; }
+ | CASCADE { $$= Foreign_key::FK_OPTION_CASCADE; }
+ | SET NULL_SYM { $$= Foreign_key::FK_OPTION_SET_NULL; }
+ | NO_SYM ACTION { $$= Foreign_key::FK_OPTION_NO_ACTION; }
+ | SET DEFAULT { $$= Foreign_key::FK_OPTION_DEFAULT; }
;
normal_key_type:
@@ -5569,6 +6077,7 @@ key_using_alg:
all_key_opt:
KEY_BLOCK_SIZE opt_equal ulong_num
{ Lex->key_create_info.block_size= $3; }
+ | COMMENT_SYM TEXT_STRING_sys { Lex->key_create_info.comment= $2; }
;
normal_key_opt:
@@ -5608,7 +6117,7 @@ key_list:
key_part:
ident
{
- $$= new Key_part_spec($1.str);
+ $$= new Key_part_spec($1, 0);
if ($$ == NULL)
MYSQL_YYABORT;
}
@@ -5619,15 +6128,15 @@ key_part:
{
my_error(ER_KEY_PART_0, MYF(0), $1.str);
}
- $$= new Key_part_spec($1.str,(uint) key_part_len);
+ $$= new Key_part_spec($1, (uint) key_part_len);
if ($$ == NULL)
MYSQL_YYABORT;
}
;
opt_ident:
- /* empty */ { $$=(char*) 0; /* Default length */ }
- | field_ident { $$=$1.str; }
+ /* empty */ { $$= null_lex_str; }
+ | field_ident { $$= $1; }
;
opt_component:
@@ -5653,9 +6162,10 @@ alter:
lex->sql_command= SQLCOM_ALTER_TABLE;
lex->duplicates= DUP_ERROR;
if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
- TL_OPTION_UPDATING))
+ TL_OPTION_UPDATING,
+ TL_READ_NO_INSERT,
+ MDL_SHARED_NO_WRITE))
MYSQL_YYABORT;
- lex->alter_info.reset();
lex->col_list.empty();
lex->select_lex.init_order();
lex->select_lex.db= (lex->select_lex.table_list.first)->db;
@@ -5666,9 +6176,21 @@ alter:
lex->alter_info.reset();
lex->no_write_to_binlog= 0;
lex->create_info.storage_media= HA_SM_DEFAULT;
+ lex->create_last_non_select_table= lex->last_table();
+ DBUG_ASSERT(!lex->m_stmt);
}
alter_commands
- {}
+ {
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ if (!lex->m_stmt)
+ {
+ /* Create a generic ALTER TABLE statment. */
+ lex->m_stmt= new (thd->mem_root) Alter_table_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
+ }
+ }
| ALTER DATABASE ident_or_empty
{
Lex->create_info.default_table_charset= NULL;
@@ -5694,7 +6216,7 @@ alter:
lex->sql_command= SQLCOM_ALTER_DB_UPGRADE;
lex->name= $3;
}
- | ALTER PROCEDURE sp_name
+ | ALTER PROCEDURE_SYM sp_name
{
LEX *lex= Lex;
@@ -5887,38 +6409,54 @@ alter_commands:
| OPTIMIZE PARTITION_SYM opt_no_write_to_binlog
all_or_alt_part_name_list
{
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_OPTIMIZE;
- lex->alter_info.flags|= ALTER_ADMIN_PARTITION;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
lex->no_write_to_binlog= $3;
lex->check_opt.init();
+ DBUG_ASSERT(!lex->m_stmt);
+ lex->m_stmt= new (thd->mem_root)
+ Alter_table_optimize_partition_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
}
opt_no_write_to_binlog
| ANALYZE_SYM PARTITION_SYM opt_no_write_to_binlog
all_or_alt_part_name_list
{
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_ANALYZE;
- lex->alter_info.flags|= ALTER_ADMIN_PARTITION;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
lex->no_write_to_binlog= $3;
lex->check_opt.init();
+ DBUG_ASSERT(!lex->m_stmt);
+ lex->m_stmt= new (thd->mem_root)
+ Alter_table_analyze_partition_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
}
| CHECK_SYM PARTITION_SYM all_or_alt_part_name_list
{
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_CHECK;
- lex->alter_info.flags|= ALTER_ADMIN_PARTITION;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
lex->check_opt.init();
+ DBUG_ASSERT(!lex->m_stmt);
+ lex->m_stmt= new (thd->mem_root)
+ Alter_table_check_partition_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
}
opt_mi_check_type
| REPAIR PARTITION_SYM opt_no_write_to_binlog
all_or_alt_part_name_list
{
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_REPAIR;
- lex->alter_info.flags|= ALTER_ADMIN_PARTITION;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
lex->no_write_to_binlog= $3;
lex->check_opt.init();
+ DBUG_ASSERT(!lex->m_stmt);
+ lex->m_stmt= new (thd->mem_root)
+ Alter_table_repair_partition_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
}
opt_mi_repair_type
| COALESCE PARTITION_SYM opt_no_write_to_binlog real_ulong_num
@@ -5926,7 +6464,18 @@ alter_commands:
LEX *lex= Lex;
lex->alter_info.flags|= ALTER_COALESCE_PARTITION;
lex->no_write_to_binlog= $3;
- lex->alter_info.no_parts= $4;
+ lex->alter_info.num_parts= $4;
+ }
+ | TRUNCATE_SYM PARTITION_SYM all_or_alt_part_name_list
+ {
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ lex->check_opt.init();
+ DBUG_ASSERT(!lex->m_stmt);
+ lex->m_stmt= new (thd->mem_root)
+ Alter_table_truncate_partition_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
}
| reorg_partition_rule
;
@@ -5968,12 +6517,11 @@ add_part_extra:
| '(' part_def_list ')'
{
LEX *lex= Lex;
- lex->part_info->no_parts= lex->part_info->partitions.elements;
+ lex->part_info->num_parts= lex->part_info->partitions.elements;
}
| PARTITIONS_SYM real_ulong_num
{
- LEX *lex= Lex;
- lex->part_info->no_parts= $2;
+ Lex->part_info->num_parts= $2;
}
;
@@ -6003,8 +6551,8 @@ reorg_parts_rule:
}
INTO '(' part_def_list ')'
{
- LEX *lex= Lex;
- lex->part_info->no_parts= lex->part_info->partitions.elements;
+ partition_info *part_info= Lex->part_info;
+ part_info->num_parts= part_info->partitions.elements;
}
;
@@ -6043,12 +6591,16 @@ add_column:
;
alter_list_item:
- add_column column_def opt_place { }
+ add_column column_def opt_place
+ {
+ Lex->create_last_non_select_table= Lex->last_table();
+ }
| ADD key_def
{
+ Lex->create_last_non_select_table= Lex->last_table();
Lex->alter_info.flags|= ALTER_ADD_INDEX;
}
- | add_column '(' field_list ')'
+ | add_column '(' create_field_list ')'
{
Lex->alter_info.flags|= ALTER_ADD_COLUMN | ALTER_ADD_INDEX;
}
@@ -6059,6 +6611,9 @@ alter_list_item:
lex->alter_info.flags|= ALTER_CHANGE_COLUMN;
}
field_spec opt_place
+ {
+ Lex->create_last_non_select_table= Lex->last_table();
+ }
| MODIFY_SYM opt_column field_ident
{
LEX *lex=Lex;
@@ -6081,6 +6636,9 @@ alter_list_item:
MYSQL_YYABORT;
}
opt_place
+ {
+ Lex->create_last_non_select_table= Lex->last_table();
+ }
| DROP opt_column field_ident opt_restrict
{
LEX *lex=Lex;
@@ -6324,33 +6882,13 @@ slave_until_opts:
| slave_until_opts ',' master_file_def
;
-restore:
- RESTORE_SYM table_or_tables
- {
- Lex->sql_command = SQLCOM_RESTORE_TABLE;
- }
- table_list FROM TEXT_STRING_sys
- {
- Lex->backup_dir = $6.str;
- }
- ;
-
-backup:
- BACKUP_SYM table_or_tables
- {
- Lex->sql_command = SQLCOM_BACKUP_TABLE;
- }
- table_list TO_SYM TEXT_STRING_sys
- {
- Lex->backup_dir = $6.str;
- }
- ;
-
checksum:
CHECKSUM_SYM table_or_tables
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_CHECKSUM;
+ /* Will be overriden during execution. */
+ YYPS->m_lock_type= TL_UNLOCK;
}
table_list opt_checksum_type
{}
@@ -6370,9 +6908,18 @@ repair:
lex->no_write_to_binlog= $2;
lex->check_opt.init();
lex->alter_info.reset();
+ /* Will be overriden during execution. */
+ YYPS->m_lock_type= TL_UNLOCK;
}
table_list opt_mi_repair_type
- {}
+ {
+ THD *thd= YYTHD;
+ LEX* lex= thd->lex;
+ DBUG_ASSERT(!lex->m_stmt);
+ lex->m_stmt= new (thd->mem_root) Repair_table_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
+ }
;
opt_mi_repair_type:
@@ -6399,9 +6946,18 @@ analyze:
lex->no_write_to_binlog= $2;
lex->check_opt.init();
lex->alter_info.reset();
+ /* Will be overriden during execution. */
+ YYPS->m_lock_type= TL_UNLOCK;
}
table_list
- {}
+ {
+ THD *thd= YYTHD;
+ LEX* lex= thd->lex;
+ DBUG_ASSERT(!lex->m_stmt);
+ lex->m_stmt= new (thd->mem_root) Analyze_table_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
+ }
;
binlog_base64_event:
@@ -6425,9 +6981,18 @@ check:
lex->sql_command = SQLCOM_CHECK;
lex->check_opt.init();
lex->alter_info.reset();
+ /* Will be overriden during execution. */
+ YYPS->m_lock_type= TL_UNLOCK;
}
table_list opt_mi_check_type
- {}
+ {
+ THD *thd= YYTHD;
+ LEX* lex= thd->lex;
+ DBUG_ASSERT(!lex->m_stmt);
+ lex->m_stmt= new (thd->mem_root) Check_table_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
+ }
;
opt_mi_check_type:
@@ -6457,9 +7022,18 @@ optimize:
lex->no_write_to_binlog= $2;
lex->check_opt.init();
lex->alter_info.reset();
+ /* Will be overriden during execution. */
+ YYPS->m_lock_type= TL_UNLOCK;
}
table_list
- {}
+ {
+ THD *thd= YYTHD;
+ LEX* lex= thd->lex;
+ DBUG_ASSERT(!lex->m_stmt);
+ lex->m_stmt= new (thd->mem_root) Optimize_table_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
+ }
;
opt_no_write_to_binlog:
@@ -6505,22 +7079,31 @@ table_to_table:
LEX *lex=Lex;
SELECT_LEX *sl= lex->current_select;
if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING,
- TL_IGNORE) ||
+ TL_IGNORE, MDL_EXCLUSIVE) ||
!sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING,
- TL_IGNORE))
+ TL_IGNORE, MDL_EXCLUSIVE))
MYSQL_YYABORT;
}
;
keycache:
- CACHE_SYM INDEX_SYM keycache_list IN_SYM key_cache_name
+ CACHE_SYM INDEX_SYM
+ {
+ Lex->alter_info.reset();
+ }
+ keycache_list_or_parts IN_SYM key_cache_name
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_ASSIGN_TO_KEYCACHE;
- lex->ident= $5;
+ lex->ident= $6;
}
;
+keycache_list_or_parts:
+ keycache_list
+ | assign_to_keycache_parts
+ ;
+
keycache_list:
assign_to_keycache
| keycache_list ',' assign_to_keycache
@@ -6529,7 +7112,18 @@ keycache_list:
assign_to_keycache:
table_ident cache_keys_spec
{
+ if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ,
+ MDL_SHARED_READ,
+ Select->pop_index_hints()))
+ MYSQL_YYABORT;
+ }
+ ;
+
+assign_to_keycache_parts:
+ table_ident adm_partition cache_keys_spec
+ {
if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ,
+ MDL_SHARED_READ,
Select->pop_index_hints()))
MYSQL_YYABORT;
}
@@ -6545,11 +7139,17 @@ preload:
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_PRELOAD_KEYS;
+ lex->alter_info.reset();
}
- preload_list
+ preload_list_or_parts
{}
;
+preload_list_or_parts:
+ preload_keys_parts
+ | preload_list
+ ;
+
preload_list:
preload_keys
| preload_list ',' preload_keys
@@ -6559,16 +7159,35 @@ preload_keys:
table_ident cache_keys_spec opt_ignore_leaves
{
if (!Select->add_table_to_list(YYTHD, $1, NULL, $3, TL_READ,
+ MDL_SHARED_READ,
+ Select->pop_index_hints()))
+ MYSQL_YYABORT;
+ }
+ ;
+
+preload_keys_parts:
+ table_ident adm_partition cache_keys_spec opt_ignore_leaves
+ {
+ if (!Select->add_table_to_list(YYTHD, $1, NULL, $4, TL_READ,
+ MDL_SHARED_READ,
Select->pop_index_hints()))
MYSQL_YYABORT;
}
;
+adm_partition:
+ PARTITION_SYM have_partitioning
+ {
+ Lex->alter_info.flags|= ALTER_ADMIN_PARTITION;
+ }
+ '(' all_or_alt_part_name_list ')'
+ ;
+
cache_keys_spec:
{
Lex->select_lex.alloc_index_hints(YYTHD);
Select->set_index_hint_type(INDEX_HINT_USE,
- global_system_variables.old_mode ?
+ old_mode ?
INDEX_HINT_MASK_JOIN :
INDEX_HINT_MASK_ALL);
}
@@ -6608,37 +7227,22 @@ select_init:
select_paren:
SELECT_SYM select_part2
{
- LEX *lex= Lex;
- SELECT_LEX * sel= lex->current_select;
- if (sel->set_braces(1))
- {
- my_parse_error(ER(ER_SYNTAX_ERROR));
- MYSQL_YYABORT;
- }
- if (sel->linkage == UNION_TYPE &&
- !sel->master_unit()->first_select()->braces &&
- sel->master_unit()->first_select()->linkage ==
- UNION_TYPE)
- {
- my_parse_error(ER(ER_SYNTAX_ERROR));
+ if (setup_select_in_parentheses(Lex))
MYSQL_YYABORT;
- }
- if (sel->linkage == UNION_TYPE &&
- sel->olap != UNSPECIFIED_OLAP_TYPE &&
- sel->master_unit()->fake_select_lex)
- {
- my_error(ER_WRONG_USAGE, MYF(0),
- "CUBE/ROLLUP", "ORDER BY");
- MYSQL_YYABORT;
- }
- /* select in braces, can't contain global parameters */
- if (sel->master_unit()->fake_select_lex)
- sel->master_unit()->global_parameters=
- sel->master_unit()->fake_select_lex;
}
| '(' select_paren ')'
;
+/* The equivalent of select_paren for nested queries. */
+select_paren_derived:
+ SELECT_SYM select_part2_derived
+ {
+ if (setup_select_in_parentheses(Lex))
+ MYSQL_YYABORT;
+ }
+ | '(' select_paren_derived ')'
+ ;
+
select_init2:
select_part2
{
@@ -6687,8 +7291,8 @@ select_from:
opt_order_clause opt_limit_clause procedure_clause
{
Select->context.table_list=
- Select->context.first_name_resolution_table=
- (TABLE_LIST *) Select->table_list.first;
+ Select->context.first_name_resolution_table=
+ Select->table_list.first;
}
| FROM DUAL_SYM where_clause opt_limit_clause
/* oracle compatibility: oracle always requires FROM clause,
@@ -6715,50 +7319,63 @@ select_option_list:
;
select_option:
- STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; }
- | HIGH_PRIORITY
+ query_expression_option
+ | SQL_NO_CACHE_SYM
{
- if (check_simple_select())
+ /*
+ Allow this flag only on the first top-level SELECT statement, if
+ SQL_CACHE wasn't specified, and only once per query.
+ */
+ if (Lex->current_select != &Lex->select_lex)
+ {
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE");
MYSQL_YYABORT;
- Lex->lock_option= TL_READ_HIGH_PRIORITY;
- Lex->current_select->lock_option= TL_READ_HIGH_PRIORITY;
- }
- | DISTINCT { Select->options|= SELECT_DISTINCT; }
- | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
- | SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
- | SQL_BUFFER_RESULT
- {
- if (check_simple_select())
+ }
+ else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE");
MYSQL_YYABORT;
- Select->options|= OPTION_BUFFER_RESULT;
- }
- | SQL_CALC_FOUND_ROWS
- {
- if (check_simple_select())
+ }
+ else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE)
+ {
+ my_error(ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE");
MYSQL_YYABORT;
- Select->options|= OPTION_FOUND_ROWS;
- }
- | SQL_NO_CACHE_SYM
- {
- Lex->safe_to_cache_query=0;
- Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE;
- Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE;
+ }
+ else
+ {
+ Lex->safe_to_cache_query=0;
+ Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE;
+ Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE;
+ }
}
| SQL_CACHE_SYM
{
- /*
- Honor this flag only if SQL_NO_CACHE wasn't specified AND
- we are parsing the outermost SELECT in the query.
- */
- if (Lex->select_lex.sql_cache != SELECT_LEX::SQL_NO_CACHE &&
- Lex->current_select == &Lex->select_lex)
+ /*
+ Allow this flag only on the first top-level SELECT statement, if
+ SQL_NO_CACHE wasn't specified, and only once per query.
+ */
+ if (Lex->current_select != &Lex->select_lex)
+ {
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE");
+ MYSQL_YYABORT;
+ }
+ else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE");
+ MYSQL_YYABORT;
+ }
+ else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE)
+ {
+ my_error(ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE");
+ MYSQL_YYABORT;
+ }
+ else
{
Lex->safe_to_cache_query=1;
Lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE;
}
}
- | ALL { Select->options|= SELECT_ALL; }
;
select_lock_type:
@@ -6767,16 +7384,13 @@ select_lock_type:
{
LEX *lex=Lex;
lex->current_select->set_lock_for_tables(TL_WRITE);
- lex->current_select->lock_option= TL_WRITE;
lex->safe_to_cache_query=0;
- lex->protect_against_global_read_lock= TRUE;
}
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
{
LEX *lex=Lex;
lex->current_select->
set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS);
- lex->current_select->lock_option= TL_READ_WITH_SHARED_LOCKS;
lex->safe_to_cache_query=0;
}
;
@@ -6799,7 +7413,14 @@ select_item_list:
;
select_item:
- remember_name select_item2 remember_end select_alias
+ remember_name table_wild remember_end
+ {
+ THD *thd= YYTHD;
+
+ if (add_item_to_list(thd, $2))
+ MYSQL_YYABORT;
+ }
+ | remember_name expr remember_end select_alias
{
THD *thd= YYTHD;
DBUG_ASSERT($1 < $3);
@@ -6836,11 +7457,6 @@ remember_end:
}
;
-select_item2:
- table_wild { $$=$1; /* table.* */ }
- | expr { $$=$1; }
- ;
-
select_alias:
/* empty */ { $$=null_lex_str;}
| AS ident { $$=$2; }
@@ -7441,7 +8057,7 @@ function_call_keyword:
$$= new (YYTHD->mem_root) Item_func_current_user(Lex->current_context());
if ($$ == NULL)
MYSQL_YYABORT;
- Lex->set_stmt_unsafe();
+ Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
Lex->safe_to_cache_query= 0;
}
| DATE_SYM '(' expr ')'
@@ -7596,7 +8212,7 @@ function_call_keyword:
$$= new (YYTHD->mem_root) Item_func_user();
if ($$ == NULL)
MYSQL_YYABORT;
- Lex->set_stmt_unsafe();
+ Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
Lex->safe_to_cache_query=0;
}
| YEAR_SYM '(' expr ')'
@@ -7746,7 +8362,7 @@ function_call_nonkeyword:
sysdate_is_now=1, because the slave may have
sysdate_is_now=0.
*/
- Lex->set_stmt_unsafe();
+ Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
if (global_system_variables.sysdate_is_now == 0)
$$= new (YYTHD->mem_root) Item_func_sysdate_local();
else
@@ -8160,13 +8776,13 @@ udf_expr:
sum_expr:
AVG_SYM '(' in_sum_expr ')'
{
- $$= new (YYTHD->mem_root) Item_sum_avg($3);
+ $$= new (YYTHD->mem_root) Item_sum_avg($3, FALSE);
if ($$ == NULL)
MYSQL_YYABORT;
}
| AVG_SYM '(' DISTINCT in_sum_expr ')'
{
- $$= new (YYTHD->mem_root) Item_sum_avg_distinct($4);
+ $$= new (YYTHD->mem_root) Item_sum_avg($4, TRUE);
if ($$ == NULL)
MYSQL_YYABORT;
}
@@ -8209,7 +8825,7 @@ sum_expr:
{ Select->in_sum_expr--; }
')'
{
- $$= new (YYTHD->mem_root) Item_sum_count_distinct(* $5);
+ $$= new (YYTHD->mem_root) Item_sum_count(* $5);
if ($$ == NULL)
MYSQL_YYABORT;
}
@@ -8268,13 +8884,13 @@ sum_expr:
}
| SUM_SYM '(' in_sum_expr ')'
{
- $$= new (YYTHD->mem_root) Item_sum_sum($3);
+ $$= new (YYTHD->mem_root) Item_sum_sum($3, FALSE);
if ($$ == NULL)
MYSQL_YYABORT;
}
| SUM_SYM '(' DISTINCT in_sum_expr ')'
{
- $$= new (YYTHD->mem_root) Item_sum_sum_distinct($4);
+ $$= new (YYTHD->mem_root) Item_sum_sum($4, TRUE);
if ($$ == NULL)
MYSQL_YYABORT;
}
@@ -8340,7 +8956,7 @@ variable_aux:
if (!($$= get_system_var(YYTHD, $2, $3, $4)))
MYSQL_YYABORT;
if (!((Item_func_get_system_var*) $$)->is_written_to_binlog())
- Lex->set_stmt_unsafe();
+ Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_VARIABLE);
}
;
@@ -8484,6 +9100,7 @@ when_list:
}
;
+/* Equivalent to <table reference> in the SQL:2003 standard. */
/* Warning - may return NULL in case of incomplete SELECT */
table_ref:
table_factor { $$=$1; }
@@ -8511,6 +9128,7 @@ esc_table_ref:
| '{' ident table_ref '}' { $$=$3; }
;
+/* Equivalent to <table reference list> in the SQL:2003 standard. */
/* Warning - may return NULL in case of incomplete SELECT */
derived_table_list:
esc_table_ref { $$=$1; }
@@ -8664,6 +9282,13 @@ normal_join:
| CROSS JOIN_SYM {}
;
+/*
+ This is a flattening of the rules <table factor> and <table primary>
+ in the SQL:2003 standard, since we don't have <sample clause>
+
+ I.e.
+ <table factor> ::= <table primary> [ <sample clause> ]
+*/
/* Warning - may return NULL in case of incomplete SELECT */
table_factor:
{
@@ -8674,7 +9299,8 @@ table_factor:
{
if (!($$= Select->add_table_to_list(YYTHD, $2, $3,
Select->get_table_join_options(),
- Lex->lock_option,
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type,
Select->pop_index_hints())))
MYSQL_YYABORT;
Select->add_joined_table($$);
@@ -8701,12 +9327,29 @@ table_factor:
/* incomplete derived tables return NULL, we must be
nested in select_derived rule to be here. */
}
- | '(' get_select_lex select_derived union_opt ')' opt_table_alias
+ /*
+ Represents a flattening of the following rules from the SQL:2003
+ standard. This sub-rule corresponds to the sub-rule
+ <table primary> ::= ... | <derived table> [ AS ] <correlation name>
+
+ The following rules have been flattened into query_expression_body
+ (since we have no <with clause>).
+
+ <derived table> ::= <table subquery>
+ <table subquery> ::= <subquery>
+ <subquery> ::= <left paren> <query expression> <right paren>
+ <query expression> ::= [ <with clause> ] <query expression body>
+
+ For the time being we use the non-standard rule
+ select_derived_union which is a compromise between the standard
+ and our parser. Possibly this rule could be replaced by our
+ query_expression_body.
+ */
+ | '(' get_select_lex select_derived_union ')' opt_table_alias
{
/* Use $2 instead of Lex->current_select as derived table will
alter value of Lex->current_select. */
-
- if (!($3 || $6) && $2->embedding &&
+ if (!($3 || $5) && $2->embedding &&
!$2->embedding->nested_join->join_list.elements)
{
/* we have a derived table ($3 == NULL) but no alias,
@@ -8728,15 +9371,16 @@ table_factor:
if (ti == NULL)
MYSQL_YYABORT;
if (!($$= sel->add_table_to_list(lex->thd,
- ti, $6, 0,
- TL_READ)))
+ new Table_ident(unit), $5, 0,
+ TL_READ, MDL_SHARED_READ)))
MYSQL_YYABORT;
sel->add_joined_table($$);
lex->pop_context();
lex->nest_level--;
}
- else if ($4 || $6)
+ else if (($3->select_lex &&
+ $3->select_lex->master_unit()->is_union()) || $5)
{
/* simple nested joins cannot have aliases or unions */
my_parse_error(ER(ER_SYNTAX_ERROR));
@@ -8751,6 +9395,62 @@ table_factor:
}
;
+select_derived_union:
+ select_derived opt_order_clause opt_limit_clause
+ | select_derived_union
+ UNION_SYM
+ union_option
+ {
+ if (add_select_to_union_list(Lex, (bool)$3, FALSE))
+ MYSQL_YYABORT;
+ }
+ query_specification
+ {
+ /*
+ Remove from the name resolution context stack the context of the
+ last select in the union.
+ */
+ Lex->pop_context();
+ }
+ opt_order_clause opt_limit_clause
+ ;
+
+/* The equivalent of select_init2 for nested queries. */
+select_init2_derived:
+ select_part2_derived
+ {
+ LEX *lex= Lex;
+ SELECT_LEX * sel= lex->current_select;
+ if (lex->current_select->set_braces(0))
+ {
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
+ }
+ if (sel->linkage == UNION_TYPE &&
+ sel->master_unit()->first_select()->braces)
+ {
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
+ }
+ }
+ ;
+
+/* The equivalent of select_part2 for nested queries. */
+select_part2_derived:
+ {
+ LEX *lex= Lex;
+ SELECT_LEX *sel= lex->current_select;
+ if (sel->linkage != UNION_TYPE)
+ mysql_init_select(lex);
+ lex->current_select->parsing_place= SELECT_LIST;
+ }
+ opt_query_expression_options select_item_list
+ {
+ Select->parsing_place= NO_MATTER;
+ }
+ opt_select_from select_lock_type
+ ;
+
/* handle contents of parentheses in join expression */
select_derived:
get_select_lex
@@ -8837,8 +9537,7 @@ opt_outer:
index_hint_clause:
/* empty */
{
- $$= global_system_variables.old_mode ?
- INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL;
+ $$= old_mode ? INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL;
}
| FOR_SYM JOIN_SYM { $$= INDEX_HINT_MASK_JOIN; }
| FOR_SYM ORDER_SYM BY { $$= INDEX_HINT_MASK_ORDER; }
@@ -8920,7 +9619,7 @@ using_list:
;
interval:
- interval_time_st {}
+ interval_time_stamp {}
| DAY_HOUR_SYM { $$=INTERVAL_DAY_HOUR; }
| DAY_MICROSECOND_SYM { $$=INTERVAL_DAY_MICROSECOND; }
| DAY_MINUTE_SYM { $$=INTERVAL_DAY_MINUTE; }
@@ -8935,26 +9634,6 @@ interval:
;
interval_time_stamp:
- interval_time_st {}
- | FRAC_SECOND_SYM {
- $$=INTERVAL_MICROSECOND;
- /*
- FRAC_SECOND was mistakenly implemented with
- a wrong resolution. According to the ODBC
- standard it should be nanoseconds, not
- microseconds. Changing it to nanoseconds
- in MySQL would mean making TIMESTAMPDIFF
- and TIMESTAMPADD to return DECIMAL, since
- the return value would be too big for BIGINT
- Hence we just deprecate the incorrect
- implementation without changing its
- resolution.
- */
- WARN_DEPRECATED(yythd, VER_CELOSIA, "FRAC_SECOND", "MICROSECOND");
- }
- ;
-
-interval_time_st:
DAY_SYM { $$=INTERVAL_DAY; }
| WEEK_SYM { $$=INTERVAL_WEEK; }
| HOUR_SYM { $$=INTERVAL_HOUR; }
@@ -9062,8 +9741,15 @@ group_list:
olap_opt:
/* empty */ {}
- | WITH CUBE_SYM
+ | WITH_CUBE_SYM
{
+ /*
+ 'WITH CUBE' is reserved in the MySQL syntax, but not implemented,
+ and cause LALR(2) conflicts.
+ This syntax is not standard.
+ MySQL syntax: GROUP BY col1, col2, col3 WITH CUBE
+ SQL-2003: GROUP BY ... CUBE(col1, col2, col3)
+ */
LEX *lex=Lex;
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
@@ -9073,10 +9759,17 @@ olap_opt:
}
lex->current_select->olap= CUBE_TYPE;
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "CUBE");
- MYSQL_YYABORT; /* To be deleted in 5.1 */
+ MYSQL_YYABORT;
}
- | WITH ROLLUP_SYM
+ | WITH_ROLLUP_SYM
{
+ /*
+ 'WITH ROLLUP' is needed for backward compatibility,
+ and cause LALR(2) conflicts.
+ This syntax is not standard.
+ MySQL syntax: GROUP BY col1, col2, col3 WITH ROLLUP
+ SQL-2003: GROUP BY ... ROLLUP(col1, col2, col3)
+ */
LEX *lex= Lex;
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
@@ -9185,7 +9878,10 @@ opt_limit_clause:
;
limit_clause:
- LIMIT limit_options {}
+ LIMIT limit_options
+ {
+ Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
+ }
;
limit_options:
@@ -9213,7 +9909,40 @@ limit_options:
;
limit_option:
- param_marker
+ ident
+ {
+ Item_splocal *splocal;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= & thd->m_parser_state->m_lip;
+ sp_variable_t *spv;
+ sp_pcontext *spc = lex->spcont;
+ if (spc && (spv = spc->find_variable(&$1)))
+ {
+ splocal= new (thd->mem_root)
+ Item_splocal($1, spv->offset, spv->type,
+ lip->get_tok_start() - lex->sphead->m_tmp_query,
+ lip->get_ptr() - lip->get_tok_start());
+ if (splocal == NULL)
+ MYSQL_YYABORT;
+#ifndef DBUG_OFF
+ splocal->m_sp= lex->sphead;
+#endif
+ lex->safe_to_cache_query=0;
+ }
+ else
+ {
+ my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
+ MYSQL_YYABORT;
+ }
+ if (splocal->type() != Item::INT_ITEM)
+ {
+ my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0));
+ MYSQL_YYABORT;
+ }
+ splocal->limit_clause_param= TRUE;
+ $$= splocal;
+ } | param_marker
{
((Item_param *) $1)->limit_clause_param= TRUE;
}
@@ -9247,6 +9976,7 @@ delete_limit_clause:
{
SELECT_LEX *sel= Select;
sel->select_limit= $2;
+ Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
sel->explicit_limit= 1;
}
;
@@ -9295,7 +10025,7 @@ dec_num:
procedure_clause:
/* empty */
- | PROCEDURE ident /* Procedure name */
+ | PROCEDURE_SYM ident /* Procedure name */
{
LEX *lex=Lex;
@@ -9350,8 +10080,7 @@ procedure_item:
select_var_list_init:
{
LEX *lex=Lex;
- if (!lex->describe &&
- (!(lex->result= new select_dumpvar(lex->nest_level))))
+ if (!lex->describe && (!(lex->result= new select_dumpvar())))
MYSQL_YYABORT;
}
select_var_list
@@ -9432,7 +10161,7 @@ into_destination:
LEX *lex= Lex;
lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
if (!(lex->exchange= new sql_exchange($2.str, 0)) ||
- !(lex->result= new select_export(lex->exchange, lex->nest_level)))
+ !(lex->result= new select_export(lex->exchange)))
MYSQL_YYABORT;
}
opt_load_data_charset
@@ -9446,7 +10175,7 @@ into_destination:
lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
if (!(lex->exchange= new sql_exchange($2.str,1)))
MYSQL_YYABORT;
- if (!(lex->result= new select_dump(lex->exchange, lex->nest_level)))
+ if (!(lex->result= new select_dump(lex->exchange)))
MYSQL_YYABORT;
}
}
@@ -9478,13 +10207,17 @@ do:
*/
drop:
- DROP opt_temporary table_or_tables if_exists table_list opt_restrict
+ DROP opt_temporary table_or_tables if_exists
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_TABLE;
lex->drop_temporary= $2;
lex->drop_if_exists= $4;
+ YYPS->m_lock_type= TL_UNLOCK;
+ YYPS->m_mdl_type= MDL_EXCLUSIVE;
}
+ table_list opt_restrict
+ {}
| DROP INDEX_SYM ident ON table_ident {}
{
LEX *lex=Lex;
@@ -9496,7 +10229,9 @@ drop:
lex->alter_info.flags= ALTER_DROP_INDEX;
lex->alter_info.drop_list.push_back(ad);
if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,
- TL_OPTION_UPDATING))
+ TL_OPTION_UPDATING,
+ TL_READ_NO_INSERT,
+ MDL_SHARED_NO_WRITE))
MYSQL_YYABORT;
}
| DROP DATABASE if_exists ident
@@ -9550,7 +10285,7 @@ drop:
spname->init_qname(thd);
lex->spname= spname;
}
- | DROP PROCEDURE if_exists sp_name
+ | DROP PROCEDURE_SYM if_exists sp_name
{
LEX *lex=Lex;
if (lex->sphead)
@@ -9566,12 +10301,16 @@ drop:
{
Lex->sql_command = SQLCOM_DROP_USER;
}
- | DROP VIEW_SYM if_exists table_list opt_restrict
+ | DROP VIEW_SYM if_exists
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_DROP_VIEW;
lex->drop_if_exists= $3;
+ YYPS->m_lock_type= TL_UNLOCK;
+ YYPS->m_mdl_type= MDL_EXCLUSIVE;
}
+ table_list opt_restrict
+ {}
| DROP EVENT_SYM if_exists sp_name
{
Lex->drop_if_exists= $3;
@@ -9612,7 +10351,10 @@ table_list:
table_name:
table_ident
{
- if (!Select->add_table_to_list(YYTHD, $1, NULL, TL_OPTION_UPDATING))
+ if (!Select->add_table_to_list(YYTHD, $1, NULL,
+ TL_OPTION_UPDATING,
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
}
;
@@ -9627,7 +10369,8 @@ table_alias_ref:
{
if (!Select->add_table_to_list(YYTHD, $1, NULL,
TL_OPTION_UPDATING | TL_OPTION_ALIAS,
- Lex->lock_option ))
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
}
;
@@ -9652,8 +10395,6 @@ insert:
lex->sql_command= SQLCOM_INSERT;
lex->duplicates= DUP_ERROR;
mysql_init_select(lex);
- /* for subselects */
- lex->lock_option= TL_READ_DEFAULT;
}
insert_lock_option
opt_ignore insert2
@@ -9697,13 +10438,27 @@ insert_lock_option:
#endif
}
| LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
- | DELAYED_SYM { $$= TL_WRITE_DELAYED; }
+ | DELAYED_SYM
+ {
+ Lex->keyword_delayed_begin_offset= (uint)(YYLIP->get_tok_start() -
+ YYTHD->query());
+ Lex->keyword_delayed_end_offset= Lex->keyword_delayed_begin_offset +
+ YYLIP->yyLength() + 1;
+ $$= TL_WRITE_DELAYED;
+ }
| HIGH_PRIORITY { $$= TL_WRITE; }
;
replace_lock_option:
opt_low_priority { $$= $1; }
- | DELAYED_SYM { $$= TL_WRITE_DELAYED; }
+ | DELAYED_SYM
+ {
+ Lex->keyword_delayed_begin_offset= (uint)(YYLIP->get_tok_start() -
+ YYTHD->query());
+ Lex->keyword_delayed_end_offset= Lex->keyword_delayed_begin_offset +
+ YYLIP->yyLength() + 1;
+ $$= TL_WRITE_DELAYED;
+ }
;
insert2:
@@ -9836,7 +10591,6 @@ update:
LEX *lex= Lex;
mysql_init_select(lex);
lex->sql_command= SQLCOM_UPDATE;
- lex->lock_option= TL_UNLOCK; /* Will be set later */
lex->duplicates= DUP_ERROR;
}
opt_low_priority opt_ignore join_table_list
@@ -9903,66 +10657,81 @@ delete:
LEX *lex= Lex;
lex->sql_command= SQLCOM_DELETE;
mysql_init_select(lex);
- lex->lock_option= TL_WRITE_DEFAULT;
+ YYPS->m_lock_type= TL_WRITE_DEFAULT;
+ YYPS->m_mdl_type= MDL_SHARED_WRITE;
+
lex->ignore= 0;
lex->select_lex.init_order();
}
- opt_delete_options single_multi {}
+ opt_delete_options single_multi
;
single_multi:
FROM table_ident
{
if (!Select->add_table_to_list(YYTHD, $2, NULL, TL_OPTION_UPDATING,
- Lex->lock_option))
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
+ YYPS->m_lock_type= TL_READ_DEFAULT;
+ YYPS->m_mdl_type= MDL_SHARED_READ;
}
where_clause opt_order_clause
delete_limit_clause {}
| table_wild_list
- { mysql_init_multi_delete(Lex); }
+ {
+ mysql_init_multi_delete(Lex);
+ YYPS->m_lock_type= TL_READ_DEFAULT;
+ YYPS->m_mdl_type= MDL_SHARED_READ;
+ }
FROM join_table_list where_clause
- {
+ {
if (multi_delete_set_locks_and_link_aux_tables(Lex))
MYSQL_YYABORT;
}
| FROM table_alias_ref_list
- { mysql_init_multi_delete(Lex); }
+ {
+ mysql_init_multi_delete(Lex);
+ YYPS->m_lock_type= TL_READ_DEFAULT;
+ YYPS->m_mdl_type= MDL_SHARED_READ;
+ }
USING join_table_list where_clause
- {
+ {
if (multi_delete_set_locks_and_link_aux_tables(Lex))
MYSQL_YYABORT;
}
;
table_wild_list:
- table_wild_one {}
- | table_wild_list ',' table_wild_one {}
+ table_wild_one
+ | table_wild_list ',' table_wild_one
;
table_wild_one:
- ident opt_wild opt_table_alias
+ ident opt_wild
{
Table_ident *ti= new Table_ident($1);
if (ti == NULL)
MYSQL_YYABORT;
if (!Select->add_table_to_list(YYTHD,
ti,
- $3,
+ NULL,
TL_OPTION_UPDATING | TL_OPTION_ALIAS,
- Lex->lock_option))
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
}
- | ident '.' ident opt_wild opt_table_alias
+ | ident '.' ident opt_wild
{
Table_ident *ti= new Table_ident(YYTHD, $1, $3, 0);
if (ti == NULL)
MYSQL_YYABORT;
if (!Select->add_table_to_list(YYTHD,
ti,
- $5,
+ NULL,
TL_OPTION_UPDATING | TL_OPTION_ALIAS,
- Lex->lock_option))
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
}
;
@@ -9979,18 +10748,30 @@ opt_delete_options:
opt_delete_option:
QUICK { Select->options|= OPTION_QUICK; }
- | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; }
+ | LOW_PRIORITY { YYPS->m_lock_type= TL_WRITE_LOW_PRIORITY; }
| IGNORE_SYM { Lex->ignore= 1; }
;
truncate:
- TRUNCATE_SYM opt_table_sym table_name
+ TRUNCATE_SYM opt_table_sym
{
LEX* lex= Lex;
lex->sql_command= SQLCOM_TRUNCATE;
+ lex->alter_info.reset();
lex->select_lex.options= 0;
lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
lex->select_lex.init_order();
+ YYPS->m_lock_type= TL_WRITE;
+ YYPS->m_mdl_type= MDL_EXCLUSIVE;
+ }
+ table_name
+ {
+ THD *thd= YYTHD;
+ LEX* lex= thd->lex;
+ DBUG_ASSERT(!lex->m_stmt);
+ lex->m_stmt= new (thd->mem_root) Truncate_statement(lex);
+ if (lex->m_stmt == NULL)
+ MYSQL_YYABORT;
}
;
@@ -10064,7 +10845,6 @@ show:
{
LEX *lex=Lex;
lex->wild=0;
- lex->lock_option= TL_READ;
mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LIST;
bzero((char*) &lex->create_info,sizeof(lex->create_info));
@@ -10121,14 +10901,6 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_OPEN_TABLES))
MYSQL_YYABORT;
}
- | opt_full PLUGIN_SYM
- {
- LEX *lex= Lex;
- WARN_DEPRECATED(yythd, "6.0", "SHOW PLUGIN", "'SHOW PLUGINS'");
- lex->sql_command= SQLCOM_SHOW_PLUGINS;
- if (prepare_schema_table(YYTHD, lex, 0, SCH_PLUGINS))
- MYSQL_YYABORT;
- }
| PLUGINS_SYM
{
LEX *lex= Lex;
@@ -10175,6 +10947,11 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS;
} opt_limit_clause_init
+ | RELAYLOG_SYM EVENTS_SYM binlog_in binlog_from
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS;
+ } opt_limit_clause_init
| keys_or_index from_or_in table_ident opt_db where_clause
{
LEX *lex= Lex;
@@ -10184,19 +10961,6 @@ show_param:
if (prepare_schema_table(YYTHD, lex, $3, SCH_STATISTICS))
MYSQL_YYABORT;
}
- | COLUMN_SYM TYPES_SYM
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_SHOW_COLUMN_TYPES;
- }
- | TABLE_SYM TYPES_SYM
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_SHOW_STORAGE_ENGINES;
- WARN_DEPRECATED(yythd, "6.0", "SHOW TABLE TYPES", "'SHOW [STORAGE] ENGINES'");
- if (prepare_schema_table(YYTHD, lex, 0, SCH_ENGINES))
- MYSQL_YYABORT;
- }
| opt_storage ENGINES_SYM
{
LEX *lex=Lex;
@@ -10244,30 +11008,6 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_STATUS))
MYSQL_YYABORT;
}
- | INNOBASE_SYM STATUS_SYM
- {
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_SHOW_ENGINE_STATUS;
- if (!(lex->create_info.db_type=
- ha_resolve_by_legacy_type(YYTHD, DB_TYPE_INNODB)))
- {
- my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), "InnoDB");
- MYSQL_YYABORT;
- }
- WARN_DEPRECATED(yythd, "6.0", "SHOW INNODB STATUS", "'SHOW ENGINE INNODB STATUS'");
- }
- | MUTEX_SYM STATUS_SYM
- {
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_SHOW_ENGINE_MUTEX;
- if (!(lex->create_info.db_type=
- ha_resolve_by_legacy_type(YYTHD, DB_TYPE_INNODB)))
- {
- my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), "InnoDB");
- MYSQL_YYABORT;
- }
- WARN_DEPRECATED(yythd, "6.0", "SHOW MUTEX STATUS", "'SHOW ENGINE INNODB MUTEX'");
- }
| opt_full PROCESSLIST_SYM
{ Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;}
| opt_var_type VARIABLES wild_and_where
@@ -10340,7 +11080,7 @@ show_param:
{
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
}
- | CREATE PROCEDURE sp_name
+ | CREATE PROCEDURE_SYM sp_name
{
LEX *lex= Lex;
@@ -10360,7 +11100,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_CREATE_TRIGGER;
lex->spname= $3;
}
- | PROCEDURE STATUS_SYM wild_and_where
+ | PROCEDURE_SYM STATUS_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_STATUS_PROC;
@@ -10374,25 +11114,15 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
MYSQL_YYABORT;
}
- | PROCEDURE CODE_SYM sp_name
+ | PROCEDURE_SYM CODE_SYM sp_name
{
-#ifdef DBUG_OFF
- my_parse_error(ER(ER_SYNTAX_ERROR));
- MYSQL_YYABORT;
-#else
Lex->sql_command= SQLCOM_SHOW_PROC_CODE;
Lex->spname= $3;
-#endif
}
| FUNCTION_SYM CODE_SYM sp_name
{
-#ifdef DBUG_OFF
- my_parse_error(ER(ER_SYNTAX_ERROR));
- MYSQL_YYABORT;
-#else
Lex->sql_command= SQLCOM_SHOW_FUNC_CODE;
Lex->spname= $3;
-#endif
}
| CREATE EVENT_SYM sp_name
{
@@ -10467,7 +11197,6 @@ describe:
describe_command table_ident
{
LEX *lex= Lex;
- lex->lock_option= TL_READ;
mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LIST;
lex->sql_command= SQLCOM_SHOW_FIELDS;
@@ -10526,16 +11255,55 @@ flush:
;
flush_options:
- flush_options ',' flush_option
+ table_or_tables
+ {
+ Lex->type|= REFRESH_TABLES;
+ /*
+ Set type of metadata and table locks for
+ FLUSH TABLES table_list [WITH READ LOCK].
+ */
+ YYPS->m_lock_type= TL_READ_NO_INSERT;
+ YYPS->m_mdl_type= MDL_SHARED_HIGH_PRIO;
+ }
+ opt_table_list {}
+ opt_with_read_lock {}
+ | flush_options_list
+ ;
+
+opt_with_read_lock:
+ /* empty */ {}
+ | WITH READ_SYM LOCK_SYM
+ {
+ TABLE_LIST *tables= Lex->query_tables;
+ Lex->type|= REFRESH_READ_LOCK;
+ for (; tables; tables= tables->next_global)
+ {
+ tables->mdl_request.set_type(MDL_SHARED_NO_WRITE);
+ tables->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
+ tables->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
+ }
+ }
+ ;
+
+flush_options_list:
+ flush_options_list ',' flush_option
| flush_option
+ {}
;
flush_option:
- table_or_tables
- { Lex->type|= REFRESH_TABLES; }
- opt_table_list {}
- | TABLES WITH READ_SYM LOCK_SYM
- { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; }
+ ERROR_SYM LOGS_SYM
+ { Lex->type|= REFRESH_ERROR_LOG; }
+ | ENGINE_SYM LOGS_SYM
+ { Lex->type|= REFRESH_ENGINE_LOG; }
+ | GENERAL LOGS_SYM
+ { Lex->type|= REFRESH_GENERAL_LOG; }
+ | SLOW LOGS_SYM
+ { Lex->type|= REFRESH_SLOW_LOG; }
+ | BINARY LOGS_SYM
+ { Lex->type|= REFRESH_BINARY_LOG; }
+ | RELAY LOGS_SYM
+ { Lex->type|= REFRESH_RELAY_LOG; }
| QUERY_SYM CACHE_SYM
{ Lex->type|= REFRESH_QUERY_CACHE_FREE; }
| HOSTS_SYM
@@ -10643,69 +11411,49 @@ use:
/* import, export of files */
load:
- LOAD DATA_SYM
+ LOAD data_or_xml
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
if (lex->sphead)
{
- my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD DATA");
- MYSQL_YYABORT;
- }
- }
- load_data
- {}
- | LOAD TABLE_SYM table_ident FROM MASTER_SYM
- {
- LEX *lex=Lex;
- WARN_DEPRECATED(yythd, "6.0", "LOAD TABLE FROM MASTER",
- "MySQL Administrator (mysqldump, mysql)");
- if (lex->sphead)
- {
- my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD TABLE");
+ my_error(ER_SP_BADSTATEMENT, MYF(0),
+ $2 == FILETYPE_CSV ? "LOAD DATA" : "LOAD XML");
MYSQL_YYABORT;
}
- lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
- if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
- MYSQL_YYABORT;
}
- ;
-
-load_data:
load_data_lock opt_local INFILE TEXT_STRING_filesystem
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_LOAD;
- lex->lock_option= $1;
- lex->local_file= $2;
+ lex->local_file= $5;
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
- if (!(lex->exchange= new sql_exchange($4.str, 0)))
+ if (!(lex->exchange= new sql_exchange($7.str, 0, $2)))
MYSQL_YYABORT;
}
opt_duplicate INTO TABLE_SYM table_ident
{
LEX *lex=Lex;
- if (!Select->add_table_to_list(YYTHD, $9, NULL, TL_OPTION_UPDATING,
- lex->lock_option))
+ if (!Select->add_table_to_list(YYTHD, $12, NULL, TL_OPTION_UPDATING,
+ $4, MDL_SHARED_WRITE))
MYSQL_YYABORT;
lex->field_list.empty();
lex->update_list.empty();
lex->value_list.empty();
}
opt_load_data_charset
- { Lex->exchange->cs= $11; }
+ { Lex->exchange->cs= $14; }
+ opt_xml_rows_identified_by
opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
opt_load_data_set_spec
{}
- | FROM MASTER_SYM
- {
- Lex->sql_command = SQLCOM_LOAD_MASTER_DATA;
- WARN_DEPRECATED(yythd, "6.0", "LOAD DATA FROM MASTER",
- "mysqldump or future "
- "BACKUP/RESTORE DATABASE facility");
- }
+ ;
+
+data_or_xml:
+ DATA_SYM { $$= FILETYPE_CSV; }
+ | XML_SYM { $$= FILETYPE_XML; }
;
opt_local:
@@ -10794,15 +11542,26 @@ line_term:
}
;
+opt_xml_rows_identified_by:
+ /* empty */ { }
+ | ROWS_SYM IDENTIFIED_SYM BY text_string
+ { Lex->exchange->line_term = $4; };
+
opt_ignore_lines:
/* empty */
- | IGNORE_SYM NUM LINES
+ | IGNORE_SYM NUM lines_or_rows
{
DBUG_ASSERT(Lex->exchange != 0);
Lex->exchange->skip_lines= atol($2.str);
}
;
+lines_or_rows:
+ LINES { }
+
+ | ROWS_SYM { }
+ ;
+
opt_field_or_var_spec:
/* empty */ {}
| '(' fields_or_vars ')' {}
@@ -11446,8 +12205,9 @@ IDENT_sys:
$1.length, &dummy_error);
if (wlen < $1.length)
{
+ ErrConvString err($1.str, $1.length, &my_charset_bin);
my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
- cs->csname, $1.str + wlen);
+ cs->csname, err.ptr());
MYSQL_YYABORT;
}
$$= $1;
@@ -11549,6 +12309,9 @@ user:
$$->user = $1;
$$->host.str= (char *) "%";
$$->host.length= 1;
+ $$->password= null_lex_str;
+ $$->plugin= empty_lex_str;
+ $$->auth= empty_lex_str;
if (check_string_char_length(&$$->user, ER(ER_USERNAME),
USERNAME_CHAR_LENGTH,
@@ -11561,6 +12324,9 @@ user:
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
MYSQL_YYABORT;
$$->user = $1; $$->host=$3;
+ $$->password= null_lex_str;
+ $$->plugin= empty_lex_str;
+ $$->auth= empty_lex_str;
if (check_string_char_length(&$$->user, ER(ER_USERNAME),
USERNAME_CHAR_LENGTH,
@@ -11668,13 +12434,16 @@ keyword_sp:
| BOOLEAN_SYM {}
| BTREE_SYM {}
| CASCADED {}
+ | CATALOG_NAME_SYM {}
| CHAIN_SYM {}
| CHANGED {}
| CIPHER_SYM {}
| CLIENT_SYM {}
+ | CLASS_ORIGIN_SYM {}
| COALESCE {}
| CODE_SYM {}
| COLLATION_SYM {}
+ | COLUMN_NAME_SYM {}
| COLUMNS {}
| COMMITTED_SYM {}
| COMPACT_SYM {}
@@ -11683,10 +12452,14 @@ keyword_sp:
| CONCURRENT {}
| CONNECTION_SYM {}
| CONSISTENT_SYM {}
+ | CONSTRAINT_CATALOG_SYM {}
+ | CONSTRAINT_SCHEMA_SYM {}
+ | CONSTRAINT_NAME_SYM {}
| CONTEXT_SYM {}
| CONTRIBUTORS_SYM {}
| CPU_SYM {}
| CUBE_SYM {}
+ | CURSOR_NAME_SYM {}
| DATA_SYM {}
| DATAFILE_SYM {}
| DATETIME {}
@@ -11706,6 +12479,7 @@ keyword_sp:
| ENUM {}
| ENGINE_SYM {}
| ENGINES_SYM {}
+ | ERROR_SYM {}
| ERRORS {}
| ESCAPE_SYM {}
| EVENT_SYM {}
@@ -11722,7 +12496,7 @@ keyword_sp:
| FILE_SYM {}
| FIRST_SYM {}
| FIXED_SYM {}
- | FRAC_SECOND_SYM {}
+ | GENERAL {}
| GEOMETRY_SYM {}
| GEOMETRYCOLLECTION {}
| GET_FORMAT {}
@@ -11732,6 +12506,7 @@ keyword_sp:
| HOSTS_SYM {}
| HOUR_SYM {}
| IDENTIFIED_SYM {}
+ | IGNORE_SERVER_IDS_SYM {}
| INVOKER_SYM {}
| IMPORT {}
| INDEXES {}
@@ -11740,7 +12515,6 @@ keyword_sp:
| IPC_SYM {}
| ISOLATION {}
| ISSUER_SYM {}
- | INNOBASE_SYM {}
| INSERT_METHOD {}
| KEY_BLOCK_SIZE {}
| LAST_SYM {}
@@ -11755,6 +12529,7 @@ keyword_sp:
| LOGS_SYM {}
| MAX_ROWS {}
| MASTER_SYM {}
+ | MASTER_HEARTBEAT_PERIOD_SYM {}
| MASTER_HOST_SYM {}
| MASTER_PORT_SYM {}
| MASTER_LOG_FILE_SYM {}
@@ -11774,10 +12549,10 @@ keyword_sp:
| MAX_SIZE_SYM {}
| MAX_UPDATES_PER_HOUR {}
| MAX_USER_CONNECTIONS_SYM {}
- | MAX_VALUE_SYM {}
| MEDIUM_SYM {}
| MEMORY_SYM {}
| MERGE_SYM {}
+ | MESSAGE_TEXT_SYM {}
| MICROSECOND_SYM {}
| MIGRATE_SYM {}
| MINUTE_SYM {}
@@ -11789,6 +12564,7 @@ keyword_sp:
| MULTIPOINT {}
| MULTIPOLYGON {}
| MUTEX_SYM {}
+ | MYSQL_ERRNO_SYM {}
| NAME_SYM {}
| NAMES_SYM {}
| NATIONAL_SYM {}
@@ -11822,6 +12598,7 @@ keyword_sp:
| PROCESSLIST_SYM {}
| PROFILE_SYM {}
| PROFILES_SYM {}
+ | PROXY_SYM {}
| QUARTER_SYM {}
| QUERY_SYM {}
| QUICK {}
@@ -11831,6 +12608,8 @@ keyword_sp:
| REDO_BUFFER_SIZE_SYM {}
| REDOFILE_SYM {}
| REDUNDANT_SYM {}
+ | RELAY {}
+ | RELAYLOG_SYM {}
| RELAY_LOG_FILE_SYM {}
| RELAY_LOG_POS_SYM {}
| RELAY_THREAD {}
@@ -11848,6 +12627,7 @@ keyword_sp:
| ROW_SYM {}
| RTREE_SYM {}
| SCHEDULE_SYM {}
+ | SCHEMA_NAME_SYM {}
| SECOND_SYM {}
| SERIAL_SYM {}
| SERIALIZABLE_SYM {}
@@ -11855,6 +12635,7 @@ keyword_sp:
| SIMPLE_SYM {}
| SHARE_SYM {}
| SHUTDOWN {}
+ | SLOW {}
| SNAPSHOT_SYM {}
| SOUNDS_SYM {}
| SOURCE_SYM {}
@@ -11866,6 +12647,7 @@ keyword_sp:
| STATUS_SYM {}
| STORAGE_SYM {}
| STRING_SYM {}
+ | SUBCLASS_ORIGIN_SYM {}
| SUBDATE_SYM {}
| SUBJECT_SYM {}
| SUBPARTITION_SYM {}
@@ -11874,6 +12656,7 @@ keyword_sp:
| SUSPEND_SYM {}
| SWAPS_SYM {}
| SWITCHES_SYM {}
+ | TABLE_NAME_SYM {}
| TABLES {}
| TABLE_CHECKSUM_SYM {}
| TABLESPACE {}
@@ -11907,6 +12690,7 @@ keyword_sp:
| WEEK_SYM {}
| WORK_SYM {}
| X509_SYM {}
+ | XML_SYM {}
| YEAR_SYM {}
;
@@ -12202,7 +12986,7 @@ option_value:
if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
MYSQL_YYABORT;
user->host=null_lex_str;
- user->user.str=thd->security_ctx->priv_user;
+ user->user.str=thd->security_ctx->user;
set_var_password *var= new set_var_password(user, $3);
if (var == NULL)
MYSQL_YYABORT;
@@ -12391,11 +13175,12 @@ table_lock:
table_ident opt_table_alias lock_option
{
thr_lock_type lock_type= (thr_lock_type) $3;
- if (!Select->add_table_to_list(YYTHD, $1, $2, 0, lock_type))
+ bool lock_for_write= (lock_type >= TL_WRITE_ALLOW_WRITE);
+ if (!Select->add_table_to_list(YYTHD, $1, $2, 0, lock_type,
+ (lock_for_write ?
+ MDL_SHARED_NO_READ_WRITE :
+ MDL_SHARED_READ)))
MYSQL_YYABORT;
- /* If table is to be write locked, protect from a impending GRL. */
- if (lock_type >= TL_WRITE_ALLOW_WRITE)
- Lex->protect_against_global_read_lock= TRUE;
}
;
@@ -12473,6 +13258,13 @@ handler:
handler_read_or_scan where_clause opt_limit_clause
{
Lex->expr_allows_subselect= TRUE;
+ /* Stored functions are not supported for HANDLER READ. */
+ if (Lex->uses_stored_routines())
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "stored functions in HANDLER ... READ");
+ MYSQL_YYABORT;
+ }
}
;
@@ -12536,7 +13328,7 @@ revoke_command:
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_FUNCTION;
}
- | grant_privileges ON PROCEDURE grant_ident FROM grant_list
+ | grant_privileges ON PROCEDURE_SYM grant_ident FROM grant_list
{
LEX *lex= Lex;
if (lex->columns.elements)
@@ -12551,6 +13343,13 @@ revoke_command:
{
Lex->sql_command = SQLCOM_REVOKE_ALL;
}
+ | PROXY_SYM ON user FROM grant_list
+ {
+ LEX *lex= Lex;
+ lex->users_list.push_front ($3);
+ lex->sql_command= SQLCOM_REVOKE;
+ lex->type= TYPE_ENUM_PROXY;
+ }
;
grant:
@@ -12578,7 +13377,7 @@ grant_command:
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_FUNCTION;
}
- | grant_privileges ON PROCEDURE grant_ident TO_SYM grant_list
+ | grant_privileges ON PROCEDURE_SYM grant_ident TO_SYM grant_list
require_clause grant_options
{
LEX *lex= Lex;
@@ -12590,6 +13389,13 @@ grant_command:
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_PROCEDURE;
}
+ | PROXY_SYM ON user TO_SYM grant_list opt_grant_option
+ {
+ LEX *lex= Lex;
+ lex->users_list.push_front ($3);
+ lex->sql_command= SQLCOM_GRANT;
+ lex->type= TYPE_ENUM_PROXY;
+ }
;
opt_table:
@@ -12654,6 +13460,7 @@ object_privilege:
| CREATE USER { Lex->grant |= CREATE_USER_ACL; }
| EVENT_SYM { Lex->grant |= EVENT_ACL;}
| TRIGGER_SYM { Lex->grant |= TRIGGER_ACL; }
+ | CREATE TABLESPACE { Lex->grant |= CREATE_TABLESPACE_ACL; }
;
opt_and:
@@ -12782,6 +13589,8 @@ grant_user:
user IDENTIFIED_SYM BY TEXT_STRING
{
$$=$1; $1->password=$4;
+ if (Lex->sql_command == SQLCOM_REVOKE)
+ MYSQL_YYABORT;
if ($4.length)
{
if (YYTHD->variables.old_passwords)
@@ -12807,7 +13616,28 @@ grant_user:
}
}
| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
- { $$= $1; $1->password= $5; }
+ {
+ if (Lex->sql_command == SQLCOM_REVOKE)
+ MYSQL_YYABORT;
+ $$= $1;
+ $1->password= $5;
+ }
+ | user IDENTIFIED_SYM WITH ident_or_text
+ {
+ if (Lex->sql_command == SQLCOM_REVOKE)
+ MYSQL_YYABORT;
+ $$= $1;
+ $1->plugin= $4;
+ $1->auth= empty_lex_str;
+ }
+ | user IDENTIFIED_SYM WITH ident_or_text AS TEXT_STRING_sys
+ {
+ if (Lex->sql_command == SQLCOM_REVOKE)
+ MYSQL_YYABORT;
+ $$= $1;
+ $1->plugin= $4;
+ $1->auth= $6;
+ }
| user
{ $$= $1; $1->password= null_lex_str; }
;
@@ -12879,6 +13709,11 @@ grant_options:
| WITH grant_option_list
;
+opt_grant_option:
+ /* empty */ {}
+ | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;}
+ ;
+
grant_option_list:
grant_option_list grant_option {}
| grant_option {}
@@ -12929,16 +13764,16 @@ opt_work:
opt_chain:
/* empty */
- { $$= (YYTHD->variables.completion_type == 1); }
- | AND_SYM NO_SYM CHAIN_SYM { $$=0; }
- | AND_SYM CHAIN_SYM { $$=1; }
+ { $$= TVL_UNKNOWN; }
+ | AND_SYM NO_SYM CHAIN_SYM { $$= TVL_NO; }
+ | AND_SYM CHAIN_SYM { $$= TVL_YES; }
;
opt_release:
/* empty */
- { $$= (YYTHD->variables.completion_type == 2); }
- | RELEASE_SYM { $$=1; }
- | NO_SYM RELEASE_SYM { $$=0; }
+ { $$= TVL_UNKNOWN; }
+ | RELEASE_SYM { $$= TVL_YES; }
+ | NO_SYM RELEASE_SYM { $$= TVL_NO; }
;
opt_savepoint:
@@ -12951,7 +13786,9 @@ commit:
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_COMMIT;
- lex->tx_chain= $3;
+ /* Don't allow AND CHAIN RELEASE. */
+ MYSQL_YYABORT_UNLESS($3 != TVL_YES || $4 != TVL_YES);
+ lex->tx_chain= $3;
lex->tx_release= $4;
}
;
@@ -12961,7 +13798,9 @@ rollback:
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_ROLLBACK;
- lex->tx_chain= $3;
+ /* Don't allow AND CHAIN RELEASE. */
+ MYSQL_YYABORT_UNLESS($3 != TVL_YES || $4 != TVL_YES);
+ lex->tx_chain= $3;
lex->tx_release= $4;
}
| ROLLBACK_SYM opt_work
@@ -13004,33 +13843,8 @@ union_clause:
union_list:
UNION_SYM union_option
{
- LEX *lex=Lex;
- if (lex->result &&
- (lex->result->get_nest_level() == -1 ||
- lex->result->get_nest_level() == lex->nest_level))
- {
- /*
- Only the last SELECT can have INTO unless the INTO and UNION
- are at different nest levels. In version 5.1 and above, INTO
- will onle be allowed at top level.
- */
- my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO");
- MYSQL_YYABORT;
- }
- if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
- {
- my_parse_error(ER(ER_SYNTAX_ERROR));
- MYSQL_YYABORT;
- }
- /* This counter shouldn't be incremented for UNION parts */
- Lex->nest_level--;
- if (mysql_new_select(lex, 0))
+ if (add_select_to_union_list(Lex, (bool)$2, TRUE))
MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->current_select->linkage=UNION_TYPE;
- if ($2) /* UNION DISTINCT - remember position */
- lex->current_select->master_unit()->union_distinct=
- lex->current_select;
}
select_init
{
@@ -13083,22 +13897,39 @@ union_option:
| ALL { $$=0; }
;
-take_first_select: /* empty */
- {
- $$= Lex->current_select->master_unit()->first_select();
- };
+query_specification:
+ SELECT_SYM select_init2_derived
+ {
+ $$= Lex->current_select->master_unit()->first_select();
+ }
+ | '(' select_paren_derived ')'
+ {
+ $$= Lex->current_select->master_unit()->first_select();
+ }
+ ;
+
+query_expression_body:
+ query_specification
+ | query_expression_body
+ UNION_SYM union_option
+ {
+ if (add_select_to_union_list(Lex, (bool)$3, FALSE))
+ MYSQL_YYABORT;
+ }
+ query_specification
+ {
+ Lex->pop_context();
+ $$= $1;
+ }
+ ;
+/* Corresponds to <query expression> in the SQL:2003 standard. */
subselect:
- SELECT_SYM subselect_start select_init2 take_first_select
- subselect_end
- {
- $$= $4;
- }
- | '(' subselect_start select_paren take_first_select
- subselect_end ')'
- {
- $$= $4;
- };
+ subselect_start query_expression_body subselect_end
+ {
+ $$= $2;
+ }
+ ;
subselect_start:
{
@@ -13124,17 +13955,6 @@ subselect_start:
subselect_end:
{
LEX *lex=Lex;
- /*
- Set the required lock level for the tables associated with the
- current sub-select. This will overwrite previous lock options set
- using st_select_lex::add_table_to_list in any of the following
- rules: single_multi, table_wild_one, load_data, table_alias_ref,
- table_factor.
- The default lock level is TL_READ_DEFAULT but it can be modified
- with query options specific for a certain (sub-)SELECT.
- */
- lex->current_select->
- set_lock_for_tables(lex->current_select->lock_option);
lex->pop_context();
SELECT_LEX *child= lex->current_select;
@@ -13150,6 +13970,44 @@ subselect_end:
}
;
+opt_query_expression_options:
+ /* empty */
+ | query_expression_option_list
+ ;
+
+query_expression_option_list:
+ query_expression_option_list query_expression_option
+ | query_expression_option
+ ;
+
+query_expression_option:
+ STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; }
+ | HIGH_PRIORITY
+ {
+ if (check_simple_select())
+ MYSQL_YYABORT;
+ YYPS->m_lock_type= TL_READ_HIGH_PRIORITY;
+ YYPS->m_mdl_type= MDL_SHARED_READ;
+ Select->options|= SELECT_HIGH_PRIORITY;
+ }
+ | DISTINCT { Select->options|= SELECT_DISTINCT; }
+ | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
+ | SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
+ | SQL_BUFFER_RESULT
+ {
+ if (check_simple_select())
+ MYSQL_YYABORT;
+ Select->options|= OPTION_BUFFER_RESULT;
+ }
+ | SQL_CALC_FOUND_ROWS
+ {
+ if (check_simple_select())
+ MYSQL_YYABORT;
+ Select->options|= OPTION_FOUND_ROWS;
+ }
+ | ALL { Select->options|= SELECT_ALL; }
+ ;
+
/**************************************************************************
CREATE VIEW | TRIGGER | PROCEDURE statements.
@@ -13259,8 +14117,12 @@ view_tail:
LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_VIEW;
/* first table in list is target VIEW name */
- if (!lex->select_lex.add_table_to_list(thd, $3, NULL, TL_OPTION_UPDATING))
+ if (!lex->select_lex.add_table_to_list(thd, $3, NULL,
+ TL_OPTION_UPDATING,
+ TL_IGNORE,
+ MDL_EXCLUSIVE))
MYSQL_YYABORT;
+ lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
}
view_list_opt AS view_select
;
@@ -13399,7 +14261,8 @@ trigger_tail:
if (!lex->select_lex.add_table_to_list(YYTHD, $9,
(LEX_STRING*) 0,
TL_OPTION_UPDATING,
- TL_IGNORE))
+ TL_READ_NO_INSERT,
+ MDL_SHARED_NO_WRITE))
MYSQL_YYABORT;
}
;
@@ -13497,7 +14360,7 @@ sf_tail:
lex->interval_list.empty();
lex->type= 0;
}
- type /* $11 */
+ type_with_opt_collate /* $11 */
{ /* $12 */
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -13585,7 +14448,7 @@ sf_tail:
;
sp_tail:
- PROCEDURE remember_name sp_name
+ PROCEDURE_SYM remember_name sp_name
{
LEX *lex= Lex;
sp_head *sp;
diff --git a/sql/strfunc.cc b/sql/strfunc.cc
index 56fa4a380ea..a0e2f39f8dc 100644
--- a/sql/strfunc.cc
+++ b/sql/strfunc.cc
@@ -15,7 +15,13 @@
/* Some useful string utility functions used by the MySQL server */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "strfunc.h"
+#include "sql_class.h"
+#include "typelib.h" // TYPELIB
+#include "m_ctype.h" // my_charset_latin1
+#include "mysqld.h" // system_charset_info
/*
Return bitmap for strings used in a set
@@ -45,6 +51,7 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs,
const char *end= str + strip->cset->lengthsp(strip, str, length);
ulonglong found= 0;
*err_pos= 0; // No error yet
+ *err_len= 0;
if (str != end)
{
const char *start= str;
@@ -71,7 +78,7 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs,
var_len= (uint) (pos - start);
uint find= cs ? find_type2(lib, start, var_len, cs) :
find_type(lib, start, var_len, (bool) 0);
- if (!find)
+ if (!find && *err_len == 0) // report the first error with length > 0
{
*err_pos= (char*) start;
*err_len= var_len;
@@ -87,209 +94,6 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs,
return found;
}
-
-static const char *on_off_default_names[]=
-{
- "off","on","default", NullS
-};
-
-static const unsigned int on_off_default_names_len[]=
-{
- sizeof("off") - 1,
- sizeof("on") - 1,
- sizeof("default") - 1
-};
-
-static TYPELIB on_off_default_typelib= {array_elements(on_off_default_names)-1,
- "", on_off_default_names,
- (unsigned int *)on_off_default_names_len};
-
-
-/*
- Parse a TYPELIB name from the buffer
-
- SYNOPSIS
- parse_name()
- lib Set of names to scan for.
- strpos INOUT Start of the buffer (updated to point to the next
- character after the name)
- end End of the buffer
- cs Charset used in the buffer
-
- DESCRIPTION
- Parse a TYPELIB name from the buffer. The buffer is assumed to contain
- one of the names specified in the TYPELIB, followed by comma, '=', or
- end of the buffer.
-
- RETURN
- 0 No matching name
- >0 Offset+1 in typelib for matched name
-*/
-
-static uint parse_name(TYPELIB *lib, const char **strpos, const char *end,
- CHARSET_INFO *cs)
-{
- const char *pos= *strpos;
- const char *start= pos;
-
- /* Find the length */
- if (cs && cs->mbminlen > 1)
- {
- int mblen= 0;
- for ( ; pos < end; pos+= mblen)
- {
- my_wc_t wc;
- if ((mblen= cs->cset->mb_wc(cs, &wc, (const uchar *) pos,
- (const uchar *) end)) < 1)
- mblen= 1; // Not to hang on a wrong multibyte sequence
- if (wc == (my_wc_t) '=' || wc == (my_wc_t) ',')
- break;
- }
- }
- else
- for (; pos != end && *pos != '=' && *pos !=',' ; pos++) ;
-
- uint var_len= (uint) (pos - start);
- /* Determine which flag it is */
- uint find= cs ? find_type2(lib, start, var_len, cs) :
- find_type(lib, start, var_len, (bool) 0);
- *strpos= pos;
- return find;
-}
-
-
-/* Read next character from the buffer in a charset-aware way */
-
-static my_wc_t get_next_char(const char **pos, const char *end, CHARSET_INFO *cs)
-{
- my_wc_t wc;
- if (*pos == end)
- return (my_wc_t)-1;
-
- if (cs && cs->mbminlen > 1)
- {
- int mblen;
- if ((mblen= cs->cset->mb_wc(cs, &wc, (const uchar *) *pos,
- (const uchar *) end)) < 1)
- mblen= 1; // Not to hang on a wrong multibyte sequence
- *pos += mblen;
- return wc;
- }
- else
- return *((*pos)++);
-}
-
-
-/*
- Parse and apply a set of flag assingments
-
- SYNOPSIS
- find_set_from_flags()
- lib Flag names
- default_name Number of "default" in the typelib
- cur_set Current set of flags (start from this state)
- default_set Default set of flags (use this for assign-default
- keyword and flag=default assignments)
- str String to be parsed
- length Length of the string
- cs String charset
- err_pos OUT If error, set to point to start of wrong set string
- NULL on success
- err_len OUT If error, set to the length of wrong set string
- set_warning OUT TRUE <=> Some string in set couldn't be used
-
- DESCRIPTION
- Parse a set of flag assignments, that is, parse a string in form:
-
- param_name1=value1,param_name2=value2,...
-
- where the names are specified in the TYPELIB, and each value can be
- either 'on','off', or 'default'. Setting the same name twice is not
- allowed.
-
- Besides param=val assignments, we support the "default" keyword (keyword
- #default_name in the typelib). It can be used one time, if specified it
- causes us to build the new set over the default_set rather than cur_set
- value.
-
- RETURN
- Parsed set value if (*errpos == NULL)
- Otherwise undefined
-*/
-
-ulonglong find_set_from_flags(TYPELIB *lib, uint default_name,
- ulonglong cur_set, ulonglong default_set,
- const char *str, uint length, CHARSET_INFO *cs,
- char **err_pos, uint *err_len, bool *set_warning)
-{
- CHARSET_INFO *strip= cs ? cs : &my_charset_latin1;
- const char *end= str + strip->cset->lengthsp(strip, str, length);
- ulonglong flags_to_set= 0, flags_to_clear= 0;
- bool set_defaults= 0;
- *err_pos= 0; // No error yet
- if (str != end)
- {
- const char *start= str;
- for (;;)
- {
- const char *pos= start;
- uint flag_no, value;
-
- if (!(flag_no= parse_name(lib, &pos, end, cs)))
- goto err;
-
- if (flag_no == default_name)
- {
- /* Using 'default' twice isn't allowed. */
- if (set_defaults)
- goto err;
- set_defaults= TRUE;
- }
- else
- {
- ulonglong bit= ((longlong) 1 << (flag_no - 1));
- /* parse the '=on|off|default' */
- if ((flags_to_clear | flags_to_set) & bit ||
- get_next_char(&pos, end, cs) != '=' ||
- !(value= parse_name(&on_off_default_typelib, &pos, end, cs)))
- {
- goto err;
- }
-
- if (value == 1) // this is '=off'
- flags_to_clear|= bit;
- else if (value == 2) // this is '=on'
- flags_to_set|= bit;
- else // this is '=default'
- {
- if (default_set & bit)
- flags_to_set|= bit;
- else
- flags_to_clear|= bit;
- }
- }
- if (pos >= end)
- break;
-
- if (get_next_char(&pos, end, cs) != ',')
- goto err;
-
- start=pos;
- continue;
- err:
- *err_pos= (char*)start;
- *err_len= end - start;
- *set_warning= TRUE;
- break;
- }
- }
- ulonglong res= set_defaults? default_set : cur_set;
- res|= flags_to_set;
- res&= ~flags_to_clear;
- return res;
-}
-
-
/*
Function to find a string in a TYPELIB
(Same format as mysys/typelib.c)
@@ -543,3 +347,60 @@ int find_string_in_array(LEX_STRING * const haystack, LEX_STRING * const needle,
}
return -1;
}
+
+
+char *set_to_string(THD *thd, LEX_STRING *result, ulonglong set,
+ const char *lib[])
+{
+ char buff[STRING_BUFFER_USUAL_SIZE*8];
+ String tmp(buff, sizeof(buff), &my_charset_latin1);
+ LEX_STRING unused;
+
+ if (!result)
+ result= &unused;
+
+ tmp.length(0);
+
+ for (uint i= 0; set; i++, set >>= 1)
+ if (set & 1) {
+ tmp.append(lib[i]);
+ tmp.append(',');
+ }
+
+ if (tmp.length())
+ {
+ result->str= thd->strmake(tmp.ptr(), tmp.length()-1);
+ result->length= tmp.length()-1;
+ }
+ else
+ {
+ result->str= const_cast<char*>("");
+ result->length= 0;
+ }
+ return result->str;
+}
+
+char *flagset_to_string(THD *thd, LEX_STRING *result, ulonglong set,
+ const char *lib[])
+{
+ char buff[STRING_BUFFER_USUAL_SIZE*8];
+ String tmp(buff, sizeof(buff), &my_charset_latin1);
+ LEX_STRING unused;
+
+ if (!result) result= &unused;
+
+ tmp.length(0);
+
+ // note that the last element is always "default", and it's ignored below
+ for (uint i= 0; lib[i+1]; i++, set >>= 1)
+ {
+ tmp.append(lib[i]);
+ tmp.append(set & 1 ? "=on," : "=off,");
+ }
+
+ result->str= thd->strmake(tmp.ptr(), tmp.length()-1);
+ result->length= tmp.length()-1;
+
+ return result->str;
+}
+
diff --git a/sql/strfunc.h b/sql/strfunc.h
new file mode 100644
index 00000000000..f1eb83ff0de
--- /dev/null
+++ b/sql/strfunc.h
@@ -0,0 +1,51 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 STRFUNC_INCLUDED
+#define STRFUNC_INCLUDED
+
+#include "my_global.h" /* ulonglong, uint */
+
+typedef struct charset_info_st CHARSET_INFO;
+typedef struct st_mysql_lex_string LEX_STRING;
+typedef struct st_typelib TYPELIB;
+
+ulonglong find_set(TYPELIB *lib, const char *x, uint 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,
+ const char *str, uint length, CHARSET_INFO *cs,
+ char **err_pos, uint *err_len, bool *set_warning);
+uint find_type(const TYPELIB *lib, const char *find, uint length,
+ bool part_match);
+uint find_type2(const TYPELIB *lib, const char *find, uint length,
+ CHARSET_INFO *cs);
+void unhex_type2(TYPELIB *lib);
+uint check_word(TYPELIB *lib, const char *val, const char *end,
+ const char **end_of_word);
+int find_string_in_array(LEX_STRING * const haystack, LEX_STRING * const needle,
+ CHARSET_INFO * const cs);
+char *flagset_to_string(THD *thd, LEX_STRING *result, ulonglong set,
+ const char *lib[]);
+char *set_to_string(THD *thd, LEX_STRING *result, ulonglong set,
+ const char *lib[]);
+
+/*
+ These functions were protected by INNODB_COMPATIBILITY_HOOKS
+ */
+uint strconvert(CHARSET_INFO *from_cs, const char *from,
+ CHARSET_INFO *to_cs, char *to, uint to_length, uint *errors);
+
+#endif /* STRFUNC_INCLUDED */
diff --git a/sql/structs.h b/sql/structs.h
index 2546d241059..8290227830c 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -1,3 +1,6 @@
+#ifndef STRUCTS_INCLUDED
+#define STRUCTS_INCLUDED
+
/* Copyright (C) 2000-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -14,11 +17,20 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
/* The old structures from unireg */
-struct st_table;
+#include "sql_plugin.h" /* plugin_ref */
+#include "sql_const.h" /* MAX_REFLENGTH */
+#include "my_time.h" /* enum_mysql_timestamp_type */
+#include "thr_lock.h" /* thr_lock_type */
+#include "my_base.h" /* ha_rows, ha_key_alg */
+
+struct TABLE;
class Field;
+class THD;
+
typedef struct st_date_time_format {
uchar positions[8];
char time_separator; /* Separator between hour and minute */
@@ -97,7 +109,8 @@ typedef struct st_key {
union {
int bdb_return_if_eq;
} handler;
- struct st_table *table;
+ TABLE *table;
+ LEX_STRING comment;
} KEY;
@@ -115,36 +128,6 @@ typedef struct st_reginfo { /* Extra info about reg */
} REGINFO;
-class SQL_SELECT;
-class THD;
-class handler;
-struct st_join_table;
-
-void rr_unlock_row(st_join_table *tab);
-
-struct READ_RECORD { /* Parameter to read_record */
- typedef int (*Read_func)(READ_RECORD*);
- typedef void (*Unlock_row_func)(st_join_table *);
- struct st_table *table; /* Head-form */
- handler *file;
- struct st_table **forms; /* head and ref forms */
-
- Read_func read_record;
- Unlock_row_func unlock_row;
- THD *thd;
- SQL_SELECT *select;
- uint cache_records;
- uint ref_length,struct_length,reclength,rec_cache_size,error_offset;
- uint index;
- uchar *ref_pos; /* pointer to form->refpos */
- uchar *record;
- uchar *rec_buf; /* to read field values after filesort */
- uchar *cache,*cache_pos,*cache_end,*read_positions;
- IO_CACHE *io_cache;
- bool print_error, ignore_not_found_rows;
-};
-
-
/*
Originally MySQL used MYSQL_TIME structure inside server only, but since
4.1 it's exported to user in the new client API. Define aliases for
@@ -168,14 +151,12 @@ typedef struct st_known_date_time_format {
const char *time_format;
} KNOWN_DATE_TIME_FORMAT;
-enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED};
-
extern const char *show_comp_option_name[];
typedef int *(*update_var)(THD *, struct st_mysql_show_var *);
typedef struct st_lex_user {
- LEX_STRING user, host, password;
+ LEX_STRING user, host, password, plugin, auth;
} LEX_USER;
/*
@@ -386,3 +367,5 @@ public:
Discrete_interval* get_tail() const { return tail; };
Discrete_interval* get_current() const { return current; };
};
+
+#endif /* STRUCTS_INCLUDED */
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
new file mode 100644
index 00000000000..ed2c44fb03f
--- /dev/null
+++ b/sql/sys_vars.cc
@@ -0,0 +1,3121 @@
+/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 */
+
+/*
+ How to add new variables:
+
+ 1. copy one of the existing variables, and edit the declaration.
+ 2. if you need special behavior on assignment or additional checks
+ use ON_CHECK and ON_UPDATE callbacks.
+ 3. *Don't* add new Sys_var classes or uncle Occam will come
+ with his razor to haunt you at nights
+
+ Note - all storage engine variables (for example myisam_whatever)
+ should go into the corresponding storage engine sources
+ (for example in storage/myisam/ha_myisam.cc) !
+*/
+
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "sql_class.h" // set_var.h: THD
+#include "sys_vars.h"
+
+#include "events.h"
+#include <thr_alarm.h>
+#include "slave.h"
+#include "rpl_mi.h"
+#include "transaction.h"
+#include "mysqld.h"
+#include "lock.h"
+#include "sql_time.h" // known_date_time_formats
+#include "sql_acl.h" // SUPER_ACL,
+ // mysql_user_table_is_in_short_password_format
+#include "derror.h" // read_texts
+#include "sql_base.h" // close_cached_tables
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+#include "../storage/perfschema/pfs_server.h"
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
+/*
+ This forward declaration is needed because including sql_base.h
+ causes further includes. [TODO] Eliminate this forward declaration
+ and include a file with the prototype instead.
+*/
+extern void close_thread_tables(THD *thd);
+
+/*
+ The rule for this file: everything should be 'static'. When a sys_var
+ variable or a function from this file is - in very rare cases - needed
+ elsewhere it should be explicitly declared 'export' here to show that it's
+ not a mistakenly forgotten 'static' keyword.
+*/
+#define export /* not static */
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+
+#define PFS_TRAILING_PROPERTIES \
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL), ON_UPDATE(NULL), \
+ 0, NULL, sys_var::PARSE_EARLY
+
+static Sys_var_mybool Sys_pfs_enabled(
+ "performance_schema",
+ "Enable the performance schema.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_enabled),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_events_waits_history_long_size(
+ "performance_schema_events_waits_history_long_size",
+ "Number of rows in EVENTS_WAITS_HISTORY_LONG.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_events_waits_history_long_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
+ DEFAULT(PFS_WAITS_HISTORY_LONG_SIZE),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_events_waits_history_size(
+ "performance_schema_events_waits_history_size",
+ "Number of rows per thread in EVENTS_WAITS_HISTORY.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_events_waits_history_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024),
+ DEFAULT(PFS_WAITS_HISTORY_SIZE),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_cond_classes(
+ "performance_schema_max_cond_classes",
+ "Maximum number of condition instruments.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_cond_class_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256),
+ DEFAULT(PFS_MAX_COND_CLASS),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_cond_instances(
+ "performance_schema_max_cond_instances",
+ "Maximum number of instrumented condition objects.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_cond_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
+ DEFAULT(PFS_MAX_COND),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_file_classes(
+ "performance_schema_max_file_classes",
+ "Maximum number of file instruments.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_file_class_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256),
+ DEFAULT(PFS_MAX_FILE_CLASS),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_file_handles(
+ "performance_schema_max_file_handles",
+ "Maximum number of opened instrumented files.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_file_handle_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
+ DEFAULT(PFS_MAX_FILE_HANDLE),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_file_instances(
+ "performance_schema_max_file_instances",
+ "Maximum number of instrumented files.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_file_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
+ DEFAULT(PFS_MAX_FILE),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_mutex_classes(
+ "performance_schema_max_mutex_classes",
+ "Maximum number of mutex instruments.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_mutex_class_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256),
+ DEFAULT(PFS_MAX_MUTEX_CLASS),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_mutex_instances(
+ "performance_schema_max_mutex_instances",
+ "Maximum number of instrumented MUTEX objects.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_mutex_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 100*1024*1024),
+ DEFAULT(PFS_MAX_MUTEX),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_rwlock_classes(
+ "performance_schema_max_rwlock_classes",
+ "Maximum number of rwlock instruments.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_rwlock_class_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256),
+ DEFAULT(PFS_MAX_RWLOCK_CLASS),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_rwlock_instances(
+ "performance_schema_max_rwlock_instances",
+ "Maximum number of instrumented RWLOCK objects.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_rwlock_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 100*1024*1024),
+ DEFAULT(PFS_MAX_RWLOCK),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_table_handles(
+ "performance_schema_max_table_handles",
+ "Maximum number of opened instrumented tables.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_table_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
+ DEFAULT(PFS_MAX_TABLE),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_table_instances(
+ "performance_schema_max_table_instances",
+ "Maximum number of instrumented tables.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_table_share_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
+ DEFAULT(PFS_MAX_TABLE_SHARE),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_thread_classes(
+ "performance_schema_max_thread_classes",
+ "Maximum number of thread instruments.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_thread_class_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256),
+ DEFAULT(PFS_MAX_THREAD_CLASS),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_max_thread_instances(
+ "performance_schema_max_thread_instances",
+ "Maximum number of instrumented threads.",
+ READ_ONLY GLOBAL_VAR(pfs_param.m_thread_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
+ DEFAULT(PFS_MAX_THREAD),
+ BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
+static Sys_var_ulong Sys_auto_increment_increment(
+ "auto_increment_increment",
+ "Auto-increment columns are incremented by this",
+ SESSION_VAR(auto_increment_increment),
+ CMD_LINE(OPT_ARG),
+ VALID_RANGE(1, 65535), DEFAULT(1), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, IN_BINLOG);
+
+static Sys_var_ulong Sys_auto_increment_offset(
+ "auto_increment_offset",
+ "Offset added to Auto-increment columns. Used when "
+ "auto-increment-increment != 1",
+ SESSION_VAR(auto_increment_offset),
+ CMD_LINE(OPT_ARG),
+ VALID_RANGE(1, 65535), DEFAULT(1), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, IN_BINLOG);
+
+static Sys_var_mybool Sys_automatic_sp_privileges(
+ "automatic_sp_privileges",
+ "Creating and dropping stored procedures alters ACLs",
+ GLOBAL_VAR(sp_automatic_privileges),
+ CMD_LINE(OPT_ARG), DEFAULT(TRUE));
+
+static Sys_var_ulong Sys_back_log(
+ "back_log", "The number of outstanding connection requests "
+ "MySQL can have. This comes into play when the main MySQL thread "
+ "gets very many connection requests in a very short time",
+ READ_ONLY GLOBAL_VAR(back_log), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, 65535), DEFAULT(50), BLOCK_SIZE(1));
+
+static Sys_var_charptr Sys_basedir(
+ "basedir", "Path to installation directory. All paths are "
+ "usually resolved relative to this",
+ READ_ONLY GLOBAL_VAR(mysql_home_ptr), CMD_LINE(REQUIRED_ARG, 'b'),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_ulong Sys_binlog_cache_size(
+ "binlog_cache_size", "The size of the transactional cache for "
+ "updates to transactional engines for the binary log. "
+ "If you often use transactions containing many statements, "
+ "you can increase this to get more performance",
+ GLOBAL_VAR(binlog_cache_size),
+ CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(IO_SIZE, ULONG_MAX), DEFAULT(32768), BLOCK_SIZE(IO_SIZE));
+
+static Sys_var_ulong Sys_binlog_stmt_cache_size(
+ "binlog_stmt_cache_size", "The size of the statement cache for "
+ "updates to non-transactional engines for the binary log. "
+ "If you often use statements updating a great number of rows, "
+ "you can increase this to get more performance",
+ GLOBAL_VAR(binlog_stmt_cache_size),
+ CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(IO_SIZE, ULONG_MAX), DEFAULT(32768), BLOCK_SIZE(IO_SIZE));
+
+static bool check_has_super(sys_var *self, THD *thd, set_var *var)
+{
+ DBUG_ASSERT(self->scope() != sys_var::GLOBAL);// don't abuse check_has_super()
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (!(thd->security_ctx->master_access & SUPER_ACL))
+ {
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+ return true;
+ }
+#endif
+ return false;
+}
+static bool binlog_format_check(sys_var *self, THD *thd, set_var *var)
+{
+ if (check_has_super(self, thd, var))
+ return true;
+
+ if (var->type == OPT_GLOBAL)
+ return false;
+
+ /*
+ If RBR and open temporary tables, their CREATE TABLE may not be in the
+ binlog, so we can't toggle to SBR in this connection.
+
+ If binlog_format=MIXED, there are open temporary tables, and an unsafe
+ statement is executed, then subsequent statements are logged in row
+ format and hence changes to temporary tables may be lost. So we forbid
+ switching @@SESSION.binlog_format from MIXED to STATEMENT when there are
+ open temp tables and we are logging in row format.
+ */
+ if (thd->temporary_tables && var->type == OPT_SESSION &&
+ var->save_result.ulonglong_value == BINLOG_FORMAT_STMT &&
+ ((thd->variables.binlog_format == BINLOG_FORMAT_MIXED &&
+ thd->is_current_stmt_binlog_format_row()) ||
+ thd->variables.binlog_format == BINLOG_FORMAT_ROW))
+ {
+ my_error(ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR, MYF(0));
+ return true;
+ }
+
+ /*
+ if in a stored function/trigger, it's too late to change mode
+ */
+ if (thd->in_sub_stmt)
+ {
+ my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
+ return true;
+ }
+ /*
+ Make the session variable 'binlog_format' read-only inside a transaction.
+ */
+ if (thd->in_active_multi_stmt_transaction())
+ {
+ my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
+ return true;
+ }
+
+ return false;
+}
+
+static bool fix_binlog_format_after_update(sys_var *self, THD *thd,
+ enum_var_type type)
+{
+ if (type == OPT_SESSION)
+ thd->reset_current_stmt_binlog_format_row();
+ return false;
+}
+
+static Sys_var_enum Sys_binlog_format(
+ "binlog_format", "What form of binary logging the master will "
+ "use: either ROW for row-based binary logging, STATEMENT "
+ "for statement-based binary logging, or MIXED. MIXED is statement-"
+ "based binary logging except for those statements where only row-"
+ "based is correct: those which involve user-defined functions (i.e. "
+ "UDFs) or the UUID() function; for those, row-based binary logging is "
+ "automatically used. If NDBCLUSTER is enabled and binlog-format is "
+ "MIXED, the format switches to row-based and back implicitly per each "
+ "query accessing an NDBCLUSTER table",
+ SESSION_VAR(binlog_format), CMD_LINE(REQUIRED_ARG, OPT_BINLOG_FORMAT),
+ binlog_format_names, DEFAULT(BINLOG_FORMAT_STMT),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(binlog_format_check),
+ ON_UPDATE(fix_binlog_format_after_update));
+
+static bool binlog_direct_check(sys_var *self, THD *thd, set_var *var)
+{
+ if (check_has_super(self, thd, var))
+ return true;
+
+ if (var->type == OPT_GLOBAL)
+ return false;
+
+ /*
+ Makes the session variable 'binlog_direct_non_transactional_updates'
+ read-only if within a procedure, trigger or function.
+ */
+ if (thd->in_sub_stmt)
+ {
+ my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0));
+ return true;
+ }
+ /*
+ Makes the session variable 'binlog_direct_non_transactional_updates'
+ read-only inside a transaction.
+ */
+ if (thd->in_active_multi_stmt_transaction())
+ {
+ my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0));
+ return true;
+ }
+
+ return false;
+}
+
+static Sys_var_mybool Sys_binlog_direct(
+ "binlog_direct_non_transactional_updates",
+ "Causes updates to non-transactional engines using statement format to "
+ "be written directly to binary log. Before using this option make sure "
+ "that there are no dependencies between transactional and "
+ "non-transactional tables such as in the statement INSERT INTO t_myisam "
+ "SELECT * FROM t_innodb; otherwise, slaves may diverge from the master.",
+ SESSION_VAR(binlog_direct_non_trans_update),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(binlog_direct_check));
+
+static Sys_var_ulong Sys_bulk_insert_buff_size(
+ "bulk_insert_buffer_size", "Size of tree cache used in bulk "
+ "insert optimisation. Note that this is a limit per thread!",
+ SESSION_VAR(bulk_insert_buff_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, ULONG_MAX), DEFAULT(8192*1024), BLOCK_SIZE(1));
+
+static Sys_var_charptr Sys_character_sets_dir(
+ "character_sets_dir", "Directory where character sets are",
+ READ_ONLY GLOBAL_VAR(charsets_dir), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static bool check_not_null(sys_var *self, THD *thd, set_var *var)
+{
+ return var->value && var->value->is_null();
+}
+static bool check_charset(sys_var *self, THD *thd, set_var *var)
+{
+ if (!var->value)
+ return false;
+
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ if (var->value->result_type() == STRING_RESULT)
+ {
+ String str(buff, sizeof(buff), system_charset_info), *res;
+ if (!(res=var->value->val_str(&str)))
+ var->save_result.ptr= NULL;
+ else if (!(var->save_result.ptr= get_charset_by_csname(res->c_ptr(),
+ MY_CS_PRIMARY,
+ MYF(0))) &&
+ !(var->save_result.ptr= get_old_charset_by_name(res->c_ptr())))
+ {
+ ErrConvString err(res);
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), err.ptr());
+ return true;
+ }
+ }
+ else // INT_RESULT
+ {
+ int csno= (int)var->value->val_int();
+ if (!(var->save_result.ptr= get_charset(csno, MYF(0))))
+ {
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), llstr(csno, buff));
+ return true;
+ }
+ }
+ return false;
+}
+static bool check_charset_not_null(sys_var *self, THD *thd, set_var *var)
+{
+ return check_charset(self, thd, var) || check_not_null(self, thd, var);
+}
+static Sys_var_struct Sys_character_set_system(
+ "character_set_system", "The character set used by the server "
+ "for storing identifiers",
+ READ_ONLY GLOBAL_VAR(system_charset_info), NO_CMD_LINE,
+ offsetof(CHARSET_INFO, csname), DEFAULT(0));
+
+static Sys_var_struct Sys_character_set_server(
+ "character_set_server", "The default character set",
+ SESSION_VAR(collation_server), NO_CMD_LINE,
+ offsetof(CHARSET_INFO, csname), DEFAULT(&default_charset_info),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_charset_not_null));
+
+static bool check_charset_db(sys_var *self, THD *thd, set_var *var)
+{
+ if (check_charset_not_null(self, thd, var))
+ return true;
+ if (!var->value) // = DEFAULT
+ var->save_result.ptr= thd->db_charset;
+ return false;
+}
+static Sys_var_struct Sys_character_set_database(
+ "character_set_database",
+ " The character set used by the default database",
+ SESSION_VAR(collation_database), NO_CMD_LINE,
+ offsetof(CHARSET_INFO, csname), DEFAULT(&default_charset_info),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_charset_db));
+
+static bool check_cs_client(sys_var *self, THD *thd, set_var *var)
+{
+ if (check_charset_not_null(self, thd, var))
+ return true;
+
+ // Currently, UCS-2 cannot be used as a client character set
+ if (((CHARSET_INFO *)(var->save_result.ptr))->mbminlen > 1)
+ return true;
+
+ return false;
+}
+static bool fix_thd_charset(sys_var *self, THD *thd, enum_var_type type)
+{
+ if (type == OPT_SESSION)
+ thd->update_charset();
+ return false;
+}
+static Sys_var_struct Sys_character_set_client(
+ "character_set_client", "The character set for statements "
+ "that arrive from the client",
+ SESSION_VAR(character_set_client), NO_CMD_LINE,
+ offsetof(CHARSET_INFO, csname), DEFAULT(&default_charset_info),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_cs_client),
+ ON_UPDATE(fix_thd_charset));
+
+static Sys_var_struct Sys_character_set_connection(
+ "character_set_connection", "The character set used for "
+ "literals that do not have a character set introducer and for "
+ "number-to-string conversion",
+ SESSION_VAR(collation_connection), NO_CMD_LINE,
+ offsetof(CHARSET_INFO, csname), DEFAULT(&default_charset_info),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_charset_not_null),
+ ON_UPDATE(fix_thd_charset));
+
+static Sys_var_struct Sys_character_set_results(
+ "character_set_results", "The character set used for returning "
+ "query results to the client",
+ SESSION_VAR(character_set_results), NO_CMD_LINE,
+ offsetof(CHARSET_INFO, csname), DEFAULT(&default_charset_info),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_charset));
+
+static Sys_var_struct Sys_character_set_filesystem(
+ "character_set_filesystem", "The filesystem character set",
+ SESSION_VAR(character_set_filesystem), NO_CMD_LINE,
+ offsetof(CHARSET_INFO, csname), DEFAULT(&character_set_filesystem),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_charset_not_null),
+ ON_UPDATE(fix_thd_charset));
+
+static const char *completion_type_names[]= {"NO_CHAIN", "CHAIN", "RELEASE", 0};
+static Sys_var_enum Sys_completion_type(
+ "completion_type", "The transaction completion type, one of "
+ "NO_CHAIN, CHAIN, RELEASE",
+ SESSION_VAR(completion_type), CMD_LINE(REQUIRED_ARG),
+ completion_type_names, DEFAULT(0));
+
+static bool check_collation_not_null(sys_var *self, THD *thd, set_var *var)
+{
+ if (!var->value)
+ return false;
+
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ if (var->value->result_type() == STRING_RESULT)
+ {
+ String str(buff, sizeof(buff), system_charset_info), *res;
+ if (!(res= var->value->val_str(&str)))
+ var->save_result.ptr= NULL;
+ else if (!(var->save_result.ptr= get_charset_by_name(res->c_ptr(), MYF(0))))
+ {
+ ErrConvString err(res);
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), err.ptr());
+ return true;
+ }
+ }
+ else // INT_RESULT
+ {
+ int csno= (int)var->value->val_int();
+ if (!(var->save_result.ptr= get_charset(csno, MYF(0))))
+ {
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), llstr(csno, buff));
+ return true;
+ }
+ }
+ return check_not_null(self, thd, var);
+}
+static Sys_var_struct Sys_collation_connection(
+ "collation_connection", "The collation of the connection "
+ "character set",
+ SESSION_VAR(collation_connection), NO_CMD_LINE,
+ offsetof(CHARSET_INFO, name), DEFAULT(&default_charset_info),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_collation_not_null),
+ ON_UPDATE(fix_thd_charset));
+
+static bool check_collation_db(sys_var *self, THD *thd, set_var *var)
+{
+ if (check_collation_not_null(self, thd, var))
+ return true;
+ if (!var->value) // = DEFAULT
+ var->save_result.ptr= thd->db_charset;
+ return false;
+}
+static Sys_var_struct Sys_collation_database(
+ "collation_database", "The collation of the database "
+ "character set",
+ SESSION_VAR(collation_database), NO_CMD_LINE,
+ offsetof(CHARSET_INFO, name), DEFAULT(&default_charset_info),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_collation_db));
+
+static Sys_var_struct Sys_collation_server(
+ "collation_server", "The server default collation",
+ SESSION_VAR(collation_server), NO_CMD_LINE,
+ offsetof(CHARSET_INFO, name), DEFAULT(&default_charset_info),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_collation_not_null));
+
+static const char *concurrent_insert_names[]= {"NEVER", "AUTO", "ALWAYS", 0};
+static Sys_var_enum Sys_concurrent_insert(
+ "concurrent_insert", "Use concurrent insert with MyISAM. Possible "
+ "values are NEVER, AUTO, ALWAYS",
+ GLOBAL_VAR(myisam_concurrent_insert), CMD_LINE(OPT_ARG),
+ concurrent_insert_names, DEFAULT(1));
+
+static Sys_var_ulong Sys_connect_timeout(
+ "connect_timeout",
+ "The number of seconds the mysqld server is waiting for a connect "
+ "packet before responding with 'Bad handshake'",
+ GLOBAL_VAR(connect_timeout), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(2, LONG_TIMEOUT), DEFAULT(CONNECT_TIMEOUT), BLOCK_SIZE(1));
+
+static Sys_var_charptr Sys_datadir(
+ "datadir", "Path to the database root directory",
+ READ_ONLY GLOBAL_VAR(mysql_real_data_home_ptr),
+ CMD_LINE(REQUIRED_ARG, 'h'), IN_FS_CHARSET, DEFAULT(0));
+
+#ifndef DBUG_OFF
+static Sys_var_dbug Sys_dbug(
+ "debug", "Debug log", sys_var::SESSION,
+ CMD_LINE(OPT_ARG, '#'), DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_has_super));
+#endif
+
+/**
+ @todo
+ When updating myisam_delay_key_write, we should do a 'flush tables'
+ of all MyISAM tables to ensure that they are reopen with the
+ new attribute.
+*/
+export bool fix_delay_key_write(sys_var *self, THD *thd, enum_var_type type)
+{
+ switch (delay_key_write_options) {
+ case DELAY_KEY_WRITE_NONE:
+ myisam_delay_key_write=0;
+ break;
+ case DELAY_KEY_WRITE_ON:
+ myisam_delay_key_write=1;
+ break;
+ case DELAY_KEY_WRITE_ALL:
+ myisam_delay_key_write=1;
+ ha_open_options|= HA_OPEN_DELAY_KEY_WRITE;
+ break;
+ }
+ return false;
+}
+static const char *delay_key_write_names[]= { "OFF", "ON", "ALL", NullS };
+static Sys_var_enum Sys_delay_key_write(
+ "delay_key_write", "Type of DELAY_KEY_WRITE",
+ GLOBAL_VAR(delay_key_write_options), CMD_LINE(OPT_ARG),
+ delay_key_write_names, DEFAULT(DELAY_KEY_WRITE_ON),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_delay_key_write));
+
+static Sys_var_ulong Sys_delayed_insert_limit(
+ "delayed_insert_limit",
+ "After inserting delayed_insert_limit rows, the INSERT DELAYED "
+ "handler will check if there are any SELECT statements pending. "
+ "If so, it allows these to execute before continuing",
+ GLOBAL_VAR(delayed_insert_limit), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, ULONG_MAX), DEFAULT(DELAYED_LIMIT), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_delayed_insert_timeout(
+ "delayed_insert_timeout",
+ "How long a INSERT DELAYED thread should wait for INSERT statements "
+ "before terminating",
+ GLOBAL_VAR(delayed_insert_timeout), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(DELAYED_WAIT_TIMEOUT),
+ BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_delayed_queue_size(
+ "delayed_queue_size",
+ "What size queue (in rows) should be allocated for handling INSERT "
+ "DELAYED. If the queue becomes full, any client that does INSERT "
+ "DELAYED will wait until there is room in the queue again",
+ GLOBAL_VAR(delayed_queue_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, ULONG_MAX), DEFAULT(DELAYED_QUEUE_SIZE), BLOCK_SIZE(1));
+
+#ifdef HAVE_EVENT_SCHEDULER
+static const char *event_scheduler_names[]= { "OFF", "ON", "DISABLED", NullS };
+static bool event_scheduler_check(sys_var *self, THD *thd, set_var *var)
+{
+ /* DISABLED is only accepted on the command line */
+ if (var->save_result.ulonglong_value == Events::EVENTS_DISABLED)
+ return true;
+ /*
+ If the scheduler was disabled because there are no/bad
+ system tables, produce a more meaningful error message
+ than ER_OPTION_PREVENTS_STATEMENT
+ */
+ if (Events::check_if_system_tables_error())
+ return true;
+ if (Events::opt_event_scheduler == Events::EVENTS_DISABLED)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
+ "--event-scheduler=DISABLED or --skip-grant-tables");
+ return true;
+ }
+ return false;
+}
+static bool event_scheduler_update(sys_var *self, THD *thd, enum_var_type type)
+{
+ uint opt_event_scheduler_value= Events::opt_event_scheduler;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ /*
+ Events::start() is heavyweight. In particular it creates a new THD,
+ which takes LOCK_global_system_variables internally.
+ Thus we have to release it here.
+ We need to re-take it before returning, though.
+
+ Note that since we release LOCK_global_system_variables before calling
+ start/stop, there is a possibility that the server variable
+ can become out of sync with the real event scheduler state.
+
+ This can happen with two concurrent statments if the first gets
+ interrupted after start/stop but before retaking
+ LOCK_global_system_variables. However, this problem should be quite
+ rare and it's difficult to avoid it without opening up possibilities
+ for deadlocks. See bug#51160.
+ */
+ bool ret= opt_event_scheduler_value == Events::EVENTS_ON
+ ? Events::start()
+ : Events::stop();
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ if (ret)
+ my_error(ER_EVENT_SET_VAR_ERROR, MYF(0));
+ return ret;
+}
+
+static Sys_var_enum Sys_event_scheduler(
+ "event_scheduler", "Enable the event scheduler. Possible values are "
+ "ON, OFF, and DISABLED (keep the event scheduler completely "
+ "deactivated, it cannot be activated run-time)",
+ GLOBAL_VAR(Events::opt_event_scheduler), CMD_LINE(OPT_ARG),
+ event_scheduler_names, DEFAULT(Events::EVENTS_OFF),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(event_scheduler_check), ON_UPDATE(event_scheduler_update));
+#endif
+
+static Sys_var_ulong Sys_expire_logs_days(
+ "expire_logs_days",
+ "If non-zero, binary logs will be purged after expire_logs_days "
+ "days; possible purges happen at startup and at binary log rotation",
+ GLOBAL_VAR(expire_logs_days),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 99), DEFAULT(0), BLOCK_SIZE(1));
+
+static Sys_var_mybool Sys_flush(
+ "flush", "Flush MyISAM tables to disk between SQL commands",
+ GLOBAL_VAR(myisam_flush),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_ulong Sys_flush_time(
+ "flush_time",
+ "A dedicated thread is created to flush all tables at the "
+ "given interval",
+ GLOBAL_VAR(flush_time),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, LONG_TIMEOUT),
+ DEFAULT(FLUSH_TIME), BLOCK_SIZE(1));
+
+static bool check_ftb_syntax(sys_var *self, THD *thd, set_var *var)
+{
+ return ft_boolean_check_syntax_string((uchar*)
+ (var->save_result.string_value.str));
+}
+static bool query_cache_flush(sys_var *self, THD *thd, enum_var_type type)
+{
+#ifdef HAVE_QUERY_CACHE
+ query_cache.flush();
+#endif /* HAVE_QUERY_CACHE */
+ return false;
+}
+/// @todo make SESSION_VAR (usability enhancement and a fix for a race condition)
+static Sys_var_charptr Sys_ft_boolean_syntax(
+ "ft_boolean_syntax", "List of operators for "
+ "MATCH ... AGAINST ( ... IN BOOLEAN MODE)",
+ GLOBAL_VAR(ft_boolean_syntax),
+ CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ DEFAULT(DEFAULT_FTB_SYNTAX), NO_MUTEX_GUARD,
+ NOT_IN_BINLOG, ON_CHECK(check_ftb_syntax), ON_UPDATE(query_cache_flush));
+
+static Sys_var_ulong Sys_ft_max_word_len(
+ "ft_max_word_len",
+ "The maximum length of the word to be included in a FULLTEXT index. "
+ "Note: FULLTEXT indexes must be rebuilt after changing this variable",
+ READ_ONLY GLOBAL_VAR(ft_max_word_len), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(10, HA_FT_MAXCHARLEN), DEFAULT(HA_FT_MAXCHARLEN),
+ BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_ft_min_word_len(
+ "ft_min_word_len",
+ "The minimum length of the word to be included in a FULLTEXT index. "
+ "Note: FULLTEXT indexes must be rebuilt after changing this variable",
+ READ_ONLY GLOBAL_VAR(ft_min_word_len), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, HA_FT_MAXCHARLEN), DEFAULT(4), BLOCK_SIZE(1));
+
+/// @todo make it an updatable SESSION_VAR
+static Sys_var_ulong Sys_ft_query_expansion_limit(
+ "ft_query_expansion_limit",
+ "Number of best matches to use for query expansion",
+ READ_ONLY GLOBAL_VAR(ft_query_expansion_limit),
+ CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 1000), DEFAULT(20), BLOCK_SIZE(1));
+
+static Sys_var_charptr Sys_ft_stopword_file(
+ "ft_stopword_file",
+ "Use stopwords from this file instead of built-in list",
+ READ_ONLY GLOBAL_VAR(ft_stopword_file), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_mybool Sys_ignore_builtin_innodb(
+ "ignore_builtin_innodb",
+ "Disable initialization of builtin InnoDB plugin",
+ READ_ONLY GLOBAL_VAR(opt_ignore_builtin_innodb),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static bool check_init_string(sys_var *self, THD *thd, set_var *var)
+{
+ if (var->save_result.string_value.str == 0)
+ {
+ var->save_result.string_value.str= const_cast<char*>("");
+ var->save_result.string_value.length= 0;
+ }
+ return false;
+}
+static PolyLock_rwlock PLock_sys_init_connect(&LOCK_sys_init_connect);
+static Sys_var_lexstring Sys_init_connect(
+ "init_connect", "Command(s) that are executed for each "
+ "new connection", GLOBAL_VAR(opt_init_connect),
+ CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ DEFAULT(""), &PLock_sys_init_connect, NOT_IN_BINLOG,
+ ON_CHECK(check_init_string));
+
+static Sys_var_charptr Sys_init_file(
+ "init_file", "Read SQL commands from this file at startup",
+ READ_ONLY GLOBAL_VAR(opt_init_file),
+#ifdef DISABLE_GRANT_OPTIONS
+ NO_CMD_LINE,
+#else
+ CMD_LINE(REQUIRED_ARG),
+#endif
+ IN_FS_CHARSET, DEFAULT(0));
+
+static PolyLock_rwlock PLock_sys_init_slave(&LOCK_sys_init_slave);
+static Sys_var_lexstring Sys_init_slave(
+ "init_slave", "Command(s) that are executed by a slave server "
+ "each time the SQL thread starts", GLOBAL_VAR(opt_init_slave),
+ CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ DEFAULT(""), &PLock_sys_init_slave,
+ NOT_IN_BINLOG, ON_CHECK(check_init_string));
+
+static Sys_var_ulong Sys_interactive_timeout(
+ "interactive_timeout",
+ "The number of seconds the server waits for activity on an interactive "
+ "connection before closing it",
+ SESSION_VAR(net_interactive_timeout),
+ CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(NET_WAIT_TIMEOUT), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_join_buffer_size(
+ "join_buffer_size",
+ "The size of the buffer that is used for full joins",
+ SESSION_VAR(join_buff_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(128, ULONG_MAX), DEFAULT(128*1024), BLOCK_SIZE(128));
+
+static Sys_var_keycache Sys_key_buffer_size(
+ "key_buffer_size", "The size of the buffer used for "
+ "index blocks for MyISAM tables. Increase this to get better index "
+ "handling (for all reads and multiple writes) to as much as you can "
+ "afford",
+ KEYCACHE_VAR(param_buff_size),
+ CMD_LINE(REQUIRED_ARG, OPT_KEY_BUFFER_SIZE),
+ VALID_RANGE(0, SIZE_T_MAX), DEFAULT(KEY_CACHE_SIZE),
+ BLOCK_SIZE(IO_SIZE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(update_buffer_size));
+
+static Sys_var_keycache Sys_key_cache_block_size(
+ "key_cache_block_size", "The default size of key cache blocks",
+ KEYCACHE_VAR(param_block_size),
+ CMD_LINE(REQUIRED_ARG, OPT_KEY_CACHE_BLOCK_SIZE),
+ VALID_RANGE(512, 1024*16), DEFAULT(KEY_CACHE_BLOCK_SIZE),
+ BLOCK_SIZE(512), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(update_keycache_param));
+
+static Sys_var_keycache Sys_key_cache_division_limit(
+ "key_cache_division_limit",
+ "The minimum percentage of warm blocks in key cache",
+ KEYCACHE_VAR(param_division_limit),
+ CMD_LINE(REQUIRED_ARG, OPT_KEY_CACHE_DIVISION_LIMIT),
+ VALID_RANGE(1, 100), DEFAULT(100),
+ BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(update_keycache_param));
+
+static Sys_var_keycache Sys_key_cache_age_threshold(
+ "key_cache_age_threshold", "This characterizes the number of "
+ "hits a hot block has to be untouched until it is considered aged "
+ "enough to be downgraded to a warm block. This specifies the "
+ "percentage ratio of that number of hits to the total number of "
+ "blocks in key cache",
+ KEYCACHE_VAR(param_age_threshold),
+ CMD_LINE(REQUIRED_ARG, OPT_KEY_CACHE_AGE_THRESHOLD),
+ VALID_RANGE(100, ULONG_MAX), DEFAULT(300),
+ BLOCK_SIZE(100), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(update_keycache_param));
+
+static Sys_var_mybool Sys_large_files_support(
+ "large_files_support",
+ "Whether mysqld was compiled with options for large file support",
+ READ_ONLY GLOBAL_VAR(opt_large_files),
+ NO_CMD_LINE, DEFAULT(sizeof(my_off_t) > 4));
+
+static Sys_var_uint Sys_large_page_size(
+ "large_page_size",
+ "If large page support is enabled, this shows the size of memory pages",
+ READ_ONLY GLOBAL_VAR(opt_large_page_size), NO_CMD_LINE,
+ VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1));
+
+static Sys_var_mybool Sys_large_pages(
+ "large_pages", "Enable support for large pages",
+ READ_ONLY GLOBAL_VAR(opt_large_pages),
+ IF_WIN(NO_CMD_LINE, CMD_LINE(OPT_ARG)), DEFAULT(FALSE));
+
+static Sys_var_charptr Sys_language(
+ "lc_messages_dir", "Directory where error messages are",
+ READ_ONLY GLOBAL_VAR(lc_messages_dir_ptr), CMD_LINE(REQUIRED_ARG, 'L'),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_mybool Sys_local_infile(
+ "local_infile", "Enable LOAD DATA LOCAL INFILE",
+ GLOBAL_VAR(opt_local_infile), CMD_LINE(OPT_ARG), DEFAULT(TRUE));
+
+static Sys_var_ulong Sys_lock_wait_timeout(
+ "lock_wait_timeout",
+ "Timeout in seconds to wait for a lock before returning an error.",
+ SESSION_VAR(lock_wait_timeout), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(LONG_TIMEOUT), BLOCK_SIZE(1));
+
+#ifdef HAVE_MLOCKALL
+static Sys_var_mybool Sys_locked_in_memory(
+ "locked_in_memory",
+ "Whether mysqld was locked in memory with --memlock",
+ READ_ONLY GLOBAL_VAR(locked_in_memory), NO_CMD_LINE, DEFAULT(FALSE));
+#endif
+
+/* this says NO_CMD_LINE, as command-line option takes a string, not a bool */
+static Sys_var_mybool Sys_log_bin(
+ "log_bin", "Whether the binary log is enabled",
+ READ_ONLY GLOBAL_VAR(opt_bin_log), NO_CMD_LINE, DEFAULT(FALSE));
+
+static Sys_var_mybool Sys_trust_function_creators(
+ "log_bin_trust_function_creators",
+ "If set to FALSE (the default), then when --log-bin is used, creation "
+ "of a stored function (or trigger) is allowed only to users having the "
+ "SUPER privilege and only if this stored function (trigger) may not "
+ "break binary logging. Note that if ALL connections to this server "
+ "ALWAYS use row-based binary logging, the security issues do not "
+ "exist and the binary logging cannot break, so you can safely set "
+ "this to TRUE",
+ GLOBAL_VAR(trust_function_creators),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_charptr Sys_log_error(
+ "log_error", "Error log file",
+ READ_ONLY GLOBAL_VAR(log_error_file_ptr),
+ CMD_LINE(OPT_ARG, OPT_LOG_ERROR),
+ IN_FS_CHARSET, DEFAULT(disabled_my_option));
+
+static Sys_var_mybool Sys_log_queries_not_using_indexes(
+ "log_queries_not_using_indexes",
+ "Log queries that are executed without benefit of any index to the "
+ "slow log if it is open",
+ GLOBAL_VAR(opt_log_queries_not_using_indexes),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_ulong Sys_log_warnings(
+ "log_warnings",
+ "Log some not critical warnings to the log file",
+ SESSION_VAR(log_warnings),
+ CMD_LINE(OPT_ARG, 'W'),
+ VALID_RANGE(0, ULONG_MAX), DEFAULT(1), BLOCK_SIZE(1));
+
+static bool update_cached_long_query_time(sys_var *self, THD *thd,
+ enum_var_type type)
+{
+ if (type == OPT_SESSION)
+ thd->variables.long_query_time=
+ double2ulonglong(thd->variables.long_query_time_double * 1e6);
+ else
+ global_system_variables.long_query_time=
+ double2ulonglong(global_system_variables.long_query_time_double * 1e6);
+ return false;
+}
+
+static Sys_var_double Sys_long_query_time(
+ "long_query_time",
+ "Log all queries that have taken more than long_query_time seconds "
+ "to execute to file. The argument will be treated as a decimal value "
+ "with microsecond precision",
+ SESSION_VAR(long_query_time_double),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, LONG_TIMEOUT), DEFAULT(10),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(update_cached_long_query_time));
+
+static bool fix_low_prio_updates(sys_var *self, THD *thd, enum_var_type type)
+{
+ if (type == OPT_SESSION)
+ thd->update_lock_default= (thd->variables.low_priority_updates ?
+ TL_WRITE_LOW_PRIORITY : TL_WRITE);
+ else
+ thr_upgraded_concurrent_insert_lock=
+ (global_system_variables.low_priority_updates ?
+ TL_WRITE_LOW_PRIORITY : TL_WRITE);
+ return false;
+}
+static Sys_var_mybool Sys_low_priority_updates(
+ "low_priority_updates",
+ "INSERT/DELETE/UPDATE has lower priority than selects",
+ SESSION_VAR(low_priority_updates),
+ CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_low_prio_updates));
+
+#ifndef TO_BE_DELETED /* Alias for the low_priority_updates */
+static Sys_var_mybool Sys_sql_low_priority_updates(
+ "sql_low_priority_updates",
+ "INSERT/DELETE/UPDATE has lower priority than selects",
+ SESSION_VAR(low_priority_updates), NO_CMD_LINE,
+ DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_low_prio_updates));
+#endif
+
+static Sys_var_mybool Sys_lower_case_file_system(
+ "lower_case_file_system",
+ "Case sensitivity of file names on the file system where the "
+ "data directory is located",
+ READ_ONLY GLOBAL_VAR(lower_case_file_system), NO_CMD_LINE,
+ DEFAULT(FALSE));
+
+static Sys_var_uint Sys_lower_case_table_names(
+ "lower_case_table_names",
+ "If set to 1 table names are stored in lowercase on disk and table "
+ "names will be case-insensitive. Should be set to 2 if you are using "
+ "a case insensitive file system",
+ READ_ONLY GLOBAL_VAR(lower_case_table_names),
+ CMD_LINE(OPT_ARG, OPT_LOWER_CASE_TABLE_NAMES),
+ VALID_RANGE(0, 2),
+#ifdef FN_NO_CASE_SENSE
+ DEFAULT(1),
+#else
+ DEFAULT(0),
+#endif
+ BLOCK_SIZE(1));
+
+static bool session_readonly(sys_var *self, THD *thd, set_var *var)
+{
+ if (var->type == OPT_GLOBAL)
+ return false;
+ my_error(ER_VARIABLE_IS_READONLY, MYF(0), "SESSION",
+ self->name.str, "GLOBAL");
+ return true;
+}
+static Sys_var_ulong Sys_max_allowed_packet(
+ "max_allowed_packet",
+ "Max packet length to send to or receive from the server",
+ SESSION_VAR(max_allowed_packet), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1024, 1024*1024*1024), DEFAULT(1024*1024),
+ BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(session_readonly));
+
+static Sys_var_ulonglong Sys_max_binlog_cache_size(
+ "max_binlog_cache_size",
+ "Sets the total size of the transactional cache",
+ GLOBAL_VAR(max_binlog_cache_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(IO_SIZE, ULONGLONG_MAX),
+ DEFAULT((ULONGLONG_MAX/IO_SIZE)*IO_SIZE),
+ BLOCK_SIZE(IO_SIZE));
+
+static Sys_var_ulonglong Sys_max_binlog_stmt_cache_size(
+ "max_binlog_stmt_cache_size",
+ "Sets the total size of the statement cache",
+ GLOBAL_VAR(max_binlog_stmt_cache_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(IO_SIZE, ULONGLONG_MAX),
+ DEFAULT((ULONGLONG_MAX/IO_SIZE)*IO_SIZE),
+ BLOCK_SIZE(IO_SIZE));
+
+static bool fix_max_binlog_size(sys_var *self, THD *thd, enum_var_type type)
+{
+ mysql_bin_log.set_max_size(max_binlog_size);
+#ifdef HAVE_REPLICATION
+ if (!max_relay_log_size)
+ active_mi->rli.relay_log.set_max_size(max_binlog_size);
+#endif
+ return false;
+}
+static Sys_var_ulong Sys_max_binlog_size(
+ "max_binlog_size",
+ "Binary log will be rotated automatically when the size exceeds this "
+ "value. Will also apply to relay logs if max_relay_log_size is 0",
+ GLOBAL_VAR(max_binlog_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(IO_SIZE, 1024*1024L*1024L), DEFAULT(1024*1024L*1024L),
+ BLOCK_SIZE(IO_SIZE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_max_binlog_size));
+
+static bool fix_max_connections(sys_var *self, THD *thd, enum_var_type type)
+{
+#ifndef EMBEDDED_LIBRARY
+ resize_thr_alarm(max_connections +
+ global_system_variables.max_insert_delayed_threads + 10);
+#endif
+ return false;
+}
+
+// Default max_connections of 151 is larger than Apache's default max
+// children, to avoid "too many connections" error in a common setup
+static Sys_var_ulong Sys_max_connections(
+ "max_connections", "The number of simultaneous clients allowed",
+ GLOBAL_VAR(max_connections), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, 100000), DEFAULT(151), BLOCK_SIZE(1), NO_MUTEX_GUARD,
+ NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_max_connections));
+
+static Sys_var_ulong Sys_max_connect_errors(
+ "max_connect_errors",
+ "If there is more than this number of interrupted connections from "
+ "a host this host will be blocked from further connections",
+ GLOBAL_VAR(max_connect_errors), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, ULONG_MAX), DEFAULT(MAX_CONNECT_ERRORS),
+ BLOCK_SIZE(1));
+
+static bool check_max_delayed_threads(sys_var *self, THD *thd, set_var *var)
+{
+ return var->type != OPT_GLOBAL &&
+ var->save_result.ulonglong_value != 0 &&
+ var->save_result.ulonglong_value !=
+ global_system_variables.max_insert_delayed_threads;
+}
+
+// Alias for max_delayed_threads
+static Sys_var_ulong Sys_max_insert_delayed_threads(
+ "max_insert_delayed_threads",
+ "Don't start more than this number of threads to handle INSERT "
+ "DELAYED statements. If set to zero INSERT DELAYED will be not used",
+ SESSION_VAR(max_insert_delayed_threads),
+ NO_CMD_LINE, VALID_RANGE(0, 16384), DEFAULT(20),
+ BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_max_delayed_threads), ON_UPDATE(fix_max_connections));
+
+static Sys_var_ulong Sys_max_delayed_threads(
+ "max_delayed_threads",
+ "Don't start more than this number of threads to handle INSERT "
+ "DELAYED statements. If set to zero INSERT DELAYED will be not used",
+ SESSION_VAR(max_insert_delayed_threads),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 16384), DEFAULT(20),
+ BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_max_delayed_threads), ON_UPDATE(fix_max_connections));
+
+static Sys_var_ulong Sys_max_error_count(
+ "max_error_count",
+ "Max number of errors/warnings to store for a statement",
+ SESSION_VAR(max_error_count), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 65535), DEFAULT(DEFAULT_ERROR_COUNT), BLOCK_SIZE(1));
+
+static Sys_var_ulonglong Sys_max_heap_table_size(
+ "max_heap_table_size",
+ "Don't allow creation of heap tables bigger than this",
+ SESSION_VAR(max_heap_table_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(16384, (ulonglong)~(intptr)0), DEFAULT(16*1024*1024),
+ BLOCK_SIZE(1024));
+
+static Sys_var_ulong Sys_pseudo_thread_id(
+ "pseudo_thread_id",
+ "This variable is for internal server use",
+ SESSION_ONLY(pseudo_thread_id),
+ NO_CMD_LINE, VALID_RANGE(0, ULONG_MAX), DEFAULT(0),
+ BLOCK_SIZE(1), NO_MUTEX_GUARD, IN_BINLOG,
+ ON_CHECK(check_has_super));
+
+static bool fix_max_join_size(sys_var *self, THD *thd, enum_var_type type)
+{
+ SV *sv= type == OPT_GLOBAL ? &global_system_variables : &thd->variables;
+ if (sv->max_join_size == HA_POS_ERROR)
+ sv->option_bits|= OPTION_BIG_SELECTS;
+ else
+ sv->option_bits&= ~OPTION_BIG_SELECTS;
+ return false;
+}
+static Sys_var_harows Sys_max_join_size(
+ "max_join_size",
+ "Joins that are probably going to read more than max_join_size "
+ "records return an error",
+ SESSION_VAR(max_join_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, HA_POS_ERROR), DEFAULT(HA_POS_ERROR), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_max_join_size));
+
+static Sys_var_ulong Sys_max_seeks_for_key(
+ "max_seeks_for_key",
+ "Limit assumed max number of seeks when looking up rows based on a key",
+ SESSION_VAR(max_seeks_for_key), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, ULONG_MAX), DEFAULT(ULONG_MAX), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_max_length_for_sort_data(
+ "max_length_for_sort_data",
+ "Max number of bytes in sorted records",
+ SESSION_VAR(max_length_for_sort_data), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(4, 8192*1024L), DEFAULT(1024), BLOCK_SIZE(1));
+
+static Sys_var_harows Sys_sql_max_join_size(
+ "sql_max_join_size", "Alias for max_join_size",
+ SESSION_VAR(max_join_size), NO_CMD_LINE,
+ VALID_RANGE(1, HA_POS_ERROR), DEFAULT(HA_POS_ERROR), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_max_join_size), DEPRECATED(70000, 0));
+
+static PolyLock_mutex PLock_prepared_stmt_count(&LOCK_prepared_stmt_count);
+static Sys_var_ulong Sys_max_prepared_stmt_count(
+ "max_prepared_stmt_count",
+ "Maximum number of prepared statements in the server",
+ GLOBAL_VAR(max_prepared_stmt_count), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 1024*1024), DEFAULT(16382), BLOCK_SIZE(1),
+ &PLock_prepared_stmt_count);
+
+static bool fix_max_relay_log_size(sys_var *self, THD *thd, enum_var_type type)
+{
+#ifdef HAVE_REPLICATION
+ active_mi->rli.relay_log.set_max_size(max_relay_log_size ?
+ max_relay_log_size: max_binlog_size);
+#endif
+ return false;
+}
+static Sys_var_ulong Sys_max_relay_log_size(
+ "max_relay_log_size",
+ "If non-zero: relay log will be rotated automatically when the "
+ "size exceeds this value; if zero: when the size "
+ "exceeds max_binlog_size",
+ GLOBAL_VAR(max_relay_log_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 1024L*1024*1024), DEFAULT(0), BLOCK_SIZE(IO_SIZE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_max_relay_log_size));
+
+static Sys_var_ulong Sys_max_sort_length(
+ "max_sort_length",
+ "The number of bytes to use when sorting BLOB or TEXT values (only "
+ "the first max_sort_length bytes of each value are used; the rest "
+ "are ignored)",
+ SESSION_VAR(max_sort_length), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(4, 8192*1024L), DEFAULT(1024), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_max_sp_recursion_depth(
+ "max_sp_recursion_depth",
+ "Maximum stored procedure recursion depth",
+ SESSION_VAR(max_sp_recursion_depth), CMD_LINE(OPT_ARG),
+ VALID_RANGE(0, 255), DEFAULT(0), BLOCK_SIZE(1));
+
+// non-standard session_value_ptr() here
+static Sys_var_max_user_conn Sys_max_user_connections(
+ "max_user_connections",
+ "The maximum number of active connections for a single user "
+ "(0 = no limit)",
+ SESSION_VAR(max_user_connections), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1), NO_MUTEX_GUARD,
+ NOT_IN_BINLOG, ON_CHECK(session_readonly));
+
+static Sys_var_ulong Sys_max_tmp_tables(
+ "max_tmp_tables",
+ "Maximum number of temporary tables a client can keep open at a time",
+ SESSION_VAR(max_tmp_tables), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, ULONG_MAX), DEFAULT(32), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_max_write_lock_count(
+ "max_write_lock_count",
+ "After this many write locks, allow some read locks to run in between",
+ GLOBAL_VAR(max_write_lock_count), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, ULONG_MAX), DEFAULT(ULONG_MAX), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_min_examined_row_limit(
+ "min_examined_row_limit",
+ "Don't write queries to slow log that examine fewer rows "
+ "than that",
+ SESSION_VAR(min_examined_row_limit), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1));
+
+#ifdef _WIN32
+static Sys_var_mybool Sys_named_pipe(
+ "named_pipe", "Enable the named pipe (NT)",
+ READ_ONLY GLOBAL_VAR(opt_enable_named_pipe), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE));
+#endif
+
+static Sys_var_ulong Sys_net_buffer_length(
+ "net_buffer_length",
+ "Buffer length for TCP/IP and socket communication",
+ SESSION_VAR(net_buffer_length), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1024, 1024*1024), DEFAULT(16384), BLOCK_SIZE(1024),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(session_readonly));
+
+static bool fix_net_read_timeout(sys_var *self, THD *thd, enum_var_type type)
+{
+ if (type != OPT_GLOBAL)
+ my_net_set_read_timeout(&thd->net, thd->variables.net_read_timeout);
+ return false;
+}
+static Sys_var_ulong Sys_net_read_timeout(
+ "net_read_timeout",
+ "Number of seconds to wait for more data from a connection before "
+ "aborting the read",
+ SESSION_VAR(net_read_timeout), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(NET_READ_TIMEOUT), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_net_read_timeout));
+
+static bool fix_net_write_timeout(sys_var *self, THD *thd, enum_var_type type)
+{
+ if (type != OPT_GLOBAL)
+ my_net_set_write_timeout(&thd->net, thd->variables.net_write_timeout);
+ return false;
+}
+static Sys_var_ulong Sys_net_write_timeout(
+ "net_write_timeout",
+ "Number of seconds to wait for a block to be written to a connection "
+ "before aborting the write",
+ SESSION_VAR(net_write_timeout), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(NET_WRITE_TIMEOUT), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_net_write_timeout));
+
+static bool fix_net_retry_count(sys_var *self, THD *thd, enum_var_type type)
+{
+ if (type != OPT_GLOBAL)
+ thd->net.retry_count=thd->variables.net_retry_count;
+ return false;
+}
+static Sys_var_ulong Sys_net_retry_count(
+ "net_retry_count",
+ "If a read on a communication port is interrupted, retry this "
+ "many times before giving up",
+ SESSION_VAR(net_retry_count), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, ULONG_MAX), DEFAULT(MYSQLD_NET_RETRY_COUNT),
+ BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_net_retry_count));
+
+static Sys_var_mybool Sys_new_mode(
+ "new", "Use very new possible \"unsafe\" functions",
+ SESSION_VAR(new_mode), CMD_LINE(OPT_ARG, 'n'), DEFAULT(FALSE));
+
+static Sys_var_mybool Sys_old_mode(
+ "old", "Use compatible behavior",
+ READ_ONLY GLOBAL_VAR(old_mode), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_mybool Sys_old_alter_table(
+ "old_alter_table", "Use old, non-optimized alter table",
+ SESSION_VAR(old_alter_table), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static bool check_old_passwords(sys_var *self, THD *thd, set_var *var)
+{
+ return mysql_user_table_is_in_short_password_format;
+}
+static Sys_var_mybool Sys_old_passwords(
+ "old_passwords",
+ "Use old password encryption method (needed for 4.0 and older clients)",
+ SESSION_VAR(old_passwords), CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_old_passwords));
+
+static Sys_var_ulong Sys_open_files_limit(
+ "open_files_limit",
+ "If this is not 0, then mysqld will use this value to reserve file "
+ "descriptors to use with setrlimit(). If this value is 0 then mysqld "
+ "will reserve max_connections*5 or max_connections + table_cache*2 "
+ "(whichever is larger) number of file descriptors",
+ READ_ONLY GLOBAL_VAR(open_files_limit), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, OS_FILE_LIMIT), DEFAULT(0), BLOCK_SIZE(1));
+
+/// @todo change to enum
+static Sys_var_ulong Sys_optimizer_prune_level(
+ "optimizer_prune_level",
+ "Controls the heuristic(s) applied during query optimization to prune "
+ "less-promising partial plans from the optimizer search space. "
+ "Meaning: 0 - do not apply any heuristic, thus perform exhaustive "
+ "search; 1 - prune plans based on number of retrieved rows",
+ SESSION_VAR(optimizer_prune_level), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 1), DEFAULT(1), BLOCK_SIZE(1));
+
+/** Warns about deprecated value 63 */
+static bool fix_optimizer_search_depth(sys_var *self, THD *thd,
+ enum_var_type type)
+{
+ SV *sv= type == OPT_GLOBAL ? &global_system_variables : &thd->variables;
+ if (sv->optimizer_search_depth == MAX_TABLES+2)
+ WARN_DEPRECATED(thd, 6, 0, "optimizer-search-depth=63",
+ "a search depth less than 63");
+ return false;
+}
+
+static Sys_var_ulong Sys_optimizer_search_depth(
+ "optimizer_search_depth",
+ "Maximum depth of search performed by the query optimizer. Values "
+ "larger than the number of relations in a query result in better "
+ "query plans, but take longer to compile a query. Values smaller "
+ "than the number of tables in a relation result in faster "
+ "optimization, but may produce very bad query plans. If set to 0, "
+ "the system will automatically pick a reasonable value; if set to "
+ "63, the optimizer will switch to the original find_best search. "
+ "NOTE: The value 63 and its associated behaviour is deprecated",
+ SESSION_VAR(optimizer_search_depth), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, MAX_TABLES+2), DEFAULT(MAX_TABLES+1), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_optimizer_search_depth));
+
+static const char *optimizer_switch_names[]=
+{
+ "index_merge", "index_merge_union", "index_merge_sort_union",
+ "index_merge_intersection", "engine_condition_pushdown",
+ "default", NullS
+};
+/** propagates changes to @@engine_condition_pushdown */
+static bool fix_optimizer_switch(sys_var *self, THD *thd,
+ enum_var_type type)
+{
+ SV *sv= (type == OPT_GLOBAL) ? &global_system_variables : &thd->variables;
+ sv->engine_condition_pushdown=
+ test(sv->optimizer_switch & OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN);
+ return false;
+}
+static Sys_var_flagset Sys_optimizer_switch(
+ "optimizer_switch",
+ "optimizer_switch=option=val[,option=val...], where option is one of "
+ "{index_merge, index_merge_union, index_merge_sort_union, "
+ "index_merge_intersection, engine_condition_pushdown}"
+ " and val is one of {on, off, default}",
+ SESSION_VAR(optimizer_switch), CMD_LINE(REQUIRED_ARG),
+ optimizer_switch_names, DEFAULT(OPTIMIZER_SWITCH_DEFAULT),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL),
+ ON_UPDATE(fix_optimizer_switch));
+
+static Sys_var_charptr Sys_pid_file(
+ "pid_file", "Pid file used by safe_mysqld",
+ READ_ONLY GLOBAL_VAR(pidfile_name_ptr), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_charptr Sys_plugin_dir(
+ "plugin_dir", "Directory for plugins",
+ READ_ONLY GLOBAL_VAR(opt_plugin_dir_ptr), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_uint Sys_port(
+ "port",
+ "Port number to use for connection or 0 to default to, "
+ "my.cnf, $MYSQL_TCP_PORT, "
+#if MYSQL_PORT_DEFAULT == 0
+ "/etc/services, "
+#endif
+ "built-in default (" STRINGIFY_ARG(MYSQL_PORT) "), whatever comes first",
+ READ_ONLY GLOBAL_VAR(mysqld_port), CMD_LINE(REQUIRED_ARG, 'P'),
+ VALID_RANGE(0, UINT_MAX32), DEFAULT(0), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_preload_buff_size(
+ "preload_buffer_size",
+ "The size of the buffer that is allocated when preloading indexes",
+ SESSION_VAR(preload_buff_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1024, 1024*1024*1024), DEFAULT(32768), BLOCK_SIZE(1));
+
+static Sys_var_uint Sys_protocol_version(
+ "protocol_version",
+ "The version of the client/server protocol used by the MySQL server",
+ READ_ONLY GLOBAL_VAR(protocol_version), NO_CMD_LINE,
+ VALID_RANGE(0, ~0), DEFAULT(PROTOCOL_VERSION), BLOCK_SIZE(1));
+
+static Sys_var_proxy_user Sys_proxy_user(
+ "proxy_user", "The proxy user account name used when logging in",
+ IN_SYSTEM_CHARSET);
+
+static Sys_var_external_user Sys_exterenal_user(
+ "external_user", "The external user account used when logging in",
+ IN_SYSTEM_CHARSET);
+
+static Sys_var_ulong Sys_read_buff_size(
+ "read_buffer_size",
+ "Each thread that does a sequential scan allocates a buffer of "
+ "this size for each table it scans. If you do many sequential scans, "
+ "you may want to increase this value",
+ SESSION_VAR(read_buff_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(IO_SIZE*2, INT_MAX32), DEFAULT(128*1024),
+ BLOCK_SIZE(IO_SIZE));
+
+static my_bool read_only;
+static bool check_read_only(sys_var *self, THD *thd, set_var *var)
+{
+ /* Prevent self dead-lock */
+ if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction())
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ return true;
+ }
+ return false;
+}
+static bool fix_read_only(sys_var *self, THD *thd, enum_var_type type)
+{
+ bool result= true;
+ my_bool new_read_only= read_only; // make a copy before releasing a mutex
+ DBUG_ENTER("sys_var_opt_readonly::update");
+
+ if (read_only == FALSE || read_only == opt_readonly)
+ {
+ opt_readonly= read_only;
+ DBUG_RETURN(false);
+ }
+
+ if (check_read_only(self, thd, 0)) // just in case
+ goto end;
+
+ if (thd->global_read_lock.is_acquired())
+ {
+ /*
+ This connection already holds the global read lock.
+ This can be the case with:
+ - FLUSH TABLES WITH READ LOCK
+ - SET GLOBAL READ_ONLY = 1
+ */
+ opt_readonly= read_only;
+ DBUG_RETURN(false);
+ }
+
+ /*
+ Perform a 'FLUSH TABLES WITH READ LOCK'.
+ This is a 3 step process:
+ - [1] lock_global_read_lock()
+ - [2] close_cached_tables()
+ - [3] make_global_read_lock_block_commit()
+ [1] prevents new connections from obtaining tables locked for write.
+ [2] waits until all existing connections close their tables.
+ [3] prevents transactions from being committed.
+ */
+
+ read_only= opt_readonly;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+
+ if (thd->global_read_lock.lock_global_read_lock(thd))
+ goto end_with_mutex_unlock;
+
+ /*
+ This call will be blocked by any connection holding a READ or WRITE lock.
+ Ideally, we want to wait only for pending WRITE locks, but since:
+ con 1> LOCK TABLE T FOR READ;
+ con 2> LOCK TABLE T FOR WRITE; (blocked by con 1)
+ con 3> SET GLOBAL READ ONLY=1; (blocked by con 2)
+ can cause to wait on a read lock, it's required for the client application
+ to unlock everything, and acceptable for the server to wait on all locks.
+ */
+ if ((result= close_cached_tables(thd, NULL, TRUE,
+ thd->variables.lock_wait_timeout)))
+ goto end_with_read_lock;
+
+ if ((result= thd->global_read_lock.make_global_read_lock_block_commit(thd)))
+ goto end_with_read_lock;
+
+ /* Change the opt_readonly system variable, safe because the lock is held */
+ opt_readonly= new_read_only;
+ result= false;
+
+ end_with_read_lock:
+ /* Release the lock */
+ thd->global_read_lock.unlock_global_read_lock(thd);
+ end_with_mutex_unlock:
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ end:
+ read_only= opt_readonly;
+ DBUG_RETURN(result);
+}
+static Sys_var_mybool Sys_readonly(
+ "read_only",
+ "Make all non-temporary tables read-only, with the exception for "
+ "replication (slave) threads and users with the SUPER privilege",
+ GLOBAL_VAR(read_only), CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_read_only), ON_UPDATE(fix_read_only));
+
+// Small lower limit to be able to test MRR
+static Sys_var_ulong Sys_read_rnd_buff_size(
+ "read_rnd_buffer_size",
+ "When reading rows in sorted order after a sort, the rows are read "
+ "through this buffer to avoid a disk seeks",
+ SESSION_VAR(read_rnd_buff_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, INT_MAX32), DEFAULT(256*1024), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_div_precincrement(
+ "div_precision_increment", "Precision of the result of '/' "
+ "operator will be increased on that value",
+ SESSION_VAR(div_precincrement), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, DECIMAL_MAX_SCALE), DEFAULT(4), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_rpl_recovery_rank(
+ "rpl_recovery_rank", "Unused, will be removed",
+ GLOBAL_VAR(rpl_recovery_rank), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
+ DEPRECATED(70000, 0));
+
+static Sys_var_ulong Sys_range_alloc_block_size(
+ "range_alloc_block_size",
+ "Allocation block size for storing ranges during optimization",
+ SESSION_VAR(range_alloc_block_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(RANGE_ALLOC_BLOCK_SIZE, ULONG_MAX),
+ DEFAULT(RANGE_ALLOC_BLOCK_SIZE), BLOCK_SIZE(1024));
+
+static Sys_var_ulong Sys_multi_range_count(
+ "multi_range_count", "Number of key ranges to request at once",
+ SESSION_VAR(multi_range_count), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, ULONG_MAX), DEFAULT(256), BLOCK_SIZE(1));
+
+static bool fix_thd_mem_root(sys_var *self, THD *thd, enum_var_type type)
+{
+ if (type != OPT_GLOBAL)
+ reset_root_defaults(thd->mem_root,
+ thd->variables.query_alloc_block_size,
+ thd->variables.query_prealloc_size);
+ return false;
+}
+static Sys_var_ulong Sys_query_alloc_block_size(
+ "query_alloc_block_size",
+ "Allocation block size for query parsing and execution",
+ SESSION_VAR(query_alloc_block_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1024, ULONG_MAX), DEFAULT(QUERY_ALLOC_BLOCK_SIZE),
+ BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_thd_mem_root));
+
+static Sys_var_ulong Sys_query_prealloc_size(
+ "query_prealloc_size",
+ "Persistent buffer for query parsing and execution",
+ SESSION_VAR(query_prealloc_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(QUERY_ALLOC_PREALLOC_SIZE, ULONG_MAX),
+ DEFAULT(QUERY_ALLOC_PREALLOC_SIZE),
+ BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_thd_mem_root));
+
+#ifdef HAVE_SMEM
+static Sys_var_mybool Sys_shared_memory(
+ "shared_memory", "Enable the shared memory",
+ READ_ONLY GLOBAL_VAR(opt_enable_shared_memory), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE));
+
+static Sys_var_charptr Sys_shared_memory_base_name(
+ "shared_memory_base_name", "Base name of shared memory",
+ READ_ONLY GLOBAL_VAR(shared_memory_base_name), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+#endif
+
+// this has to be NO_CMD_LINE as the command-line option has a different name
+static Sys_var_mybool Sys_skip_external_locking(
+ "skip_external_locking", "Don't use system (external) locking",
+ READ_ONLY GLOBAL_VAR(my_disable_locking), NO_CMD_LINE, DEFAULT(TRUE));
+
+static Sys_var_mybool Sys_skip_networking(
+ "skip_networking", "Don't allow connection with TCP/IP",
+ READ_ONLY GLOBAL_VAR(opt_disable_networking), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE));
+
+static Sys_var_mybool Sys_skip_name_resolve(
+ "skip_name_resolve",
+ "Don't resolve hostnames. All hostnames are IP's or 'localhost'.",
+ READ_ONLY GLOBAL_VAR(opt_skip_name_resolve),
+ CMD_LINE(OPT_ARG, OPT_SKIP_RESOLVE),
+ DEFAULT(FALSE));
+
+static Sys_var_mybool Sys_skip_show_database(
+ "skip_show_database", "Don't allow 'SHOW DATABASE' commands",
+ READ_ONLY GLOBAL_VAR(opt_skip_show_db), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE));
+
+static Sys_var_charptr Sys_socket(
+ "socket", "Socket file to use for connection",
+ READ_ONLY GLOBAL_VAR(mysqld_unix_port), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+/*
+ thread_concurrency is a no-op on all platforms since
+ MySQL 5.1. It will be removed in the context of
+ WL#5265
+*/
+static Sys_var_ulong Sys_thread_concurrency(
+ "thread_concurrency",
+ "Permits the application to give the threads system a hint for "
+ "the desired number of threads that should be run at the same time",
+ READ_ONLY GLOBAL_VAR(concurrency), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, 512), DEFAULT(DEFAULT_CONCURRENCY), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_thread_stack(
+ "thread_stack", "The stack size for each thread",
+ READ_ONLY GLOBAL_VAR(my_thread_stack_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(128*1024, ULONG_MAX), DEFAULT(DEFAULT_THREAD_STACK),
+ BLOCK_SIZE(1024));
+
+static Sys_var_charptr Sys_tmpdir(
+ "tmpdir", "Path for temporary files. Several paths may "
+ "be specified, separated by a "
+#if defined(__WIN__)
+ "semicolon (;)"
+#else
+ "colon (:)"
+#endif
+ ", in this case they are used in a round-robin fashion",
+ READ_ONLY GLOBAL_VAR(opt_mysql_tmpdir), CMD_LINE(REQUIRED_ARG, 't'),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static bool fix_trans_mem_root(sys_var *self, THD *thd, enum_var_type type)
+{
+ if (type != OPT_GLOBAL)
+ reset_root_defaults(&thd->transaction.mem_root,
+ thd->variables.trans_alloc_block_size,
+ thd->variables.trans_prealloc_size);
+ return false;
+}
+static Sys_var_ulong Sys_trans_alloc_block_size(
+ "transaction_alloc_block_size",
+ "Allocation block size for transactions to be stored in binary log",
+ SESSION_VAR(trans_alloc_block_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1024, ULONG_MAX), DEFAULT(QUERY_ALLOC_BLOCK_SIZE),
+ BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_trans_mem_root));
+
+static Sys_var_ulong Sys_trans_prealloc_size(
+ "transaction_prealloc_size",
+ "Persistent buffer for transactions to be stored in binary log",
+ SESSION_VAR(trans_prealloc_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1024, ULONG_MAX), DEFAULT(TRANS_ALLOC_PREALLOC_SIZE),
+ BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_trans_mem_root));
+
+static const char *thread_handling_names[]=
+{
+ "one-thread-per-connection", "no-threads", "loaded-dynamically",
+ 0
+};
+static Sys_var_enum Sys_thread_handling(
+ "thread_handling",
+ "Define threads usage for handling queries, one of "
+ "one-thread-per-connection, no-threads, loaded-dynamically"
+ , READ_ONLY GLOBAL_VAR(thread_handling), CMD_LINE(REQUIRED_ARG),
+ thread_handling_names, DEFAULT(0));
+
+#ifdef HAVE_QUERY_CACHE
+static bool fix_query_cache_size(sys_var *self, THD *thd, enum_var_type type)
+{
+ ulong new_cache_size= query_cache.resize(query_cache_size);
+ /*
+ Note: query_cache_size is a global variable reflecting the
+ requested cache size. See also query_cache_size_arg
+ */
+ if (query_cache_size != new_cache_size)
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_QC_RESIZE, ER(ER_WARN_QC_RESIZE),
+ query_cache_size, new_cache_size);
+
+ query_cache_size= new_cache_size;
+ return false;
+}
+static Sys_var_ulong Sys_query_cache_size(
+ "query_cache_size",
+ "The memory allocated to store results from old queries",
+ GLOBAL_VAR(query_cache_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1024),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_query_cache_size));
+
+static Sys_var_ulong Sys_query_cache_limit(
+ "query_cache_limit",
+ "Don't cache results that are bigger than this",
+ GLOBAL_VAR(query_cache.query_cache_limit), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, ULONG_MAX), DEFAULT(1024*1024), BLOCK_SIZE(1));
+
+static bool fix_qcache_min_res_unit(sys_var *self, THD *thd, enum_var_type type)
+{
+ query_cache_min_res_unit=
+ query_cache.set_min_res_unit(query_cache_min_res_unit);
+ return false;
+}
+static Sys_var_ulong Sys_query_cache_min_res_unit(
+ "query_cache_min_res_unit",
+ "The minimum size for blocks allocated by the query cache",
+ GLOBAL_VAR(query_cache_min_res_unit), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, ULONG_MAX), DEFAULT(QUERY_CACHE_MIN_RESULT_DATA_SIZE),
+ BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_qcache_min_res_unit));
+
+static const char *query_cache_type_names[]= { "OFF", "ON", "DEMAND", 0 };
+static bool check_query_cache_type(sys_var *self, THD *thd, set_var *var)
+{
+ if (query_cache.is_disabled())
+ {
+ my_error(ER_QUERY_CACHE_DISABLED, MYF(0));
+ return true;
+ }
+ return false;
+}
+static Sys_var_enum Sys_query_cache_type(
+ "query_cache_type",
+ "OFF = Don't cache or retrieve results. ON = Cache all results "
+ "except SELECT SQL_NO_CACHE ... queries. DEMAND = Cache only "
+ "SELECT SQL_CACHE ... queries",
+ SESSION_VAR(query_cache_type), CMD_LINE(REQUIRED_ARG),
+ query_cache_type_names, DEFAULT(1), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_query_cache_type));
+
+static Sys_var_mybool Sys_query_cache_wlock_invalidate(
+ "query_cache_wlock_invalidate",
+ "Invalidate queries in query cache on LOCK for write",
+ SESSION_VAR(query_cache_wlock_invalidate), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE));
+#endif /* HAVE_QUERY_CACHE */
+
+static Sys_var_mybool Sys_secure_auth(
+ "secure_auth",
+ "Disallow authentication for accounts that have old (pre-4.1) "
+ "passwords",
+ GLOBAL_VAR(opt_secure_auth), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE));
+
+static Sys_var_charptr Sys_secure_file_priv(
+ "secure_file_priv",
+ "Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files "
+ "within specified directory",
+ PREALLOCATED READ_ONLY GLOBAL_VAR(opt_secure_file_priv),
+ CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(0));
+
+static bool fix_server_id(sys_var *self, THD *thd, enum_var_type type)
+{
+ server_id_supplied = 1;
+ thd->server_id= server_id;
+ return false;
+}
+static Sys_var_ulong Sys_server_id(
+ "server_id",
+ "Uniquely identifies the server instance in the community of "
+ "replication partners",
+ GLOBAL_VAR(server_id), CMD_LINE(REQUIRED_ARG, OPT_SERVER_ID),
+ VALID_RANGE(0, UINT_MAX32), DEFAULT(0), BLOCK_SIZE(1), NO_MUTEX_GUARD,
+ NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_server_id));
+
+static Sys_var_mybool Sys_slave_compressed_protocol(
+ "slave_compressed_protocol",
+ "Use compression on master/slave protocol",
+ GLOBAL_VAR(opt_slave_compressed_protocol), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE));
+
+#ifdef HAVE_REPLICATION
+static const char *slave_exec_mode_names[]= {"STRICT", "IDEMPOTENT", 0};
+static Sys_var_enum Slave_exec_mode(
+ "slave_exec_mode",
+ "Modes for how replication events should be executed. Legal values "
+ "are STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode, "
+ "replication will not stop for operations that are idempotent. "
+ "In STRICT mode, replication will stop on any unexpected difference "
+ "between the master and the slave",
+ GLOBAL_VAR(slave_exec_mode_options), CMD_LINE(REQUIRED_ARG),
+ slave_exec_mode_names, DEFAULT(SLAVE_EXEC_MODE_STRICT));
+const char *slave_type_conversions_name[]= {"ALL_LOSSY", "ALL_NON_LOSSY", 0};
+static Sys_var_set Slave_type_conversions(
+ "slave_type_conversions",
+ "Set of slave type conversions that are enabled. Legal values are:"
+ " ALL_LOSSY to enable lossy conversions and"
+ " ALL_NON_LOSSY to enable non-lossy conversions."
+ " If the variable is assigned the empty set, no conversions are"
+ " allowed and it is expected that the types match exactly.",
+ GLOBAL_VAR(slave_type_conversions_options), CMD_LINE(REQUIRED_ARG),
+ slave_type_conversions_name,
+ DEFAULT(0));
+#endif
+
+
+static Sys_var_ulong Sys_slow_launch_time(
+ "slow_launch_time",
+ "If creating the thread takes longer than this value (in seconds), "
+ "the Slow_launch_threads counter will be incremented",
+ GLOBAL_VAR(slow_launch_time), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, LONG_TIMEOUT), DEFAULT(2), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_sort_buffer(
+ "sort_buffer_size",
+ "Each thread that needs to do a sort allocates a buffer of this size",
+ SESSION_VAR(sortbuff_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(MIN_SORT_MEMORY, ULONG_MAX), DEFAULT(MAX_SORT_MEMORY),
+ BLOCK_SIZE(1));
+
+export ulong expand_sql_mode(ulonglong sql_mode)
+{
+ if (sql_mode & MODE_ANSI)
+ {
+ /*
+ Note that we dont set
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | MODE_NO_FIELD_OPTIONS
+ to allow one to get full use of MySQL in this mode.
+
+ MODE_ONLY_FULL_GROUP_BY was removed from ANSI mode because it is
+ currently overly restrictive (see BUG#8510).
+ */
+ sql_mode|= (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE);
+ }
+ if (sql_mode & MODE_ORACLE)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS | MODE_NO_AUTO_CREATE_USER);
+ if (sql_mode & MODE_MSSQL)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_POSTGRESQL)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_DB2)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_MAXDB)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS | MODE_NO_AUTO_CREATE_USER);
+ if (sql_mode & MODE_MYSQL40)
+ sql_mode|= MODE_HIGH_NOT_PRECEDENCE;
+ if (sql_mode & MODE_MYSQL323)
+ sql_mode|= MODE_HIGH_NOT_PRECEDENCE;
+ if (sql_mode & MODE_TRADITIONAL)
+ sql_mode|= (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES |
+ MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_ERROR_FOR_DIVISION_BY_ZERO | MODE_NO_AUTO_CREATE_USER |
+ MODE_NO_ENGINE_SUBSTITUTION);
+ return sql_mode;
+}
+static bool check_sql_mode(sys_var *self, THD *thd, set_var *var)
+{
+ var->save_result.ulonglong_value=
+ expand_sql_mode(var->save_result.ulonglong_value);
+ return false;
+}
+static bool fix_sql_mode(sys_var *self, THD *thd, enum_var_type type)
+{
+ if (type != OPT_GLOBAL)
+ {
+ /* Update thd->server_status */
+ if (thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
+ thd->server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
+ else
+ thd->server_status&= ~SERVER_STATUS_NO_BACKSLASH_ESCAPES;
+ }
+ return false;
+}
+/*
+ WARNING: When adding new SQL modes don't forget to update the
+ tables definitions that stores it's value (ie: mysql.event, mysql.proc)
+*/
+static const char *sql_mode_names[]=
+{
+ "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", ",",
+ "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", "NO_DIR_IN_CREATE",
+ "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "MAXDB", "NO_KEY_OPTIONS",
+ "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI",
+ "NO_AUTO_VALUE_ON_ZERO", "NO_BACKSLASH_ESCAPES", "STRICT_TRANS_TABLES",
+ "STRICT_ALL_TABLES", "NO_ZERO_IN_DATE", "NO_ZERO_DATE",
+ "ALLOW_INVALID_DATES", "ERROR_FOR_DIVISION_BY_ZERO", "TRADITIONAL",
+ "NO_AUTO_CREATE_USER", "HIGH_NOT_PRECEDENCE", "NO_ENGINE_SUBSTITUTION",
+ "PAD_CHAR_TO_FULL_LENGTH",
+ 0
+};
+export bool sql_mode_string_representation(THD *thd, ulong sql_mode,
+ LEX_STRING *ls)
+{
+ set_to_string(thd, ls, sql_mode, sql_mode_names);
+ return ls->str == 0;
+}
+/*
+ sql_mode should *not* be IN_BINLOG: even though it is written to the binlog,
+ the slave ignores the MODE_NO_DIR_IN_CREATE variable, so slave's value
+ differs from master's (see log_event.cc: Query_log_event::do_apply_event()).
+*/
+static Sys_var_set Sys_sql_mode(
+ "sql_mode",
+ "Syntax: sql-mode=mode[,mode[,mode...]]. See the manual for the "
+ "complete list of valid sql modes",
+ SESSION_VAR(sql_mode), CMD_LINE(REQUIRED_ARG),
+ sql_mode_names, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_sql_mode), ON_UPDATE(fix_sql_mode));
+
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
+#define SSL_OPT(X) CMD_LINE(REQUIRED_ARG,X)
+#else
+#define SSL_OPT(X) NO_CMD_LINE
+#endif
+
+static Sys_var_charptr Sys_ssl_ca(
+ "ssl_ca",
+ "CA file in PEM format (check OpenSSL docs, implies --ssl)",
+ READ_ONLY GLOBAL_VAR(opt_ssl_ca), SSL_OPT(OPT_SSL_CA),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_charptr Sys_ssl_capath(
+ "ssl_capath",
+ "CA directory (check OpenSSL docs, implies --ssl)",
+ READ_ONLY GLOBAL_VAR(opt_ssl_capath), SSL_OPT(OPT_SSL_CAPATH),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_charptr Sys_ssl_cert(
+ "ssl_cert", "X509 cert in PEM format (implies --ssl)",
+ READ_ONLY GLOBAL_VAR(opt_ssl_cert), SSL_OPT(OPT_SSL_CERT),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_charptr Sys_ssl_cipher(
+ "ssl_cipher", "SSL cipher to use (implies --ssl)",
+ READ_ONLY GLOBAL_VAR(opt_ssl_cipher), SSL_OPT(OPT_SSL_CIPHER),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_charptr Sys_ssl_key(
+ "ssl_key", "X509 key in PEM format (implies --ssl)",
+ READ_ONLY GLOBAL_VAR(opt_ssl_key), SSL_OPT(OPT_SSL_KEY),
+ IN_FS_CHARSET, DEFAULT(0));
+
+// why ENUM and not BOOL ?
+static const char *updatable_views_with_limit_names[]= {"NO", "YES", 0};
+static Sys_var_enum Sys_updatable_views_with_limit(
+ "updatable_views_with_limit",
+ "YES = Don't issue an error message (warning only) if a VIEW without "
+ "presence of a key of the underlying table is used in queries with a "
+ "LIMIT clause for updating. NO = Prohibit update of a VIEW, which "
+ "does not contain a key of the underlying table and the query uses "
+ "a LIMIT clause (usually get from GUI tools)",
+ SESSION_VAR(updatable_views_with_limit), CMD_LINE(REQUIRED_ARG),
+ updatable_views_with_limit_names, DEFAULT(TRUE));
+
+static Sys_var_mybool Sys_sync_frm(
+ "sync_frm", "Sync .frm files to disk on creation",
+ GLOBAL_VAR(opt_sync_frm), CMD_LINE(OPT_ARG),
+ DEFAULT(TRUE));
+
+static char *system_time_zone_ptr;
+static Sys_var_charptr Sys_system_time_zone(
+ "system_time_zone", "The server system time zone",
+ READ_ONLY GLOBAL_VAR(system_time_zone_ptr), NO_CMD_LINE,
+ IN_FS_CHARSET, DEFAULT(system_time_zone));
+
+static Sys_var_ulong Sys_table_def_size(
+ "table_definition_cache",
+ "The number of cached table definitions",
+ GLOBAL_VAR(table_def_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(TABLE_DEF_CACHE_MIN, 512*1024),
+ DEFAULT(TABLE_DEF_CACHE_DEFAULT), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_table_cache_size(
+ "table_open_cache", "The number of cached open tables",
+ GLOBAL_VAR(table_cache_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, 512*1024), DEFAULT(TABLE_OPEN_CACHE_DEFAULT),
+ BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_thread_cache_size(
+ "thread_cache_size",
+ "How many threads we should keep in a cache for reuse",
+ GLOBAL_VAR(thread_cache_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 16384), DEFAULT(0), BLOCK_SIZE(1));
+
+/**
+ Can't change the 'next' tx_isolation if we are already in a
+ transaction.
+*/
+
+static bool check_tx_isolation(sys_var *self, THD *thd, set_var *var)
+{
+ if (var->type == OPT_DEFAULT && thd->in_active_multi_stmt_transaction())
+ {
+ DBUG_ASSERT(thd->in_multi_stmt_transaction_mode());
+ my_error(ER_CANT_CHANGE_TX_ISOLATION, MYF(0));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+bool Sys_var_tx_isolation::session_update(THD *thd, set_var *var)
+{
+ if (var->type == OPT_SESSION && Sys_var_enum::session_update(thd, var))
+ return TRUE;
+ if (var->type == OPT_DEFAULT || !thd->in_active_multi_stmt_transaction())
+ {
+ /*
+ Update the isolation level of the next transaction.
+ I.e. if one did:
+ COMMIT;
+ SET SESSION ISOLATION LEVEL ...
+ BEGIN; <-- this transaction has the new isolation
+ Note, that in case of:
+ COMMIT;
+ SET TRANSACTION ISOLATION LEVEL ...
+ SET SESSION ISOLATION LEVEL ...
+ BEGIN; <-- the session isolation level is used, not the
+ result of SET TRANSACTION statement.
+ */
+ thd->tx_isolation= (enum_tx_isolation) var->save_result.ulonglong_value;
+ }
+ return FALSE;
+}
+
+
+// NO_CMD_LINE - different name of the option
+static Sys_var_tx_isolation Sys_tx_isolation(
+ "tx_isolation", "Default transaction isolation level",
+ SESSION_VAR(tx_isolation), NO_CMD_LINE,
+ tx_isolation_names, DEFAULT(ISO_REPEATABLE_READ),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_tx_isolation));
+
+static Sys_var_ulonglong Sys_tmp_table_size(
+ "tmp_table_size",
+ "If an internal in-memory temporary table exceeds this size, MySQL "
+ "will automatically convert it to an on-disk MyISAM table",
+ SESSION_VAR(tmp_table_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1024, (ulonglong)~(intptr)0), DEFAULT(16*1024*1024),
+ BLOCK_SIZE(1));
+
+static Sys_var_mybool Sys_timed_mutexes(
+ "timed_mutexes",
+ "Specify whether to time mutexes (only InnoDB mutexes are currently "
+ "supported)",
+ GLOBAL_VAR(timed_mutexes), CMD_LINE(OPT_ARG), DEFAULT(0));
+
+static char *server_version_ptr;
+static Sys_var_charptr Sys_version(
+ "version", "Server version",
+ READ_ONLY GLOBAL_VAR(server_version_ptr), NO_CMD_LINE,
+ IN_SYSTEM_CHARSET, DEFAULT(server_version));
+
+static char *server_version_comment_ptr;
+static Sys_var_charptr Sys_version_comment(
+ "version_comment", "version_comment",
+ READ_ONLY GLOBAL_VAR(server_version_comment_ptr), NO_CMD_LINE,
+ IN_SYSTEM_CHARSET, DEFAULT(MYSQL_COMPILATION_COMMENT));
+
+static char *server_version_compile_machine_ptr;
+static Sys_var_charptr Sys_version_compile_machine(
+ "version_compile_machine", "version_compile_machine",
+ READ_ONLY GLOBAL_VAR(server_version_compile_machine_ptr), NO_CMD_LINE,
+ IN_SYSTEM_CHARSET, DEFAULT(MACHINE_TYPE));
+
+static char *server_version_compile_os_ptr;
+static Sys_var_charptr Sys_version_compile_os(
+ "version_compile_os", "version_compile_os",
+ READ_ONLY GLOBAL_VAR(server_version_compile_os_ptr), NO_CMD_LINE,
+ IN_SYSTEM_CHARSET, DEFAULT(SYSTEM_TYPE));
+
+static Sys_var_ulong Sys_net_wait_timeout(
+ "wait_timeout",
+ "The number of seconds the server waits for activity on a "
+ "connection before closing it",
+ SESSION_VAR(net_wait_timeout), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT)),
+ DEFAULT(NET_WAIT_TIMEOUT), BLOCK_SIZE(1));
+
+/** propagates changes to the relevant flag of @@optimizer_switch */
+static bool fix_engine_condition_pushdown(sys_var *self, THD *thd,
+ enum_var_type type)
+{
+ SV *sv= (type == OPT_GLOBAL) ? &global_system_variables : &thd->variables;
+ if (sv->engine_condition_pushdown)
+ sv->optimizer_switch|= OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN;
+ else
+ sv->optimizer_switch&= ~OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN;
+ return false;
+}
+static Sys_var_mybool Sys_engine_condition_pushdown(
+ "engine_condition_pushdown",
+ "Push supported query conditions to the storage engine."
+ " Deprecated, use --optimizer-switch instead.",
+ SESSION_VAR(engine_condition_pushdown),
+ CMD_LINE(OPT_ARG, OPT_ENGINE_CONDITION_PUSHDOWN),
+ DEFAULT(TRUE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL),
+ ON_UPDATE(fix_engine_condition_pushdown),
+ DEPRECATED(70000, "'@@optimizer_switch'"));
+
+static Sys_var_plugin Sys_default_storage_engine(
+ "default_storage_engine", "The default storage engine for new tables",
+ SESSION_VAR(table_plugin), NO_CMD_LINE,
+ MYSQL_STORAGE_ENGINE_PLUGIN, DEFAULT(&default_storage_engine),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_not_null));
+
+// Alias for @@default_storage_engine
+static Sys_var_plugin Sys_storage_engine(
+ "storage_engine", "Alias for @@default_storage_engine. Deprecated",
+ SESSION_VAR(table_plugin), NO_CMD_LINE,
+ MYSQL_STORAGE_ENGINE_PLUGIN, DEFAULT(&default_storage_engine),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_not_null));
+
+#if defined(ENABLED_DEBUG_SYNC)
+/*
+ Variable can be set for the session only.
+
+ This could be changed later. Then we need to have a global array of
+ actions in addition to the thread local ones. SET GLOBAL would
+ manage the global array, SET [SESSION] the local array. A sync point
+ would need to look for a local and a global action. Setting and
+ executing of global actions need to be protected by a mutex.
+
+ The purpose of global actions could be to allow synchronizing with
+ connectionless threads that cannot execute SET statements.
+*/
+static Sys_var_debug_sync Sys_debug_sync(
+ "debug_sync", "Debug Sync Facility",
+ sys_var::ONLY_SESSION, NO_CMD_LINE,
+ DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super));
+#endif /* defined(ENABLED_DEBUG_SYNC) */
+
+/**
+ "time_format" "date_format" "datetime_format"
+
+ the following three variables are unused, and the source of confusion
+ (bug reports like "I've changed date_format, but date format hasn't changed.
+ I've made them read-only, to alleviate the situation somewhat.
+
+ @todo make them NO_CMD_LINE ?
+*/
+static Sys_var_charptr Sys_date_format(
+ "date_format", "The DATE format (ignored)",
+ READ_ONLY GLOBAL_VAR(global_date_format.format.str),
+ CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ DEFAULT(known_date_time_formats[ISO_FORMAT].date_format));
+
+static Sys_var_charptr Sys_datetime_format(
+ "datetime_format", "The DATETIME format (ignored)",
+ READ_ONLY GLOBAL_VAR(global_datetime_format.format.str),
+ CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ DEFAULT(known_date_time_formats[ISO_FORMAT].datetime_format));
+
+static Sys_var_charptr Sys_time_format(
+ "time_format", "The TIME format (ignored)",
+ READ_ONLY GLOBAL_VAR(global_time_format.format.str),
+ CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ DEFAULT(known_date_time_formats[ISO_FORMAT].time_format));
+
+static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type)
+{
+ if (type == OPT_GLOBAL)
+ {
+ if (global_system_variables.option_bits & OPTION_AUTOCOMMIT)
+ global_system_variables.option_bits&= ~OPTION_NOT_AUTOCOMMIT;
+ else
+ global_system_variables.option_bits|= OPTION_NOT_AUTOCOMMIT;
+ return false;
+ }
+
+ if (thd->variables.option_bits & OPTION_AUTOCOMMIT &&
+ thd->variables.option_bits & OPTION_NOT_AUTOCOMMIT)
+ { // activating autocommit
+
+ if (trans_commit_stmt(thd) || trans_commit(thd))
+ {
+ thd->variables.option_bits&= ~OPTION_AUTOCOMMIT;
+ return true;
+ }
+ /*
+ Don't close thread tables or release metadata locks: if we do so, we
+ risk releasing locks/closing tables of expressions used to assign
+ other variables, as in:
+ set @var=my_stored_function1(), @@autocommit=1, @var2=(select max(a)
+ from my_table), ...
+ The locks will be released at statement end anyway, as SET
+ statement that assigns autocommit is marked to commit
+ transaction implicitly at the end (@sa stmt_causes_implicitcommit()).
+ */
+ thd->variables.option_bits&=
+ ~(OPTION_BEGIN | OPTION_KEEP_LOG | OPTION_NOT_AUTOCOMMIT);
+ thd->transaction.all.modified_non_trans_table= false;
+ thd->server_status|= SERVER_STATUS_AUTOCOMMIT;
+ return false;
+ }
+
+ if (!(thd->variables.option_bits & OPTION_AUTOCOMMIT) &&
+ !(thd->variables.option_bits & OPTION_NOT_AUTOCOMMIT))
+ { // disabling autocommit
+
+ thd->transaction.all.modified_non_trans_table= false;
+ thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT;
+ thd->variables.option_bits|= OPTION_NOT_AUTOCOMMIT;
+ return false;
+ }
+
+ return false; // autocommit value wasn't changed
+}
+static Sys_var_bit Sys_autocommit(
+ "autocommit", "autocommit",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_AUTOCOMMIT, DEFAULT(TRUE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_autocommit));
+export sys_var *Sys_autocommit_ptr= &Sys_autocommit; // for sql_yacc.yy
+
+static Sys_var_mybool Sys_big_tables(
+ "big_tables", "Allow big result sets by saving all "
+ "temporary sets on file (Solves most 'table full' errors)",
+ SESSION_VAR(big_tables), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+#ifndef TO_BE_DELETED /* Alias for big_tables */
+static Sys_var_mybool Sys_sql_big_tables(
+ "sql_big_tables", "alias for big_tables",
+ SESSION_VAR(big_tables), NO_CMD_LINE, DEFAULT(FALSE));
+#endif
+
+static Sys_var_bit Sys_big_selects(
+ "sql_big_selects", "sql_big_selects",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_BIG_SELECTS,
+ DEFAULT(FALSE));
+
+static Sys_var_bit Sys_log_off(
+ "sql_log_off", "sql_log_off",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_LOG_OFF,
+ DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super));
+
+/**
+ This function sets the session variable thd->variables.sql_log_bin
+ to reflect changes to @@session.sql_log_bin.
+
+ @param[IN] self A pointer to the sys_var, i.e. Sys_log_binlog.
+ @param[IN] type The type either session or global.
+
+ @return @c FALSE.
+*/
+static bool fix_sql_log_bin_after_update(sys_var *self, THD *thd,
+ enum_var_type type)
+{
+ if (type == OPT_SESSION)
+ {
+ if (thd->variables.sql_log_bin)
+ thd->variables.option_bits |= OPTION_BIN_LOG;
+ else
+ thd->variables.option_bits &= ~OPTION_BIN_LOG;
+ }
+ return FALSE;
+}
+
+/**
+ This function checks if the sql_log_bin can be changed,
+ what is possible if:
+ - the user is a super user;
+ - the set is not called from within a function/trigger;
+ - there is no on-going transaction.
+
+ @param[IN] self A pointer to the sys_var, i.e. Sys_log_binlog.
+ @param[IN] var A pointer to the set_var created by the parser.
+
+ @return @c FALSE if the change is allowed, otherwise @c TRUE.
+*/
+static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var)
+{
+ if (check_has_super(self, thd, var))
+ return TRUE;
+
+ if (var->type == OPT_GLOBAL)
+ return FALSE;
+
+ /* If in a stored function/trigger, it's too late to change sql_log_bin. */
+ if (thd->in_sub_stmt)
+ {
+ my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN, MYF(0));
+ return TRUE;
+ }
+ /* Make the session variable 'sql_log_bin' read-only inside a transaction. */
+ if (thd->in_active_multi_stmt_transaction())
+ {
+ my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN, MYF(0));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static Sys_var_mybool Sys_log_binlog(
+ "sql_log_bin", "sql_log_bin",
+ SESSION_VAR(sql_log_bin), NO_CMD_LINE,
+ DEFAULT(TRUE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_sql_log_bin),
+ ON_UPDATE(fix_sql_log_bin_after_update));
+
+static Sys_var_bit Sys_sql_warnings(
+ "sql_warnings", "sql_warnings",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_WARNINGS,
+ DEFAULT(FALSE));
+
+static Sys_var_bit Sys_sql_notes(
+ "sql_notes", "sql_notes",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_SQL_NOTES,
+ DEFAULT(TRUE));
+
+static Sys_var_bit Sys_auto_is_null(
+ "sql_auto_is_null", "sql_auto_is_null",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_AUTO_IS_NULL,
+ DEFAULT(FALSE), NO_MUTEX_GUARD, IN_BINLOG);
+
+static Sys_var_bit Sys_safe_updates(
+ "sql_safe_updates", "sql_safe_updates",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_SAFE_UPDATES,
+ DEFAULT(FALSE));
+
+static Sys_var_bit Sys_buffer_results(
+ "sql_buffer_result", "sql_buffer_result",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_BUFFER_RESULT,
+ DEFAULT(FALSE));
+
+static Sys_var_bit Sys_quote_show_create(
+ "sql_quote_show_create", "sql_quote_show_create",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_QUOTE_SHOW_CREATE,
+ DEFAULT(TRUE));
+
+static Sys_var_bit Sys_foreign_key_checks(
+ "foreign_key_checks", "foreign_key_checks",
+ SESSION_VAR(option_bits), NO_CMD_LINE,
+ REVERSE(OPTION_NO_FOREIGN_KEY_CHECKS),
+ DEFAULT(TRUE), NO_MUTEX_GUARD, IN_BINLOG);
+
+static Sys_var_bit Sys_unique_checks(
+ "unique_checks", "unique_checks",
+ SESSION_VAR(option_bits), NO_CMD_LINE,
+ REVERSE(OPTION_RELAXED_UNIQUE_CHECKS),
+ DEFAULT(TRUE), NO_MUTEX_GUARD, IN_BINLOG);
+
+#ifdef ENABLED_PROFILING
+static Sys_var_bit Sys_profiling(
+ "profiling", "profiling",
+ SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_PROFILING,
+ DEFAULT(FALSE));
+
+static Sys_var_ulong Sys_profiling_history_size(
+ "profiling_history_size", "Limit of query profiling memory",
+ SESSION_VAR(profiling_history_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 100), DEFAULT(15), BLOCK_SIZE(1));
+#endif
+
+static Sys_var_harows Sys_select_limit(
+ "sql_select_limit",
+ "The maximum number of rows to return from SELECT statements",
+ SESSION_VAR(select_limit), NO_CMD_LINE,
+ VALID_RANGE(0, HA_POS_ERROR), DEFAULT(HA_POS_ERROR), BLOCK_SIZE(1));
+
+static bool update_timestamp(THD *thd, set_var *var)
+{
+ if (var->value)
+ thd->set_time((time_t) var->save_result.ulonglong_value);
+ else // SET timestamp=DEFAULT
+ thd->user_time= 0;
+ return false;
+}
+static ulonglong read_timestamp(THD *thd)
+{
+ return (ulonglong) thd->start_time;
+}
+
+
+static bool check_timestamp(sys_var *self, THD *thd, set_var *var)
+{
+ time_t val;
+
+ if (!var->value)
+ return FALSE;
+
+ val= (time_t) var->save_result.ulonglong_value;
+ if (val < (time_t) MY_TIME_T_MIN || val > (time_t) MY_TIME_T_MAX)
+ {
+ my_message(ER_UNKNOWN_ERROR,
+ "This version of MySQL doesn't support dates later than 2038",
+ MYF(0));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+static Sys_var_session_special Sys_timestamp(
+ "timestamp", "Set the time for this client",
+ sys_var::ONLY_SESSION, NO_CMD_LINE,
+ VALID_RANGE(0, ~(time_t)0), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_timestamp),
+ ON_UPDATE(update_timestamp), ON_READ(read_timestamp));
+
+static bool update_last_insert_id(THD *thd, set_var *var)
+{
+ if (!var->value)
+ {
+ my_error(ER_NO_DEFAULT, MYF(0), var->var->name);
+ return true;
+ }
+ thd->first_successful_insert_id_in_prev_stmt=
+ var->save_result.ulonglong_value;
+ return false;
+}
+static ulonglong read_last_insert_id(THD *thd)
+{
+ return (ulonglong) thd->read_first_successful_insert_id_in_prev_stmt();
+}
+static Sys_var_session_special Sys_last_insert_id(
+ "last_insert_id", "The value to be returned from LAST_INSERT_ID()",
+ sys_var::ONLY_SESSION, NO_CMD_LINE,
+ VALID_RANGE(0, ULONGLONG_MAX), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(update_last_insert_id), ON_READ(read_last_insert_id));
+
+// alias for last_insert_id(), Sybase-style
+static Sys_var_session_special Sys_identity(
+ "identity", "Synonym for the last_insert_id variable",
+ sys_var::ONLY_SESSION, NO_CMD_LINE,
+ VALID_RANGE(0, ULONGLONG_MAX), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(update_last_insert_id), ON_READ(read_last_insert_id));
+
+/*
+ insert_id should *not* be marked as written to the binlog (i.e., it
+ should *not* be IN_BINLOG), because we want any statement that
+ refers to insert_id explicitly to be unsafe. (By "explicitly", we
+ mean using @@session.insert_id, whereas insert_id is used
+ "implicitly" when NULL value is inserted into an auto_increment
+ column).
+
+ We want statements referring explicitly to @@session.insert_id to be
+ unsafe, because insert_id is modified internally by the slave sql
+ thread when NULL values are inserted in an AUTO_INCREMENT column.
+ This modification interfers with the value of the
+ @@session.insert_id variable if @@session.insert_id is referred
+ explicitly by an insert statement (as is seen by executing "SET
+ @@session.insert_id=0; CREATE TABLE t (a INT, b INT KEY
+ AUTO_INCREMENT); INSERT INTO t(a) VALUES (@@session.insert_id);" in
+ statement-based logging mode: t will be different on master and
+ slave).
+*/
+static bool update_insert_id(THD *thd, set_var *var)
+{
+ if (!var->value)
+ {
+ my_error(ER_NO_DEFAULT, MYF(0), var->var->name);
+ return true;
+ }
+ thd->force_one_auto_inc_interval(var->save_result.ulonglong_value);
+ return false;
+}
+
+static ulonglong read_insert_id(THD *thd)
+{
+ return thd->auto_inc_intervals_forced.minimum();
+}
+static Sys_var_session_special Sys_insert_id(
+ "insert_id", "The value to be used by the following INSERT "
+ "or ALTER TABLE statement when inserting an AUTO_INCREMENT value",
+ sys_var::ONLY_SESSION, NO_CMD_LINE,
+ VALID_RANGE(0, ULONGLONG_MAX), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(update_insert_id), ON_READ(read_insert_id));
+
+static bool update_rand_seed1(THD *thd, set_var *var)
+{
+ if (!var->value)
+ {
+ my_error(ER_NO_DEFAULT, MYF(0), var->var->name);
+ return true;
+ }
+ thd->rand.seed1= (ulong) var->save_result.ulonglong_value;
+ return false;
+}
+static ulonglong read_rand_seed(THD *thd)
+{
+ return 0;
+}
+static Sys_var_session_special Sys_rand_seed1(
+ "rand_seed1", "Sets the internal state of the RAND() "
+ "generator for replication purposes",
+ sys_var::ONLY_SESSION, NO_CMD_LINE,
+ VALID_RANGE(0, ULONG_MAX), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(update_rand_seed1), ON_READ(read_rand_seed));
+
+static bool update_rand_seed2(THD *thd, set_var *var)
+{
+ if (!var->value)
+ {
+ my_error(ER_NO_DEFAULT, MYF(0), var->var->name);
+ return true;
+ }
+ thd->rand.seed2= (ulong) var->save_result.ulonglong_value;
+ return false;
+}
+static Sys_var_session_special Sys_rand_seed2(
+ "rand_seed2", "Sets the internal state of the RAND() "
+ "generator for replication purposes",
+ sys_var::ONLY_SESSION, NO_CMD_LINE,
+ VALID_RANGE(0, ULONG_MAX), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(update_rand_seed2), ON_READ(read_rand_seed));
+
+static ulonglong read_error_count(THD *thd)
+{
+ return thd->warning_info->error_count();
+}
+// this really belongs to the SHOW STATUS
+static Sys_var_session_special Sys_error_count(
+ "error_count", "The number of errors that resulted from the "
+ "last statement that generated messages",
+ READ_ONLY sys_var::ONLY_SESSION, NO_CMD_LINE,
+ VALID_RANGE(0, ULONGLONG_MAX), BLOCK_SIZE(1), NO_MUTEX_GUARD,
+ NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0), ON_READ(read_error_count));
+
+static ulonglong read_warning_count(THD *thd)
+{
+ return thd->warning_info->warn_count();
+}
+// this really belongs to the SHOW STATUS
+static Sys_var_session_special Sys_warning_count(
+ "warning_count", "The number of errors, warnings, and notes "
+ "that resulted from the last statement that generated messages",
+ READ_ONLY sys_var::ONLY_SESSION, NO_CMD_LINE,
+ VALID_RANGE(0, ULONGLONG_MAX), BLOCK_SIZE(1), NO_MUTEX_GUARD,
+ NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0), ON_READ(read_warning_count));
+
+static Sys_var_ulong Sys_default_week_format(
+ "default_week_format",
+ "The default week format used by WEEK() functions",
+ SESSION_VAR(default_week_format), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 7), DEFAULT(0), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_group_concat_max_len(
+ "group_concat_max_len",
+ "The maximum length of the result of function GROUP_CONCAT()",
+ SESSION_VAR(group_concat_max_len), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(4, ULONG_MAX), DEFAULT(1024), BLOCK_SIZE(1));
+
+static char *glob_hostname_ptr;
+static Sys_var_charptr Sys_hostname(
+ "hostname", "Server host name",
+ READ_ONLY GLOBAL_VAR(glob_hostname_ptr), NO_CMD_LINE,
+ IN_FS_CHARSET, DEFAULT(glob_hostname));
+
+#ifndef EMBEDDED_LIBRARY
+static Sys_var_charptr Sys_repl_report_host(
+ "report_host",
+ "Hostname or IP of the slave to be reported to the master during "
+ "slave registration. Will appear in the output of SHOW SLAVE HOSTS. "
+ "Leave unset if you do not want the slave to register itself with the "
+ "master. Note that it is not sufficient for the master to simply read "
+ "the IP of the slave off the socket once the slave connects. Due to "
+ "NAT and other routing issues, that IP may not be valid for connecting "
+ "to the slave from the master or other hosts",
+ READ_ONLY GLOBAL_VAR(report_host), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_charptr Sys_repl_report_user(
+ "report_user",
+ "The account user name of the slave to be reported to the master "
+ "during slave registration",
+ READ_ONLY GLOBAL_VAR(report_user), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_charptr Sys_repl_report_password(
+ "report_password",
+ "The account password of the slave to be reported to the master "
+ "during slave registration",
+ READ_ONLY GLOBAL_VAR(report_password), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_uint Sys_repl_report_port(
+ "report_port",
+ "Port for connecting to slave reported to the master during slave "
+ "registration. Set it only if the slave is listening on a non-default "
+ "port or if you have a special tunnel from the master or other clients "
+ "to the slave. If not sure, leave this option unset",
+ READ_ONLY GLOBAL_VAR(report_port), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, UINT_MAX), DEFAULT(MYSQL_PORT), BLOCK_SIZE(1));
+#endif
+
+static Sys_var_mybool Sys_keep_files_on_create(
+ "keep_files_on_create",
+ "Don't overwrite stale .MYD and .MYI even if no directory is specified",
+ SESSION_VAR(keep_files_on_create), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE));
+
+static char *license;
+static Sys_var_charptr Sys_license(
+ "license", "The type of license the server has",
+ READ_ONLY GLOBAL_VAR(license), NO_CMD_LINE, IN_SYSTEM_CHARSET,
+ DEFAULT(STRINGIFY_ARG(LICENSE)));
+
+static bool check_log_path(sys_var *self, THD *thd, set_var *var)
+{
+ if (!var->value)
+ return false; // DEFAULT is ok
+
+ if (!var->save_result.string_value.str)
+ return true;
+
+ if (var->save_result.string_value.length > FN_REFLEN)
+ { // path is too long
+ my_error(ER_PATH_LENGTH, MYF(0), self->name.str);
+ return true;
+ }
+
+ char path[FN_REFLEN];
+ size_t path_length= unpack_filename(path, var->save_result.string_value.str);
+
+ if (!path_length)
+ return true;
+
+ MY_STAT f_stat;
+
+ if (my_stat(path, &f_stat, MYF(0)))
+ {
+ if (!MY_S_ISREG(f_stat.st_mode) || !(f_stat.st_mode & MY_S_IWRITE))
+ return true; // not a regular writable file
+ return false;
+ }
+
+ (void) dirname_part(path, var->save_result.string_value.str, &path_length);
+
+ if (var->save_result.string_value.length - path_length >= FN_LEN)
+ { // filename is too long
+ my_error(ER_PATH_LENGTH, MYF(0), self->name.str);
+ return true;
+ }
+
+ if (!path_length) // no path is good path (remember, relative to datadir)
+ return false;
+
+ if (my_access(path, (F_OK|W_OK)))
+ return true; // directory is not writable
+
+ return false;
+}
+static bool fix_log(char** logname, const char* default_logname,
+ const char*ext, bool enabled, void (*reopen)(char*))
+{
+ if (!*logname) // SET ... = DEFAULT
+ {
+ char buff[FN_REFLEN];
+ *logname= my_strdup(make_log_name(buff, default_logname, ext),
+ MYF(MY_FAE+MY_WME));
+ if (!*logname)
+ return true;
+ }
+ logger.lock_exclusive();
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ if (enabled)
+ reopen(*logname);
+ logger.unlock();
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ return false;
+}
+static void reopen_general_log(char* name)
+{
+ logger.get_log_file_handler()->close(0);
+ logger.get_log_file_handler()->open_query_log(name);
+}
+static bool fix_general_log_file(sys_var *self, THD *thd, enum_var_type type)
+{
+ return fix_log(&opt_logname, default_logfile_name, ".log", opt_log,
+ reopen_general_log);
+}
+static Sys_var_charptr Sys_general_log_path(
+ "general_log_file", "Log connections and queries to given file",
+ PREALLOCATED GLOBAL_VAR(opt_logname), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_log_path), ON_UPDATE(fix_general_log_file));
+
+static void reopen_slow_log(char* name)
+{
+ logger.get_slow_log_file_handler()->close(0);
+ logger.get_slow_log_file_handler()->open_slow_log(name);
+}
+static bool fix_slow_log_file(sys_var *self, THD *thd, enum_var_type type)
+{
+ return fix_log(&opt_slow_logname, default_logfile_name, "-slow.log",
+ opt_slow_log, reopen_slow_log);
+}
+static Sys_var_charptr Sys_slow_log_path(
+ "slow_query_log_file", "Log slow queries to given log file. "
+ "Defaults logging to hostname-slow.log. Must be enabled to activate "
+ "other slow log options",
+ PREALLOCATED GLOBAL_VAR(opt_slow_logname), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_log_path), ON_UPDATE(fix_slow_log_file));
+
+/// @todo deprecate these four legacy have_PLUGIN variables and use I_S instead
+export SHOW_COMP_OPTION have_csv, have_innodb;
+export SHOW_COMP_OPTION have_ndbcluster, have_partitioning;
+static Sys_var_have Sys_have_csv(
+ "have_csv", "have_csv",
+ READ_ONLY GLOBAL_VAR(have_csv), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_innodb(
+ "have_innodb", "have_innodb",
+ READ_ONLY GLOBAL_VAR(have_innodb), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_ndbcluster(
+ "have_ndbcluster", "have_ndbcluster",
+ READ_ONLY GLOBAL_VAR(have_ndbcluster), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_partition_db(
+ "have_partitioning", "have_partitioning",
+ READ_ONLY GLOBAL_VAR(have_partitioning), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_compress(
+ "have_compress", "have_compress",
+ READ_ONLY GLOBAL_VAR(have_compress), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_crypt(
+ "have_crypt", "have_crypt",
+ READ_ONLY GLOBAL_VAR(have_crypt), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_dlopen(
+ "have_dynamic_loading", "have_dynamic_loading",
+ READ_ONLY GLOBAL_VAR(have_dlopen), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_geometry(
+ "have_geometry", "have_geometry",
+ READ_ONLY GLOBAL_VAR(have_geometry), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_openssl(
+ "have_openssl", "have_openssl",
+ READ_ONLY GLOBAL_VAR(have_ssl), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_profiling(
+ "have_profiling", "have_profiling",
+ READ_ONLY GLOBAL_VAR(have_profiling), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_query_cache(
+ "have_query_cache", "have_query_cache",
+ READ_ONLY GLOBAL_VAR(have_query_cache), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_rtree_keys(
+ "have_rtree_keys", "have_rtree_keys",
+ READ_ONLY GLOBAL_VAR(have_rtree_keys), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_ssl(
+ "have_ssl", "have_ssl",
+ READ_ONLY GLOBAL_VAR(have_ssl), NO_CMD_LINE);
+
+static Sys_var_have Sys_have_symlink(
+ "have_symlink", "have_symlink",
+ READ_ONLY GLOBAL_VAR(have_symlink), NO_CMD_LINE);
+
+static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type);
+static Sys_var_mybool Sys_general_log(
+ "general_log", "Log connections and queries to a table or log file. "
+ "Defaults logging to a file hostname.log or a table mysql.general_log"
+ "if --log-output=TABLE is used",
+ GLOBAL_VAR(opt_log), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_log_state));
+
+// Synonym of "general_log" for consistency with SHOW VARIABLES output
+static Sys_var_mybool Sys_log(
+ "log", "Alias for --general-log. Deprecated",
+ GLOBAL_VAR(opt_log), NO_CMD_LINE,
+ DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_log_state), DEPRECATED(70000, "'@@general_log'"));
+
+static Sys_var_mybool Sys_slow_query_log(
+ "slow_query_log",
+ "Log slow queries to a table or log file. Defaults logging to a file "
+ "hostname-slow.log or a table mysql.slow_log if --log-output=TABLE is "
+ "used. Must be enabled to activate other slow log options",
+ GLOBAL_VAR(opt_slow_log), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_log_state));
+
+/* Synonym of "slow_query_log" for consistency with SHOW VARIABLES output */
+static Sys_var_mybool Sys_log_slow(
+ "log_slow_queries",
+ "Alias for --slow-query-log. Deprecated",
+ GLOBAL_VAR(opt_slow_log), NO_CMD_LINE,
+ DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_log_state), DEPRECATED(70000, "'@@slow_query_log'"));
+
+static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type)
+{
+ bool res;
+ my_bool *UNINIT_VAR(newvalptr), newval, UNINIT_VAR(oldval);
+ uint UNINIT_VAR(log_type);
+
+ if (self == &Sys_general_log || self == &Sys_log)
+ {
+ newvalptr= &opt_log;
+ oldval= logger.get_log_file_handler()->is_open();
+ log_type= QUERY_LOG_GENERAL;
+ }
+ else if (self == &Sys_slow_query_log || self == &Sys_log_slow)
+ {
+ newvalptr= &opt_slow_log;
+ oldval= logger.get_slow_log_file_handler()->is_open();
+ log_type= QUERY_LOG_SLOW;
+ }
+ else
+ DBUG_ASSERT(FALSE);
+
+ newval= *newvalptr;
+ if (oldval == newval)
+ return false;
+
+ *newvalptr= oldval; // [de]activate_log_handler works that way (sigh)
+
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ if (!newval)
+ {
+ logger.deactivate_log_handler(thd, log_type);
+ res= false;
+ }
+ else
+ res= logger.activate_log_handler(thd, log_type);
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ return res;
+}
+
+static bool check_not_empty_set(sys_var *self, THD *thd, set_var *var)
+{
+ return var->save_result.ulonglong_value == 0;
+}
+static bool fix_log_output(sys_var *self, THD *thd, enum_var_type type)
+{
+ logger.lock_exclusive();
+ logger.init_slow_log(log_output_options);
+ logger.init_general_log(log_output_options);
+ logger.unlock();
+ return false;
+}
+
+static const char *log_output_names[] = { "NONE", "FILE", "TABLE", NULL};
+
+static Sys_var_set Sys_log_output(
+ "log_output", "Syntax: log-output=value[,value...], "
+ "where \"value\" could be TABLE, FILE or NONE",
+ GLOBAL_VAR(log_output_options), CMD_LINE(REQUIRED_ARG),
+ log_output_names, DEFAULT(LOG_FILE), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_not_empty_set), ON_UPDATE(fix_log_output));
+
+#ifdef HAVE_REPLICATION
+static Sys_var_mybool Sys_log_slave_updates(
+ "log_slave_updates", "Tells the slave to log the updates from "
+ "the slave thread to the binary log. You will need to turn it on if "
+ "you plan to daisy-chain the slaves",
+ READ_ONLY GLOBAL_VAR(opt_log_slave_updates), CMD_LINE(OPT_ARG),
+ DEFAULT(0));
+
+static Sys_var_charptr Sys_relay_log(
+ "relay_log", "The location and name to use for relay logs",
+ READ_ONLY GLOBAL_VAR(opt_relay_logname), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_charptr Sys_relay_log_index(
+ "relay_log_index", "The location and name to use for the file "
+ "that keeps a list of the last relay logs",
+ READ_ONLY GLOBAL_VAR(opt_relaylog_index_name), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_charptr Sys_relay_log_info_file(
+ "relay_log_info_file", "The location and name of the file that "
+ "remembers where the SQL replication thread is in the relay logs",
+ READ_ONLY GLOBAL_VAR(relay_log_info_file), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static Sys_var_mybool Sys_relay_log_purge(
+ "relay_log_purge", "if disabled - do not purge relay logs. "
+ "if enabled - purge them as soon as they are no more needed",
+ GLOBAL_VAR(relay_log_purge), CMD_LINE(OPT_ARG), DEFAULT(TRUE));
+
+static Sys_var_mybool Sys_relay_log_recovery(
+ "relay_log_recovery", "Enables automatic relay log recovery "
+ "right after the database startup, which means that the IO Thread "
+ "starts re-fetching from the master right after the last transaction "
+ "processed",
+ GLOBAL_VAR(relay_log_recovery), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_charptr Sys_slave_load_tmpdir(
+ "slave_load_tmpdir", "The location where the slave should put "
+ "its temporary files when replicating a LOAD DATA INFILE command",
+ READ_ONLY GLOBAL_VAR(slave_load_tmpdir), CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(0));
+
+static bool fix_slave_net_timeout(sys_var *self, THD *thd, enum_var_type type)
+{
+ mysql_mutex_lock(&LOCK_active_mi);
+ DBUG_PRINT("info", ("slave_net_timeout=%u mi->heartbeat_period=%.3f",
+ slave_net_timeout,
+ (active_mi? active_mi->heartbeat_period : 0.0)));
+ if (active_mi && slave_net_timeout < active_mi->heartbeat_period)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX,
+ ER(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX));
+ mysql_mutex_unlock(&LOCK_active_mi);
+ return false;
+}
+static Sys_var_uint Sys_slave_net_timeout(
+ "slave_net_timeout", "Number of seconds to wait for more data "
+ "from a master/slave connection before aborting the read",
+ GLOBAL_VAR(slave_net_timeout), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(SLAVE_NET_TIMEOUT), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(fix_slave_net_timeout));
+
+static bool check_slave_skip_counter(sys_var *self, THD *thd, set_var *var)
+{
+ bool result= false;
+ mysql_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&active_mi->rli.run_lock);
+ if (active_mi->rli.slave_running)
+ {
+ my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
+ result= true;
+ }
+ mysql_mutex_unlock(&active_mi->rli.run_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ return result;
+}
+static bool fix_slave_skip_counter(sys_var *self, THD *thd, enum_var_type type)
+{
+ mysql_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&active_mi->rli.run_lock);
+ /*
+ The following test should normally never be true as we test this
+ in the check function; To be safe against multiple
+ SQL_SLAVE_SKIP_COUNTER request, we do the check anyway
+ */
+ if (!active_mi->rli.slave_running)
+ {
+ mysql_mutex_lock(&active_mi->rli.data_lock);
+ active_mi->rli.slave_skip_counter= sql_slave_skip_counter;
+ mysql_mutex_unlock(&active_mi->rli.data_lock);
+ }
+ mysql_mutex_unlock(&active_mi->rli.run_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ return 0;
+}
+static Sys_var_uint Sys_slave_skip_counter(
+ "sql_slave_skip_counter", "sql_slave_skip_counter",
+ GLOBAL_VAR(sql_slave_skip_counter), NO_CMD_LINE,
+ VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_slave_skip_counter),
+ ON_UPDATE(fix_slave_skip_counter));
+
+static Sys_var_charptr Sys_slave_skip_errors(
+ "slave_skip_errors", "Tells the slave thread to continue "
+ "replication when a query event returns an error from the "
+ "provided list",
+ READ_ONLY GLOBAL_VAR(opt_slave_skip_errors), CMD_LINE(REQUIRED_ARG),
+ IN_SYSTEM_CHARSET, DEFAULT(0));
+
+static Sys_var_ulonglong Sys_relay_log_space_limit(
+ "relay_log_space_limit", "Maximum space to use for all relay logs",
+ READ_ONLY GLOBAL_VAR(relay_log_space_limit), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1));
+
+static Sys_var_uint Sys_sync_relaylog_period(
+ "sync_relay_log", "Synchronously flush relay log to disk after "
+ "every #th event. Use 0 (default) to disable synchronous flushing",
+ GLOBAL_VAR(sync_relaylog_period), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1));
+
+static Sys_var_uint Sys_sync_relayloginfo_period(
+ "sync_relay_log_info", "Synchronously flush relay log info "
+ "to disk after every #th transaction. Use 0 (default) to disable "
+ "synchronous flushing",
+ GLOBAL_VAR(sync_relayloginfo_period), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1));
+#endif
+
+static Sys_var_uint Sys_sync_binlog_period(
+ "sync_binlog", "Synchronously flush binary log to disk after "
+ "every #th event. Use 0 (default) to disable synchronous flushing",
+ GLOBAL_VAR(sync_binlog_period), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1));
+
+static Sys_var_uint Sys_sync_masterinfo_period(
+ "sync_master_info", "Synchronously flush master info to disk "
+ "after every #th event. Use 0 (default) to disable synchronous flushing",
+ GLOBAL_VAR(sync_masterinfo_period), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1));
+
+#ifdef HAVE_REPLICATION
+static Sys_var_ulong Sys_slave_trans_retries(
+ "slave_transaction_retries", "Number of times the slave SQL "
+ "thread will retry a transaction in case it failed with a deadlock "
+ "or elapsed lock wait timeout, before giving up and stopping",
+ GLOBAL_VAR(slave_trans_retries), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, ULONG_MAX), DEFAULT(10), BLOCK_SIZE(1));
+#endif
+
+static bool check_locale(sys_var *self, THD *thd, set_var *var)
+{
+ if (!var->value)
+ return false;
+
+ MY_LOCALE *locale;
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ if (var->value->result_type() == INT_RESULT)
+ {
+ int lcno= (int)var->value->val_int();
+ if (!(locale= my_locale_by_number(lcno)))
+ {
+ my_error(ER_UNKNOWN_LOCALE, MYF(0), llstr(lcno, buff));
+ return true;
+ }
+ if (check_not_null(self, thd, var))
+ return true;
+ }
+ else // STRING_RESULT
+ {
+ String str(buff, sizeof(buff), system_charset_info), *res;
+ if (!(res=var->value->val_str(&str)))
+ return true;
+ else if (!(locale= my_locale_by_name(res->c_ptr())))
+ {
+ ErrConvString err(res);
+ my_error(ER_UNKNOWN_LOCALE, MYF(0), err.ptr());
+ return true;
+ }
+ }
+
+ var->save_result.ptr= locale;
+
+ if (!locale->errmsgs->errmsgs)
+ {
+ mysql_mutex_lock(&LOCK_error_messages);
+ if (!locale->errmsgs->errmsgs &&
+ read_texts(ERRMSG_FILE, locale->errmsgs->language,
+ &locale->errmsgs->errmsgs,
+ ER_ERROR_LAST - ER_ERROR_FIRST + 1))
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
+ "Can't process error message file for locale '%s'",
+ locale->name);
+ mysql_mutex_unlock(&LOCK_error_messages);
+ return true;
+ }
+ mysql_mutex_unlock(&LOCK_error_messages);
+ }
+ return false;
+}
+static Sys_var_struct Sys_lc_messages(
+ "lc_messages", "Set the language used for the error messages",
+ SESSION_VAR(lc_messages), NO_CMD_LINE,
+ my_offsetof(MY_LOCALE, name), DEFAULT(&my_default_lc_messages),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_locale));
+
+static Sys_var_struct Sys_lc_time_names(
+ "lc_time_names", "Set the language used for the month "
+ "names and the days of the week",
+ SESSION_VAR(lc_time_names), NO_CMD_LINE,
+ my_offsetof(MY_LOCALE, name), DEFAULT(&my_default_lc_time_names),
+ NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_locale));
+
+static Sys_var_tz Sys_time_zone(
+ "time_zone", "time_zone",
+ SESSION_VAR(time_zone), NO_CMD_LINE,
+ DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG);
+
diff --git a/sql/sys_vars.h b/sql/sys_vars.h
new file mode 100644
index 00000000000..e16bd3c5330
--- /dev/null
+++ b/sql/sys_vars.h
@@ -0,0 +1,1689 @@
+/* Copyright (C) 2002-2006 MySQL AB, 2009-2010 Sun Microsystems, Inc.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/**
+ @file
+ "private" interface to sys_var - server configuration variables.
+
+ This header is included only by the file that contains declarations
+ of sys_var variables (sys_vars.cc).
+*/
+
+#include "sys_vars_shared.h"
+#include <my_getopt.h>
+#include <my_bit.h>
+#include <my_dir.h>
+#include "keycaches.h"
+#include "strfunc.h"
+#include "tztime.h" // my_tz_find, my_tz_SYSTEM, struct Time_zone
+
+/*
+ a set of mostly trivial (as in f(X)=X) defines below to make system variable
+ declarations more readable
+*/
+#define VALID_RANGE(X,Y) X,Y
+#define DEFAULT(X) X
+#define BLOCK_SIZE(X) X
+#define GLOBAL_VAR(X) sys_var::GLOBAL, (((char*)&(X))-(char*)&global_system_variables), sizeof(X)
+#define SESSION_VAR(X) sys_var::SESSION, offsetof(SV, X), sizeof(((SV *)0)->X)
+#define SESSION_ONLY(X) sys_var::ONLY_SESSION, offsetof(SV, X), sizeof(((SV *)0)->X)
+#define NO_CMD_LINE CMD_LINE(NO_ARG, -1)
+/*
+ the define below means that there's no *second* mutex guard,
+ LOCK_global_system_variables always guards all system variables
+*/
+#define NO_MUTEX_GUARD ((PolyLock*)0)
+#define IN_BINLOG sys_var::SESSION_VARIABLE_IN_BINLOG
+#define NOT_IN_BINLOG sys_var::VARIABLE_NOT_IN_BINLOG
+#define ON_READ(X) X
+#define ON_CHECK(X) X
+#define ON_UPDATE(X) X
+#define READ_ONLY sys_var::READONLY+
+// this means that Sys_var_charptr initial value was malloc()ed
+#define PREALLOCATED sys_var::ALLOCATED+
+/*
+ Sys_var_bit meaning is reversed, like in
+ @@foreign_key_checks <-> OPTION_NO_FOREIGN_KEY_CHECKS
+*/
+#define REVERSE(X) ~(X)
+#define DEPRECATED(X, Y) X, Y
+
+#define session_var(THD, TYPE) (*(TYPE*)session_var_ptr(THD))
+#define global_var(TYPE) (*(TYPE*)global_var_ptr())
+
+#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
+#define GET_HA_ROWS GET_ULL
+#else
+#define GET_HA_ROWS GET_ULONG
+#endif
+
+enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET};
+
+static const char *bool_values[3]= {"OFF", "ON", 0};
+TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 };
+
+/**
+ A small wrapper class to pass getopt arguments as a pair
+ to the Sys_var_* constructors. It improves type safety and helps
+ to catch errors in the argument order.
+*/
+struct CMD_LINE
+{
+ int id;
+ enum get_opt_arg_type arg_type;
+ CMD_LINE(enum get_opt_arg_type getopt_arg_type, int getopt_id=0)
+ : id(getopt_id), arg_type(getopt_arg_type) {}
+};
+
+/**
+ Sys_var_unsigned template is used to generate Sys_var_* classes
+ for variables that represent the value as an unsigned integer.
+ They are Sys_var_uint, Sys_var_ulong, Sys_var_harows, Sys_var_ulonglong.
+
+ An integer variable has a minimal and maximal values, and a "block_size"
+ (any valid value of the variable must be divisible by the block_size).
+
+ Class specific constructor arguments: min, max, block_size
+ Backing store: uint, ulong, ha_rows, ulonglong, depending on the Sys_var_*
+*/
+template <typename T, ulong ARGT, enum enum_mysql_show_type SHOWT>
+class Sys_var_unsigned: public sys_var
+{
+public:
+ Sys_var_unsigned(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ T min_val, T max_val, T def_val, uint block_size, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0,
+ int parse_flag= PARSE_NORMAL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOWT, def_val, lock, binlog_status_arg,
+ on_check_func, on_update_func, deprecated_version,
+ substitute, parse_flag)
+ {
+ option.var_type= ARGT;
+ option.min_value= min_val;
+ option.max_value= max_val;
+ option.block_size= block_size;
+ option.u_max_value= (uchar**)max_var_ptr();
+ if (max_var_ptr())
+ *max_var_ptr()= max_val;
+ global_var(T)= def_val;
+ DBUG_ASSERT(size == sizeof(T));
+ DBUG_ASSERT(min_val < max_val);
+ DBUG_ASSERT(min_val <= def_val);
+ DBUG_ASSERT(max_val >= def_val);
+ DBUG_ASSERT(block_size > 0);
+ DBUG_ASSERT(def_val % block_size == 0);
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ my_bool fixed= FALSE;
+ ulonglong uv;
+ longlong v;
+
+ v= var->value->val_int();
+ if (var->value->unsigned_flag)
+ uv= (ulonglong) v;
+ else
+ uv= (ulonglong) (v < 0 ? 0 : v);
+
+ var->save_result.ulonglong_value=
+ getopt_ull_limit_value(uv, &option, &fixed);
+
+ if (max_var_ptr() && var->save_result.ulonglong_value > *max_var_ptr())
+ var->save_result.ulonglong_value= *max_var_ptr();
+
+ return throw_bounds_warning(thd, name.str,
+ var->save_result.ulonglong_value != uv,
+ var->value->unsigned_flag, v);
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, T)= var->save_result.ulonglong_value;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(T)= var->save_result.ulonglong_value;
+ return false;
+ }
+ bool check_update_type(Item_result type)
+ { return type != INT_RESULT; }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= (ulonglong)*(T*)global_value_ptr(thd, 0); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+ private:
+ T *max_var_ptr()
+ {
+ return scope() == SESSION ? (T*)(((uchar*)&max_system_variables) + offset)
+ : 0;
+ }
+};
+
+typedef Sys_var_unsigned<uint, GET_UINT, SHOW_INT> Sys_var_uint;
+typedef Sys_var_unsigned<ulong, GET_ULONG, SHOW_LONG> Sys_var_ulong;
+typedef Sys_var_unsigned<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS> Sys_var_harows;
+typedef Sys_var_unsigned<ulonglong, GET_ULL, SHOW_LONGLONG> Sys_var_ulonglong;
+
+/**
+ Helper class for variables that take values from a TYPELIB
+*/
+class Sys_var_typelib: public sys_var
+{
+protected:
+ TYPELIB typelib;
+public:
+ Sys_var_typelib(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off,
+ CMD_LINE getopt,
+ SHOW_TYPE show_val_type_arg, const char *values[],
+ ulonglong def_val, PolyLock *lock,
+ enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func, on_update_function on_update_func,
+ uint deprecated_version, const char *substitute, int parse_flag= PARSE_NORMAL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, show_val_type_arg, def_val, lock,
+ binlog_status_arg, on_check_func,
+ on_update_func, deprecated_version, substitute, parse_flag)
+ {
+ for (typelib.count= 0; values[typelib.count]; typelib.count++) /*no-op */;
+ typelib.name="";
+ typelib.type_names= values;
+ typelib.type_lengths= 0; // only used by Fields_enum and Field_set
+ option.typelib= &typelib;
+ }
+ bool do_check(THD *thd, set_var *var) // works for enums and my_bool
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+
+ if (var->value->result_type() == STRING_RESULT)
+ {
+ if (!(res=var->value->val_str(&str)))
+ return true;
+ else
+ if (!(var->save_result.ulonglong_value=
+ find_type(&typelib, res->ptr(), res->length(), false)))
+ return true;
+ else
+ var->save_result.ulonglong_value--;
+ }
+ else
+ {
+ longlong tmp=var->value->val_int();
+ if (tmp < 0 || tmp >= typelib.count)
+ return true;
+ else
+ var->save_result.ulonglong_value= tmp;
+ }
+
+ return false;
+ }
+ bool check_update_type(Item_result type)
+ { return type != INT_RESULT && type != STRING_RESULT; }
+};
+
+/**
+ The class for ENUM variables - variables that take one value from a fixed
+ list of values.
+
+ Class specific constructor arguments:
+ char* values[] - 0-terminated list of strings of valid values
+
+ Backing store: uint
+
+ @note
+ Do *not* use "enum FOO" variables as a backing store, there is no
+ guarantee that sizeof(enum FOO) == sizeof(uint), there is no guarantee
+ even that sizeof(enum FOO) == sizeof(enum BAR)
+*/
+class Sys_var_enum: public Sys_var_typelib
+{
+public:
+ Sys_var_enum(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *values[], uint def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0)
+ : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
+ SHOW_CHAR, values, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute)
+ {
+ option.var_type= GET_ENUM;
+ global_var(ulong)= def_val;
+ DBUG_ASSERT(def_val < typelib.count);
+ DBUG_ASSERT(size == sizeof(ulong));
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, ulong)= var->save_result.ulonglong_value;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(ulong)= var->save_result.ulonglong_value;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= global_var(ulong); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ { return (uchar*)typelib.type_names[session_var(thd, ulong)]; }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ { return (uchar*)typelib.type_names[global_var(ulong)]; }
+};
+
+/**
+ The class for boolean variables - a variant of ENUM variables
+ with the fixed list of values of { OFF , ON }
+
+ Backing store: my_bool
+*/
+class Sys_var_mybool: public Sys_var_typelib
+{
+public:
+ Sys_var_mybool(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ my_bool def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0,
+ int parse_flag= PARSE_NORMAL)
+ : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
+ SHOW_MY_BOOL, bool_values, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute, parse_flag)
+ {
+ option.var_type= GET_BOOL;
+ global_var(my_bool)= def_val;
+ DBUG_ASSERT(def_val < 2);
+ DBUG_ASSERT(getopt.arg_type == OPT_ARG || getopt.id == -1);
+ DBUG_ASSERT(size == sizeof(my_bool));
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, my_bool)= var->save_result.ulonglong_value;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(my_bool)= var->save_result.ulonglong_value;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= (ulonglong)*(my_bool *)global_value_ptr(thd, 0); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+};
+
+/**
+ The class for string variables. The string can be in character_set_filesystem
+ or in character_set_system. The string can be allocated with my_malloc()
+ or not. The state of the initial value is specified in the constructor,
+ after that it's managed automatically. The value of NULL is supported.
+
+ Class specific constructor arguments:
+ enum charset_enum is_os_charset_arg
+
+ Backing store: char*
+
+ @note
+ This class supports only GLOBAL variables, because THD on destruction
+ does not destroy individual members of SV, there's no way to free
+ allocated string variables for every thread.
+*/
+class Sys_var_charptr: public sys_var
+{
+public:
+ Sys_var_charptr(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ enum charset_enum is_os_charset_arg,
+ const char *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0,
+ int parse_flag= PARSE_NORMAL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR_PTR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute, parse_flag)
+ {
+ is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
+ /*
+ use GET_STR_ALLOC - if ALLOCATED it must be *always* allocated,
+ otherwise (GET_STR) you'll never know whether to free it or not.
+ (think of an exit because of an error right after my_getopt)
+ */
+ option.var_type= (flags & ALLOCATED) ? GET_STR_ALLOC : GET_STR;
+ global_var(const char*)= def_val;
+ DBUG_ASSERT(scope() == GLOBAL);
+ DBUG_ASSERT(size == sizeof(char *));
+ }
+ void cleanup()
+ {
+ if (flags & ALLOCATED)
+ my_free(global_var(char*));
+ flags&= ~ALLOCATED;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE], buff2[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), charset(thd));
+ String str2(buff2, sizeof(buff2), charset(thd)), *res;
+
+ if (!(res=var->value->val_str(&str)))
+ var->save_result.string_value.str= 0;
+ else
+ {
+ uint32 unused;
+ if (String::needs_conversion(res->length(), res->charset(),
+ charset(thd), &unused))
+ {
+ uint errors;
+ str2.copy(res->ptr(), res->length(), res->charset(), charset(thd),
+ &errors);
+ res=&str2;
+
+ }
+ var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
+ var->save_result.string_value.length= res->length();
+ }
+
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ char *new_val, *ptr= var->save_result.string_value.str;
+ size_t len=var->save_result.string_value.length;
+ if (ptr)
+ {
+ new_val= (char*)my_memdup(ptr, len+1, MYF(MY_WME));
+ if (!new_val) return true;
+ new_val[len]=0;
+ }
+ else
+ new_val= 0;
+ if (flags & ALLOCATED)
+ my_free(global_var(char*));
+ flags|= ALLOCATED;
+ global_var(char*)= new_val;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ char *ptr= (char*)(intptr)option.def_value;
+ var->save_result.string_value.str= ptr;
+ var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
+ }
+ bool check_update_type(Item_result type)
+ { return type != STRING_RESULT; }
+};
+
+
+class Sys_var_proxy_user: public sys_var
+{
+public:
+ Sys_var_proxy_user(const char *name_arg,
+ const char *comment, enum charset_enum is_os_charset_arg)
+ : sys_var(&all_sys_vars, name_arg, comment,
+ sys_var::READONLY+sys_var::ONLY_SESSION, 0, -1,
+ NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, 0, NULL, PARSE_NORMAL)
+ {
+ is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
+ option.var_type= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+ void global_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+ bool check_update_type(Item_result type)
+ { return true; }
+protected:
+ virtual uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ return thd->security_ctx->proxy_user[0] ?
+ (uchar *) &(thd->security_ctx->proxy_user[0]) : NULL;
+ }
+};
+
+class Sys_var_external_user : public Sys_var_proxy_user
+{
+public:
+ Sys_var_external_user(const char *name_arg, const char *comment_arg,
+ enum charset_enum is_os_charset_arg)
+ : Sys_var_proxy_user (name_arg, comment_arg, is_os_charset_arg)
+ {}
+
+protected:
+ virtual uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ return thd->security_ctx->proxy_user[0] ?
+ (uchar *) &(thd->security_ctx->proxy_user[0]) : NULL;
+ }
+};
+
+/**
+ The class for string variables. Useful for strings that aren't necessarily
+ \0-terminated. Otherwise the same as Sys_var_charptr.
+
+ Class specific constructor arguments:
+ enum charset_enum is_os_charset_arg
+
+ Backing store: LEX_STRING
+
+ @note
+ Behaves exactly as Sys_var_charptr, only the backing store is different.
+*/
+class Sys_var_lexstring: public Sys_var_charptr
+{
+public:
+ Sys_var_lexstring(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ enum charset_enum is_os_charset_arg,
+ const char *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0)
+ : Sys_var_charptr(name_arg, comment, flag_args, off, sizeof(char*),
+ getopt, is_os_charset_arg, def_val, lock, binlog_status_arg,
+ on_check_func, on_update_func, deprecated_version, substitute)
+ {
+ global_var(LEX_STRING).length= strlen(def_val);
+ DBUG_ASSERT(size == sizeof(LEX_STRING));
+ *const_cast<SHOW_TYPE*>(&show_val_type)= SHOW_LEX_STRING;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ if (Sys_var_charptr::global_update(thd, var))
+ return true;
+ global_var(LEX_STRING).length= var->save_result.string_value.length;
+ return false;
+ }
+};
+
+#ifndef DBUG_OFF
+/**
+ @@session.dbug and @@global.dbug variables.
+
+ @@dbug variable differs from other variables in one aspect:
+ if its value is not assigned in the session, it "points" to the global
+ value, and so when the global value is changed, the change
+ immediately takes effect in the session.
+
+ This semantics is intentional, to be able to debug one session from
+ another.
+*/
+class Sys_var_dbug: public sys_var
+{
+public:
+ Sys_var_dbug(const char *name_arg,
+ const char *comment, int flag_args,
+ CMD_LINE getopt,
+ const char *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0,
+ int parse_flag= PARSE_NORMAL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute, parse_flag)
+ { option.var_type= GET_NO_ARG; }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+
+ if (!(res=var->value->val_str(&str)))
+ var->save_result.string_value.str= const_cast<char*>("");
+ else
+ var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ const char *val= var->save_result.string_value.str;
+ if (!var->value)
+ DBUG_POP();
+ else
+ DBUG_SET(val);
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ const char *val= var->save_result.string_value.str;
+ DBUG_SET_INITIAL(val);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ char *ptr= (char*)(intptr)option.def_value;
+ var->save_result.string_value.str= ptr;
+ }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ char buf[256];
+ DBUG_EXPLAIN(buf, sizeof(buf));
+ return (uchar*) thd->strdup(buf);
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ char buf[256];
+ DBUG_EXPLAIN_INITIAL(buf, sizeof(buf));
+ return (uchar*) thd->strdup(buf);
+ }
+ bool check_update_type(Item_result type)
+ { return type != STRING_RESULT; }
+};
+#endif
+
+#define KEYCACHE_VAR(X) sys_var::GLOBAL,offsetof(KEY_CACHE, X), sizeof(((KEY_CACHE *)0)->X)
+#define keycache_var_ptr(KC, OFF) (((uchar*)(KC))+(OFF))
+#define keycache_var(KC, OFF) (*(ulonglong*)keycache_var_ptr(KC, OFF))
+typedef bool (*keycache_update_function)(THD *, KEY_CACHE *, ptrdiff_t, ulonglong);
+
+/**
+ The class for keycache_* variables. Supports structured names,
+ keycache_name.variable_name.
+
+ Class specific constructor arguments:
+ everything derived from Sys_var_ulonglong
+
+ Backing store: ulonglong
+
+ @note these variables can be only GLOBAL
+*/
+class Sys_var_keycache: public Sys_var_ulonglong
+{
+ keycache_update_function keycache_update;
+public:
+ Sys_var_keycache(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ ulonglong min_val, ulonglong max_val, ulonglong def_val,
+ ulonglong block_size, PolyLock *lock,
+ enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func,
+ keycache_update_function on_update_func,
+ uint deprecated_version=0, const char *substitute=0)
+ : Sys_var_ulonglong(name_arg, comment, flag_args, off, size,
+ getopt, min_val, max_val, def_val,
+ block_size, lock, binlog_status_arg, on_check_func, 0,
+ deprecated_version, substitute),
+ keycache_update(on_update_func)
+ {
+ option.var_type|= GET_ASK_ADDR;
+ option.value= (uchar**)1; // crash me, please
+ keycache_var(dflt_key_cache, off)= def_val;
+ DBUG_ASSERT(scope() == GLOBAL);
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ ulonglong new_value= var->save_result.ulonglong_value;
+ LEX_STRING *base_name= &var->base;
+ KEY_CACHE *key_cache;
+
+ /* If no basename, assume it's for the key cache named 'default' */
+ if (!base_name->length)
+ base_name= &default_key_cache_base;
+
+ key_cache= get_key_cache(base_name);
+
+ if (!key_cache)
+ { // Key cache didn't exists */
+ if (!new_value) // Tried to delete cache
+ return false; // Ok, nothing to do
+ if (!(key_cache= create_key_cache(base_name->str, base_name->length)))
+ return true;
+ }
+
+ /**
+ Abort if some other thread is changing the key cache
+ @todo This should be changed so that we wait until the previous
+ assignment is done and then do the new assign
+ */
+ if (key_cache->in_init)
+ return true;
+
+ return keycache_update(thd, key_cache, offset, new_value);
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ KEY_CACHE *key_cache= get_key_cache(base);
+ if (!key_cache)
+ key_cache= &zero_key_cache;
+ return keycache_var_ptr(key_cache, offset);
+ }
+};
+
+static bool update_buffer_size(THD *thd, KEY_CACHE *key_cache,
+ ptrdiff_t offset, ulonglong new_value)
+{
+ bool error= false;
+ DBUG_ASSERT(offset == offsetof(KEY_CACHE, param_buff_size));
+
+ if (new_value == 0)
+ {
+ if (key_cache == dflt_key_cache)
+ {
+ my_error(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, MYF(0));
+ return true;
+ }
+
+ if (key_cache->key_cache_inited) // If initied
+ {
+ /*
+ Move tables using this key cache to the default key cache
+ and clear the old key cache.
+ */
+ key_cache->in_init= 1;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ key_cache->param_buff_size= 0;
+ ha_resize_key_cache(key_cache);
+ ha_change_key_cache(key_cache, dflt_key_cache);
+ /*
+ We don't delete the key cache as some running threads my still be in
+ the key cache code with a pointer to the deleted (empty) key cache
+ */
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ key_cache->in_init= 0;
+ }
+ return error;
+ }
+
+ key_cache->param_buff_size= new_value;
+
+ /* If key cache didn't exist initialize it, else resize it */
+ key_cache->in_init= 1;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+
+ if (!key_cache->key_cache_inited)
+ error= ha_init_key_cache(0, key_cache);
+ else
+ error= ha_resize_key_cache(key_cache);
+
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ key_cache->in_init= 0;
+
+ return error;
+}
+
+static bool update_keycache_param(THD *thd, KEY_CACHE *key_cache,
+ ptrdiff_t offset, ulonglong new_value)
+{
+ bool error= false;
+ DBUG_ASSERT(offset != offsetof(KEY_CACHE, param_buff_size));
+
+ keycache_var(key_cache, offset)= new_value;
+
+ key_cache->in_init= 1;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ error= ha_resize_key_cache(key_cache);
+
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ key_cache->in_init= 0;
+
+ return error;
+}
+
+/**
+ The class for floating point variables
+
+ Class specific constructor arguments: min, max
+
+ Backing store: double
+*/
+class Sys_var_double: public sys_var
+{
+public:
+ Sys_var_double(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ double min_val, double max_val, double def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0,
+ int parse_flag= PARSE_NORMAL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_DOUBLE, (longlong) double2ulonglong(def_val),
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute, parse_flag)
+ {
+ option.var_type= GET_DOUBLE;
+ option.min_value= (longlong) double2ulonglong(min_val);
+ option.max_value= (longlong) double2ulonglong(max_val);
+ global_var(double)= (double)option.def_value;
+ DBUG_ASSERT(min_val < max_val);
+ DBUG_ASSERT(min_val <= def_val);
+ DBUG_ASSERT(max_val >= def_val);
+ DBUG_ASSERT(size == sizeof(double));
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ my_bool fixed;
+ double v= var->value->val_real();
+ var->save_result.double_value= getopt_double_limit_value(v, &option, &fixed);
+
+ return throw_bounds_warning(thd, name.str, fixed, v);
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, double)= var->save_result.double_value;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(double)= var->save_result.double_value;
+ return false;
+ }
+ bool check_update_type(Item_result type)
+ {
+ return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.double_value= global_var(double); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.double_value= (double)option.def_value; }
+};
+
+/**
+ The class for the @max_user_connections.
+ It's derived from Sys_var_uint, but non-standard session value
+ requires a new class.
+
+ Class specific constructor arguments:
+ everything derived from Sys_var_uint
+
+ Backing store: uint
+*/
+class Sys_var_max_user_conn: public Sys_var_uint
+{
+public:
+ Sys_var_max_user_conn(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ uint min_val, uint max_val, uint def_val,
+ uint block_size, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0)
+ : Sys_var_uint(name_arg, comment, SESSION, off, size, getopt,
+ min_val, max_val, def_val, block_size,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute)
+ { }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ if (thd->user_connect && thd->user_connect->user_resources.user_conn)
+ return (uchar*) &(thd->user_connect->user_resources.user_conn);
+ return global_value_ptr(thd, base);
+ }
+};
+
+// overflow-safe (1 << X)-1
+#define MAX_SET(X) ((((1UL << ((X)-1))-1) << 1) | 1)
+
+/**
+ The class for flagset variables - a variant of SET that allows in-place
+ editing (turning on/off individual bits). String representations looks like
+ a "flag=val,flag=val,...". Example: @@optimizer_switch
+
+ Class specific constructor arguments:
+ char* values[] - 0-terminated list of strings of valid values
+
+ Backing store: ulonglong
+
+ @note
+ the last value in the values[] array should
+ *always* be the string "default".
+*/
+class Sys_var_flagset: public Sys_var_typelib
+{
+public:
+ Sys_var_flagset(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *values[], ulonglong def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0)
+ : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
+ SHOW_CHAR, values, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute)
+ {
+ option.var_type= GET_FLAGSET;
+ global_var(ulonglong)= def_val;
+ DBUG_ASSERT(typelib.count > 1);
+ DBUG_ASSERT(typelib.count <= 65);
+ DBUG_ASSERT(def_val < MAX_SET(typelib.count));
+ DBUG_ASSERT(strcmp(values[typelib.count-1], "default") == 0);
+ DBUG_ASSERT(size == sizeof(ulonglong));
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+ ulonglong default_value, current_value;
+ if (var->type == OPT_GLOBAL)
+ {
+ default_value= option.def_value;
+ current_value= global_var(ulonglong);
+ }
+ else
+ {
+ default_value= global_var(ulonglong);
+ current_value= session_var(thd, ulonglong);
+ }
+
+ if (var->value->result_type() == STRING_RESULT)
+ {
+ if (!(res=var->value->val_str(&str)))
+ return true;
+ else
+ {
+ char *error;
+ uint error_len;
+
+ var->save_result.ulonglong_value=
+ find_set_from_flags(&typelib,
+ typelib.count,
+ current_value,
+ default_value,
+ res->ptr(), res->length(),
+ &error, &error_len);
+ if (error)
+ {
+ ErrConvString err(error, error_len, res->charset());
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
+ return true;
+ }
+ }
+ }
+ else
+ {
+ longlong tmp=var->value->val_int();
+ if ((tmp < 0 && ! var->value->unsigned_flag)
+ || (ulonglong)tmp > MAX_SET(typelib.count))
+ return true;
+ else
+ var->save_result.ulonglong_value= tmp;
+ }
+
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, ulonglong)= var->save_result.ulonglong_value;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(ulonglong)= var->save_result.ulonglong_value;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= global_var(ulonglong); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ return (uchar*)flagset_to_string(thd, 0, session_var(thd, ulonglong),
+ typelib.type_names);
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ return (uchar*)flagset_to_string(thd, 0, global_var(ulonglong),
+ typelib.type_names);
+ }
+};
+
+/**
+ The class for SET variables - variables taking zero or more values
+ from the given list. Example: @@sql_mode
+
+ Class specific constructor arguments:
+ char* values[] - 0-terminated list of strings of valid values
+
+ Backing store: ulonglong
+*/
+class Sys_var_set: public Sys_var_typelib
+{
+public:
+ Sys_var_set(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *values[], ulonglong def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0)
+ : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
+ SHOW_CHAR, values, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute)
+ {
+ option.var_type= GET_SET;
+ global_var(ulonglong)= def_val;
+ DBUG_ASSERT(typelib.count > 0);
+ DBUG_ASSERT(typelib.count <= 64);
+ DBUG_ASSERT(def_val < MAX_SET(typelib.count));
+ DBUG_ASSERT(size == sizeof(ulonglong));
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+
+ if (var->value->result_type() == STRING_RESULT)
+ {
+ if (!(res=var->value->val_str(&str)))
+ return true;
+ else
+ {
+ char *error;
+ uint error_len;
+ bool not_used;
+
+ var->save_result.ulonglong_value=
+ find_set(&typelib, res->ptr(), res->length(), NULL,
+ &error, &error_len, &not_used);
+ /*
+ note, we only issue an error if error_len > 0.
+ That is even while empty (zero-length) values are considered
+ errors by find_set(), these errors are ignored here
+ */
+ if (error_len)
+ {
+ ErrConvString err(error, error_len, res->charset());
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
+ return true;
+ }
+ }
+ }
+ else
+ {
+ longlong tmp=var->value->val_int();
+ if ((tmp < 0 && ! var->value->unsigned_flag)
+ || (ulonglong)tmp > MAX_SET(typelib.count))
+ return true;
+ else
+ var->save_result.ulonglong_value= tmp;
+ }
+
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, ulonglong)= var->save_result.ulonglong_value;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(ulonglong)= var->save_result.ulonglong_value;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= global_var(ulonglong); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ return (uchar*)set_to_string(thd, 0, session_var(thd, ulonglong),
+ typelib.type_names);
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ return (uchar*)set_to_string(thd, 0, global_var(ulonglong),
+ typelib.type_names);
+ }
+};
+
+/**
+ The class for variables which value is a plugin.
+ Example: @@default_storage_engine
+
+ Class specific constructor arguments:
+ int plugin_type_arg (for example MYSQL_STORAGE_ENGINE_PLUGIN)
+
+ Backing store: plugin_ref
+
+ @note
+ these variables don't support command-line equivalents, any such
+ command-line options should be added manually to my_long_options in mysqld.cc
+*/
+class Sys_var_plugin: public sys_var
+{
+ int plugin_type;
+public:
+ Sys_var_plugin(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ int plugin_type_arg, char **def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0,
+ int parse_flag= PARSE_NORMAL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute, parse_flag),
+ plugin_type(plugin_type_arg)
+ {
+ option.var_type= GET_STR;
+ DBUG_ASSERT(size == sizeof(plugin_ref));
+ DBUG_ASSERT(getopt.id == -1); // force NO_CMD_LINE
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff,sizeof(buff), system_charset_info), *res;
+ if (!(res=var->value->val_str(&str)))
+ var->save_result.plugin= NULL;
+ else
+ {
+ const LEX_STRING pname= { const_cast<char*>(res->ptr()), res->length() };
+ plugin_ref plugin;
+
+ // special code for storage engines (e.g. to handle historical aliases)
+ if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
+ plugin= ha_resolve_by_name(thd, &pname);
+ else
+ plugin= my_plugin_lock_by_name(thd, &pname, plugin_type);
+ if (!plugin)
+ {
+ // historically different error code
+ if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
+ {
+ ErrConvString err(res);
+ my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr());
+ }
+ return true;
+ }
+ var->save_result.plugin= plugin;
+ }
+ return false;
+ }
+ void do_update(plugin_ref *valptr, plugin_ref newval)
+ {
+ plugin_ref oldval= *valptr;
+ if (oldval != newval)
+ {
+ *valptr= my_plugin_lock(NULL, &newval);
+ plugin_unlock(NULL, oldval);
+ }
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ do_update((plugin_ref*)session_var_ptr(thd),
+ var->save_result.plugin);
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ do_update((plugin_ref*)global_var_ptr(),
+ var->save_result.plugin);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ plugin_ref plugin= global_var(plugin_ref);
+ var->save_result.plugin= my_plugin_lock(thd, &plugin);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ LEX_STRING pname;
+ pname.str= *(char**)option.def_value;
+ pname.length= strlen(pname.str);
+
+ plugin_ref plugin;
+ if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
+ plugin= ha_resolve_by_name(thd, &pname);
+ else
+ plugin= my_plugin_lock_by_name(thd, &pname, plugin_type);
+ DBUG_ASSERT(plugin);
+
+ var->save_result.plugin= my_plugin_lock(thd, &plugin);
+ }
+ bool check_update_type(Item_result type)
+ { return type != STRING_RESULT; }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ plugin_ref plugin= session_var(thd, plugin_ref);
+ return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str,
+ plugin_name(plugin)->length) : 0);
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ plugin_ref plugin= global_var(plugin_ref);
+ return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str,
+ plugin_name(plugin)->length) : 0);
+ }
+};
+
+#if defined(ENABLED_DEBUG_SYNC)
+/**
+ The class for @@debug_sync session-only variable
+*/
+class Sys_var_debug_sync :public sys_var
+{
+public:
+ Sys_var_debug_sync(const char *name_arg,
+ const char *comment, int flag_args,
+ CMD_LINE getopt,
+ const char *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0,
+ int parse_flag= PARSE_NORMAL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute, parse_flag)
+ {
+ DBUG_ASSERT(scope() == ONLY_SESSION);
+ option.var_type= GET_NO_ARG;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+
+ if (!(res=var->value->val_str(&str)))
+ var->save_result.string_value.str= const_cast<char*>("");
+ else
+ var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ extern bool debug_sync_update(THD *thd, char *val_str);
+ return debug_sync_update(thd, var->save_result.string_value.str);
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ var->save_result.string_value.str= const_cast<char*>("");
+ var->save_result.string_value.length= 0;
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ extern uchar *debug_sync_value_ptr(THD *thd);
+ return debug_sync_value_ptr(thd);
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ DBUG_ASSERT(FALSE);
+ return 0;
+ }
+ bool check_update_type(Item_result type)
+ { return type != STRING_RESULT; }
+};
+#endif /* defined(ENABLED_DEBUG_SYNC) */
+
+/**
+ The class for bit variables - a variant of boolean that stores the value
+ in a bit.
+
+ Class specific constructor arguments:
+ ulonglong bitmask_arg - the mask for the bit to set in the ulonglong
+ backing store
+
+ Backing store: ulonglong
+
+ @note
+ This class supports the "reverse" semantics, when the value of the bit
+ being 0 corresponds to the value of variable being set. To activate it
+ use REVERSE(bitmask) instead of simply bitmask in the constructor.
+
+ @note
+ variables of this class cannot be set from the command line as
+ my_getopt does not support bits.
+*/
+class Sys_var_bit: public Sys_var_typelib
+{
+ ulonglong bitmask;
+ bool reverse_semantics;
+ void set(uchar *ptr, ulonglong value)
+ {
+ if ((value != 0) ^ reverse_semantics)
+ (*(ulonglong *)ptr)|= bitmask;
+ else
+ (*(ulonglong *)ptr)&= ~bitmask;
+ }
+public:
+ Sys_var_bit(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ ulonglong bitmask_arg, my_bool def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0)
+ : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
+ SHOW_MY_BOOL, bool_values, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute)
+ {
+ option.var_type= GET_BOOL;
+ reverse_semantics= my_count_bits(bitmask_arg) > 1;
+ bitmask= reverse_semantics ? ~bitmask_arg : bitmask_arg;
+ set(global_var_ptr(), def_val);
+ DBUG_ASSERT(def_val < 2);
+ DBUG_ASSERT(getopt.id == -1); // force NO_CMD_LINE
+ DBUG_ASSERT(size == sizeof(ulonglong));
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ set(session_var_ptr(thd), var->save_result.ulonglong_value);
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ set(global_var_ptr(), var->save_result.ulonglong_value);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= global_var(ulonglong) & bitmask; }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ thd->sys_var_tmp.my_bool_value= reverse_semantics ^
+ ((session_var(thd, ulonglong) & bitmask) != 0);
+ return (uchar*) &thd->sys_var_tmp.my_bool_value;
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ thd->sys_var_tmp.my_bool_value= reverse_semantics ^
+ ((global_var(ulonglong) & bitmask) != 0);
+ return (uchar*) &thd->sys_var_tmp.my_bool_value;
+ }
+};
+
+/**
+ The class for variables that have a special meaning for a session,
+ such as @@timestamp or @@rnd_seed1, their values typically cannot be read
+ from SV structure, and a special "read" callback is provided.
+
+ Class specific constructor arguments:
+ everything derived from Sys_var_ulonglong
+ session_special_read_function read_func_arg
+
+ Backing store: ulonglong
+
+ @note
+ These variables are session-only, global or command-line equivalents
+ are not supported as they're generally meaningless.
+*/
+class Sys_var_session_special: public Sys_var_ulonglong
+{
+ typedef bool (*session_special_update_function)(THD *thd, set_var *var);
+ typedef ulonglong (*session_special_read_function)(THD *thd);
+
+ session_special_read_function read_func;
+ session_special_update_function update_func;
+public:
+ Sys_var_session_special(const char *name_arg,
+ const char *comment, int flag_args,
+ CMD_LINE getopt,
+ ulonglong min_val, ulonglong max_val, ulonglong block_size,
+ PolyLock *lock, enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func,
+ session_special_update_function update_func_arg,
+ session_special_read_function read_func_arg,
+ uint deprecated_version=0, const char *substitute=0)
+ : Sys_var_ulonglong(name_arg, comment, flag_args, 0,
+ sizeof(ulonglong), getopt, min_val,
+ max_val, 0, block_size, lock, binlog_status_arg, on_check_func, 0,
+ deprecated_version, substitute),
+ read_func(read_func_arg), update_func(update_func_arg)
+ {
+ DBUG_ASSERT(scope() == ONLY_SESSION);
+ DBUG_ASSERT(getopt.id == -1); // NO_CMD_LINE, because the offset is fake
+ }
+ bool session_update(THD *thd, set_var *var)
+ { return update_func(thd, var); }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->value= 0; }
+ void global_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ thd->sys_var_tmp.ulonglong_value= read_func(thd);
+ return (uchar*) &thd->sys_var_tmp.ulonglong_value;
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ DBUG_ASSERT(FALSE);
+ return 0;
+ }
+};
+
+/**
+ The class for read-only variables that show whether a particular
+ feature is supported by the server. Example: have_compression
+
+ Backing store: enum SHOW_COMP_OPTION
+
+ @note
+ These variables are necessarily read-only, only global, and have no
+ command-line equivalent.
+*/
+class Sys_var_have: public sys_var
+{
+public:
+ Sys_var_have(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0,
+ int parse_flag= PARSE_NORMAL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, 0,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute, parse_flag)
+ {
+ DBUG_ASSERT(scope() == GLOBAL);
+ DBUG_ASSERT(getopt.id == -1);
+ DBUG_ASSERT(lock == 0);
+ DBUG_ASSERT(binlog_status_arg == VARIABLE_NOT_IN_BINLOG);
+ DBUG_ASSERT(is_readonly());
+ DBUG_ASSERT(on_update == 0);
+ DBUG_ASSERT(size == sizeof(enum SHOW_COMP_OPTION));
+ }
+ bool do_check(THD *thd, set_var *var) {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ void session_save_default(THD *thd, set_var *var) { }
+ void global_save_default(THD *thd, set_var *var) { }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ DBUG_ASSERT(FALSE);
+ return 0;
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ return (uchar*)show_comp_option_name[global_var(enum SHOW_COMP_OPTION)];
+ }
+ bool check_update_type(Item_result type) { return false; }
+};
+
+/**
+ Generic class for variables for storing entities that are internally
+ represented as structures, have names, and possibly can be referred to by
+ numbers. Examples: character sets, collations, locales,
+
+ Class specific constructor arguments:
+ ptrdiff_t name_offset - offset of the 'name' field in the structure
+
+ Backing store: void*
+
+ @note
+ As every such a structure requires special treatment from my_getopt,
+ these variables don't support command-line equivalents, any such
+ command-line options should be added manually to my_long_options in mysqld.cc
+*/
+class Sys_var_struct: public sys_var
+{
+ ptrdiff_t name_offset; // offset to the 'name' property in the structure
+public:
+ Sys_var_struct(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ ptrdiff_t name_off, void *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0,
+ int parse_flag= PARSE_NORMAL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute, parse_flag),
+ name_offset(name_off)
+ {
+ option.var_type= GET_STR;
+ /*
+ struct variables are special on the command line - often (e.g. for
+ charsets) the name cannot be immediately resolved, but only after all
+ options (in particular, basedir) are parsed.
+
+ thus all struct command-line options should be added manually
+ to my_long_options in mysqld.cc
+ */
+ DBUG_ASSERT(getopt.id == -1);
+ DBUG_ASSERT(size == sizeof(void *));
+ }
+ bool do_check(THD *thd, set_var *var)
+ { return false; }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, void*)= var->save_result.ptr;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(void*)= var->save_result.ptr;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ptr= global_var(void*); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ptr= *(void**)option.def_value; }
+ bool check_update_type(Item_result type)
+ { return type != INT_RESULT && type != STRING_RESULT; }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ uchar *ptr= session_var(thd, uchar*);
+ return ptr ? *(uchar**)(ptr+name_offset) : 0;
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ uchar *ptr= global_var(uchar*);
+ return ptr ? *(uchar**)(ptr+name_offset) : 0;
+ }
+};
+
+/**
+ The class for variables that store time zones
+
+ Backing store: Time_zone*
+
+ @note
+ Time zones cannot be supported directly by my_getopt, thus
+ these variables don't support command-line equivalents, any such
+ command-line options should be added manually to my_long_options in mysqld.cc
+*/
+class Sys_var_tz: public sys_var
+{
+public:
+ Sys_var_tz(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ Time_zone **def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ uint deprecated_version=0, const char *substitute=0,
+ int parse_flag= PARSE_NORMAL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ deprecated_version, substitute, parse_flag)
+ {
+ DBUG_ASSERT(getopt.id == -1);
+ DBUG_ASSERT(size == sizeof(Time_zone *));
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[MAX_TIME_ZONE_NAME_LENGTH];
+ String str(buff, sizeof(buff), &my_charset_latin1);
+ String *res= var->value->val_str(&str);
+
+ if (!res)
+ return true;
+
+ if (!(var->save_result.time_zone= my_tz_find(thd, res)))
+ {
+ ErrConvString err(res);
+ my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), err.ptr());
+ return true;
+ }
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, Time_zone*)= var->save_result.time_zone;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(Time_zone*)= var->save_result.time_zone;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ var->save_result.time_zone= global_var(Time_zone*);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ var->save_result.time_zone=
+ *(Time_zone**)(intptr)option.def_value;
+ }
+ uchar *session_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ /*
+ This is an ugly fix for replication: we don't replicate properly queries
+ invoking system variables' values to update tables; but
+ CONVERT_TZ(,,@@session.time_zone) is so popular that we make it
+ replicable (i.e. we tell the binlog code to store the session
+ timezone). If it's the global value which was used we can't replicate
+ (binlog code stores session value only).
+ */
+ thd->time_zone_used= 1;
+ return (uchar *)(session_var(thd, Time_zone*)->get_name()->ptr());
+ }
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base)
+ {
+ return (uchar *)(global_var(Time_zone*)->get_name()->ptr());
+ }
+ bool check_update_type(Item_result type)
+ { return type != STRING_RESULT; }
+};
+
+
+class Sys_var_tx_isolation: public Sys_var_enum
+{
+public:
+ Sys_var_tx_isolation(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *values[], uint def_val, PolyLock *lock,
+ enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func)
+ :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
+ values, def_val, lock, binlog_status_arg, on_check_func)
+ {}
+ virtual bool session_update(THD *thd, set_var *var);
+};
+
+/****************************************************************************
+ Used templates
+****************************************************************************/
+
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
+template class List<set_var_base>;
+template class List_iterator_fast<set_var_base>;
+template class Sys_var_unsigned<uint, GET_UINT, SHOW_INT>;
+template class Sys_var_unsigned<ulong, GET_ULONG, SHOW_LONG>;
+template class Sys_var_unsigned<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS>;
+template class Sys_var_unsigned<ulonglong, GET_ULL, SHOW_LONGLONG>;
+#endif
+
diff --git a/sql/sys_vars_shared.h b/sql/sys_vars_shared.h
new file mode 100644
index 00000000000..644cc10c853
--- /dev/null
+++ b/sql/sys_vars_shared.h
@@ -0,0 +1,86 @@
+#ifndef SYS_VARS_SHARED_INCLUDED
+#define SYS_VARS_SHARED_INCLUDED
+
+/* Copyright (C) 2002-2006 MySQL AB, 2009-2010 Sun Microsystems, Inc.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/**
+ @file
+ "protected" interface to sys_var - server configuration variables.
+
+ This header is included by files implementing support and utility
+ functions of sys_var's (set_var.cc) and files implementing
+ classes in the sys_var hierarchy (sql_plugin.cc)
+*/
+
+#include <sql_priv.h>
+#include "set_var.h"
+
+extern bool throw_bounds_warning(THD *thd, const char *name,
+ bool fixed, bool is_unsigned, longlong v);
+extern bool throw_bounds_warning(THD *thd, const char *name, bool fixed,
+ double v);
+extern sys_var *intern_find_sys_var(const char *str, uint length);
+
+extern sys_var_chain all_sys_vars;
+
+/** wrapper to hide a mutex and an rwlock under a common interface */
+class PolyLock
+{
+public:
+ virtual void rdlock()= 0;
+ virtual void wrlock()= 0;
+ virtual void unlock()= 0;
+ virtual ~PolyLock() {}
+};
+
+class PolyLock_mutex: public PolyLock
+{
+ mysql_mutex_t *mutex;
+public:
+ PolyLock_mutex(mysql_mutex_t *arg): mutex(arg) {}
+ void rdlock() { mysql_mutex_lock(mutex); }
+ void wrlock() { mysql_mutex_lock(mutex); }
+ void unlock() { mysql_mutex_unlock(mutex); }
+};
+
+class PolyLock_rwlock: public PolyLock
+{
+ mysql_rwlock_t *rwlock;
+public:
+ PolyLock_rwlock(mysql_rwlock_t *arg): rwlock(arg) {}
+ void rdlock() { mysql_rwlock_rdlock(rwlock); }
+ void wrlock() { mysql_rwlock_wrlock(rwlock); }
+ void unlock() { mysql_rwlock_unlock(rwlock); }
+};
+
+class AutoWLock
+{
+ PolyLock *lock;
+public:
+ AutoWLock(PolyLock *l) : lock(l) { if (lock) lock->wrlock(); }
+ ~AutoWLock() { if (lock) lock->unlock(); }
+};
+
+class AutoRLock
+{
+ PolyLock *lock;
+public:
+ AutoRLock(PolyLock *l) : lock(l) { if (lock) lock->rdlock(); }
+ ~AutoRLock() { if (lock) lock->unlock(); }
+};
+
+
+#endif /* SYS_VARS_SHARED_INCLUDED */
diff --git a/sql/table.cc b/sql/table.cc
index 18523f08551..8cd2e9e9bab 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -16,14 +16,32 @@
/* Some general useful functions */
-#include "mysql_priv.h"
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "table.h"
+#include "frm_crypt.h" // get_crypt_for_frm
+#include "key.h" // find_ref_key
+#include "sql_table.h" // build_table_filename,
+ // primary_key_name
#include "sql_trigger.h"
+#include "sql_parse.h" // free_items
+#include "strfunc.h" // unhex_type2
+#include "sql_partition.h" // mysql_unpack_partition,
+ // fix_partition_func, partition_info
+#include "sql_acl.h" // *_ACL, acl_getroot_no_password
+#include "sql_base.h" // release_table_share
#include <m_ctype.h>
#include "my_md5.h"
+#include "sql_select.h"
+#include "mdl.h" // MDL_wait_for_graph_visitor
/* INFORMATION_SCHEMA name */
LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")};
+/* PERFORMANCE_SCHEMA name */
+LEX_STRING PERFORMANCE_SCHEMA_DB_NAME= {C_STRING_WITH_LEN("performance_schema")};
+
/* MYSQL_SCHEMA name */
LEX_STRING MYSQL_SCHEMA_NAME= {C_STRING_WITH_LEN("mysql")};
@@ -214,36 +232,34 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name)
DBUG_ASSERT(db != NULL);
DBUG_ASSERT(name != NULL);
- if (is_schema_db(db->str, db->length))
- {
+ if (is_infoschema_db(db->str, db->length))
return TABLE_CATEGORY_INFORMATION;
- }
+
+ if ((db->length == PERFORMANCE_SCHEMA_DB_NAME.length) &&
+ (my_strcasecmp(system_charset_info,
+ PERFORMANCE_SCHEMA_DB_NAME.str,
+ db->str) == 0))
+ return TABLE_CATEGORY_PERFORMANCE;
if ((db->length == MYSQL_SCHEMA_NAME.length) &&
(my_strcasecmp(system_charset_info,
- MYSQL_SCHEMA_NAME.str,
- db->str) == 0))
+ MYSQL_SCHEMA_NAME.str,
+ db->str) == 0))
{
if (is_system_table_name(name->str, name->length))
- {
return TABLE_CATEGORY_SYSTEM;
- }
if ((name->length == GENERAL_LOG_NAME.length) &&
(my_strcasecmp(system_charset_info,
- GENERAL_LOG_NAME.str,
- name->str) == 0))
- {
- return TABLE_CATEGORY_PERFORMANCE;
- }
+ GENERAL_LOG_NAME.str,
+ name->str) == 0))
+ return TABLE_CATEGORY_LOG;
if ((name->length == SLOW_LOG_NAME.length) &&
(my_strcasecmp(system_charset_info,
- SLOW_LOG_NAME.str,
- name->str) == 0))
- {
- return TABLE_CATEGORY_PERFORMANCE;
- }
+ SLOW_LOG_NAME.str,
+ name->str) == 0))
+ return TABLE_CATEGORY_LOG;
}
return TABLE_CATEGORY_USER;
@@ -308,9 +324,13 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
share->table_map_id= ~0UL;
share->cached_row_logging_check= -1;
+ share->used_tables.empty();
+ share->free_tables.empty();
+ share->m_flush_tickets.empty();
+
memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root));
- pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&share->cond, NULL);
+ mysql_mutex_init(key_TABLE_SHARE_LOCK_ha_data,
+ &share->LOCK_ha_data, MY_MUTEX_INIT_FAST);
}
DBUG_RETURN(share);
}
@@ -369,70 +389,106 @@ void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
*/
share->table_map_id= (ulong) thd->query_id;
+ share->used_tables.empty();
+ share->free_tables.empty();
+ share->m_flush_tickets.empty();
+
DBUG_VOID_RETURN;
}
+/**
+ Release resources (plugins) used by the share and free its memory.
+ TABLE_SHARE is self-contained -- it's stored in its own MEM_ROOT.
+ Free this MEM_ROOT.
+*/
+
+void TABLE_SHARE::destroy()
+{
+ uint idx;
+ KEY *info_it;
+
+ /* The mutex is initialized only for shares that are part of the TDC */
+ if (tmp_table == NO_TMP_TABLE)
+ mysql_mutex_destroy(&LOCK_ha_data);
+ my_hash_free(&name_hash);
+
+ plugin_unlock(NULL, db_plugin);
+ db_plugin= NULL;
+
+ /* Release fulltext parsers */
+ info_it= key_info;
+ for (idx= keys; idx; idx--, info_it++)
+ {
+ if (info_it->flags & HA_USES_PARSER)
+ {
+ plugin_unlock(NULL, info_it->parser);
+ info_it->flags= 0;
+ }
+ }
+ if (ha_data_destroy)
+ {
+ ha_data_destroy(ha_data);
+ ha_data_destroy= NULL;
+ }
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (ha_part_data_destroy)
+ {
+ ha_part_data_destroy(ha_part_data);
+ ha_part_data_destroy= NULL;
+ }
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
+ /*
+ Make a copy since the share is allocated in its own root,
+ and free_root() updates its argument after freeing the memory.
+ */
+ MEM_ROOT own_root= mem_root;
+ free_root(&own_root, MYF(0));
+}
+
/*
Free table share and memory used by it
SYNOPSIS
free_table_share()
share Table share
-
- NOTES
- share->mutex must be locked when we come here if it's not a temp table
*/
void free_table_share(TABLE_SHARE *share)
{
- MEM_ROOT mem_root;
- uint idx;
- KEY *key_info;
DBUG_ENTER("free_table_share");
DBUG_PRINT("enter", ("table: %s.%s", share->db.str, share->table_name.str));
DBUG_ASSERT(share->ref_count == 0);
- /*
- If someone is waiting for this to be deleted, inform it about this.
- Don't do a delete until we know that no one is refering to this anymore.
- */
- if (share->tmp_table == NO_TMP_TABLE)
- {
- /* share->mutex is locked in release_table_share() */
- while (share->waiting_on_cond)
- {
- pthread_cond_broadcast(&share->cond);
- pthread_cond_wait(&share->cond, &share->mutex);
- }
- /* No thread refers to this anymore */
- pthread_mutex_unlock(&share->mutex);
- pthread_mutex_destroy(&share->mutex);
- pthread_cond_destroy(&share->cond);
- }
- hash_free(&share->name_hash);
-
- plugin_unlock(NULL, share->db_plugin);
- share->db_plugin= NULL;
-
- /* Release fulltext parsers */
- key_info= share->key_info;
- for (idx= share->keys; idx; idx--, key_info++)
+ if (share->m_flush_tickets.is_empty())
{
- if (key_info->flags & HA_USES_PARSER)
- {
- plugin_unlock(NULL, key_info->parser);
- key_info->flags= 0;
- }
+ /*
+ No threads are waiting for this share to be flushed (the
+ share is not old, is for a temporary table, or just nobody
+ happens to be waiting for it). Destroy it.
+ */
+ share->destroy();
}
- if (share->ha_data_destroy)
+ else
{
- share->ha_data_destroy(share->ha_data);
- share->ha_data_destroy= NULL;
+ Wait_for_flush_list::Iterator it(share->m_flush_tickets);
+ Wait_for_flush *ticket;
+ /*
+ We're about to iterate over a list that is used
+ concurrently. Make sure this never happens without a lock.
+ */
+ mysql_mutex_assert_owner(&LOCK_open);
+
+ while ((ticket= it++))
+ (void) ticket->get_ctx()->m_wait.set_status(MDL_wait::GRANTED);
+ /*
+ If there are threads waiting for this share to be flushed,
+ the last one to receive the notification will destroy the
+ share. At this point the share is removed from the table
+ definition cache, so is OK to proceed here without waiting
+ for this thread to do the work.
+ */
}
- /* We must copy mem_root from share because share is allocated through it */
- memcpy((char*) &mem_root, (char*) &share->mem_root, sizeof(mem_root));
- free_root(&mem_root, MYF(0)); // Free's share
DBUG_VOID_RETURN;
}
@@ -539,7 +595,7 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
int error, table_type;
bool error_given;
File file;
- uchar head[288];
+ uchar head[64];
char path[FN_REFLEN];
MEM_ROOT **root_ptr, *old_root;
DBUG_ENTER("open_table_def");
@@ -550,7 +606,8 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
error_given= 0;
strxmov(path, share->normalized_path.str, reg_ext, NullS);
- if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)
+ if ((file= mysql_file_open(key_file_frm,
+ path, O_RDONLY | O_SHARE, MYF(0))) < 0)
{
/*
We don't try to open 5.0 unencoded name, if
@@ -561,7 +618,7 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
- non-encoded db or table name contain "#mysql50#" prefix.
This kind of tables must have been opened only by the
- my_open() above.
+ mysql_file_open() above.
*/
if (has_disabled_path_chars(share->table_name.str) ||
has_disabled_path_chars(share->db.str) ||
@@ -588,7 +645,8 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
so no need to check the old file name.
*/
if (length == share->normalized_path.length ||
- ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0))
+ ((file= mysql_file_open(key_file_frm,
+ path, O_RDONLY | O_SHARE, MYF(0))) < 0))
goto err_not_open;
/* Unencoded 5.0 table name found */
@@ -598,7 +656,7 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
}
error= 4;
- if (my_read(file, head, 64, MYF(MY_NABP)))
+ if (mysql_file_read(file, head, 64, MYF(MY_NABP)))
goto err;
if (head[0] == (uchar) 254 && head[1] == 1)
@@ -651,7 +709,7 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
thd->status_var.opened_shares++;
err:
- my_close(file, MYF(MY_WME));
+ mysql_file_close(file, MYF(MY_WME));
err_not_open:
if (error && !error_given)
@@ -680,6 +738,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
uint i,j;
bool use_hash;
char *keynames, *names, *comment_pos;
+ uchar forminfo[288];
uchar *record;
uchar *disk_buff, *strpos, *null_flags, *null_pos;
ulong pos, record_offset, *rec_per_key, rec_buff_length;
@@ -703,6 +762,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if (!(pos= get_form_pos(file, head)))
goto err; /* purecov: inspected */
+ mysql_file_seek(file,pos,MY_SEEK_SET,MYF(0));
+ if (mysql_file_read(file, forminfo,288,MYF(MY_NABP)))
+ goto err;
share->frm_version= head[2];
/*
Check if .frm file created by MySQL 5.0. In this case we want to
@@ -738,7 +800,8 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
{
share->avg_row_length= uint4korr(head+34);
share->row_type= (row_type) head[40];
- share->table_charset= get_charset((uint) head[38],MYF(0));
+ share->table_charset= get_charset((((uint) head[41]) << 8) +
+ (uint) head[38],MYF(0));
share->null_field_first= 1;
}
if (!share->table_charset)
@@ -765,7 +828,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
/* Read keyinformation */
key_info_length= (uint) uint2korr(head+28);
- VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
+ mysql_file_seek(file, (ulong) uint2korr(head+6), MY_SEEK_SET, MYF(0));
if (read_string(file,(uchar**) &disk_buff,key_info_length))
goto err; /* purecov: inspected */
if (disk_buff[0] & 0x80)
@@ -787,7 +850,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
goto err; /* purecov: inspected */
bzero((char*) keyinfo,n_length);
share->key_info= keyinfo;
- key_part= my_reinterpret_cast(KEY_PART_INFO*) (keyinfo+keys);
+ key_part= reinterpret_cast<KEY_PART_INFO*>(keyinfo+keys);
strpos=disk_buff+6;
if (!(rec_per_key= (ulong*) alloc_root(&share->mem_root,
@@ -847,6 +910,20 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
keynames=(char*) key_part;
strpos+= (strmov(keynames, (char *) strpos) - keynames)+1;
+ //reading index comments
+ for (keyinfo= share->key_info, i=0; i < keys; i++, keyinfo++)
+ {
+ if (keyinfo->flags & HA_USES_COMMENT)
+ {
+ keyinfo->comment.length= uint2korr(strpos);
+ keyinfo->comment.str= strmake_root(&share->mem_root, (char*) strpos+2,
+ keyinfo->comment.length);
+ strpos+= 2 + keyinfo->comment.length;
+ }
+ DBUG_ASSERT(test(keyinfo->flags & HA_USES_COMMENT) ==
+ (keyinfo->comment.length > 0));
+ }
+
share->reclength = uint2korr((head+16));
if (*(head+26) == 1)
share->system= 1; /* one-record-database */
@@ -869,10 +946,10 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
DBUG_PRINT("info", ("extra segment size is %u bytes", n_length));
if (!(next_chunk= buff= (uchar*) my_malloc(n_length, MYF(MY_WME))))
goto err;
- if (my_pread(file, buff, n_length, record_offset + share->reclength,
- MYF(MY_NABP)))
+ if (mysql_file_pread(file, buff, n_length, record_offset + share->reclength,
+ MYF(MY_NABP)))
{
- my_free(buff, MYF(0));
+ my_free(buff);
goto err;
}
share->connect_string.length= uint2korr(buff);
@@ -881,7 +958,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
share->connect_string.
length)))
{
- my_free(buff, MYF(0));
+ my_free(buff);
goto err;
}
next_chunk+= share->connect_string.length + 2;
@@ -902,7 +979,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
plugin_data(tmp_plugin, handlerton *)))
{
/* bad file, legacy_db_type did not match the name */
- my_free(buff, MYF(0));
+ my_free(buff);
goto err;
}
/*
@@ -932,7 +1009,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
error= 8;
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
"--skip-partition");
- my_free(buff, MYF(0));
+ my_free(buff);
goto err;
}
plugin_unlock(NULL, share->db_plugin);
@@ -946,8 +1023,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
{
/* purecov: begin inspected */
error= 8;
+ name.str[name.length]=0;
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), name.str);
- my_free(buff, MYF(0));
+ my_free(buff);
goto err;
/* purecov: end */
}
@@ -955,28 +1033,28 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
}
if (next_chunk + 5 < buff_end)
{
- uint32 partition_info_len = uint4korr(next_chunk);
+ uint32 partition_info_str_len = uint4korr(next_chunk);
#ifdef WITH_PARTITION_STORAGE_ENGINE
if ((share->partition_info_buffer_size=
- share->partition_info_len= partition_info_len))
+ share->partition_info_str_len= partition_info_str_len))
{
- if (!(share->partition_info= (char*)
+ if (!(share->partition_info_str= (char*)
memdup_root(&share->mem_root, next_chunk + 4,
- partition_info_len + 1)))
+ partition_info_str_len + 1)))
{
- my_free(buff, MYF(0));
+ my_free(buff);
goto err;
}
}
#else
- if (partition_info_len)
+ if (partition_info_str_len)
{
DBUG_PRINT("info", ("WITH_PARTITION_STORAGE_ENGINE is not defined"));
- my_free(buff, MYF(0));
+ my_free(buff);
goto err;
}
#endif
- next_chunk+= 5 + partition_info_len;
+ next_chunk+= 5 + partition_info_str_len;
}
#if MYSQL_VERSION_ID < 50200
if (share->mysql_version >= 50106 && share->mysql_version <= 50109)
@@ -990,8 +1068,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
*/
next_chunk+= 4;
}
- else if (share->mysql_version >= 50110)
+ else
#endif
+ if (share->mysql_version >= 50110)
{
/* New auto_partitioned indicator introduced in 5.1.11 */
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -1009,7 +1088,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
{
DBUG_PRINT("error",
("fulltext key uses parser that is not defined in .frm"));
- my_free(buff, MYF(0));
+ my_free(buff);
goto err;
}
parser_name.str= (char*) next_chunk;
@@ -1020,12 +1099,31 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if (! keyinfo->parser)
{
my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), parser_name.str);
- my_free(buff, MYF(0));
+ my_free(buff);
goto err;
}
}
}
- my_free(buff, MYF(0));
+ if (forminfo[46] == (uchar)255)
+ {
+ //reading long table comment
+ if (next_chunk + 2 > buff_end)
+ {
+ DBUG_PRINT("error",
+ ("long table comment is not defined in .frm"));
+ my_free(buff);
+ goto err;
+ }
+ share->comment.length = uint2korr(next_chunk);
+ if (! (share->comment.str= strmake_root(&share->mem_root,
+ (char*)next_chunk + 2, share->comment.length)))
+ {
+ my_free(buff);
+ goto err;
+ }
+ next_chunk+= 2 + share->comment.length;
+ }
+ my_free(buff);
}
share->key_block_size= uint2korr(head+62);
@@ -1037,33 +1135,34 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
rec_buff_length)))
goto err; /* purecov: inspected */
share->default_values= record;
- if (my_pread(file, record, (size_t) share->reclength,
- record_offset, MYF(MY_NABP)))
+ if (mysql_file_pread(file, record, (size_t) share->reclength,
+ record_offset, MYF(MY_NABP)))
goto err; /* purecov: inspected */
- VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
- if (my_read(file, head,288,MYF(MY_NABP)))
- goto err;
+ mysql_file_seek(file, pos+288, MY_SEEK_SET, MYF(0));
#ifdef HAVE_CRYPTED_FRM
if (crypted)
{
- crypted->decode((char*) head+256,288-256);
- if (sint2korr(head+284) != 0) // Should be 0
+ crypted->decode((char*) forminfo+256,288-256);
+ if (sint2korr(forminfo+284) != 0) // Should be 0
goto err; // Wrong password
}
#endif
- share->fields= uint2korr(head+258);
- pos= uint2korr(head+260); /* Length of all screens */
- n_length= uint2korr(head+268);
- interval_count= uint2korr(head+270);
- interval_parts= uint2korr(head+272);
- int_length= uint2korr(head+274);
- share->null_fields= uint2korr(head+282);
- com_length= uint2korr(head+284);
- share->comment.length= (int) (head[46]);
- share->comment.str= strmake_root(&share->mem_root, (char*) head+47,
- share->comment.length);
+ share->fields= uint2korr(forminfo+258);
+ pos= uint2korr(forminfo+260); /* Length of all screens */
+ n_length= uint2korr(forminfo+268);
+ interval_count= uint2korr(forminfo+270);
+ interval_parts= uint2korr(forminfo+272);
+ int_length= uint2korr(forminfo+274);
+ share->null_fields= uint2korr(forminfo+282);
+ com_length= uint2korr(forminfo+284);
+ if (forminfo[46] != (uchar)255)
+ {
+ share->comment.length= (int) (forminfo[46]);
+ share->comment.str= strmake_root(&share->mem_root, (char*) forminfo+47,
+ share->comment.length);
+ }
DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d com_length: %d", interval_count,interval_parts, share->keys,n_length,int_length, com_length));
@@ -1159,10 +1258,10 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
use_hash= share->fields >= MAX_FIELDS_BEFORE_HASH;
if (use_hash)
- use_hash= !hash_init(&share->name_hash,
- system_charset_info,
- share->fields,0,0,
- (hash_get_key) get_field_name,0,0);
+ use_hash= !my_hash_init(&share->name_hash,
+ system_charset_info,
+ share->fields,0,0,
+ (my_hash_get_key) get_field_name,0,0);
for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
{
@@ -1196,12 +1295,13 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
}
else
{
- if (!strpos[14])
+ uint csid= strpos[14] + (((uint) strpos[11]) << 8);
+ if (!csid)
charset= &my_charset_bin;
- else if (!(charset=get_charset((uint) strpos[14], MYF(0))))
+ else if (!(charset= get_charset(csid, MYF(0))))
{
error= 5; // Unknown or unavailable charset
- errarg= (int) strpos[14];
+ errarg= (int) csid;
goto err;
}
}
@@ -1274,7 +1374,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
"Please do \"ALTER TABLE '%s' FORCE\" to fix it!",
share->fieldnames.type_names[i], share->table_name.str,
share->table_name.str);
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_CRASHED_ON_USAGE,
"Found incompatible DECIMAL field '%s' in %s; "
"Please do \"ALTER TABLE '%s' FORCE\" to fix it!",
@@ -1416,12 +1516,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
keyinfo->extra_length+=HA_KEY_BLOB_LENGTH;
key_part->store_length+=HA_KEY_BLOB_LENGTH;
keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
- /*
- Mark that there may be many matching values for one key
- combination ('a', 'a ', 'a '...)
- */
- if (!(field->flags & BINARY_FLAG))
- keyinfo->flags|= HA_END_SPACE_KEY;
}
if (field->type() == MYSQL_TYPE_BIT)
key_part->key_part_flag|= HA_BIT_PART;
@@ -1484,7 +1578,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
"Please do \"ALTER TABLE '%s' FORCE \" to fix it!",
share->table_name.str,
share->table_name.str);
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_CRASHED_ON_USAGE,
"Found wrong key definition in %s; "
"Please do \"ALTER TABLE '%s' FORCE\" to fix "
@@ -1545,7 +1639,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
}
else
share->primary_key= MAX_KEY;
- x_free((uchar*) disk_buff);
+ my_free(disk_buff);
disk_buff=0;
if (new_field_pack_flag <= 1)
{
@@ -1609,7 +1703,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
delete handler_file;
#ifndef DBUG_OFF
if (use_hash)
- (void) hash_check(&share->name_hash);
+ (void) my_hash_check(&share->name_hash);
#endif
DBUG_RETURN (0);
@@ -1617,15 +1711,22 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
share->error= error;
share->open_errno= my_errno;
share->errarg= errarg;
- x_free((uchar*) disk_buff);
+ my_free(disk_buff);
delete crypted;
delete handler_file;
- hash_free(&share->name_hash);
+ my_hash_free(&share->name_hash);
if (share->ha_data_destroy)
{
share->ha_data_destroy(share->ha_data);
share->ha_data_destroy= NULL;
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (share->ha_part_data_destroy)
+ {
+ share->ha_part_data_destroy(share->ha_part_data);
+ share->ha_data_destroy= NULL;
+ }
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
open_table_error(share, error, share->open_errno, errarg);
DBUG_RETURN(error);
@@ -1670,9 +1771,6 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
DBUG_PRINT("enter",("name: '%s.%s' form: 0x%lx", share->db.str,
share->table_name.str, (long) outparam));
- /* Parsing of partitioning information from .frm needs thd->lex set up. */
- DBUG_ASSERT(thd->lex->is_lex_started);
-
error= 1;
bzero((char*) outparam, sizeof(*outparam));
outparam->in_use= thd;
@@ -1783,8 +1881,8 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
if (!(key_info= (KEY*) alloc_root(&outparam->mem_root, n_length)))
goto err;
outparam->key_info= key_info;
- key_part= (my_reinterpret_cast(KEY_PART_INFO*) (key_info+share->keys));
-
+ key_part= (reinterpret_cast<KEY_PART_INFO*>(key_info+share->keys));
+
memcpy(key_info, share->key_info, sizeof(*key_info)*share->keys);
memcpy(key_part, share->key_info[0].key_part, (sizeof(*key_part) *
share->key_parts));
@@ -1820,7 +1918,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (share->partition_info_len && outparam->file)
+ if (share->partition_info_str_len && outparam->file)
{
/*
In this execution we must avoid calling thd->change_item_tree since
@@ -1841,10 +1939,8 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
bool tmp;
bool work_part_info_used;
- tmp= mysql_unpack_partition(thd, share->partition_info,
- share->partition_info_len,
- share->part_state,
- share->part_state_len,
+ tmp= mysql_unpack_partition(thd, share->partition_info_str,
+ share->partition_info_str_len,
outparam, is_create_table,
share->default_part_db_type,
&work_part_info_used);
@@ -1973,7 +2069,7 @@ partititon_err:
outparam->file= 0; // For easier error checking
outparam->db_stat=0;
free_root(&outparam->mem_root, MYF(0)); // Safe to call on bzero'd root
- my_free((char*) outparam->alias, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((void *) outparam->alias);
DBUG_RETURN (error);
}
@@ -1995,7 +2091,7 @@ int closefrm(register TABLE *table, bool free_share)
if (table->db_stat)
error=table->file->close();
- my_free((char*) table->alias, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((void *) table->alias);
table->alias= 0;
if (table->field)
{
@@ -2016,7 +2112,7 @@ int closefrm(register TABLE *table, bool free_share)
if (free_share)
{
if (table->s->tmp_table == NO_TMP_TABLE)
- release_table_share(table->s, RELEASE_NORMAL);
+ release_table_share(table->s);
else
free_table_share(table->s);
}
@@ -2083,21 +2179,21 @@ static ulong get_form_pos(File file, uchar *head)
length= uint2korr(head+4);
- my_seek(file, 64L, MY_SEEK_SET, MYF(0));
+ mysql_file_seek(file, 64L, MY_SEEK_SET, MYF(0));
if (!(buf= (uchar*) my_malloc(length+names*4, MYF(MY_WME))))
DBUG_RETURN(0);
- if (my_read(file, buf, length+names*4, MYF(MY_NABP)))
+ if (mysql_file_read(file, buf, length+names*4, MYF(MY_NABP)))
{
- x_free(buf);
+ my_free(buf);
DBUG_RETURN(0);
}
pos= buf+length;
ret_value= uint4korr(pos);
- my_free(buf, MYF(0));
+ my_free(buf);
DBUG_RETURN(ret_value);
}
@@ -2114,11 +2210,11 @@ int read_string(File file, uchar**to, size_t length)
{
DBUG_ENTER("read_string");
- x_free(*to);
+ my_free(*to);
if (!(*to= (uchar*) my_malloc(length+1,MYF(MY_WME))) ||
- my_read(file, *to, length,MYF(MY_NABP)))
+ mysql_file_read(file, *to, length, MYF(MY_NABP)))
{
- x_free(*to); /* purecov: inspected */
+ my_free(*to); /* purecov: inspected */
*to= 0; /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
@@ -2148,23 +2244,24 @@ ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
{ /* Expand file */
newpos+=IO_SIZE;
int4store(fileinfo+10,newpos);
- endpos=(ulong) my_seek(file,0L,MY_SEEK_END,MYF(0));/* Copy from file-end */
+ /* Copy from file-end */
+ endpos= (ulong) mysql_file_seek(file, 0L, MY_SEEK_END, MYF(0));
bufflength= (uint) (endpos & (IO_SIZE-1)); /* IO_SIZE is a power of 2 */
while (endpos > maxlength)
{
- VOID(my_seek(file,(ulong) (endpos-bufflength),MY_SEEK_SET,MYF(0)));
- if (my_read(file, buff, bufflength, MYF(MY_NABP+MY_WME)))
+ mysql_file_seek(file, (ulong) (endpos-bufflength), MY_SEEK_SET, MYF(0));
+ if (mysql_file_read(file, buff, bufflength, MYF(MY_NABP+MY_WME)))
DBUG_RETURN(0L);
- VOID(my_seek(file,(ulong) (endpos-bufflength+IO_SIZE),MY_SEEK_SET,
- MYF(0)));
- if ((my_write(file, buff,bufflength,MYF(MY_NABP+MY_WME))))
+ mysql_file_seek(file, (ulong) (endpos-bufflength+IO_SIZE), MY_SEEK_SET,
+ MYF(0));
+ if ((mysql_file_write(file, buff, bufflength, MYF(MY_NABP+MY_WME))))
DBUG_RETURN(0);
endpos-=bufflength; bufflength=IO_SIZE;
}
bzero(buff,IO_SIZE); /* Null new block */
- VOID(my_seek(file,(ulong) maxlength,MY_SEEK_SET,MYF(0)));
- if (my_write(file,buff,bufflength,MYF(MY_NABP+MY_WME)))
+ mysql_file_seek(file, (ulong) maxlength, MY_SEEK_SET, MYF(0));
+ if (mysql_file_write(file, buff, bufflength, MYF(MY_NABP+MY_WME)))
DBUG_RETURN(0L);
maxlength+=IO_SIZE; /* Fix old ref */
int2store(fileinfo+6,maxlength);
@@ -2179,20 +2276,21 @@ ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
if (n_length == 1 )
{ /* First name */
length++;
- VOID(strxmov((char*) buff,"/",newname,"/",NullS));
+ (void) strxmov((char*) buff,"/",newname,"/",NullS);
}
else
- VOID(strxmov((char*) buff,newname,"/",NullS)); /* purecov: inspected */
- VOID(my_seek(file,63L+(ulong) n_length,MY_SEEK_SET,MYF(0)));
- if (my_write(file, buff, (size_t) length+1,MYF(MY_NABP+MY_WME)) ||
- (names && my_write(file,(uchar*) (*formnames->type_names+n_length-1),
- names*4, MYF(MY_NABP+MY_WME))) ||
- my_write(file, fileinfo+10, 4,MYF(MY_NABP+MY_WME)))
+ (void) strxmov((char*) buff,newname,"/",NullS); /* purecov: inspected */
+ mysql_file_seek(file, 63L+(ulong) n_length, MY_SEEK_SET, MYF(0));
+ if (mysql_file_write(file, buff, (size_t) length+1, MYF(MY_NABP+MY_WME)) ||
+ (names && mysql_file_write(file,
+ (uchar*) (*formnames->type_names+n_length-1),
+ names*4, MYF(MY_NABP+MY_WME))) ||
+ mysql_file_write(file, fileinfo+10, 4, MYF(MY_NABP+MY_WME)))
DBUG_RETURN(0L); /* purecov: inspected */
int2store(fileinfo+8,names+1);
int2store(fileinfo+4,n_length+length);
- VOID(my_chsize(file, newpos, 0, MYF(MY_WME)));/* Append file with '\0' */
+ (void) mysql_file_chsize(file, newpos, 0, MYF(MY_WME));/* Append file with '\0' */
DBUG_RETURN(newpos);
} /* make_new_entry */
@@ -2458,12 +2556,14 @@ void append_unescaped(String *res, const char *pos, uint length)
File create_frm(THD *thd, const char *name, const char *db,
const char *table, uint reclength, uchar *fileinfo,
- HA_CREATE_INFO *create_info, uint keys)
+ HA_CREATE_INFO *create_info, uint keys, KEY *key_info)
{
register File file;
ulong length;
uchar fill[IO_SIZE];
int create_flags= O_RDWR | O_TRUNC;
+ ulong key_comment_total_bytes= 0;
+ uint i;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
create_flags|= O_EXCL | O_NOFOLLOW;
@@ -2474,10 +2574,10 @@ File create_frm(THD *thd, const char *name, const char *db,
if (create_info->min_rows > UINT_MAX32)
create_info->min_rows= UINT_MAX32;
- if ((file= my_create(name, CREATE_MODE, create_flags, MYF(0))) >= 0)
+ if ((file= mysql_file_create(key_file_frm,
+ name, CREATE_MODE, create_flags, MYF(0))) >= 0)
{
- uint key_length, tmp_key_length;
- uint tmp;
+ uint key_length, tmp_key_length, tmp, csid;
bzero((char*) fileinfo,64);
/* header */
fileinfo[0]=(uchar) 254;
@@ -2500,7 +2600,17 @@ File create_frm(THD *thd, const char *name, const char *db,
1 byte for the NAMES_SEP_CHAR (after the last name)
9 extra bytes (padding for safety? alignment?)
*/
- key_length= keys * (8 + MAX_REF_PARTS * 9 + NAME_LEN + 1) + 16;
+ for (i= 0; i < keys; i++)
+ {
+ DBUG_ASSERT(test(key_info[i].flags & HA_USES_COMMENT) ==
+ (key_info[i].comment.length > 0));
+ if (key_info[i].flags & HA_USES_COMMENT)
+ key_comment_total_bytes += 2 + key_info[i].comment.length;
+ }
+
+ key_length= keys * (8 + MAX_REF_PARTS * 9 + NAME_LEN + 1) + 16
+ + key_comment_total_bytes;
+
length= next_io_size((ulong) (IO_SIZE+key_length+reclength+
create_info->extra_size));
int4store(fileinfo+10,length);
@@ -2517,8 +2627,9 @@ File create_frm(THD *thd, const char *name, const char *db,
fileinfo[32]=0; // No filename anymore
fileinfo[33]=5; // Mark for 5.0 frm file
int4store(fileinfo+34,create_info->avg_row_length);
- fileinfo[38]= (create_info->default_table_charset ?
- create_info->default_table_charset->number : 0);
+ csid= (create_info->default_table_charset ?
+ create_info->default_table_charset->number : 0);
+ fileinfo[38]= (uchar) csid;
/*
In future versions, we will store in fileinfo[39] the values of the
TRANSACTIONAL and PAGE_CHECKSUM clauses of CREATE TABLE.
@@ -2526,7 +2637,7 @@ File create_frm(THD *thd, const char *name, const char *db,
fileinfo[39]= 0;
fileinfo[40]= (uchar) create_info->row_type;
/* Next few bytes where for RAID support */
- fileinfo[41]= 0;
+ fileinfo[41]= (uchar) (csid >> 8);
fileinfo[42]= 0;
fileinfo[43]= 0;
fileinfo[44]= 0;
@@ -2544,10 +2655,10 @@ File create_frm(THD *thd, const char *name, const char *db,
bzero(fill,IO_SIZE);
for (; length > IO_SIZE ; length-= IO_SIZE)
{
- if (my_write(file,fill, IO_SIZE, MYF(MY_WME | MY_NABP)))
+ if (mysql_file_write(file, fill, IO_SIZE, MYF(MY_WME | MY_NABP)))
{
- VOID(my_close(file,MYF(0)));
- VOID(my_delete(name,MYF(0)));
+ (void) mysql_file_close(file, MYF(0));
+ (void) mysql_file_delete(key_file_frm, name, MYF(0));
return(-1);
}
}
@@ -2584,9 +2695,9 @@ int
rename_file_ext(const char * from,const char * to,const char * ext)
{
char from_b[FN_REFLEN],to_b[FN_REFLEN];
- VOID(strxmov(from_b,from,ext,NullS));
- VOID(strxmov(to_b,to,ext,NullS));
- return (my_rename(from_b,to_b,MYF(MY_WME)));
+ (void) strxmov(from_b,from,ext,NullS);
+ (void) strxmov(to_b,to,ext,NullS);
+ return (mysql_file_rename(key_file_frm, from_b, to_b, MYF(MY_WME)));
}
@@ -2719,9 +2830,10 @@ bool check_db_name(LEX_STRING *org_name)
returns 1 on error
*/
-bool check_table_name(const char *name, uint length, bool check_for_path_chars)
+bool check_table_name(const char *name, size_t length, bool check_for_path_chars)
{
- uint name_length= 0; // name length in symbols
+ // name length in symbols
+ size_t name_length= 0;
const char *end= name+length;
if (!length || length > NAME_LEN)
return 1;
@@ -2754,18 +2866,19 @@ bool check_table_name(const char *name, uint length, bool check_for_path_chars)
name_length++;
}
#if defined(USE_MB) && defined(USE_MB_IDENT)
- return (last_char_is_space || name_length > NAME_CHAR_LEN) ;
+ return last_char_is_space || (name_length > NAME_CHAR_LEN);
#else
- return 0;
+ return FALSE;
#endif
}
bool check_column_name(const char *name)
{
- uint name_length= 0; // name length in symbols
+ // name length in symbols
+ size_t name_length= 0;
bool last_char_is_space= TRUE;
-
+
while (*name)
{
#if defined(USE_MB) && defined(USE_MB_IDENT)
@@ -2790,7 +2903,7 @@ bool check_column_name(const char *name)
name_length++;
}
/* Error if empty or too long column name */
- return last_char_is_space || (uint) name_length > NAME_CHAR_LEN;
+ return last_char_is_space || (name_length > NAME_CHAR_LEN);
}
@@ -2942,11 +3055,256 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def)
}
+/**
+ Traverse portion of wait-for graph which is reachable through edge
+ represented by this flush ticket in search for deadlocks.
+
+ @retval TRUE A deadlock is found. A victim is remembered
+ by the visitor.
+ @retval FALSE Success, no deadlocks.
+*/
+
+bool Wait_for_flush::accept_visitor(MDL_wait_for_graph_visitor *gvisitor)
+{
+ return m_share->visit_subgraph(this, gvisitor);
+}
+
+
+uint Wait_for_flush::get_deadlock_weight() const
+{
+ return m_deadlock_weight;
+}
+
+
+/**
+ Traverse portion of wait-for graph which is reachable through this
+ table share in search for deadlocks.
+
+ @param waiting_ticket Ticket representing wait for this share.
+ @param dvisitor Deadlock detection visitor.
+
+ @retval TRUE A deadlock is found. A victim is remembered
+ by the visitor.
+ @retval FALSE No deadlocks, it's OK to begin wait.
+*/
+
+bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
+ MDL_wait_for_graph_visitor *gvisitor)
+{
+ TABLE *table;
+ MDL_context *src_ctx= wait_for_flush->get_ctx();
+ bool result= TRUE;
+
+ /*
+ To protect used_tables list from being concurrently modified
+ while we are iterating through it we acquire LOCK_open.
+ This does not introduce deadlocks in the deadlock detector
+ because we won't try to acquire LOCK_open while
+ holding a write-lock on MDL_lock::m_rwlock.
+ */
+ if (gvisitor->m_lock_open_count++ == 0)
+ mysql_mutex_lock(&LOCK_open);
+
+ I_P_List_iterator <TABLE, TABLE_share> tables_it(used_tables);
+
+ /*
+ In case of multiple searches running in parallel, avoid going
+ over the same loop twice and shortcut the search.
+ Do it after taking the lock to weed out unnecessary races.
+ */
+ if (src_ctx->m_wait.get_status() != MDL_wait::EMPTY)
+ {
+ result= FALSE;
+ goto end;
+ }
+
+ if (gvisitor->enter_node(src_ctx))
+ goto end;
+
+ while ((table= tables_it++))
+ {
+ if (gvisitor->inspect_edge(&table->in_use->mdl_context))
+ {
+ goto end_leave_node;
+ }
+ }
+
+ tables_it.rewind();
+ while ((table= tables_it++))
+ {
+ if (table->in_use->mdl_context.visit_subgraph(gvisitor))
+ {
+ goto end_leave_node;
+ }
+ }
+
+ result= FALSE;
+
+end_leave_node:
+ gvisitor->leave_node(src_ctx);
+
+end:
+ if (gvisitor->m_lock_open_count-- == 1)
+ mysql_mutex_unlock(&LOCK_open);
+
+ return result;
+}
+
+
+/**
+ Wait until the subject share is removed from the table
+ definition cache and make sure it's destroyed.
+
+ @param mdl_context MDL context for thread which is going to wait.
+ @param abstime Timeout for waiting as absolute time value.
+ @param deadlock_weight Weight of this wait for deadlock detector.
+
+ @pre LOCK_open is write locked, the share is used (has
+ non-zero reference count), is marked for flush and
+ this connection does not reference the share.
+ LOCK_open will be unlocked temporarily during execution.
+
+ @retval FALSE - Success.
+ @retval TRUE - Error (OOM, deadlock, timeout, etc...).
+*/
+
+bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime,
+ uint deadlock_weight)
+{
+ MDL_context *mdl_context= &thd->mdl_context;
+ Wait_for_flush ticket(mdl_context, this, deadlock_weight);
+ MDL_wait::enum_wait_status wait_status;
+
+ mysql_mutex_assert_owner(&LOCK_open);
+ /*
+ We should enter this method only when share's version is not
+ up to date and the share is referenced. Otherwise our
+ thread will never be woken up from wait.
+ */
+ DBUG_ASSERT(version != refresh_version && ref_count != 0);
+
+ m_flush_tickets.push_front(&ticket);
+
+ mdl_context->m_wait.reset_status();
+
+ mysql_mutex_unlock(&LOCK_open);
+
+ mdl_context->will_wait_for(&ticket);
+
+ mdl_context->find_deadlock();
+
+ wait_status= mdl_context->m_wait.timed_wait(thd, abstime, TRUE,
+ "Waiting for table flush");
+
+ mdl_context->done_waiting_for();
+
+ mysql_mutex_lock(&LOCK_open);
+
+ m_flush_tickets.remove(&ticket);
+
+ if (m_flush_tickets.is_empty() && ref_count == 0)
+ {
+ /*
+ If our thread was the last one using the share,
+ we must destroy it here.
+ */
+ destroy();
+ }
+
+ /*
+ In cases when our wait was aborted by KILL statement,
+ a deadlock or a timeout, the share might still be referenced,
+ so we don't delete it. Note, that we can't determine this
+ condition by checking wait_status alone, since, for example,
+ a timeout can happen after all references to the table share
+ were released, but before the share is removed from the
+ cache and we receive the notification. This is why
+ we first destroy the share, and then look at
+ wait_status.
+ */
+ switch (wait_status)
+ {
+ case MDL_wait::GRANTED:
+ return FALSE;
+ case MDL_wait::VICTIM:
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ return TRUE;
+ case MDL_wait::TIMEOUT:
+ my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
+ return TRUE;
+ case MDL_wait::KILLED:
+ return TRUE;
+ default:
+ DBUG_ASSERT(0);
+ return TRUE;
+ }
+}
+
+
+/**
+ Initialize TABLE instance (newly created, or coming either from table
+ cache or THD::temporary_tables list) and prepare it for further use
+ during statement execution. Set the 'alias' attribute from the specified
+ TABLE_LIST element. Remember the TABLE_LIST element in the
+ TABLE::pos_in_table_list member.
+
+ @param thd Thread context.
+ @param tl TABLE_LIST element.
+*/
+
+void TABLE::init(THD *thd, TABLE_LIST *tl)
+{
+ DBUG_ASSERT(s->ref_count > 0 || s->tmp_table != NO_TMP_TABLE);
+
+ if (thd->lex->need_correct_ident())
+ alias_name_used= my_strcasecmp(table_alias_charset,
+ s->table_name.str,
+ tl->alias);
+ /* Fix alias if table name changes. */
+ if (strcmp(alias, tl->alias))
+ {
+ uint length= (uint) strlen(tl->alias)+1;
+ alias= (char*) my_realloc((char*) alias, length, MYF(MY_WME));
+ memcpy((char*) alias, tl->alias, length);
+ }
+
+ tablenr= thd->current_tablenr++;
+ used_fields= 0;
+ const_table= 0;
+ null_row= 0;
+ maybe_null= 0;
+ force_index= 0;
+ force_index_order= 0;
+ force_index_group= 0;
+ status= STATUS_NO_RECORD;
+ insert_values= 0;
+ fulltext_searched= 0;
+ file->ft_handler= 0;
+ reginfo.impossible_range= 0;
+
+ /* Catch wrong handling of the auto_increment_field_not_null. */
+ DBUG_ASSERT(!auto_increment_field_not_null);
+ auto_increment_field_not_null= FALSE;
+
+ if (timestamp_field)
+ timestamp_field_type= timestamp_field->get_auto_set_type();
+
+ pos_in_table_list= tl;
+
+ clear_column_bitmaps();
+
+ DBUG_ASSERT(key_read == 0);
+
+ /* Tables may be reused in a sub statement. */
+ DBUG_ASSERT(!file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
+}
+
+
/*
Create Item_field for each column in the table.
SYNPOSIS
- st_table::fill_item_list()
+ TABLE::fill_item_list()
item_list a pointer to an empty list used to store items
DESCRIPTION
@@ -2959,7 +3317,7 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def)
1 out of memory
*/
-bool st_table::fill_item_list(List<Item> *item_list) const
+bool TABLE::fill_item_list(List<Item> *item_list) const
{
/*
All Item_field's created using a direct pointer to a field
@@ -2979,7 +3337,7 @@ bool st_table::fill_item_list(List<Item> *item_list) const
Fields of this table.
SYNPOSIS
- st_table::fill_item_list()
+ TABLE::fill_item_list()
item_list a non-empty list with Item_fields
DESCRIPTION
@@ -2989,7 +3347,7 @@ bool st_table::fill_item_list(List<Item> *item_list) const
is the same as the number of columns in the table.
*/
-void st_table::reset_item_list(List<Item> *item_list) const
+void TABLE::reset_item_list(List<Item> *item_list) const
{
List_iterator_fast<Item> it(*item_list);
for (Field **ptr= field; *ptr; ptr++)
@@ -3373,20 +3731,20 @@ void TABLE_LIST::hide_view_error(THD *thd)
/* Hide "Unknown column" or "Unknown function" error */
DBUG_ASSERT(thd->is_error());
- if (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR ||
- thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST ||
- thd->main_da.sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION ||
- thd->main_da.sql_errno() == ER_PROCACCESS_DENIED_ERROR ||
- thd->main_da.sql_errno() == ER_COLUMNACCESS_DENIED_ERROR ||
- thd->main_da.sql_errno() == ER_TABLEACCESS_DENIED_ERROR ||
- thd->main_da.sql_errno() == ER_TABLE_NOT_LOCKED ||
- thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
+ if (thd->stmt_da->sql_errno() == ER_BAD_FIELD_ERROR ||
+ thd->stmt_da->sql_errno() == ER_SP_DOES_NOT_EXIST ||
+ thd->stmt_da->sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION ||
+ thd->stmt_da->sql_errno() == ER_PROCACCESS_DENIED_ERROR ||
+ thd->stmt_da->sql_errno() == ER_COLUMNACCESS_DENIED_ERROR ||
+ thd->stmt_da->sql_errno() == ER_TABLEACCESS_DENIED_ERROR ||
+ thd->stmt_da->sql_errno() == ER_TABLE_NOT_LOCKED ||
+ thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
{
TABLE_LIST *top= top_table();
thd->clear_error();
my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str);
}
- else if (thd->main_da.sql_errno() == ER_NO_DEFAULT_FOR_FIELD)
+ else if (thd->stmt_da->sql_errno() == ER_NO_DEFAULT_FOR_FIELD)
{
TABLE_LIST *top= top_table();
thd->clear_error();
@@ -3464,7 +3822,7 @@ int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure)
TABLE_LIST *main_view= top_table();
if (ignore_failure)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED),
main_view->view_db.str, main_view->view_name.str);
return(VIEW_CHECK_SKIP);
@@ -3733,11 +4091,8 @@ bool TABLE_LIST::prepare_view_securety_context(THD *thd)
{
DBUG_PRINT("info", ("This table is suid view => load contest"));
DBUG_ASSERT(view && view_sctx);
- if (acl_getroot_no_password(view_sctx,
- definer.user.str,
- definer.host.str,
- definer.host.str,
- thd->db))
+ if (acl_getroot(view_sctx, definer.user.str, definer.host.str,
+ definer.host.str, thd->db))
{
if ((thd->lex->sql_command == SQLCOM_SHOW_CREATE) ||
(thd->lex->sql_command == SQLCOM_SHOW_FIELDS))
@@ -3756,10 +4111,15 @@ bool TABLE_LIST::prepare_view_securety_context(THD *thd)
}
else
{
- my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
- thd->security_ctx->priv_user,
- thd->security_ctx->priv_host,
- (thd->password ? ER(ER_YES) : ER(ER_NO)));
+ if (thd->password == 2)
+ my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
+ thd->security_ctx->priv_user,
+ thd->security_ctx->priv_host);
+ else
+ my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
+ thd->security_ctx->priv_user,
+ thd->security_ctx->priv_host,
+ (thd->password ? ER(ER_YES) : ER(ER_NO)));
}
DBUG_RETURN(TRUE);
}
@@ -3931,14 +4291,15 @@ const char *Natural_join_column::db_name()
return table_ref->view_db.str;
/*
- Test that TABLE_LIST::db is the same as st_table_share::db to
+ Test that TABLE_LIST::db is the same as TABLE_SHARE::db to
ensure consistency. An exception are I_S schema tables, which
are inconsistent in this respect.
*/
DBUG_ASSERT(!strcmp(table_ref->db,
table_ref->table->s->db.str) ||
(table_ref->schema_table &&
- table_ref->table->s->db.str[0] == 0));
+ is_infoschema_db(table_ref->table->s->db.str,
+ table_ref->table->s->db.length)));
return table_ref->db;
}
@@ -4148,13 +4509,14 @@ const char *Field_iterator_table_ref::get_db_name()
return natural_join_it.column_ref()->db_name();
/*
- Test that TABLE_LIST::db is the same as st_table_share::db to
+ Test that TABLE_LIST::db is the same as TABLE_SHARE::db to
ensure consistency. An exception are I_S schema tables, which
are inconsistent in this respect.
*/
DBUG_ASSERT(!strcmp(table_ref->db, table_ref->table->s->db.str) ||
(table_ref->schema_table &&
- table_ref->table->s->db.str[0] == 0));
+ is_infoschema_db(table_ref->table->s->db.str,
+ table_ref->table->s->db.length)));
return table_ref->db;
}
@@ -4324,7 +4686,7 @@ Field_iterator_table_ref::get_natural_column_ref()
/* Reset all columns bitmaps */
-void st_table::clear_column_bitmaps()
+void TABLE::clear_column_bitmaps()
{
/*
Reset column read/write usage. It's identical to:
@@ -4345,9 +4707,9 @@ void st_table::clear_column_bitmaps()
key fields.
*/
-void st_table::prepare_for_position()
+void TABLE::prepare_for_position()
{
- DBUG_ENTER("st_table::prepare_for_position");
+ DBUG_ENTER("TABLE::prepare_for_position");
if ((file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
s->primary_key < MAX_KEY)
@@ -4366,14 +4728,14 @@ void st_table::prepare_for_position()
NOTE:
This changes the bitmap to use the tmp bitmap
After this, you can't access any other columns in the table until
- bitmaps are reset, for example with st_table::clear_column_bitmaps()
- or st_table::restore_column_maps_after_mark_index()
+ bitmaps are reset, for example with TABLE::clear_column_bitmaps()
+ or TABLE::restore_column_maps_after_mark_index()
*/
-void st_table::mark_columns_used_by_index(uint index)
+void TABLE::mark_columns_used_by_index(uint index)
{
MY_BITMAP *bitmap= &tmp_set;
- DBUG_ENTER("st_table::mark_columns_used_by_index");
+ DBUG_ENTER("TABLE::mark_columns_used_by_index");
set_keyread(TRUE);
bitmap_clear_all(bitmap);
@@ -4391,10 +4753,10 @@ void st_table::mark_columns_used_by_index(uint index)
restore_column_maps_after_mark_index().
*/
-void st_table::add_read_columns_used_by_index(uint index)
+void TABLE::add_read_columns_used_by_index(uint index)
{
MY_BITMAP *bitmap= &tmp_set;
- DBUG_ENTER("st_table::add_read_columns_used_by_index");
+ DBUG_ENTER("TABLE::add_read_columns_used_by_index");
set_keyread(TRUE);
bitmap_copy(bitmap, read_set);
@@ -4415,9 +4777,9 @@ void st_table::add_read_columns_used_by_index(uint index)
when calling mark_columns_used_by_index
*/
-void st_table::restore_column_maps_after_mark_index()
+void TABLE::restore_column_maps_after_mark_index()
{
- DBUG_ENTER("st_table::restore_column_maps_after_mark_index");
+ DBUG_ENTER("TABLE::restore_column_maps_after_mark_index");
set_keyread(FALSE);
default_column_bitmaps();
@@ -4430,7 +4792,7 @@ void st_table::restore_column_maps_after_mark_index()
mark columns used by key, but don't reset other fields
*/
-void st_table::mark_columns_used_by_index_no_reset(uint index,
+void TABLE::mark_columns_used_by_index_no_reset(uint index,
MY_BITMAP *bitmap)
{
KEY_PART_INFO *key_part= key_info[index].key_part;
@@ -4449,7 +4811,7 @@ void st_table::mark_columns_used_by_index_no_reset(uint index,
always set and sometimes read.
*/
-void st_table::mark_auto_increment_column()
+void TABLE::mark_auto_increment_column()
{
DBUG_ASSERT(found_next_number_field);
/*
@@ -4482,7 +4844,7 @@ void st_table::mark_auto_increment_column()
retrieve the row again.
*/
-void st_table::mark_columns_needed_for_delete()
+void TABLE::mark_columns_needed_for_delete()
{
if (triggers)
triggers->mark_fields_used(TRG_EVENT_DELETE);
@@ -4532,7 +4894,7 @@ void st_table::mark_columns_needed_for_delete()
retrieve the row again.
*/
-void st_table::mark_columns_needed_for_update()
+void TABLE::mark_columns_needed_for_update()
{
DBUG_ENTER("mark_columns_needed_for_update");
if (triggers)
@@ -4575,7 +4937,7 @@ void st_table::mark_columns_needed_for_update()
as changed.
*/
-void st_table::mark_columns_needed_for_insert()
+void TABLE::mark_columns_needed_for_insert()
{
if (triggers)
{
@@ -4593,24 +4955,6 @@ void st_table::mark_columns_needed_for_insert()
}
-/**
- @brief Check if this is part of a MERGE table with attached children.
-
- @return status
- @retval TRUE children are attached
- @retval FALSE no MERGE part or children not attached
-
- @detail
- A MERGE table consists of a parent TABLE and zero or more child
- TABLEs. Each of these TABLEs is called a part of a MERGE table.
-*/
-
-bool st_table::is_children_attached(void)
-{
- return((child_l && children_attached) ||
- (parent && parent->children_attached));
-}
-
/*
Cleanup this table for re-execution.
@@ -4639,6 +4983,8 @@ void TABLE_LIST::reinit_before_use(THD *thd)
}
while (parent_embedding &&
parent_embedding->nested_join->join_list.head() == embedded);
+
+ mdl_request.ticket= NULL;
}
/*
@@ -4669,9 +5015,9 @@ Item_subselect *TABLE_LIST::containing_subselect()
DESCRIPTION
The parser collects the index hints for each table in a "tagged list"
(TABLE_LIST::index_hints). Using the information in this tagged list
- this function sets the members st_table::keys_in_use_for_query,
+ this function sets the members st_table::keys_in_use_for_query,
st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by,
- st_table::force_index, st_table::force_index_order,
+ st_table::force_index, st_table::force_index_order,
st_table::force_index_group and st_table::covering_keys.
Current implementation of the runtime does not allow mixing FORCE INDEX
@@ -4861,6 +5207,78 @@ size_t max_row_length(TABLE *table, const uchar *data)
return length;
}
+
+/**
+ Helper function which allows to allocate metadata lock request
+ objects for all elements of table list.
+*/
+
+void init_mdl_requests(TABLE_LIST *table_list)
+{
+ for ( ; table_list ; table_list= table_list->next_global)
+ table_list->mdl_request.init(MDL_key::TABLE,
+ table_list->db, table_list->table_name,
+ table_list->lock_type >= TL_WRITE_ALLOW_WRITE ?
+ MDL_SHARED_WRITE : MDL_SHARED_READ,
+ MDL_TRANSACTION);
+}
+
+
+/**
+ Update TABLE::const_key_parts for single table UPDATE/DELETE query
+
+ @param conds WHERE clause expression
+
+ @retval TRUE error (OOM)
+ @retval FALSE success
+
+ @note
+ Set const_key_parts bits if key fields are equal to constants in
+ the WHERE expression.
+*/
+
+bool TABLE::update_const_key_parts(COND *conds)
+{
+ bzero((char*) const_key_parts, sizeof(key_part_map) * s->keys);
+
+ if (conds == NULL)
+ return FALSE;
+
+ for (uint index= 0; index < s->keys; index++)
+ {
+ KEY_PART_INFO *keyinfo= key_info[index].key_part;
+ KEY_PART_INFO *keyinfo_end= keyinfo + key_info[index].key_parts;
+
+ for (key_part_map part_map= (key_part_map)1;
+ keyinfo < keyinfo_end;
+ keyinfo++, part_map<<= 1)
+ {
+ if (const_expression_in_where(conds, NULL, keyinfo->field))
+ const_key_parts[index]|= part_map;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Test if the order list consists of simple field expressions
+
+ @param order Linked list of ORDER BY arguments
+
+ @return TRUE if @a order is empty or consist of simple field expressions
+*/
+
+bool is_simple_order(ORDER *order)
+{
+ for (ORDER *ord= order; ord; ord= ord->next)
+ {
+ if (ord->item[0]->real_item()->type() != Item::FIELD_ITEM)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
/*****************************************************************************
** Instansiate templates
*****************************************************************************/
diff --git a/sql/table.h b/sql/table.h
index 132279169cb..6aba4f21db2 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1,4 +1,7 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+#ifndef TABLE_INCLUDED
+#define TABLE_INCLUDED
+
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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
@@ -13,6 +16,18 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_plist.h"
+#include "sql_list.h" /* Sql_alloc */
+#include "mdl.h"
+#include "datadict.h"
+
+#ifndef MYSQL_CLIENT
+
+#include "hash.h" /* HASH */
+#include "handler.h" /* row_type, ha_choice, handler */
+#include "mysql_com.h" /* enum_field_types */
+#include "thr_lock.h" /* thr_lock_type */
/* Structs that defines the TABLE */
@@ -25,10 +40,132 @@ class st_select_lex;
class partition_info;
class COND_EQUAL;
class Security_context;
+struct TABLE_LIST;
+class ACL_internal_schema_access;
+class ACL_internal_table_access;
+class Field;
+
+/*
+ Used to identify NESTED_JOIN structures within a join (applicable only to
+ structures that have not been simplified away and embed more the one
+ element)
+*/
+typedef ulonglong nested_join_map;
+
+
+#define tmp_file_prefix "#sql" /**< Prefix for tmp tables */
+#define tmp_file_prefix_length 4
+#define TMP_TABLE_KEY_EXTRA 8
+
+/**
+ Enumerate possible types of a table from re-execution
+ standpoint.
+ TABLE_LIST class has a member of this type.
+ At prepared statement prepare, this member is assigned a value
+ as of the current state of the database. Before (re-)execution
+ of a prepared statement, we check that the value recorded at
+ prepare matches the type of the object we obtained from the
+ table definition cache.
+
+ @sa check_and_update_table_version()
+ @sa Execute_observer
+ @sa Prepared_statement::reprepare()
+*/
+
+enum enum_table_ref_type
+{
+ /** Initial value set by the parser */
+ TABLE_REF_NULL= 0,
+ TABLE_REF_VIEW,
+ TABLE_REF_BASE_TABLE,
+ TABLE_REF_I_S_TABLE,
+ TABLE_REF_TMP_TABLE
+};
+
+
+/*************************************************************************/
+
+/**
+ Object_creation_ctx -- interface for creation context of database objects
+ (views, stored routines, events, triggers). Creation context -- is a set
+ of attributes, that should be fixed at the creation time and then be used
+ each time the object is parsed or executed.
+*/
+
+class Object_creation_ctx
+{
+public:
+ Object_creation_ctx *set_n_backup(THD *thd);
+
+ void restore_env(THD *thd, Object_creation_ctx *backup_ctx);
+
+protected:
+ Object_creation_ctx() {}
+ virtual Object_creation_ctx *create_backup_ctx(THD *thd) const = 0;
+
+ virtual void change_env(THD *thd) const = 0;
+
+public:
+ virtual ~Object_creation_ctx()
+ { }
+};
/*************************************************************************/
/**
+ Default_object_creation_ctx -- default implementation of
+ Object_creation_ctx.
+*/
+
+class Default_object_creation_ctx : public Object_creation_ctx
+{
+public:
+ CHARSET_INFO *get_client_cs()
+ {
+ return m_client_cs;
+ }
+
+ CHARSET_INFO *get_connection_cl()
+ {
+ return m_connection_cl;
+ }
+
+protected:
+ Default_object_creation_ctx(THD *thd);
+
+ Default_object_creation_ctx(CHARSET_INFO *client_cs,
+ CHARSET_INFO *connection_cl);
+
+protected:
+ virtual Object_creation_ctx *create_backup_ctx(THD *thd) const;
+
+ virtual void change_env(THD *thd) const;
+
+protected:
+ /**
+ client_cs stores the value of character_set_client session variable.
+ The only character set attribute is used.
+
+ Client character set is included into query context, because we save
+ query in the original character set, which is client character set. So,
+ in order to parse the query properly we have to switch client character
+ set on parsing.
+ */
+ CHARSET_INFO *m_client_cs;
+
+ /**
+ connection_cl stores the value of collation_connection session
+ variable. Both character set and collation attributes are used.
+
+ Connection collation is included into query context, becase it defines
+ the character set and collation of text literals in internal
+ representation of query (item-objects).
+ */
+ CHARSET_INFO *m_connection_cl;
+};
+
+
+/**
View_creation_ctx -- creation context of view objects.
*/
@@ -67,6 +204,25 @@ typedef struct st_order {
} ORDER;
/**
+ State information for internal tables grants.
+ This structure is part of the TABLE_LIST, and is updated
+ during the ACL check process.
+ @sa GRANT_INFO
+*/
+struct st_grant_internal_info
+{
+ /** True if the internal lookup by schema name was done. */
+ bool m_schema_lookup_done;
+ /** Cached internal schema access. */
+ const ACL_internal_schema_access *m_schema_access;
+ /** True if the internal lookup by table name was done. */
+ bool m_table_lookup_done;
+ /** Cached internal table access. */
+ const ACL_internal_table_access *m_table_access;
+};
+typedef struct st_grant_internal_info GRANT_INTERNAL_INFO;
+
+/**
@brief The current state of the privilege checking process for the current
user, SQL statement and SQL object.
@@ -127,6 +283,8 @@ typedef struct st_grant_info
check access rights to the underlying tables of a view.
*/
ulong orig_want_privilege;
+ /** The grant state for internal tables. */
+ GRANT_INTERNAL_INFO m_internal;
} GRANT_INFO;
enum tmp_table_type
@@ -134,23 +292,6 @@ enum tmp_table_type
NO_TMP_TABLE, NON_TRANSACTIONAL_TMP_TABLE, TRANSACTIONAL_TMP_TABLE,
INTERNAL_TMP_TABLE, SYSTEM_TMP_TABLE
};
-
-/** Event on which trigger is invoked. */
-enum trg_event_type
-{
- TRG_EVENT_INSERT= 0,
- TRG_EVENT_UPDATE= 1,
- TRG_EVENT_DELETE= 2,
- TRG_EVENT_MAX
-};
-
-enum frm_type_enum
-{
- FRMTYPE_ERROR= 0,
- FRMTYPE_TABLE,
- FRMTYPE_VIEW
-};
-
enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP };
typedef struct st_filesort_info
@@ -243,7 +384,7 @@ enum enum_table_category
- LOCK TABLE t FOR READ/WRITE
- FLUSH TABLES WITH READ LOCK
- SET GLOBAL READ_ONLY = ON
- as there is no point in locking explicitely
+ as there is no point in locking explicitly
an INFORMATION_SCHEMA table.
Nothing is directly written to information schema tables.
Note that this value is not used currently,
@@ -258,16 +399,16 @@ enum enum_table_category
TABLE_CATEGORY_INFORMATION=4,
/**
- Performance schema tables.
+ Log tables.
These tables are an interface provided by the system
- to inspect the system performance data.
+ to inspect the system logs.
These tables do *not* honor:
- LOCK TABLE t FOR READ/WRITE
- FLUSH TABLES WITH READ LOCK
- SET GLOBAL READ_ONLY = ON
- as there is no point in locking explicitely
- a PERFORMANCE_SCHEMA table.
- An example of PERFORMANCE_SCHEMA tables are:
+ as there is no point in locking explicitly
+ a LOG table.
+ An example of LOG tables are:
- mysql.slow_log
- mysql.general_log,
which *are* updated even when there is either
@@ -275,9 +416,31 @@ enum enum_table_category
User queries do not write directly to these tables
(there are exceptions for log tables).
The server implementation perform writes.
+ Log tables are cached in the table cache.
+ */
+ TABLE_CATEGORY_LOG=5,
+
+ /**
+ Performance schema tables.
+ These tables are an interface provided by the system
+ to inspect the system performance data.
+ These tables do *not* honor:
+ - LOCK TABLE t FOR READ/WRITE
+ - FLUSH TABLES WITH READ LOCK
+ - SET GLOBAL READ_ONLY = ON
+ as there is no point in locking explicitly
+ a PERFORMANCE_SCHEMA table.
+ An example of PERFORMANCE_SCHEMA tables are:
+ - performance_schema.*
+ which *are* updated (but not using the handler interface)
+ even when there is either
+ a GLOBAL READ LOCK or a GLOBAL READ_ONLY in effect.
+ User queries do not write directly to these tables
+ (there are exceptions for SETUP_* tables).
+ The server implementation perform writes.
Performance tables are cached in the table cache.
*/
- TABLE_CATEGORY_PERFORMANCE=5
+ TABLE_CATEGORY_PERFORMANCE=6
};
typedef enum enum_table_category TABLE_CATEGORY;
@@ -285,6 +448,10 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db,
const LEX_STRING *name);
+struct TABLE_share;
+
+extern ulong refresh_version;
+
typedef struct st_table_field_type
{
LEX_STRING name;
@@ -300,6 +467,19 @@ typedef struct st_table_field_def
} TABLE_FIELD_DEF;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+/**
+ Partition specific ha_data struct.
+*/
+typedef struct st_ha_data_partition
+{
+ bool auto_inc_initialized;
+ mysql_mutex_t LOCK_auto_inc; /**< protecting auto_inc val */
+ ulonglong next_auto_inc_val; /**< first non reserved value */
+} HA_DATA_PARTITION;
+#endif
+
+
class Table_check_intact
{
protected:
@@ -314,14 +494,53 @@ public:
};
-/*
+/**
+ Class representing the fact that some thread waits for table
+ share to be flushed. Is used to represent information about
+ such waits in MDL deadlock detector.
+*/
+
+class Wait_for_flush : public MDL_wait_for_subgraph
+{
+ MDL_context *m_ctx;
+ TABLE_SHARE *m_share;
+ uint m_deadlock_weight;
+public:
+ Wait_for_flush(MDL_context *ctx_arg, TABLE_SHARE *share_arg,
+ uint deadlock_weight_arg)
+ : m_ctx(ctx_arg), m_share(share_arg),
+ m_deadlock_weight(deadlock_weight_arg)
+ {}
+
+ MDL_context *get_ctx() const { return m_ctx; }
+
+ virtual bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor);
+
+ virtual uint get_deadlock_weight() const;
+
+ /**
+ Pointers for participating in the list of waiters for table share.
+ */
+ Wait_for_flush *next_in_share;
+ Wait_for_flush **prev_in_share;
+};
+
+
+typedef I_P_List <Wait_for_flush,
+ I_P_List_adapter<Wait_for_flush,
+ &Wait_for_flush::next_in_share,
+ &Wait_for_flush::prev_in_share> >
+ Wait_for_flush_list;
+
+
+/**
This structure is shared between different table objects. There is one
instance of table share per one table in the database.
*/
-typedef struct st_table_share
+struct TABLE_SHARE
{
- st_table_share() {} /* Remove gcc warning */
+ TABLE_SHARE() {} /* Remove gcc warning */
/** Category of this table. */
TABLE_CATEGORY table_category;
@@ -332,13 +551,15 @@ typedef struct st_table_share
TYPELIB keynames; /* Pointers to keynames */
TYPELIB fieldnames; /* Pointer to fieldnames */
TYPELIB *intervals; /* pointer to interval info */
- pthread_mutex_t mutex; /* For locking the share */
- pthread_cond_t cond; /* To signal that share is ready */
- struct st_table_share *next, /* Link to unused shares */
- **prev;
-#ifdef NOT_YET
- struct st_table *open_tables; /* link to open tables */
-#endif
+ mysql_mutex_t LOCK_ha_data; /* To protect access to ha_data */
+ TABLE_SHARE *next, **prev; /* Link to unused shares */
+
+ /*
+ Doubly-linked (back-linked) lists of used and unused TABLE objects
+ for this share.
+ */
+ I_P_List <TABLE, TABLE_share> used_tables;
+ I_P_List <TABLE, TABLE_share> free_tables;
/* The following is copied to each TABLE on OPEN */
Field **field;
@@ -377,9 +598,7 @@ typedef struct st_table_share
key_map keys_for_keyread;
ha_rows min_rows, max_rows; /* create information */
ulong avg_row_length; /* create information */
- ulong raid_chunksize;
ulong version, mysql_version;
- ulong timestamp_offset; /* Set to offset+1 of record */
ulong reclength; /* Recordlength */
plugin_ref db_plugin; /* storage engine plugin */
@@ -390,11 +609,8 @@ typedef struct st_table_share
}
enum row_type row_type; /* How rows are stored */
enum tmp_table_type tmp_table;
- enum enum_ha_unused unused1;
- enum enum_ha_unused unused2;
uint ref_count; /* How many TABLE objects uses this */
- uint open_count; /* Number of tables in open list */
uint blob_ptr_size; /* 4 or 8 */
uint key_block_size; /* create key_block_size, if used */
uint null_bytes, last_null_bit_pos;
@@ -410,7 +626,6 @@ typedef struct st_table_share
uint db_create_options; /* Create options from database */
uint db_options_in_use; /* Options in use */
uint db_record_offset; /* if HA_REC_IN_SEQ */
- uint raid_type, raid_chunks;
uint rowid_field_offset; /* Field_nr +1 to rowid field */
/* Index of auto-updated TIMESTAMP field in field array */
uint primary_key;
@@ -426,8 +641,6 @@ typedef struct st_table_share
bool db_low_byte_first; /* Portable row format */
bool crashed;
bool is_view;
- bool name_lock, replace_with_name_lock;
- bool waiting_on_cond; /* Protection against free */
ulong table_map_id; /* for row-based replication */
/*
@@ -439,13 +652,11 @@ typedef struct st_table_share
int cached_row_logging_check;
#ifdef WITH_PARTITION_STORAGE_ENGINE
- /** @todo: Move into *ha_data for partitioning */
+ /* filled in when reading from frm */
bool auto_partitioned;
- char *partition_info;
- uint partition_info_len;
+ char *partition_info_str;
+ uint partition_info_str_len;
uint partition_info_buffer_size;
- const char *part_state;
- uint part_state_len;
handlerton *default_part_db_type;
#endif
@@ -463,8 +674,23 @@ typedef struct st_table_share
/** place to store storage engine specific data */
void *ha_data;
- void (*ha_data_destroy)(void *); /* An optional destructor for ha_data. */
+ void (*ha_data_destroy)(void *); /* An optional destructor for ha_data */
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ /** place to store partition specific data, LOCK_ha_data hold while init. */
+ HA_DATA_PARTITION *ha_part_data;
+ /* Destructor for ha_part_data */
+ void (*ha_part_data_destroy)(HA_DATA_PARTITION *);
+#endif
+
+
+ /** Instrumentation for this table share. */
+ PSI_table_share *m_psi;
+
+ /**
+ List of tickets representing threads waiting for the share to be flushed.
+ */
+ Wait_for_flush_list m_flush_tickets;
/*
Set share's table cache key and update its db and table name appropriately.
@@ -526,7 +752,7 @@ typedef struct st_table_share
inline bool require_write_privileges()
{
- return (table_category == TABLE_CATEGORY_PERFORMANCE);
+ return (table_category == TABLE_CATEGORY_LOG);
}
inline ulong get_table_def_version()
@@ -534,6 +760,12 @@ typedef struct st_table_share
return table_map_id;
}
+
+ /** Is this table share being expelled from the table definition cache? */
+ inline bool has_old_version() const
+ {
+ return version != refresh_version;
+ }
/**
Convert unrelated members of TABLE_SHARE to one enum
representing its type.
@@ -633,10 +865,15 @@ typedef struct st_table_share
return (tmp_table == SYSTEM_TMP_TABLE || is_view) ? 0 : table_map_id;
}
-} TABLE_SHARE;
+ bool visit_subgraph(Wait_for_flush *waiting_ticket,
+ MDL_wait_for_graph_visitor *gvisitor);
+ bool wait_for_old_version(THD *thd, struct timespec *abstime,
+ uint deadlock_weight);
+ /** Release resources and free memory occupied by the table share. */
+ void destroy();
+};
-extern ulong refresh_version;
/* Information for one open table */
enum index_hint_type
@@ -646,21 +883,25 @@ enum index_hint_type
INDEX_HINT_FORCE
};
-struct st_table {
- st_table() {} /* Remove gcc warning */
+struct TABLE
+{
+ TABLE() {} /* Remove gcc warning */
TABLE_SHARE *s;
handler *file;
-#ifdef NOT_YET
- struct st_table *used_next, **used_prev; /* Link to used tables */
- struct st_table *open_next, **open_prev; /* Link to open tables */
-#endif
- struct st_table *next, *prev;
+ TABLE *next, *prev;
+
+private:
+ /**
+ Links for the lists of used/unused TABLE objects for this share.
+ Declared as private to avoid direct manipulation with those objects.
+ One should use methods of I_P_List template instead.
+ */
+ TABLE *share_next, **share_prev;
- /* For the below MERGE related members see top comment in ha_myisammrg.cc */
- struct st_table *parent; /* Set in MERGE child. Ptr to parent */
- TABLE_LIST *child_l; /* Set in MERGE parent. List of children */
- TABLE_LIST **child_last_l; /* Set in MERGE parent. End of list */
+ friend struct TABLE_share;
+
+public:
THD *in_use; /* Which thread uses this */
Field **field; /* Pointer to fields */
@@ -700,6 +941,8 @@ struct st_table {
/* Table's triggers, 0 if there are no of them */
Table_triggers_list *triggers;
TABLE_LIST *pos_in_table_list;/* Element referring to this table */
+ /* Position in thd->locked_table_list under LOCK TABLES */
+ TABLE_LIST *pos_in_locked_tables;
ORDER *group;
const char *alias; /* alias or table name */
uchar *null_flags;
@@ -813,24 +1056,6 @@ struct st_table {
*/
my_bool key_read;
my_bool no_keyread;
- /*
- Placeholder for an open table which prevents other connections
- from taking name-locks on this table. Typically used with
- TABLE_SHARE::version member to take an exclusive name-lock on
- this table name -- a name lock that not only prevents other
- threads from opening the table, but also blocks other name
- locks. This is achieved by:
- - setting open_placeholder to 1 - this will block other name
- locks, as wait_for_locked_table_name will be forced to wait,
- see table_is_used for details.
- - setting version to 0 - this will force other threads to close
- the instance of this table and wait (this is the same approach
- as used for usual name locks).
- An exclusively name-locked table currently can have no handler
- object associated with it (db_stat is always 0), but please do
- not rely on that.
- */
- my_bool open_placeholder;
my_bool locked_by_logger;
my_bool no_replicate;
my_bool locked_by_name;
@@ -847,8 +1072,7 @@ struct st_table {
my_bool insert_or_update; /* Can be used by the handler */
my_bool alias_name_used; /* true if table_name is alias */
my_bool get_fields_in_item_tree; /* Signal to fix_field */
- /* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */
- my_bool children_attached;
+ my_bool m_needs_reopen;
REGINFO reginfo; /* field connections */
MEM_ROOT mem_root;
@@ -858,7 +1082,9 @@ struct st_table {
partition_info *part_info; /* Partition related information */
bool no_partitions_used; /* If true, all partitions have been pruned away */
#endif
+ MDL_ticket *mdl_ticket;
+ void init(THD *thd, TABLE_LIST *tl);
bool fill_item_list(List<Item> *item_list) const;
void reset_item_list(List<Item> *item_list) const;
void clear_column_bitmaps(void);
@@ -894,14 +1120,10 @@ struct st_table {
read_set= &def_read_set;
write_set= &def_write_set;
}
- /* Is table open or should be treated as such by name-locking? */
- inline bool is_name_opened() { return db_stat || open_placeholder; }
- /*
- Is this instance of the table should be reopen or represents a name-lock?
- */
- inline bool needs_reopen_or_name_lock()
- { return s->version != refresh_version; }
- bool is_children_attached(void);
+ /** Should this instance of the table be reopened? */
+ inline bool needs_reopen()
+ { return !db_stat || m_needs_reopen; }
+
inline void set_keyread(bool flag)
{
DBUG_ASSERT(file);
@@ -916,8 +1138,29 @@ struct st_table {
file->extra(HA_EXTRA_NO_KEYREAD);
}
}
+
+ bool update_const_key_parts(COND *conds);
};
+
+/**
+ Helper class which specifies which members of TABLE are used for
+ participation in the list of used/unused TABLE objects for the share.
+*/
+
+struct TABLE_share
+{
+ static inline TABLE **next_ptr(TABLE *l)
+ {
+ return &l->share_next;
+ }
+ static inline TABLE ***prev_ptr(TABLE *l)
+ {
+ return &l->share_prev;
+ }
+};
+
+
enum enum_schema_table_state
{
NOT_PROCESSED= 0,
@@ -927,7 +1170,9 @@ enum enum_schema_table_state
typedef struct st_foreign_key_info
{
- LEX_STRING *forein_id;
+ LEX_STRING *foreign_id;
+ LEX_STRING *foreign_db;
+ LEX_STRING *foreign_table;
LEX_STRING *referenced_db;
LEX_STRING *referenced_table;
LEX_STRING *update_method;
@@ -937,47 +1182,6 @@ typedef struct st_foreign_key_info
List<LEX_STRING> referenced_fields;
} FOREIGN_KEY_INFO;
-/*
- Make sure that the order of schema_tables and enum_schema_tables are the same.
-*/
-
-enum enum_schema_tables
-{
- SCH_CHARSETS= 0,
- SCH_COLLATIONS,
- SCH_COLLATION_CHARACTER_SET_APPLICABILITY,
- SCH_COLUMNS,
- SCH_COLUMN_PRIVILEGES,
- SCH_ENGINES,
- SCH_EVENTS,
- SCH_FILES,
- SCH_GLOBAL_STATUS,
- SCH_GLOBAL_VARIABLES,
- SCH_KEY_COLUMN_USAGE,
- SCH_OPEN_TABLES,
- SCH_PARTITIONS,
- SCH_PLUGINS,
- SCH_PROCESSLIST,
- SCH_PROFILES,
- SCH_REFERENTIAL_CONSTRAINTS,
- SCH_PROCEDURES,
- SCH_SCHEMATA,
- SCH_SCHEMA_PRIVILEGES,
- SCH_SESSION_STATUS,
- SCH_SESSION_VARIABLES,
- SCH_STATISTICS,
- SCH_STATUS,
- SCH_TABLES,
- SCH_TABLE_CONSTRAINTS,
- SCH_TABLE_NAMES,
- SCH_TABLE_PRIVILEGES,
- SCH_TRIGGERS,
- SCH_USER_PRIVILEGES,
- SCH_VARIABLES,
- SCH_VIEWS
-};
-
-
#define MY_I_S_MAYBE_NULL 1
#define MY_I_S_UNSIGNED 2
@@ -1067,7 +1271,6 @@ typedef struct st_schema_table
/** The threshold size a blob field buffer before it is freed */
#define MAX_TDC_BLOB_SIZE 65536
-struct st_lex;
class select_union;
class TMP_TABLE_PARAM;
@@ -1113,6 +1316,16 @@ public:
};
+/**
+ Type of table which can be open for an element of table list.
+*/
+
+enum enum_open_type
+{
+ OT_TEMPORARY_OR_BASE= 0, OT_TEMPORARY_ONLY, OT_BASE_ONLY
+};
+
+
/*
Table reference in the FROM clause.
@@ -1145,6 +1358,7 @@ public:
(TABLE_LIST::join_using_fields != NULL)
*/
+struct LEX;
class Index_hint;
struct TABLE_LIST
{
@@ -1155,13 +1369,23 @@ struct TABLE_LIST
simple_open_and_lock_tables
*/
inline void init_one_table(const char *db_name_arg,
+ size_t db_length_arg,
const char *table_name_arg,
+ size_t table_name_length_arg,
+ const char *alias_arg,
enum thr_lock_type lock_type_arg)
{
bzero((char*) this, sizeof(*this));
db= (char*) db_name_arg;
- table_name= alias= (char*) table_name_arg;
+ db_length= db_length_arg;
+ table_name= (char*) table_name_arg;
+ table_name_length= table_name_length_arg;
+ alias= (char*) alias_arg;
lock_type= lock_type_arg;
+ mdl_request.init(MDL_key::TABLE, db, table_name,
+ (lock_type >= TL_WRITE_ALLOW_WRITE) ?
+ MDL_SHARED_WRITE : MDL_SHARED_READ,
+ MDL_TRANSACTION);
}
/*
@@ -1265,7 +1489,7 @@ struct TABLE_LIST
TMP_TABLE_PARAM *schema_table_param;
/* link to select_lex where this table was used */
st_select_lex *select_lex;
- st_lex *view; /* link on VIEW lex for merging */
+ LEX *view; /* link on VIEW lex for merging */
Field_translator *field_translation; /* array of VIEW fields */
/* pointer to element after last one in translation table above */
Field_translator *field_translation_end;
@@ -1366,7 +1590,11 @@ struct TABLE_LIST
bool cacheable_table; /* stop PS caching */
/* used in multi-upd/views privilege check */
bool table_in_first_from_clause;
- bool skip_temporary; /* this table shouldn't be temporary */
+ /**
+ Specifies which kind of table should be open for this element
+ of table list.
+ */
+ enum enum_open_type open_type;
/* TRUE if this merged view contain auto_increment field */
bool contain_auto_increment;
bool multitable_view; /* TRUE iff this is multitable view */
@@ -1384,13 +1612,29 @@ struct TABLE_LIST
used for implicit LOCK TABLES only and won't be used in real statement.
*/
bool prelocking_placeholder;
- /*
- This TABLE_LIST object corresponds to the table to be created
- so it is possible that it does not exist (used in CREATE TABLE
- ... SELECT implementation).
+ /**
+ Indicates that if TABLE_LIST object corresponds to the table/view
+ which requires special handling.
*/
- bool create;
+ enum
+ {
+ /* Normal open. */
+ OPEN_NORMAL= 0,
+ /* Associate a table share only if the the table exists. */
+ OPEN_IF_EXISTS,
+ /* Don't associate a table share. */
+ OPEN_STUB
+ } open_strategy;
+ /* For transactional locking. */
+ int lock_timeout; /* NOWAIT or WAIT [X] */
+ bool lock_transactional; /* If transactional lock requested. */
bool internal_tmp_table;
+ /** TRUE if an alias for this table was specified in the SQL. */
+ bool is_alias;
+ /** TRUE if the table is referred to in the statement using a fully
+ qualified name (<db_name>.<table_name>).
+ */
+ bool is_fqtn;
/* View creation context. */
@@ -1424,12 +1668,17 @@ struct TABLE_LIST
the parsed tree is created.
*/
uint8 trg_event_map;
+ /* TRUE <=> this table is a const one and was optimized away. */
+ bool optimized_away;
uint i_s_requested_object;
bool has_db_lookup_value;
bool has_table_lookup_value;
uint table_open_method;
enum enum_schema_table_state schema_table_state;
+
+ MDL_request mdl_request;
+
void calc_md5(char *buffer);
void set_underlying_merge();
int view_check_option(THD *thd, bool ignore_failure);
@@ -1437,8 +1686,7 @@ struct TABLE_LIST
void cleanup_items();
bool placeholder()
{
- return derived || view || schema_table || (create && !table->db_stat) ||
- !table;
+ return derived || view || schema_table || !table;
}
void print(THD *thd, String *str, enum_query_type query_type);
bool check_single_table(TABLE_LIST **table, table_map map,
@@ -1480,26 +1728,12 @@ struct TABLE_LIST
Item_subselect *containing_subselect();
/*
- Compiles the tagged hints list and fills up st_table::keys_in_use_for_query,
- st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by,
- st_table::force_index and st_table::covering_keys.
+ Compiles the tagged hints list and fills up TABLE::keys_in_use_for_query,
+ TABLE::keys_in_use_for_group_by, TABLE::keys_in_use_for_order_by,
+ TABLE::force_index and TABLE::covering_keys.
*/
bool process_index_hints(TABLE *table);
- /* Access MERGE child def version. See top comment in ha_myisammrg.cc */
- inline ulong get_child_def_version()
- {
- return child_def_version;
- }
- inline void set_child_def_version(ulong version)
- {
- child_def_version= version;
- }
- inline void init_child_def_version()
- {
- child_def_version= ~0UL;
- }
-
/**
Compare the version of metadata from the previous execution
(if any) with values obtained from the current table
@@ -1522,9 +1756,14 @@ struct TABLE_LIST
*/
inline
void set_table_ref_id(TABLE_SHARE *s)
+ { set_table_ref_id(s->get_table_ref_type(), s->get_table_ref_version()); }
+
+ inline
+ void set_table_ref_id(enum_table_ref_type table_ref_type_arg,
+ ulong table_ref_version_arg)
{
- m_table_ref_type= s->get_table_ref_type();
- m_table_ref_version= s->get_table_ref_version();
+ m_table_ref_type= table_ref_type_arg;
+ m_table_ref_version= table_ref_version_arg;
}
/**
@@ -1550,13 +1789,6 @@ struct TABLE_LIST
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
- /*
- Cleanup for re-execution in a prepared statement or a stored
- procedure.
- */
-
- /* Remembered MERGE child def version. See top comment in ha_myisammrg.cc */
- ulong child_def_version;
/** See comments for set_metadata_id() */
enum enum_table_ref_type m_table_ref_type;
/** See comments for set_metadata_id() */
@@ -1799,3 +2031,87 @@ static inline void dbug_tmp_restore_column_maps(MY_BITMAP *read_set,
size_t max_row_length(TABLE *table, const uchar *data);
+
+void init_mdl_requests(TABLE_LIST *table_list);
+
+int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
+ uint db_stat, uint prgflag, uint ha_open_flags,
+ TABLE *outparam, bool is_create_table);
+TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
+ uint key_length);
+void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
+ uint key_length,
+ const char *table_name, const char *path);
+void free_table_share(TABLE_SHARE *share);
+int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags);
+void open_table_error(TABLE_SHARE *share, int error, int db_errno, int errarg);
+void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form);
+bool check_and_convert_db_name(LEX_STRING *db, bool preserve_lettercase);
+bool check_db_name(LEX_STRING *db);
+bool check_column_name(const char *name);
+bool check_table_name(const char *name, size_t length, bool check_for_path_chars);
+int rename_file_ext(const char * from,const char * to,const char * ext);
+char *get_field(MEM_ROOT *mem, Field *field);
+bool get_field(MEM_ROOT *mem, Field *field, class String *res);
+
+int closefrm(TABLE *table, bool free_share);
+int read_string(File file, uchar* *to, size_t length);
+void free_blobs(TABLE *table);
+void free_field_buffers_larger_than(TABLE *table, uint32 size);
+int set_zone(int nr,int min_zone,int max_zone);
+ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
+ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
+ const char *newname);
+ulong next_io_size(ulong pos);
+void append_unescaped(String *res, const char *pos, uint length);
+File create_frm(THD *thd, const char *name, const char *db,
+ const char *table, uint reclength, uchar *fileinfo,
+ HA_CREATE_INFO *create_info, uint keys, KEY *key_info);
+char *fn_rext(char *name);
+
+/* performance schema */
+extern LEX_STRING PERFORMANCE_SCHEMA_DB_NAME;
+
+extern LEX_STRING GENERAL_LOG_NAME;
+extern LEX_STRING SLOW_LOG_NAME;
+
+/* information schema */
+extern LEX_STRING INFORMATION_SCHEMA_NAME;
+extern LEX_STRING MYSQL_SCHEMA_NAME;
+
+inline bool is_infoschema_db(const char *name, size_t len)
+{
+ return (INFORMATION_SCHEMA_NAME.length == len &&
+ !my_strcasecmp(system_charset_info,
+ INFORMATION_SCHEMA_NAME.str, name));
+}
+
+inline bool is_infoschema_db(const char *name)
+{
+ return !my_strcasecmp(system_charset_info,
+ INFORMATION_SCHEMA_NAME.str, name);
+}
+
+TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings);
+
+/**
+ return true if the table was created explicitly.
+*/
+inline bool is_user_table(TABLE * table)
+{
+ const char *name= table->s->table_name.str;
+ return strncmp(name, tmp_file_prefix, tmp_file_prefix_length);
+}
+
+inline void mark_as_null_row(TABLE *table)
+{
+ table->null_row=1;
+ table->status|=STATUS_NULL_ROW;
+ bfill(table->null_flags,table->s->null_bytes,255);
+}
+
+bool is_simple_order(ORDER *order);
+
+#endif /* MYSQL_CLIENT */
+
+#endif /* TABLE_INCLUDED */
diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc
index 1fbab74554f..79a6fd79d4c 100644
--- a/sql/thr_malloc.cc
+++ b/sql/thr_malloc.cc
@@ -16,7 +16,10 @@
/* Mallocs for used in threads */
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "thr_malloc.h"
+#include "sql_class.h"
extern "C" {
void sql_alloc_error_handler(void)
@@ -42,9 +45,10 @@ extern "C" {
returned in the error packet.
- SHOW ERROR/SHOW WARNINGS may be empty.
*/
- thd->main_da.set_error_status(thd,
- ER_OUT_OF_RESOURCES,
- ER(ER_OUT_OF_RESOURCES));
+ thd->stmt_da->set_error_status(thd,
+ ER_OUT_OF_RESOURCES,
+ ER(ER_OUT_OF_RESOURCES),
+ NULL);
}
}
@@ -109,10 +113,6 @@ void* sql_memdup(const void *ptr, size_t len)
return pos;
}
-void sql_element_free(void *ptr __attribute__((unused)))
-{} /* purecov: deadcode */
-
-
char *sql_strmake_with_convert(const char *str, size_t arg_length,
CHARSET_INFO *from_cs,
diff --git a/sql/thr_malloc.h b/sql/thr_malloc.h
new file mode 100644
index 00000000000..6b372a285a2
--- /dev/null
+++ b/sql/thr_malloc.h
@@ -0,0 +1,35 @@
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ 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 THR_MALLOC_INCLUDED
+#define THR_MALLOC_INCLUDED
+
+#include "my_global.h" // uint, size_t
+
+typedef struct charset_info_st CHARSET_INFO;
+typedef struct st_mem_root MEM_ROOT;
+
+void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size);
+void *sql_alloc(size_t);
+void *sql_calloc(size_t);
+char *sql_strdup(const char *str);
+char *sql_strmake(const char *str, size_t len);
+void *sql_memdup(const void * ptr, size_t size);
+char *sql_strmake_with_convert(const char *str, size_t arg_length,
+ CHARSET_INFO *from_cs,
+ size_t max_res_length,
+ CHARSET_INFO *to_cs, size_t *result_length);
+
+#endif /* THR_MALLOC_INCLUDED */
diff --git a/sql/transaction.cc b/sql/transaction.cc
new file mode 100644
index 00000000000..b331fea89fe
--- /dev/null
+++ b/sql/transaction.cc
@@ -0,0 +1,744 @@
+/* Copyright (C) 2008 Sun/MySQL
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "sql_priv.h"
+#include "transaction.h"
+#include "rpl_handler.h"
+#include "debug_sync.h" // DEBUG_SYNC
+
+/* Conditions under which the transaction state must not change. */
+static bool trans_check(THD *thd)
+{
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ DBUG_ENTER("trans_check");
+
+ /*
+ Always commit statement transaction before manipulating with
+ the normal one.
+ */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+
+ if (unlikely(thd->in_sub_stmt))
+ my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
+ if (xa_state != XA_NOTR)
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ else
+ DBUG_RETURN(FALSE);
+
+ DBUG_RETURN(TRUE);
+}
+
+
+/**
+ Mark a XA transaction as rollback-only if the RM unilaterally
+ rolled back the transaction branch.
+
+ @note If a rollback was requested by the RM, this function sets
+ the appropriate rollback error code and transits the state
+ to XA_ROLLBACK_ONLY.
+
+ @return TRUE if transaction was rolled back or if the transaction
+ state is XA_ROLLBACK_ONLY. FALSE otherwise.
+*/
+static bool xa_trans_rolled_back(XID_STATE *xid_state)
+{
+ if (xid_state->rm_error)
+ {
+ switch (xid_state->rm_error) {
+ case ER_LOCK_WAIT_TIMEOUT:
+ my_error(ER_XA_RBTIMEOUT, MYF(0));
+ break;
+ case ER_LOCK_DEADLOCK:
+ my_error(ER_XA_RBDEADLOCK, MYF(0));
+ break;
+ default:
+ my_error(ER_XA_RBROLLBACK, MYF(0));
+ }
+ xid_state->xa_state= XA_ROLLBACK_ONLY;
+ }
+
+ return (xid_state->xa_state == XA_ROLLBACK_ONLY);
+}
+
+
+/**
+ Begin a new transaction.
+
+ @note Beginning a transaction implicitly commits any current
+ transaction and releases existing locks.
+
+ @param thd Current thread
+ @param flags Transaction flags
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_begin(THD *thd, uint flags)
+{
+ int res= FALSE;
+ DBUG_ENTER("trans_begin");
+
+ if (trans_check(thd))
+ DBUG_RETURN(TRUE);
+
+ thd->locked_tables_list.unlock_locked_tables(thd);
+
+ DBUG_ASSERT(!thd->locked_tables_mode);
+
+ if (thd->in_multi_stmt_transaction_mode() ||
+ (thd->variables.option_bits & OPTION_TABLE_LOCK))
+ {
+ thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ res= test(ha_commit_trans(thd, TRUE));
+ }
+
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+
+ if (res)
+ DBUG_RETURN(TRUE);
+
+ /*
+ Release transactional metadata locks only after the
+ transaction has been committed.
+ */
+ thd->mdl_context.release_transactional_locks();
+
+ thd->variables.option_bits|= OPTION_BEGIN;
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+
+ if (flags & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
+ res= ha_start_consistent_snapshot(thd);
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Commit the current transaction, making its changes permanent.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_commit(THD *thd)
+{
+ int res;
+ DBUG_ENTER("trans_commit");
+
+ if (trans_check(thd))
+ DBUG_RETURN(TRUE);
+
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ res= ha_commit_trans(thd, TRUE);
+ if (res)
+ /*
+ if res is non-zero, then ha_commit_trans has rolled back the
+ transaction, so the hooks for rollback will be called.
+ */
+ RUN_HOOK(transaction, after_rollback, (thd, FALSE));
+ else
+ RUN_HOOK(transaction, after_commit, (thd, FALSE));
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+ thd->lex->start_transaction_opt= 0;
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Implicitly commit the current transaction.
+
+ @note A implicit commit does not releases existing table locks.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_commit_implicit(THD *thd)
+{
+ bool res= FALSE;
+ DBUG_ENTER("trans_commit_implicit");
+
+ if (trans_check(thd))
+ DBUG_RETURN(TRUE);
+
+ if (thd->in_multi_stmt_transaction_mode() ||
+ (thd->variables.option_bits & OPTION_TABLE_LOCK))
+ {
+ /* Safety if one did "drop table" on locked tables */
+ if (!thd->locked_tables_mode)
+ thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ res= test(ha_commit_trans(thd, TRUE));
+ }
+
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+
+ /*
+ Upon implicit commit, reset the current transaction
+ isolation level. We do not care about
+ @@session.completion_type since it's documented
+ to not have any effect on implicit commit.
+ */
+ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+
+ DBUG_RETURN(res);
+}
+
+
+/**
+ Rollback the current transaction, canceling its changes.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_rollback(THD *thd)
+{
+ int res;
+ DBUG_ENTER("trans_rollback");
+
+ if (trans_check(thd))
+ DBUG_RETURN(TRUE);
+
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ res= ha_rollback_trans(thd, TRUE);
+ RUN_HOOK(transaction, after_rollback, (thd, FALSE));
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+ thd->lex->start_transaction_opt= 0;
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Commit the single statement transaction.
+
+ @note Note that if the autocommit is on, then the following call
+ inside InnoDB will commit or rollback the whole transaction
+ (= the statement). The autocommit mechanism built into InnoDB
+ is based on counting locks, but if the user has used LOCK
+ TABLES then that mechanism does not know to do the commit.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_commit_stmt(THD *thd)
+{
+ DBUG_ENTER("trans_commit_stmt");
+ int res= FALSE;
+ /*
+ We currently don't invoke commit/rollback at end of
+ a sub-statement. In future, we perhaps should take
+ a savepoint for each nested statement, and release the
+ savepoint when statement has succeeded.
+ */
+ DBUG_ASSERT(! thd->in_sub_stmt);
+
+ if (thd->transaction.stmt.ha_list)
+ {
+ res= ha_commit_trans(thd, FALSE);
+ if (! thd->in_active_multi_stmt_transaction())
+ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+ }
+
+ if (res)
+ /*
+ if res is non-zero, then ha_commit_trans has rolled back the
+ transaction, so the hooks for rollback will be called.
+ */
+ RUN_HOOK(transaction, after_rollback, (thd, FALSE));
+ else
+ RUN_HOOK(transaction, after_commit, (thd, FALSE));
+
+ thd->transaction.stmt.reset();
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Rollback the single statement transaction.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+bool trans_rollback_stmt(THD *thd)
+{
+ DBUG_ENTER("trans_rollback_stmt");
+
+ /*
+ We currently don't invoke commit/rollback at end of
+ a sub-statement. In future, we perhaps should take
+ a savepoint for each nested statement, and release the
+ savepoint when statement has succeeded.
+ */
+ DBUG_ASSERT(! thd->in_sub_stmt);
+
+ if (thd->transaction.stmt.ha_list)
+ {
+ ha_rollback_trans(thd, FALSE);
+ if (thd->transaction_rollback_request && !thd->in_sub_stmt)
+ ha_rollback_trans(thd, TRUE);
+ if (! thd->in_active_multi_stmt_transaction())
+ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+ }
+
+ RUN_HOOK(transaction, after_rollback, (thd, FALSE));
+
+ thd->transaction.stmt.reset();
+
+ DBUG_RETURN(FALSE);
+}
+
+/* Find a named savepoint in the current transaction. */
+static SAVEPOINT **
+find_savepoint(THD *thd, LEX_STRING name)
+{
+ SAVEPOINT **sv= &thd->transaction.savepoints;
+
+ while (*sv)
+ {
+ if (my_strnncoll(system_charset_info, (uchar *) name.str, name.length,
+ (uchar *) (*sv)->name, (*sv)->length) == 0)
+ break;
+ sv= &(*sv)->prev;
+ }
+
+ return sv;
+}
+
+
+/**
+ Set a named transaction savepoint.
+
+ @param thd Current thread
+ @param name Savepoint name
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_savepoint(THD *thd, LEX_STRING name)
+{
+ SAVEPOINT **sv, *newsv;
+ DBUG_ENTER("trans_savepoint");
+
+ if (!(thd->in_multi_stmt_transaction_mode() || thd->in_sub_stmt) ||
+ !opt_using_transactions)
+ DBUG_RETURN(FALSE);
+
+ sv= find_savepoint(thd, name);
+
+ if (*sv) /* old savepoint of the same name exists */
+ {
+ newsv= *sv;
+ ha_release_savepoint(thd, *sv);
+ *sv= (*sv)->prev;
+ }
+ else if ((newsv= (SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
+ savepoint_alloc_size)) == NULL)
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
+ newsv->name= strmake_root(&thd->transaction.mem_root, name.str, name.length);
+ newsv->length= name.length;
+
+ /*
+ if we'll get an error here, don't add new savepoint to the list.
+ we'll lose a little bit of memory in transaction mem_root, but it'll
+ be free'd when transaction ends anyway
+ */
+ if (ha_savepoint(thd, newsv))
+ DBUG_RETURN(TRUE);
+
+ newsv->prev= thd->transaction.savepoints;
+ thd->transaction.savepoints= newsv;
+
+ /*
+ Remember locks acquired before the savepoint was set.
+ They are used as a marker to only release locks acquired after
+ the setting of this savepoint.
+ Note: this works just fine if we're under LOCK TABLES,
+ since mdl_savepoint() is guaranteed to be beyond
+ the last locked table. This allows to release some
+ locks acquired during LOCK TABLES.
+ */
+ newsv->mdl_savepoint= thd->mdl_context.mdl_savepoint();
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ Rollback a transaction to the named savepoint.
+
+ @note Modifications that the current transaction made to
+ rows after the savepoint was set are undone in the
+ rollback.
+
+ @note Savepoints that were set at a later time than the
+ named savepoint are deleted.
+
+ @param thd Current thread
+ @param name Savepoint name
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name)
+{
+ int res= FALSE;
+ SAVEPOINT *sv= *find_savepoint(thd, name);
+ DBUG_ENTER("trans_rollback_to_savepoint");
+
+ if (sv == NULL)
+ {
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", name.str);
+ DBUG_RETURN(TRUE);
+ }
+
+ if (ha_rollback_to_savepoint(thd, sv))
+ res= TRUE;
+ else if (((thd->variables.option_bits & OPTION_KEEP_LOG) ||
+ thd->transaction.all.modified_non_trans_table) &&
+ !thd->slave_thread)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARNING_NOT_COMPLETE_ROLLBACK,
+ ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
+
+ thd->transaction.savepoints= sv;
+
+ /*
+ Release metadata locks that were acquired during this savepoint unit
+ unless binlogging is on. Releasing locks with binlogging on can break
+ replication as it allows other connections to drop these tables before
+ rollback to savepoint is written to the binlog.
+ */
+ bool binlog_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin;
+ if (!res && !binlog_on)
+ thd->mdl_context.rollback_to_savepoint(sv->mdl_savepoint);
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Remove the named savepoint from the set of savepoints of
+ the current transaction.
+
+ @note No commit or rollback occurs. It is an error if the
+ savepoint does not exist.
+
+ @param thd Current thread
+ @param name Savepoint name
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_release_savepoint(THD *thd, LEX_STRING name)
+{
+ int res= FALSE;
+ SAVEPOINT *sv= *find_savepoint(thd, name);
+ DBUG_ENTER("trans_release_savepoint");
+
+ if (sv == NULL)
+ {
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", name.str);
+ DBUG_RETURN(TRUE);
+ }
+
+ if (ha_release_savepoint(thd, sv))
+ res= TRUE;
+
+ thd->transaction.savepoints= sv->prev;
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Starts an XA transaction with the given xid value.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_xa_start(THD *thd)
+{
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ DBUG_ENTER("trans_xa_start");
+
+ if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
+ {
+ bool not_equal= !thd->transaction.xid_state.xid.eq(thd->lex->xid);
+ if (not_equal)
+ my_error(ER_XAER_NOTA, MYF(0));
+ else
+ thd->transaction.xid_state.xa_state= XA_ACTIVE;
+ DBUG_RETURN(not_equal);
+ }
+
+ /* TODO: JOIN is not supported yet. */
+ if (thd->lex->xa_opt != XA_NONE)
+ my_error(ER_XAER_INVAL, MYF(0));
+ else if (xa_state != XA_NOTR)
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ else if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction())
+ my_error(ER_XAER_OUTSIDE, MYF(0));
+ else if (xid_cache_search(thd->lex->xid))
+ my_error(ER_XAER_DUPID, MYF(0));
+ else if (!trans_begin(thd))
+ {
+ DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
+ thd->transaction.xid_state.xa_state= XA_ACTIVE;
+ thd->transaction.xid_state.rm_error= 0;
+ thd->transaction.xid_state.xid.set(thd->lex->xid);
+ xid_cache_insert(&thd->transaction.xid_state);
+ DBUG_RETURN(FALSE);
+ }
+
+ DBUG_RETURN(TRUE);
+}
+
+
+/**
+ Put a XA transaction in the IDLE state.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_xa_end(THD *thd)
+{
+ DBUG_ENTER("trans_xa_end");
+
+ /* TODO: SUSPEND and FOR MIGRATE are not supported yet. */
+ if (thd->lex->xa_opt != XA_NONE)
+ my_error(ER_XAER_INVAL, MYF(0));
+ else if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xid_state.xa_state]);
+ else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+ my_error(ER_XAER_NOTA, MYF(0));
+ else if (!xa_trans_rolled_back(&thd->transaction.xid_state))
+ thd->transaction.xid_state.xa_state= XA_IDLE;
+
+ DBUG_RETURN(thd->is_error() ||
+ thd->transaction.xid_state.xa_state != XA_IDLE);
+}
+
+
+/**
+ Put a XA transaction in the PREPARED state.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_xa_prepare(THD *thd)
+{
+ DBUG_ENTER("trans_xa_prepare");
+
+ if (thd->transaction.xid_state.xa_state != XA_IDLE)
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xid_state.xa_state]);
+ else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+ my_error(ER_XAER_NOTA, MYF(0));
+ else if (ha_prepare(thd))
+ {
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state= XA_NOTR;
+ my_error(ER_XA_RBROLLBACK, MYF(0));
+ }
+ else
+ thd->transaction.xid_state.xa_state= XA_PREPARED;
+
+ DBUG_RETURN(thd->is_error() ||
+ thd->transaction.xid_state.xa_state != XA_PREPARED);
+}
+
+
+/**
+ Commit and terminate the a XA transaction.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_xa_commit(THD *thd)
+{
+ bool res= TRUE;
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ DBUG_ENTER("trans_xa_commit");
+
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+ {
+ XID_STATE *xs= xid_cache_search(thd->lex->xid);
+ res= !xs || xs->in_thd;
+ if (res)
+ my_error(ER_XAER_NOTA, MYF(0));
+ else
+ {
+ res= xa_trans_rolled_back(xs);
+ ha_commit_or_rollback_by_xid(thd->lex->xid, !res);
+ xid_cache_delete(xs);
+ }
+ DBUG_RETURN(res);
+ }
+
+ if (xa_trans_rolled_back(&thd->transaction.xid_state))
+ {
+ if ((res= test(ha_rollback_trans(thd, TRUE))))
+ my_error(ER_XAER_RMERR, MYF(0));
+ }
+ else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
+ {
+ int r= ha_commit_trans(thd, TRUE);
+ if ((res= test(r)))
+ my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
+ }
+ else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE)
+ {
+ MDL_request mdl_request;
+
+ /*
+ Acquire metadata lock which will ensure that COMMIT is blocked
+ by active FLUSH TABLES WITH READ LOCK (and vice versa COMMIT in
+ progress blocks FTWRL).
+
+ We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
+ */
+ mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_TRANSACTION);
+
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
+ {
+ ha_rollback_trans(thd, TRUE);
+ my_error(ER_XAER_RMERR, MYF(0));
+ }
+ else
+ {
+ DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock");
+
+ res= test(ha_commit_one_phase(thd, 1));
+ if (res)
+ my_error(ER_XAER_RMERR, MYF(0));
+ }
+ }
+ else
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ DBUG_RETURN(TRUE);
+ }
+
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state= XA_NOTR;
+
+ DBUG_RETURN(res);
+}
+
+
+/**
+ Roll back and terminate a XA transaction.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_xa_rollback(THD *thd)
+{
+ bool res= TRUE;
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ DBUG_ENTER("trans_xa_rollback");
+
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+ {
+ XID_STATE *xs= xid_cache_search(thd->lex->xid);
+ if (!xs || xs->in_thd)
+ my_error(ER_XAER_NOTA, MYF(0));
+ else
+ {
+ xa_trans_rolled_back(xs);
+ ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
+ xid_cache_delete(xs);
+ }
+ DBUG_RETURN(thd->stmt_da->is_error());
+ }
+
+ if (xa_state != XA_IDLE && xa_state != XA_PREPARED && xa_state != XA_ROLLBACK_ONLY)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Resource Manager error is meaningless at this point, as we perform
+ explicit rollback request by user. We must reset rm_error before
+ calling ha_rollback(), so thd->transaction.xid structure gets reset
+ by ha_rollback()/THD::transaction::cleanup().
+ */
+ thd->transaction.xid_state.rm_error= 0;
+ if ((res= test(ha_rollback_trans(thd, TRUE))))
+ my_error(ER_XAER_RMERR, MYF(0));
+
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state= XA_NOTR;
+
+ DBUG_RETURN(res);
+}
diff --git a/sql/transaction.h b/sql/transaction.h
new file mode 100644
index 00000000000..135e6cae73f
--- /dev/null
+++ b/sql/transaction.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2008 Sun/MySQL
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef TRANSACTION_H
+#define TRANSACTION_H
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+#include <my_global.h>
+#include <m_string.h>
+
+class THD;
+
+bool trans_begin(THD *thd, uint flags= 0);
+bool trans_commit(THD *thd);
+bool trans_commit_implicit(THD *thd);
+bool trans_rollback(THD *thd);
+
+bool trans_commit_stmt(THD *thd);
+bool trans_rollback_stmt(THD *thd);
+
+bool trans_savepoint(THD *thd, LEX_STRING name);
+bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name);
+bool trans_release_savepoint(THD *thd, LEX_STRING name);
+
+bool trans_xa_start(THD *thd);
+bool trans_xa_end(THD *thd);
+bool trans_xa_prepare(THD *thd);
+bool trans_xa_commit(THD *thd);
+bool trans_xa_rollback(THD *thd);
+
+#endif /* TRANSACTION_H */
diff --git a/sql/tzfile.h b/sql/tzfile.h
index 1ff82d62329..1c1800ba1ed 100644
--- a/sql/tzfile.h
+++ b/sql/tzfile.h
@@ -1,3 +1,6 @@
+#ifndef TZFILE_INCLUDED
+#define TZFILE_INCLUDED
+
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -134,3 +137,5 @@ struct tzhead {
*/
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+
+#endif
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 7ebb8eb392a..a2f319d4307 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004 MySQL AB
+/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -20,7 +20,7 @@
*/
/*
- We should not include mysql_priv.h in mysql_tzinfo_to_sql utility since
+ We should not include sql_priv.h in mysql_tzinfo_to_sql utility since
it creates unsolved link dependencies on some platforms.
*/
@@ -30,7 +30,12 @@
#include <my_global.h>
#if !defined(TZINFO2SQL) && !defined(TESTTIME)
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "tztime.h"
+#include "sql_time.h" // localtime_to_TIME
+#include "sql_base.h" // open_system_tables_for_read,
+ // close_system_tables
#else
#include <my_time.h>
#include "tztime.h"
@@ -40,6 +45,9 @@
#include "tzfile.h"
#include <m_string.h>
#include <my_dir.h>
+#include <mysql/psi/mysql_file.h>
+#include "lock.h" // MYSQL_LOCK_IGNORE_FLUSH,
+ // MYSQL_LOCK_IGNORE_TIMEOUT
/*
Now we don't use abbreviations in server but we will do this in future.
@@ -156,9 +164,9 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
uchar *p;
int read_from_file;
uint i;
- FILE *file;
+ MYSQL_FILE *file;
- if (!(file= my_fopen(name, O_RDONLY|O_BINARY, MYF(MY_WME))))
+ if (!(file= mysql_file_fopen(0, name, O_RDONLY|O_BINARY, MYF(MY_WME))))
return 1;
{
union
@@ -175,9 +183,9 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
uint ttisgmtcnt;
char *tzinfo_buf;
- read_from_file= my_fread(file, u.buf, sizeof(u.buf), MYF(MY_WME));
+ read_from_file= mysql_file_fread(file, u.buf, sizeof(u.buf), MYF(MY_WME));
- if (my_fclose(file, MYF(MY_WME)) != 0)
+ if (mysql_file_fclose(file, MYF(MY_WME)) != 0)
return 1;
if (read_from_file < (int)sizeof(struct tzhead))
@@ -1432,7 +1440,7 @@ static MEM_ROOT tz_storage;
time zone in offset_tzs or creating if it didn't existed before in
tz_storage. So contention is low.
*/
-static pthread_mutex_t tz_LOCK;
+static mysql_mutex_t tz_LOCK;
static bool tz_inited= 0;
/*
@@ -1532,6 +1540,27 @@ tz_init_table_list(TABLE_LIST *tz_tabs)
}
}
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_tz_LOCK;
+
+static PSI_mutex_info all_tz_mutexes[]=
+{
+ { & key_tz_LOCK, "tz_LOCK", PSI_FLAG_GLOBAL}
+};
+
+static void init_tz_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_tz_mutexes);
+ PSI_server->register_mutex(category, all_tz_mutexes, count);
+}
+#endif /* HAVE_PSI_INTERFACE */
+
/*
Initialize time zone support infrastructure.
@@ -1563,7 +1592,6 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
{
THD *thd;
TABLE_LIST tz_tables[1+MY_TZ_TABLES_COUNT];
- Open_tables_state open_tables_state_backup;
TABLE *table;
Tz_names_entry *tmp_tzname;
my_bool return_val= 1;
@@ -1571,6 +1599,10 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
int res;
DBUG_ENTER("my_tz_init");
+#ifdef HAVE_PSI_INTERFACE
+ init_tz_psi_keys();
+#endif
+
/*
To be able to run this from boot, we allocate a temporary THD
*/
@@ -1578,24 +1610,23 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
DBUG_RETURN(1);
thd->thread_stack= (char*) &thd;
thd->store_globals();
- lex_start(thd);
/* Init all memory structures that require explicit destruction */
- if (hash_init(&tz_names, &my_charset_latin1, 20,
- 0, 0, (hash_get_key) my_tz_names_get_key, 0, 0))
+ if (my_hash_init(&tz_names, &my_charset_latin1, 20,
+ 0, 0, (my_hash_get_key) my_tz_names_get_key, 0, 0))
{
sql_print_error("Fatal error: OOM while initializing time zones");
goto end;
}
- if (hash_init(&offset_tzs, &my_charset_latin1, 26, 0, 0,
- (hash_get_key)my_offset_tzs_get_key, 0, 0))
+ if (my_hash_init(&offset_tzs, &my_charset_latin1, 26, 0, 0,
+ (my_hash_get_key)my_offset_tzs_get_key, 0, 0))
{
sql_print_error("Fatal error: OOM while initializing time zones");
- hash_free(&tz_names);
+ my_hash_free(&tz_names);
goto end;
}
- init_alloc_root(&tz_storage, 32 * 1024, 0);
- VOID(pthread_mutex_init(&tz_LOCK, MY_MUTEX_INIT_FAST));
+ init_sql_alloc(&tz_storage, 32 * 1024, 0);
+ mysql_mutex_init(key_tz_LOCK, &tz_LOCK, MY_MUTEX_INIT_FAST);
tz_inited= 1;
/* Add 'SYSTEM' time zone to tz_names hash */
@@ -1637,20 +1668,29 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
tz_init_table_list(tz_tables+1);
tz_tables[0].next_global= tz_tables[0].next_local= &tz_tables[1];
tz_tables[1].prev_global= &tz_tables[0].next_global;
+ init_mdl_requests(tz_tables);
/*
We need to open only mysql.time_zone_leap_second, but we try to
open all time zone tables to see if they exist.
*/
- if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup))
+ if (open_and_lock_tables(thd, tz_tables, FALSE,
+ MYSQL_OPEN_IGNORE_FLUSH | MYSQL_LOCK_IGNORE_TIMEOUT))
{
sql_print_warning("Can't open and lock time zone table: %s "
- "trying to live without them", thd->main_da.message());
+ "trying to live without them", thd->stmt_da->message());
/* We will try emulate that everything is ok */
return_val= time_zone_tables_exist= 0;
goto end_with_setting_default_tz;
}
+ for (TABLE_LIST *tl= tz_tables; tl; tl= tl->next_global)
+ {
+ tl->table->use_all_columns();
+ /* Force close at the end of the function to free memory. */
+ tl->table->m_needs_reopen= TRUE;
+ }
+
/*
Now we are going to load leap seconds descriptions that are shared
between all time zones that use them. We are using index for getting
@@ -1737,10 +1777,7 @@ end_with_setting_default_tz:
end_with_close:
if (time_zone_tables_exist)
- {
- thd->version--; /* Force close to free memory */
- close_system_tables(thd, &open_tables_state_backup);
- }
+ close_mysql_tables(thd);
end_with_cleanup:
@@ -1757,6 +1794,10 @@ end:
my_pthread_setspecific_ptr(THR_THD, 0);
my_pthread_setspecific_ptr(THR_MALLOC, 0);
}
+
+ default_tz= default_tz_name ? global_system_variables.time_zone
+ : my_tz_SYSTEM;
+
DBUG_RETURN(return_val);
}
@@ -1773,9 +1814,9 @@ void my_tz_free()
if (tz_inited)
{
tz_inited= 0;
- VOID(pthread_mutex_destroy(&tz_LOCK));
- hash_free(&offset_tzs);
- hash_free(&tz_names);
+ mysql_mutex_destroy(&tz_LOCK);
+ my_hash_free(&offset_tzs);
+ my_hash_free(&tz_names);
free_root(&tz_storage, MYF(0));
}
}
@@ -2262,14 +2303,14 @@ my_tz_find(THD *thd, const String *name)
if (!name || name->is_empty())
DBUG_RETURN(0);
- VOID(pthread_mutex_lock(&tz_LOCK));
+ mysql_mutex_lock(&tz_LOCK);
if (!str_to_offset(name->ptr(), name->length(), &offset))
{
- if (!(result_tz= (Time_zone_offset *)hash_search(&offset_tzs,
- (const uchar *)&offset,
- sizeof(long))))
+ if (!(result_tz= (Time_zone_offset *)my_hash_search(&offset_tzs,
+ (const uchar *)&offset,
+ sizeof(long))))
{
DBUG_PRINT("info", ("Creating new Time_zone_offset object"));
@@ -2285,16 +2326,18 @@ my_tz_find(THD *thd, const String *name)
else
{
result_tz= 0;
- if ((tmp_tzname= (Tz_names_entry *)hash_search(&tz_names,
- (const uchar *)name->ptr(),
- name->length())))
+ if ((tmp_tzname= (Tz_names_entry *)my_hash_search(&tz_names,
+ (const uchar *)
+ name->ptr(),
+ name->length())))
result_tz= tmp_tzname->tz;
else if (time_zone_tables_exist)
{
TABLE_LIST tz_tables[MY_TZ_TABLES_COUNT];
- Open_tables_state open_tables_state_backup;
+ Open_tables_backup open_tables_state_backup;
tz_init_table_list(tz_tables);
+ init_mdl_requests(tz_tables);
if (!open_system_tables_for_read(thd, tz_tables,
&open_tables_state_backup))
{
@@ -2304,7 +2347,7 @@ my_tz_find(THD *thd, const String *name)
}
}
- VOID(pthread_mutex_unlock(&tz_LOCK));
+ mysql_mutex_unlock(&tz_LOCK);
DBUG_RETURN(result_tz);
}
@@ -2498,7 +2541,6 @@ scan_tz_dir(char * name_end)
int
main(int argc, char **argv)
{
-#ifndef __NETWARE__
MY_INIT(argv[0]);
if (argc != 2 && argc != 3)
@@ -2557,10 +2599,6 @@ main(int argc, char **argv)
free_root(&tz_storage, MYF(0));
}
-#else
- fprintf(stderr, "This tool has not been ported to NetWare\n");
-#endif /* __NETWARE__ */
-
return 0;
}
diff --git a/sql/tztime.h b/sql/tztime.h
index 9bf103519c4..f3fea485152 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -1,3 +1,6 @@
+#ifndef TZTIME_INCLUDED
+#define TZTIME_INCLUDED
+
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -18,8 +21,17 @@
#pragma interface /* gcc class interface */
#endif
+#include "my_time.h" /* my_time_t */
+#include "mysql_time.h" /* MYSQL_TIME */
+#include "sql_list.h" /* Sql_alloc */
+#include "sql_string.h" /* String */
+
+class THD;
+
#if !defined(TESTTIME) && !defined(TZINFO2SQL)
+class THD;
+
/**
This class represents abstract time zone and provides
basic interface for MYSQL_TIME <-> my_time_t conversion.
@@ -79,3 +91,4 @@ static const int MY_TZ_TABLES_COUNT= 4;
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
+#endif /* TZTIME_INCLUDED */
diff --git a/sql/udf_example.c b/sql/udf_example.c
index 468118b44ef..36828bdf94d 100644
--- a/sql/udf_example.c
+++ b/sql/udf_example.c
@@ -107,7 +107,7 @@
** option.
**
** If you can't get AGGREGATES to work, check that you have the column
-** 'type' in the mysql.func table. If not, run 'mysql_fix_privilege_tables'.
+** 'type' in the mysql.func table. If not, run 'mysql_upgrade'.
**
*/
@@ -133,12 +133,16 @@ typedef long long longlong;
#include <string.h>
#define strmov(a,b) stpcpy(a,b)
#define bzero(a,b) memset(a,0,b)
-#define memcpy_fixed(a,b,c) memcpy(a,b,c)
#endif
#endif
#include <mysql.h>
#include <ctype.h>
+#ifdef _WIN32
+/* inet_aton needs winsock library */
+#pragma comment(lib, "ws2_32")
+#endif
+
#ifdef HAVE_DLOPEN
#if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
@@ -764,16 +768,16 @@ char *lookup(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
return 0;
}
#else
- VOID(pthread_mutex_lock(&LOCK_hostname));
+ pthread_mutex_lock(&LOCK_hostname);
if (!(hostent= gethostbyname((char*) name_buff)))
{
- VOID(pthread_mutex_unlock(&LOCK_hostname));
+ pthread_mutex_unlock(&LOCK_hostname);
*null_value= 1;
return 0;
}
- VOID(pthread_mutex_unlock(&LOCK_hostname));
+ pthread_mutex_unlock(&LOCK_hostname);
#endif
- memcpy_fixed((char*) &in,(char*) *hostent->h_addr_list, sizeof(in.s_addr));
+ memcpy(&in, *hostent->h_addr_list, sizeof(in.s_addr));
*res_length= (ulong) (strmov(result, inet_ntoa(in)) - result);
return result;
}
@@ -868,14 +872,14 @@ char *reverse_lookup(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
return 0;
}
#else
- VOID(pthread_mutex_lock(&LOCK_hostname));
+ pthread_mutex_lock(&LOCK_hostname);
if (!(hp= gethostbyaddr((char*) &taddr, sizeof(taddr), AF_INET)))
{
- VOID(pthread_mutex_unlock(&LOCK_hostname));
+ pthread_mutex_unlock(&LOCK_hostname);
*null_value= 1;
return 0;
}
- VOID(pthread_mutex_unlock(&LOCK_hostname));
+ pthread_mutex_unlock(&LOCK_hostname);
#endif
*res_length=(ulong) (strmov(result,hp->h_name) - result);
return result;
diff --git a/sql/uniques.cc b/sql/uniques.cc
index 7b6b628f924..690b310bde5 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -30,9 +30,12 @@
deletes in disk order.
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
#include "sql_sort.h"
-
+#include "queues.h" // QUEUE
+#include "my_tree.h" // element_count
+#include "sql_class.h" // Unique
int unique_write_to_file(uchar* key, element_count count, Unique *unique)
{
@@ -66,8 +69,8 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
*/
max_elements= (ulong) (max_in_memory_size /
ALIGN_SIZE(sizeof(TREE_ELEMENT)+size));
- VOID(open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE,
- MYF(MY_WME)));
+ (void) open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE,
+ MYF(MY_WME));
}
@@ -563,7 +566,7 @@ bool Unique::walk(tree_walk_action action, void *walk_action_arg)
(BUFFPEK *) file_ptrs.buffer + file_ptrs.elements,
action, walk_action_arg,
tree.compare, tree.custom_arg, &file);
- my_free((char*) merge_buffer, MYF(0));
+ my_free(merge_buffer);
return res;
}
@@ -639,7 +642,7 @@ bool Unique::get(TABLE *table)
goto err;
error=0;
err:
- x_free(sort_buffer);
+ my_free(sort_buffer);
if (flush_io_cache(outfile))
error=1;
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 84160da9d77..6433b8bc7c2 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2006 MySQL AB
+/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
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
@@ -23,7 +23,11 @@
str is a (long) to record position where 0 is the first position.
*/
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_partition.h" // struct partition_info
+#include "sql_table.h" // check_duplicate_warning
+#include "sql_class.h" // THD, Internal_error_handler
#include <m_ctype.h>
#include <assert.h>
@@ -55,10 +59,12 @@ static bool make_empty_rec(THD *thd, int file, enum legacy_db_type table_type,
struct Pack_header_error_handler: public Internal_error_handler
{
- virtual bool handle_error(uint sql_errno,
- const char *message,
- MYSQL_ERROR::enum_warning_level level,
- THD *thd);
+ virtual bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl);
bool is_handled;
Pack_header_error_handler() :is_handled(FALSE) {}
};
@@ -66,11 +72,14 @@ struct Pack_header_error_handler: public Internal_error_handler
bool
Pack_header_error_handler::
-handle_error(uint sql_errno,
- const char * /* message */,
- MYSQL_ERROR::enum_warning_level /* level */,
- THD * /* thd */)
+handle_condition(THD *,
+ uint sql_errno,
+ const char*,
+ MYSQL_ERROR::enum_warning_level,
+ const char*,
+ MYSQL_ERROR ** cond_hdl)
{
+ *cond_hdl= NULL;
is_handled= (sql_errno == ER_TOO_MANY_FIELDS);
return is_handled;
}
@@ -139,7 +148,7 @@ bool mysql_create_frm(THD *thd, const char *file_name,
if (error)
{
- my_free(screen_buff, MYF(0));
+ my_free(screen_buff);
if (! pack_header_error_handler.is_handled)
DBUG_RETURN(1);
@@ -150,7 +159,7 @@ bool mysql_create_frm(THD *thd, const char *file_name,
create_fields,info_length,
screens, create_info->table_options, data_offset, db_file))
{
- my_free(screen_buff, MYF(0));
+ my_free(screen_buff);
DBUG_RETURN(1);
}
}
@@ -182,34 +191,6 @@ bool mysql_create_frm(THD *thd, const char *file_name,
if (key_info[i].parser_name)
create_info->extra_size+= key_info[i].parser_name->length + 1;
}
-
- if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
- create_info, keys)) < 0)
- {
- my_free(screen_buff, MYF(0));
- DBUG_RETURN(1);
- }
-
- key_buff_length= uint4korr(fileinfo+47);
- keybuff=(uchar*) my_malloc(key_buff_length, MYF(0));
- key_info_length= pack_keys(keybuff, keys, key_info, data_offset);
-
- /*
- Ensure that there are no forms in this newly created form file.
- Even if the form file exists, create_frm must truncate it to
- ensure one form per form file.
- */
- DBUG_ASSERT(uint2korr(fileinfo+8) == 0);
-
- if (!(filepos= make_new_entry(file, fileinfo, NULL, "")))
- goto err;
- maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
- int2store(forminfo+2,maxlength);
- int4store(fileinfo+10,(ulong) (filepos+maxlength));
- fileinfo[26]= (uchar) test((create_info->max_rows == 1) &&
- (create_info->min_rows == 1) && (keys == 0));
- int2store(fileinfo+28,key_info_length);
-
/*
This gives us the byte-position of the character at
(character-position, not byte-position) TABLE_COMMENT_MAXLEN.
@@ -223,33 +204,85 @@ bool mysql_create_frm(THD *thd, const char *file_name,
string), the string is too long.
For additional credit, realise that UTF-8 has 1-3 bytes before 6.0,
- and 1-4 bytes in 6.0 (6.0 also has UTF-32). This means that the
- inlined COMMENT supposedly does not exceed 60 character plus
- terminator, vulgo, 181 bytes.
+ and 1-4 bytes in 6.0 (6.0 also has UTF-32).
*/
-
tmp_len= system_charset_info->cset->charpos(system_charset_info,
create_info->comment.str,
create_info->comment.str +
- create_info->comment.length, 60);
+ create_info->comment.length,
+ TABLE_COMMENT_MAXLEN);
+
if (tmp_len < create_info->comment.length)
{
+ char *real_table_name= (char*) table;
+ List_iterator<Create_field> it(create_fields);
+ Create_field *field;
+ while ((field=it++))
+ {
+ if (field->field && field->field->table &&
+ (real_table_name= field->field->table->s->table_name.str))
+ break;
+ }
if ((thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
{
- my_error(ER_TOO_LONG_TABLE_COMMENT, MYF(0), table, tmp_len);
- goto err;
+ my_error(ER_TOO_LONG_TABLE_COMMENT, MYF(0),
+ real_table_name, (uint) TABLE_COMMENT_MAXLEN);
+ my_free(screen_buff);
+ DBUG_RETURN(1);
}
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TOO_LONG_TABLE_COMMENT,
- ER(ER_TOO_LONG_TABLE_COMMENT),
- table, tmp_len);
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_TABLE_COMMENT),
+ real_table_name, (uint) TABLE_COMMENT_MAXLEN);
+ /* do not push duplicate warnings */
+ if (!check_duplicate_warning(current_thd, warn_buff, strlen(warn_buff)))
+ push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TOO_LONG_TABLE_COMMENT, warn_buff);
create_info->comment.length= tmp_len;
}
+ /*
+ If table comment is longer than TABLE_COMMENT_INLINE_MAXLEN bytes,
+ store the comment in an extra segment (up to TABLE_COMMENT_MAXLEN bytes).
+ Pre 6.0, the limit was 60 characters, with no extra segment-handling.
+ */
+ if (create_info->comment.length > TABLE_COMMENT_INLINE_MAXLEN)
+ {
+ forminfo[46]=255;
+ create_info->extra_size+= 2 + create_info->comment.length;
+ }
+ else{
+ strmake((char*) forminfo+47, create_info->comment.str ?
+ create_info->comment.str : "", create_info->comment.length);
+ forminfo[46]=(uchar) create_info->comment.length;
+ }
+
+ if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
+ create_info, keys, key_info)) < 0)
+ {
+ my_free(screen_buff);
+ DBUG_RETURN(1);
+ }
+
+ key_buff_length= uint4korr(fileinfo+47);
+ keybuff=(uchar*) my_malloc(key_buff_length, MYF(0));
+ key_info_length= pack_keys(keybuff, keys, key_info, data_offset);
+
+ /*
+ Ensure that there are no forms in this newly created form file.
+ Even if the form file exists, create_frm must truncate it to
+ ensure one form per form file.
+ */
+ DBUG_ASSERT(uint2korr(fileinfo+8) == 0);
+
+ if (!(filepos= make_new_entry(file, fileinfo, NULL, "")))
+ goto err;
+ maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
+ int2store(forminfo+2,maxlength);
+ int4store(fileinfo+10,(ulong) (filepos+maxlength));
+ fileinfo[26]= (uchar) test((create_info->max_rows == 1) &&
+ (create_info->min_rows == 1) && (keys == 0));
+ int2store(fileinfo+28,key_info_length);
- strmake((char*) forminfo+47, create_info->comment.str ?
- create_info->comment.str : "", create_info->comment.length);
- forminfo[46]=(uchar) create_info->comment.length;
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (part_info)
{
@@ -259,27 +292,27 @@ bool mysql_create_frm(THD *thd, const char *file_name,
#endif
int2store(fileinfo+59,db_file->extra_rec_buf_length());
- if (my_pwrite(file, fileinfo, 64, 0L, MYF_RW) ||
- my_pwrite(file, keybuff, key_info_length,
- (ulong) uint2korr(fileinfo+6),MYF_RW))
+ if (mysql_file_pwrite(file, fileinfo, 64, 0L, MYF_RW) ||
+ mysql_file_pwrite(file, keybuff, key_info_length,
+ (ulong) uint2korr(fileinfo+6), MYF_RW))
goto err;
- VOID(my_seek(file,
- (ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length,
- MY_SEEK_SET,MYF(0)));
+ mysql_file_seek(file,
+ (ulong) uint2korr(fileinfo+6) + (ulong) key_buff_length,
+ MY_SEEK_SET, MYF(0));
if (make_empty_rec(thd,file,ha_legacy_type(create_info->db_type),
create_info->table_options,
create_fields,reclength, data_offset, db_file))
goto err;
int2store(buff, create_info->connect_string.length);
- if (my_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
- my_write(file, (const uchar*)create_info->connect_string.str,
+ if (mysql_file_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
+ mysql_file_write(file, (const uchar*)create_info->connect_string.str,
create_info->connect_string.length, MYF(MY_NABP)))
goto err;
int2store(buff, str_db_type.length);
- if (my_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
- my_write(file, (const uchar*)str_db_type.str,
+ if (mysql_file_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
+ mysql_file_write(file, (const uchar*)str_db_type.str,
str_db_type.length, MYF(MY_NABP)))
goto err;
@@ -288,32 +321,41 @@ bool mysql_create_frm(THD *thd, const char *file_name,
{
char auto_partitioned= part_info->is_auto_partitioned ? 1 : 0;
int4store(buff, part_info->part_info_len);
- if (my_write(file, (const uchar*)buff, 4, MYF_RW) ||
- my_write(file, (const uchar*)part_info->part_info_string,
+ if (mysql_file_write(file, (const uchar*)buff, 4, MYF_RW) ||
+ mysql_file_write(file, (const uchar*)part_info->part_info_string,
part_info->part_info_len + 1, MYF_RW) ||
- my_write(file, (const uchar*)&auto_partitioned, 1, MYF_RW))
+ mysql_file_write(file, (const uchar*)&auto_partitioned, 1, MYF_RW))
goto err;
}
else
#endif
{
bzero((uchar*) buff, 6);
- if (my_write(file, (uchar*) buff, 6, MYF_RW))
+ if (mysql_file_write(file, (uchar*) buff, 6, MYF_RW))
goto err;
}
for (i= 0; i < keys; i++)
{
if (key_info[i].parser_name)
{
- if (my_write(file, (const uchar*)key_info[i].parser_name->str,
- key_info[i].parser_name->length + 1, MYF(MY_NABP)))
+ if (mysql_file_write(file, (const uchar*)key_info[i].parser_name->str,
+ key_info[i].parser_name->length + 1, MYF(MY_NABP)))
goto err;
}
}
+ if (forminfo[46] == (uchar)255)
+ {
+ uchar comment_length_buff[2];
+ int2store(comment_length_buff,create_info->comment.length);
+ if (mysql_file_write(file, comment_length_buff, 2, MYF(MY_NABP)) ||
+ mysql_file_write(file, (uchar*) create_info->comment.str,
+ create_info->comment.length, MYF(MY_NABP)))
+ goto err;
+ }
- VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
- if (my_write(file, forminfo, 288, MYF_RW) ||
- my_write(file, screen_buff, info_length, MYF_RW) ||
+ mysql_file_seek(file, filepos, MY_SEEK_SET, MYF(0));
+ if (mysql_file_write(file, forminfo, 288, MYF_RW) ||
+ mysql_file_write(file, screen_buff, info_length, MYF_RW) ||
pack_fields(file, create_fields, data_offset))
goto err;
@@ -322,32 +364,32 @@ bool mysql_create_frm(THD *thd, const char *file_name,
{
char tmp=2,*disk_buff=0;
SQL_CRYPT *crypted=new SQL_CRYPT(create_info->password);
- if (!crypted || my_pwrite(file,&tmp,1,26,MYF_RW)) // Mark crypted
+ if (!crypted || mysql_file_pwrite(file, &tmp, 1, 26, MYF_RW))// Mark crypted
goto err;
uint read_length=uint2korr(forminfo)-256;
- VOID(my_seek(file,filepos+256,MY_SEEK_SET,MYF(0)));
+ mysql_file_seek(file, filepos+256, MY_SEEK_SET, MYF(0));
if (read_string(file,(uchar**) &disk_buff,read_length))
goto err;
crypted->encode(disk_buff,read_length);
delete crypted;
- if (my_pwrite(file,disk_buff,read_length,filepos+256,MYF_RW))
+ if (mysql_file_pwrite(file, disk_buff, read_length, filepos+256, MYF_RW))
{
- my_free(disk_buff,MYF(0));
+ my_free(disk_buff);
goto err;
}
- my_free(disk_buff,MYF(0));
+ my_free(disk_buff);
}
#endif
- my_free(screen_buff,MYF(0));
- my_free(keybuff, MYF(0));
+ my_free(screen_buff);
+ my_free(keybuff);
if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
- (my_sync(file, MYF(MY_WME)) ||
+ (mysql_file_sync(file, MYF(MY_WME)) ||
my_sync_dir_by_file(file_name, MYF(MY_WME))))
goto err2;
- if (my_close(file,MYF(MY_WME)))
+ if (mysql_file_close(file, MYF(MY_WME)))
goto err3;
{
@@ -369,12 +411,12 @@ bool mysql_create_frm(THD *thd, const char *file_name,
DBUG_RETURN(0);
err:
- my_free(screen_buff, MYF(0));
- my_free(keybuff, MYF(0));
+ my_free(screen_buff);
+ my_free(keybuff);
err2:
- VOID(my_close(file,MYF(MY_WME)));
+ (void) mysql_file_close(file, MYF(MY_WME));
err3:
- my_delete(file_name,MYF(0));
+ mysql_file_delete(key_file_frm, file_name, MYF(0));
DBUG_RETURN(1);
} /* mysql_create_frm */
@@ -426,8 +468,8 @@ int rea_create_table(THD *thd, const char *path,
DBUG_RETURN(0);
err_handler:
- VOID(file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info));
- my_delete(frm_name, MYF(0));
+ (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info);
+ mysql_file_delete(key_file_frm, frm_name, MYF(0));
DBUG_RETURN(1);
} /* rea_create_table */
@@ -562,6 +604,16 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
pos=tmp;
}
*(pos++)=0;
+ for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
+ {
+ if (key->flags & HA_USES_COMMENT)
+ {
+ int2store(pos, key->comment.length);
+ uchar *tmp= (uchar*)strnmov((char*) pos+2,key->comment.str,
+ key->comment.length);
+ pos= tmp;
+ }
+ }
if (key_count > 127 || key_parts > 127)
{
@@ -615,19 +667,23 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
field->comment.str,
field->comment.str +
field->comment.length,
- 255);
+ COLUMN_COMMENT_MAXLEN);
if (tmp_len < field->comment.length)
{
if ((current_thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
{
- my_error(ER_TOO_LONG_FIELD_COMMENT, MYF(0), field->field_name, tmp_len);
+ my_error(ER_TOO_LONG_FIELD_COMMENT, MYF(0),
+ field->field_name, (uint) COLUMN_COMMENT_MAXLEN);
DBUG_RETURN(1);
}
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TOO_LONG_FIELD_COMMENT,
- ER(ER_TOO_LONG_FIELD_COMMENT),
- field->field_name, tmp_len);
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_FIELD_COMMENT),
+ field->field_name, (uint) COLUMN_COMMENT_MAXLEN);
+ /* do not push duplicate warnings */
+ if (!check_duplicate_warning(current_thd, warn_buff, strlen(warn_buff)))
+ push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TOO_LONG_FIELD_COMMENT, warn_buff);
field->comment.length= tmp_len;
}
@@ -802,30 +858,37 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
recpos= field->offset+1 + (uint) data_offset;
int3store(buff+5,recpos);
int2store(buff+8,field->pack_flag);
- int2store(buff+10,field->unireg_check);
+ DBUG_ASSERT(field->unireg_check < 256);
+ buff[10]= (uchar) field->unireg_check;
buff[12]= (uchar) field->interval_id;
buff[13]= (uchar) field->sql_type;
if (field->sql_type == MYSQL_TYPE_GEOMETRY)
{
+ buff[11]= 0;
buff[14]= (uchar) field->geom_type;
#ifndef HAVE_SPATIAL
DBUG_ASSERT(0); // Should newer happen
#endif
}
else if (field->charset)
+ {
+ buff[11]= (uchar) (field->charset->number >> 8);
buff[14]= (uchar) field->charset->number;
+ }
else
- buff[14]= 0; // Numerical
+ {
+ buff[11]= buff[14]= 0; // Numerical
+ }
int2store(buff+15, field->comment.length);
comment_length+= field->comment.length;
set_if_bigger(int_count,field->interval_id);
- if (my_write(file, buff, FCOMP, MYF_RW))
+ if (mysql_file_write(file, buff, FCOMP, MYF_RW))
DBUG_RETURN(1);
}
/* Write fieldnames */
buff[0]=(uchar) NAMES_SEP_CHAR;
- if (my_write(file, buff, 1, MYF_RW))
+ if (mysql_file_write(file, buff, 1, MYF_RW))
DBUG_RETURN(1);
i=0;
it.rewind();
@@ -835,7 +898,7 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
*pos++=NAMES_SEP_CHAR;
if (i == create_fields.elements-1)
*pos++=0;
- if (my_write(file, buff, (size_t) (pos-(char*) buff),MYF_RW))
+ if (mysql_file_write(file, buff, (size_t) (pos-(char*) buff), MYF_RW))
DBUG_RETURN(1);
i++;
}
@@ -895,7 +958,7 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
tmp.append('\0'); // End of intervall
}
}
- if (my_write(file,(uchar*) tmp.ptr(),tmp.length(),MYF_RW))
+ if (mysql_file_write(file, (uchar*) tmp.ptr(), tmp.length(), MYF_RW))
DBUG_RETURN(1);
}
if (comment_length)
@@ -905,8 +968,8 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
while ((field=it++))
{
if (field->comment.length)
- if (my_write(file, (uchar*) field->comment.str, field->comment.length,
- MYF_RW))
+ if (mysql_file_write(file, (uchar*) field->comment.str,
+ field->comment.length, MYF_RW))
DBUG_RETURN(1);
}
}
@@ -1029,10 +1092,10 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
if (null_count & 7)
*(null_pos + null_count / 8)|= ~(((uchar) 1 << (null_count & 7)) - 1);
- error= my_write(file, buff, (size_t) reclength,MYF_RW) != 0;
+ error= mysql_file_write(file, buff, (size_t) reclength, MYF_RW) != 0;
err:
- my_free(buff, MYF(MY_FAE));
+ my_free(buff);
thd->count_cuted_fields= old_count_cuted_fields;
DBUG_RETURN(error);
} /* make_empty_rec */
diff --git a/sql/unireg.h b/sql/unireg.h
index 4f6b647964d..b897c887c89 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -1,3 +1,6 @@
+#ifndef UNIREG_INCLUDED
+#define UNIREG_INCLUDED
+
/* Copyright (C) 2000-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@@ -14,9 +17,12 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "my_global.h" /* ulonglong */
+#include "mysql_version.h" /* FRM_VER */
+
/* Extra functions used by unireg library */
-#ifndef _unireg_h
+typedef struct st_ha_create_information HA_CREATE_INFO;
#ifndef NO_ALARM_LOOP
#define NO_ALARM_LOOP /* lib5 and popen can't use alarm */
@@ -39,76 +45,18 @@
#define PLUGINDIR "lib/plugin"
#endif
-#define ER(X) errmesg[(X) - ER_ERROR_FIRST]
+#define CURRENT_THD_ERRMSGS current_thd->variables.lc_messages->errmsgs->errmsgs
+#define DEFAULT_ERRMSGS my_default_lc_messages->errmsgs->errmsgs
+
+#define ER(X) CURRENT_THD_ERRMSGS[(X) - ER_ERROR_FIRST]
+#define ER_DEFAULT(X) DEFAULT_ERRMSGS[(X) - ER_ERROR_FIRST]
#define ER_SAFE(X) (((X) >= ER_ERROR_FIRST && (X) <= ER_ERROR_LAST) ? ER(X) : "Invalid error code")
+#define ER_THD(thd,X) ((thd)->variables.lc_messages->errmsgs->errmsgs[(X) - \
+ ER_ERROR_FIRST])
+#define ER_THD_OR_DEFAULT(thd,X) ((thd) ? ER_THD(thd, X) : ER_DEFAULT(X))
#define ERRMAPP 1 /* Errormap f|r my_error */
-#define LIBLEN FN_REFLEN-FN_LEN /* Max l{ngd p} dev */
-/* extra 4+4 bytes for slave tmp tables */
-#define MAX_DBKEY_LENGTH (NAME_LEN*2+1+1+4+4)
-#define MAX_ALIAS_NAME 256
-#define MAX_FIELD_NAME 34 /* Max colum name length +2 */
-#define MAX_SYS_VAR_LENGTH 32
-#define MAX_KEY MAX_INDEXES /* Max used keys */
-#define MAX_REF_PARTS 16 /* Max parts used as ref */
-#define MAX_KEY_LENGTH 3072 /* max possible key */
-#if SIZEOF_OFF_T > 4
-#define MAX_REFLENGTH 8 /* Max length for record ref */
-#else
-#define MAX_REFLENGTH 4 /* Max length for record ref */
-#endif
-#define MAX_HOSTNAME 61 /* len+1 in mysql.user */
-
-#define MAX_MBWIDTH 3 /* Max multibyte sequence */
-#define MAX_FIELD_CHARLENGTH 255
-#define MAX_FIELD_VARCHARLENGTH 65535
-#define MAX_FIELD_BLOBLENGTH UINT_MAX32 /* cf field_blob::get_length() */
-#define CONVERT_IF_BIGGER_TO_BLOB 512 /* Used for CREATE ... SELECT */
-
-/* Max column width +1 */
-#define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1)
-
-#define MAX_BIT_FIELD_LENGTH 64 /* Max length in bits for bit fields */
-
-#define MAX_DATE_WIDTH 10 /* YYYY-MM-DD */
-#define MAX_TIME_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */
-#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */
-#define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */
-#define MAX_DATETIME_COMPRESSED_WIDTH 14 /* YYYYMMDDHHMMSS */
-
-#define MAX_TABLES (sizeof(table_map)*8-3) /* Max tables in join */
-#define PARAM_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-3))
-#define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2))
-#define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1))
-#define PSEUDO_TABLE_BITS (PARAM_TABLE_BIT | OUTER_REF_TABLE_BIT | \
- RAND_TABLE_BIT)
-#define MAX_FIELDS 4096 /* Limit in the .frm file */
-#define MAX_PARTITIONS 1024
-
-#define MAX_SELECT_NESTING (sizeof(nesting_map)*8-1)
-
-#define MAX_SORT_MEMORY (2048*1024-MALLOC_OVERHEAD)
-#define MIN_SORT_MEMORY (32*1024-MALLOC_OVERHEAD)
-
-/* Memory allocated when parsing a statement / saving a statement */
-#define MEM_ROOT_BLOCK_SIZE 8192
-#define MEM_ROOT_PREALLOC 8192
-#define TRANS_MEM_ROOT_BLOCK_SIZE 4096
-#define TRANS_MEM_ROOT_PREALLOC 4096
-
-#define DEFAULT_ERROR_COUNT 64
-#define EXTRA_RECORDS 10 /* Extra records in sort */
-#define SCROLL_EXTRA 5 /* Extra scroll-rows. */
-#define FIELD_NAME_USED ((uint) 32768) /* Bit set if fieldname used */
-#define FORM_NAME_USED ((uint) 16384) /* Bit set if formname used */
-#define FIELD_NR_MASK 16383 /* To get fieldnumber */
-#define FERR -1 /* Error from my_functions */
-#define CREATE_MODE 0 /* Default mode on new files */
-#define NAMES_SEP_CHAR '\377' /* Char to sep. names */
-
-#define READ_RECORD_BUFFER (uint) (IO_SIZE*8) /* Pointer_buffer_size */
-#define DISK_BUFFER_SIZE (uint) (IO_SIZE*16) /* Size of diskbuffer */
#define ME_INFO (ME_HOLDTANG+ME_OLDWIN+ME_NOREFRESH)
#define ME_ERROR (ME_BELL+ME_OLDWIN+ME_NOREFRESH)
@@ -121,7 +69,7 @@
#define SPECIAL_SAME_DB_NAME 16 /* form name = file name */
#define SPECIAL_ENGLISH 32 /* English error messages */
#define SPECIAL_NO_RESOLVE 64 /* Don't use gethostname */
-#define SPECIAL_NO_PRIOR 128 /* Don't prioritize threads */
+#define SPECIAL_NO_PRIOR 128 /* Obsolete */
#define SPECIAL_BIG_SELECTS 256 /* Don't use heap tables */
#define SPECIAL_NO_HOST_CACHE 512 /* Don't cache hosts */
#define SPECIAL_SHORT_LOG_FORMAT 1024
@@ -189,11 +137,15 @@
*/
#define OPTIMIZE_I_S_TABLE OPEN_VIEW_FULL*2
+/*
+ The flag means that we need to process trigger files only.
+*/
+#define OPEN_TRIGGER_ONLY OPTIMIZE_I_S_TABLE*2
+
#define SC_INFO_LENGTH 4 /* Form format constant */
#define TE_INFO_LENGTH 3
#define MTYP_NOEMPTY_BIT 128
-#define FRM_VER_TRUE_VARCHAR (FRM_VER+4) /* 10 */
/*
Minimum length pattern before Turbo Boyer-Moore is used
for SELECT "text" LIKE "%pattern%", excluding the two
@@ -208,7 +160,6 @@
*/
#define BIN_LOG_HEADER_SIZE 4
-#define FLOATING_POINT_BUFFER 331
#define DEFAULT_KEY_CACHE_NAME "default"
@@ -216,5 +167,18 @@
#include "mysqld_error.h"
#include "structs.h" /* All structs we need */
-
+#include "sql_list.h" /* List<> */
+#include "field.h" /* Create_field */
+
+bool mysql_create_frm(THD *thd, const char *file_name,
+ const char *db, const char *table,
+ HA_CREATE_INFO *create_info,
+ List<Create_field> &create_field,
+ uint key_count,KEY *key_info,handler *db_type);
+int rea_create_table(THD *thd, const char *path,
+ const char *db, const char *table_name,
+ HA_CREATE_INFO *create_info,
+ List<Create_field> &create_field,
+ uint key_count,KEY *key_info,
+ handler *file);
#endif